ShortPixel Image Optimizer - Version 5.0.8

Version Description

Release date August 8th, 2022 * Fix: the Previous Bulks now displays the number of credits used instead of the number of Media Library items, to avoid confusion; * Fix: the notification for migrating the old format of optimization information was not getting triggered anymore; * Fix: excluded images and/or thumbnails can now be restored from the backup; * Fix: added prevention for double database queries when checking if an item is already in the queue; * Fix: the bulk restore and bulk migration of optimization data can now be done even if out of credits; * Fix: reduced the number of database table checks done on wp-admin pages to the minimum possible; * Fix: the out-of-quota message was not always showing up properly; * Fix: the bulk migration of the optimization data now marks as optimized the images that have proper backups in place; * Fix: the thousands separators are now displayed properly for all languages; * Fix: the optimized/unoptimized Media Library filter has proper pagination and also works with WPML; * Fix: in case the optimization percentage is an integer, drop the .00 (83.00% -> 83%); * Fix: improved the settings and bulk pages load time for sites with a huge number of items in the Media Library; * Fix: properly save the optimization information even if the filename is huge; * Fix: the Optimize now button wasn't showing up on Custom Media right after restoring an item from the backup; * Fix: more fixes for multisite installs where the old blogs.dir folder structure is used; * Fix: multiple fixes and improvements for WP-CLI, including more detailed embedded docs and examples; * Fix: multiple fixes and improvements to the whole exclusions module; * Fix: multiple fixes and improvements in handling how retina images are optimized; * Fix: various small fixes and improvements to the debug mode of the plugin; * Tweak: CTRL+S can now be used to save settings (you're welcome!); * Tweak: added support for bulk processing via the processing hook; * Tweak: various wording and text updates in the plugin and the readme file; * Language: 10 new strings added, 8 updated, 0 fuzzed, and 2 obsoleted.

Download this release

Release Info

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

Code changes from version 5.0.7 to 5.0.8

Files changed (54) hide show
  1. build/shortpixel/log/src/ShortPixelLogger.php +40 -5
  2. build/shortpixel/notices/src/NoticeModel.php +6 -6
  3. build/shortpixel/shortq/src/Queue/WPQ.php +1 -1
  4. class/BuildAutoLoader.php +1 -0
  5. class/Controller/AdminController.php +5 -0
  6. class/Controller/AdminNoticesController.php +18 -12
  7. class/Controller/AjaxController.php +1 -16
  8. class/Controller/ApiController.php +1 -1
  9. class/Controller/BulkController.php +12 -1
  10. class/Controller/FileSystemController.php +9 -0
  11. class/Controller/OptimizeController.php +49 -24
  12. class/Controller/Queue/Queue.php +25 -8
  13. class/Controller/QuotaController.php +5 -5
  14. class/Controller/ResponseController.php +26 -5
  15. class/Controller/SettingsController.php +2 -1
  16. class/Controller/View/BulkViewController.php +4 -1
  17. class/Controller/View/EditMediaViewController.php +2 -1
  18. class/Controller/View/ListMediaViewController.php +7 -2
  19. class/Helper/InstallHelper.php +8 -13
  20. class/Helper/UiHelper.php +16 -8
  21. class/Model/EnvironmentModel.php +1 -1
  22. class/Model/Image/CustomImageModel.php +3 -4
  23. class/Model/Image/ImageModel.php +24 -5
  24. class/Model/Image/MediaLibraryModel.php +334 -82
  25. class/Model/Image/MediaLibraryThumbnailModel.php +18 -19
  26. class/Model/StatsModel.php +18 -1
  27. class/external/cache.php +153 -0
  28. class/external/gravityforms.php +23 -8
  29. class/external/wp-cli/wp-cli-base.php +46 -31
  30. class/external/wp-cli/wp-cli-bulk.php +67 -47
  31. class/external/wp-cli/wp-cli-single.php +8 -5
  32. class/front/img-to-picture-webp.php +2 -3
  33. class/plugin.json +1 -1
  34. class/view/bulk/part-selection.php +10 -3
  35. class/view/bulk/part-summary.php +2 -2
  36. class/view/settings/part-advanced.php +59 -43
  37. class/view/settings/part-debug.php +1 -0
  38. class/wp-shortpixel-settings.php +2 -8
  39. readme.txt +39 -7
  40. res/css/shortpixel-admin.css +4 -0
  41. res/css/shortpixel-admin.css.map +1 -1
  42. res/css/shortpixel-bulk.css +3 -0
  43. res/css/shortpixel-bulk.css.map +1 -1
  44. res/css/shortpixel-othermedia.css +4 -1
  45. res/css/shortpixel-othermedia.css.map +1 -1
  46. res/js/screens/screen-bulk.js +8 -2
  47. res/js/shortpixel-processor.js +11 -1
  48. res/js/shortpixel-settings.js +30 -1
  49. res/js/shortpixel.js +1 -1
  50. res/scss/shortpixel-admin.scss +5 -0
  51. res/scss/shortpixel-bulk.scss +6 -0
  52. res/scss/shortpixel-othermedia.scss +6 -1
  53. shortpixel-plugin.php +5 -5
  54. wp-shortpixel.php +3 -2
build/shortpixel/log/src/ShortPixelLogger.php CHANGED
@@ -24,6 +24,8 @@ namespace ShortPixel\ShortPixelLogger;
24
  protected $format_data = "\t %%data%% ";
25
 
26
  protected $hooks = array();
 
 
27
  /* protected $hooks = array(
28
  'shortpixel_image_exists' => array('numargs' => 3),
29
  'shortpixel_webp_image_base' => array('numargs' => 2),
@@ -78,8 +80,6 @@ namespace ShortPixel\ShortPixelLogger;
78
 
79
  if (defined('SHORTPIXEL_DEBUG_TARGET') && SHORTPIXEL_DEBUG_TARGET || $this->is_manual_request)
80
  {
81
- //$this->logPath = SHORTPIXEL_BACKUP_FOLDER . "/shortpixel_log";
82
- //$this->logMode = defined('SHORTPIXEL_LOG_OVERWRITE') ? 0 : FILE_APPEND;
83
  if (defined('SHORTPIXEL_LOG_OVERWRITE')) // if overwrite, do this on init once.
84
  file_put_contents($this->logPath,'-- Log Reset -- ' .PHP_EOL);
85
 
@@ -130,6 +130,7 @@ namespace ShortPixel\ShortPixelLogger;
130
  public function setLogPath($logPath)
131
  {
132
  $this->logPath = $logPath;
 
133
  }
134
  protected function addLog($message, $level, $data = array())
135
  {
@@ -187,16 +188,50 @@ namespace ShortPixel\ShortPixelLogger;
187
 
188
  $line = $this->formatLine($items);
189
 
 
 
190
  // try to write to file. Don't write if directory doesn't exists (leads to notices)
191
- if ($this->logPath && is_dir(dirname($this->logPath)) )
192
  {
193
- file_put_contents($this->logPath,$line, FILE_APPEND);
 
194
  }
195
  else {
196
- error_log($line);
197
  }
198
  }
199
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
200
  protected function formatLine($args = array() )
201
  {
202
  $line= $this->format;
24
  protected $format_data = "\t %%data%% ";
25
 
26
  protected $hooks = array();
27
+
28
+ private $logFile; // pointer resource to the logFile.
29
  /* protected $hooks = array(
30
  'shortpixel_image_exists' => array('numargs' => 3),
31
  'shortpixel_webp_image_base' => array('numargs' => 2),
80
 
81
  if (defined('SHORTPIXEL_DEBUG_TARGET') && SHORTPIXEL_DEBUG_TARGET || $this->is_manual_request)
82
  {
 
 
83
  if (defined('SHORTPIXEL_LOG_OVERWRITE')) // if overwrite, do this on init once.
84
  file_put_contents($this->logPath,'-- Log Reset -- ' .PHP_EOL);
85
 
130
  public function setLogPath($logPath)
131
  {
132
  $this->logPath = $logPath;
133
+ $this->getWriteFile(true); // reset the writeFile here.
134
  }
135
  protected function addLog($message, $level, $data = array())
136
  {
188
 
189
  $line = $this->formatLine($items);
190
 
191
+ $file = $this->getWriteFile();
192
+
193
  // try to write to file. Don't write if directory doesn't exists (leads to notices)
194
+ if ($file )
195
  {
196
+ fwrite($file, $line);
197
+ // file_put_contents($this->logPath,$line, FILE_APPEND);
198
  }
199
  else {
200
+ // error_log($line);
201
  }
202
  }
203
 
204
+ protected function getWriteFile($reset = false)
205
+ {
206
+ if (! is_null($this->logFile) && $reset === false)
207
+ {
208
+ return $this->logFile;
209
+ }
210
+ elseif(is_object($this->logFile))
211
+ {
212
+ fclose($this->logFile);
213
+ }
214
+
215
+ $logDir = dirname($this->logPath);
216
+ if (! is_dir($logDir) || ! is_writable($logDir))
217
+ {
218
+ error_log('ShortpixelLogger: Log Directory is not writable');
219
+ $this->logFile = false;
220
+ return false;
221
+ }
222
+
223
+ $file = fopen($this->logPath, 'a');
224
+ if ($file === false)
225
+ {
226
+ error_log('ShortpixelLogger: File could not be opened / created: ' . $this->logPath);
227
+ $this->logFile = false;
228
+ return $file;
229
+ }
230
+
231
+ $this->logFile = $file;
232
+ return $file;
233
+ }
234
+
235
  protected function formatLine($args = array() )
236
  {
237
  $line= $this->format;
build/shortpixel/notices/src/NoticeModel.php CHANGED
@@ -234,9 +234,9 @@ class NoticeModel //extends ShortPixelModel
234
  document.getElementById('button-$id').onclick = function()
235
  {
236
  var el = document.getElementById('$id');
237
- jQuery(el).fadeTo(100,0,function() {
238
- jQuery(el).slideUp(100, 0, function () {
239
- jQuery(el).remove();
240
  })
241
  });
242
  } </script>";
@@ -289,9 +289,9 @@ class NoticeModel //extends ShortPixelModel
289
  data.id = parent.getAttribute('id');
290
  jQuery.post($url,data);
291
 
292
- jQuery(parent).fadeTo(100,0,function() {
293
- jQuery(parent).slideUp(100, 0, function () {
294
- jQuery(parent).remove();
295
  })
296
  });
297
  }";
234
  document.getElementById('button-$id').onclick = function()
235
  {
236
  var el = document.getElementById('$id');
237
+ $(el).fadeTo(100,0,function() {
238
+ $(el).slideUp(100, 0, function () {
239
+ $(el).remove();
240
  })
241
  });
242
  } </script>";
289
  data.id = parent.getAttribute('id');
290
  jQuery.post($url,data);
291
 
292
+ $(parent).fadeTo(100,0,function() {
293
+ $(parent).slideUp(100, 0, function () {
294
+ $(parent).remove();
295
  })
296
  });
297
  }";
build/shortpixel/shortq/src/Queue/WPQ.php CHANGED
@@ -486,7 +486,7 @@ class WPQ implements Queue
486
  {
487
  $this->status = get_option($this->statusName);
488
 
489
- if (! $this->status || ! is_object($this->status))
490
  $this->createStatus();
491
 
492
 
486
  {
487
  $this->status = get_option($this->statusName);
488
 
489
+ if (! $this->status || ! is_object($this->status) && ! is_array($this->status))
490
  $this->createStatus();
491
 
492
 
class/BuildAutoLoader.php CHANGED
@@ -69,6 +69,7 @@ class BuildAutoLoader
69
  'class/external/custom-suffixes.php',
70
  'class/external/pantheon.php',
71
  'class/external/spai.php',
 
72
  );
73
 
74
  echo "Build Plugin.JSON ";
69
  'class/external/custom-suffixes.php',
70
  'class/external/pantheon.php',
71
  'class/external/spai.php',
72
+ 'class/external/cache.php',
73
  );
74
 
75
  echo "Build Plugin.JSON ";
class/Controller/AdminController.php CHANGED
@@ -75,6 +75,7 @@ class AdminController extends \ShortPixel\Controller
75
  'wait' => 3, // amount of time to wait for next round. Prevents high loads
76
  'run_once' => false, // If true queue must be run at least every few minutes. If false, it tries to complete all.
77
  'queues' => array('media','custom'),
 
78
  );
79
 
80
  if (wp_doing_cron())
@@ -85,6 +86,10 @@ class AdminController extends \ShortPixel\Controller
85
  $args = wp_parse_args($args, $defaults);
86
 
87
  $control = new OptimizeController();
 
 
 
 
88
 
89
  if ($args['run_once'] === true)
90
  {
75
  'wait' => 3, // amount of time to wait for next round. Prevents high loads
76
  'run_once' => false, // If true queue must be run at least every few minutes. If false, it tries to complete all.
77
  'queues' => array('media','custom'),
78
+ 'bulk' => false,
79
  );
80
 
81
  if (wp_doing_cron())
86
  $args = wp_parse_args($args, $defaults);
87
 
88
  $control = new OptimizeController();
89
+ if ($args['bulk'] === true)
90
+ {
91
+ $control->setBulk(true);
92
+ }
93
 
94
  if ($args['run_once'] === true)
95
  {
class/Controller/AdminNoticesController.php CHANGED
@@ -44,6 +44,7 @@ class AdminNoticesController extends \ShortPixel\Controller
44
  private $remote_message_endpoint = 'https://api.shortpixel.com/v2/notices.php';
45
  private $remote_readme_endpoint = 'https://plugins.svn.wordpress.org/shortpixel-image-optimiser/trunk/readme.txt';
46
 
 
47
  public function __construct()
48
  {
49
  add_action('admin_notices', array($this, 'displayNotices'), 50); // notices occured before page load
@@ -290,11 +291,19 @@ class AdminNoticesController extends \ShortPixel\Controller
290
  // Called by MediaLibraryModel
291
  public function invokeLegacyNotice()
292
  {
293
- $message = '<p><strong>' . __('ShortPixel found items in media library with a legacy optimization format!', 'shortpixel-image-optimiser') . '</strong></p>';
 
 
 
 
 
 
 
 
294
 
295
  $message .= '<p>' . __('Prior to version 5.0, a different format was used to store ShortPixel optimization information. ShortPixel automatically migrates the media library items to the new format when they are opened. %s Please check if your images contain the optimization information after the migration. %s Read more %s', 'shortpixel-image-optimiser') . '</p>';
296
 
297
- $message .= '<p>' . __('It is recommended to migrate all items to the modern format by clicking on the button below.', 'shortpixekl-image-optimser') . '</p>';
298
  $message .= '<p><a href="%s" class="button button-primary">%s</a></p>';
299
 
300
  $read_link = esc_url('https://shortpixel.com/knowledge-base/article/539-spio-5-tells-me-to-convert-legacy-data-what-is-this');
@@ -328,6 +337,7 @@ class AdminNoticesController extends \ShortPixel\Controller
328
  $noticeController = Notices::getInstance();
329
  $statsControl = StatsController::getInstance(); // @todo Implement this. (Figure out what this was )
330
 
 
331
 
332
  if (! \wpSPIO()->settings()->verifiedKey)
333
  {
@@ -362,7 +372,7 @@ class AdminNoticesController extends \ShortPixel\Controller
362
  //looks like the user hasn't got enough credits to process the monthly images, display a notice telling this
363
  $message = $this->getMonthlyUpgradeMessage(array('monthAvg' => $this->getMonthAvg(), 'monthlyQuota' => $quotaData->monthly->total, 'onetimeTotal' => $quotaData->onetime->remaining ));
364
  $notice = Notices::addNormal($message);
365
- Notices::makePersistent($notice, self::MSG_UPGRADE_MONTH, YEAR_IN_SECONDS);
366
  }
367
  }
368
  }
@@ -374,7 +384,7 @@ class AdminNoticesController extends \ShortPixel\Controller
374
  {
375
  $message = $this->getQuotaExceededMessage();
376
  $notice = Notices::addError($message);
377
- Notices::makePersistent($notice, self::MSG_QUOTA_REACHED, WEEK_IN_SECONDS);
378
  }
379
 
380
  Notices::removeNoticeByID(self::MSG_UPGRADE_MONTH); // get rid of doubles. reset
@@ -538,6 +548,7 @@ class AdminNoticesController extends \ShortPixel\Controller
538
  return $message;
539
  }
540
 
 
541
  protected function getBulkUpgradeMessage($extra)
542
  {
543
  $message = '<p>' . sprintf(__("You currently have <strong>%d images and thumbnails to optimize</strong> but you only have <strong>%d images</strong> available in your current plan."
@@ -546,13 +557,12 @@ class AdminNoticesController extends \ShortPixel\Controller
546
  $this->proposeUpgradePopup();
547
  return $message;
548
  }
549
-
550
  protected function getMonthlyUpgradeMessage($extra)
551
  {
552
  $message = '<p>' . sprintf(__("You are adding an average of <strong>%d images and thumbnails every month</strong> to your Media Library and you have <strong>a plan of %d images/month (and %d one-time images)</strong>.%s"
553
  . " You might need to upgrade your plan in order to have all your images optimized.", 'shortpixel-image-optimiser'), $extra['monthAvg'], $extra['monthlyQuota'], $extra['onetimeTotal'], '<br>') . '</p>';
554
  $message .= ' <button class="button button-primary" id="shortpixel-upgrade-advice" onclick="ShortPixel.proposeUpgrade()" style="margin-right:10px;"><strong>' . __('Show me the best available options', 'shortpixel-image-optimiser') . '</strong></button>';
555
- $this->proposeUpgradePopup();
556
  return $message;
557
  }
558
 
@@ -623,12 +633,10 @@ class AdminNoticesController extends \ShortPixel\Controller
623
  </div>';
624
 
625
  $message .= '</div>'; /// closing div
626
- $this->proposeUpgradePopup();
627
  return $message;
628
  }
629
 
630
- protected function proposeUpgradePopup() {
631
- // @todo LoadView Snippet here.
632
  $view = new ViewController();
633
  $view->loadView('snippets/part-upgrade-options');
634
  }
@@ -722,8 +730,6 @@ class AdminNoticesController extends \ShortPixel\Controller
722
 
723
  protected function monthlyUpgradeNeeded($quotaData)
724
  {
725
-
726
-
727
  if (isset($quotaData->monthly->total))
728
  {
729
  $monthAvg = $this->getMonthAvg($quotaData);
@@ -752,7 +758,7 @@ class AdminNoticesController extends \ShortPixel\Controller
752
 
753
  protected function getMonthAvg() {
754
  $stats = StatsController::getInstance();
755
-
756
  // Count how many months have some optimized images.
757
  for($i = 4, $count = 0; $i>=1; $i--) {
758
  if($count == 0 && $stats->find('period', 'months', $i) == 0)
44
  private $remote_message_endpoint = 'https://api.shortpixel.com/v2/notices.php';
45
  private $remote_readme_endpoint = 'https://plugins.svn.wordpress.org/shortpixel-image-optimiser/trunk/readme.txt';
46
 
47
+
48
  public function __construct()
49
  {
50
  add_action('admin_notices', array($this, 'displayNotices'), 50); // notices occured before page load
291
  // Called by MediaLibraryModel
292
  public function invokeLegacyNotice()
293
  {
294
+ $noticeController = Notices::getInstance();
295
+
296
+ $notice = $noticeController->getNoticeByID(self::MSG_CONVERT_LEGACY);
297
+ Log::addTemp('Legacy Notice', $notice);
298
+ // If already in system, don't bother doing it again.
299
+ if ($notice !== false)
300
+ return;
301
+
302
+ $message = '<p><strong>' . __('ShortPixel found items in media library with a legacy optimization format!', 'shortpixel-image-optimiser') . '</strong></p>';
303
 
304
  $message .= '<p>' . __('Prior to version 5.0, a different format was used to store ShortPixel optimization information. ShortPixel automatically migrates the media library items to the new format when they are opened. %s Please check if your images contain the optimization information after the migration. %s Read more %s', 'shortpixel-image-optimiser') . '</p>';
305
 
306
+ $message .= '<p>' . __('It is recommended to migrate all items to the modern format by clicking on the button below.', 'shortpixel-image-optimser') . '</p>';
307
  $message .= '<p><a href="%s" class="button button-primary">%s</a></p>';
308
 
309
  $read_link = esc_url('https://shortpixel.com/knowledge-base/article/539-spio-5-tells-me-to-convert-legacy-data-what-is-this');
337
  $noticeController = Notices::getInstance();
338
  $statsControl = StatsController::getInstance(); // @todo Implement this. (Figure out what this was )
339
 
340
+ $callback = array(AdminNoticesController::getInstance(), 'proposeUpgradePopup');
341
 
342
  if (! \wpSPIO()->settings()->verifiedKey)
343
  {
372
  //looks like the user hasn't got enough credits to process the monthly images, display a notice telling this
373
  $message = $this->getMonthlyUpgradeMessage(array('monthAvg' => $this->getMonthAvg(), 'monthlyQuota' => $quotaData->monthly->total, 'onetimeTotal' => $quotaData->onetime->remaining ));
374
  $notice = Notices::addNormal($message);
375
+ Notices::makePersistent($notice, self::MSG_UPGRADE_MONTH, YEAR_IN_SECONDS, $callback);
376
  }
377
  }
378
  }
384
  {
385
  $message = $this->getQuotaExceededMessage();
386
  $notice = Notices::addError($message);
387
+ Notices::makePersistent($notice, self::MSG_QUOTA_REACHED, WEEK_IN_SECONDS, $callback);
388
  }
389
 
390
  Notices::removeNoticeByID(self::MSG_UPGRADE_MONTH); // get rid of doubles. reset
548
  return $message;
549
  }
550
 
551
+ /* Seems unused @todo Remove in a few versions
552
  protected function getBulkUpgradeMessage($extra)
553
  {
554
  $message = '<p>' . sprintf(__("You currently have <strong>%d images and thumbnails to optimize</strong> but you only have <strong>%d images</strong> available in your current plan."
557
  $this->proposeUpgradePopup();
558
  return $message;
559
  }
560
+ */
561
  protected function getMonthlyUpgradeMessage($extra)
562
  {
563
  $message = '<p>' . sprintf(__("You are adding an average of <strong>%d images and thumbnails every month</strong> to your Media Library and you have <strong>a plan of %d images/month (and %d one-time images)</strong>.%s"
564
  . " You might need to upgrade your plan in order to have all your images optimized.", 'shortpixel-image-optimiser'), $extra['monthAvg'], $extra['monthlyQuota'], $extra['onetimeTotal'], '<br>') . '</p>';
565
  $message .= ' <button class="button button-primary" id="shortpixel-upgrade-advice" onclick="ShortPixel.proposeUpgrade()" style="margin-right:10px;"><strong>' . __('Show me the best available options', 'shortpixel-image-optimiser') . '</strong></button>';
 
566
  return $message;
567
  }
568
 
633
  </div>';
634
 
635
  $message .= '</div>'; /// closing div
 
636
  return $message;
637
  }
638
 
639
+ public function proposeUpgradePopup() {
 
640
  $view = new ViewController();
641
  $view->loadView('snippets/part-upgrade-options');
642
  }
730
 
731
  protected function monthlyUpgradeNeeded($quotaData)
732
  {
 
 
733
  if (isset($quotaData->monthly->total))
734
  {
735
  $monthAvg = $this->getMonthAvg($quotaData);
758
 
759
  protected function getMonthAvg() {
760
  $stats = StatsController::getInstance();
761
+
762
  // Count how many months have some optimized images.
763
  for($i = 4, $count = 0; $i>=1; $i--) {
764
  if($count == 0 && $stats->find('period', 'months', $i) == 0)
class/Controller/AjaxController.php CHANGED
@@ -157,11 +157,6 @@ class AjaxController
157
  $this->checkProcessorKey();
158
 
159
 
160
- if ($this->getProcessorKey() == 'shortpixel-test')
161
- {
162
- $this->returnTestData();
163
- }
164
-
165
  // Notice that POST variables are always string, so 'true', not true.
166
  // phpcs:ignore -- Nonce is checked
167
  $isBulk = (isset($_POST['isBulk']) && $_POST['isBulk'] === 'true') ? true : false;
@@ -498,7 +493,7 @@ class AjaxController
498
 
499
  // $this->ajax_getItemView();
500
 
501
- // Changed since updated function should detect what is what.
502
  // $mediaItem->deleteMeta(); // also does reset prevent.
503
  // delete_post_meta($id, '_shortpixel_was_converted');
504
 
@@ -732,16 +727,6 @@ class AjaxController
732
  exit();
733
  }
734
 
735
- private function returnTestData()
736
- {
737
- $is_error = rand(1, 10);
738
- $path = \wpSPIO()->plugin_path('tests/jsonresults/');
739
- $json = file_get_contents($path . 'error.json');
740
- $json = json_decode($json);
741
- wp_send_json($json);
742
-
743
-
744
- }
745
 
746
  private function removeAllData($json, $data)
747
  {
157
  $this->checkProcessorKey();
158
 
159
 
 
 
 
 
 
160
  // Notice that POST variables are always string, so 'true', not true.
161
  // phpcs:ignore -- Nonce is checked
162
  $isBulk = (isset($_POST['isBulk']) && $_POST['isBulk'] === 'true') ? true : false;
493
 
494
  // $this->ajax_getItemView();
495
 
496
+ // Changed since updated function should detect what is what.
497
  // $mediaItem->deleteMeta(); // also does reset prevent.
498
  // delete_post_meta($id, '_shortpixel_was_converted');
499
 
727
  exit();
728
  }
729
 
 
 
 
 
 
 
 
 
 
 
730
 
731
  private function removeAllData($json, $data)
732
  {
class/Controller/ApiController.php CHANGED
@@ -66,7 +66,7 @@ class ApiController
66
  */
67
  public function processMediaItem($item, $imageObj)
68
  {
69
- if (! $imageObj->isProcessable())
70
  {
71
  if ($imageObj->isOptimized())
72
  {
66
  */
67
  public function processMediaItem($item, $imageObj)
68
  {
69
+ if (! $imageObj->isProcessable() || $imageObj->isOptimizePrevented() == true)
70
  {
71
  if ($imageObj->isOptimized())
72
  {
class/Controller/BulkController.php CHANGED
@@ -36,8 +36,19 @@ class BulkController
36
  $optimizeController = new OptimizeController();
37
  $optimizeController->setBulk(true);
38
 
 
 
 
 
 
 
 
 
 
 
39
  $Q = $optimizeController->getQueue($type);
40
 
 
41
  $Q->createNewBulk(array());
42
 
43
  if (! is_null($customOp))
@@ -105,7 +116,7 @@ class BulkController
105
  $q->startBulk();
106
  }
107
 
108
- return $optimizeControl->processQueue(array($types));
109
  }
110
 
111
  public function finishBulk($type = 'media')
36
  $optimizeController = new OptimizeController();
37
  $optimizeController->setBulk(true);
38
 
39
+ $fs = \wpSPIO()->filesystem();
40
+ $backupDir = $fs->getDirectory(SHORTPIXEL_BACKUP_FOLDER);
41
+ $current_log = $fs->getFile($backupDir->getPath() . 'current_bulk_' . $type . '.log');
42
+
43
+ // When starting new bulk remove any open 'current logs';
44
+ if ($current_log->exists() && $current_log->is_writable())
45
+ {
46
+ $current_log->delete();
47
+ }
48
+
49
  $Q = $optimizeController->getQueue($type);
50
 
51
+
52
  $Q->createNewBulk(array());
53
 
54
  if (! is_null($customOp))
116
  $q->startBulk();
117
  }
118
 
119
+ return $optimizeControl->processQueue($types);
120
  }
121
 
122
  public function finishBulk($type = 'media')
class/Controller/FileSystemController.php CHANGED
@@ -265,7 +265,16 @@ Class FileSystemController extends \ShortPixel\Controller
265
  // This is used by getting preview path ( backup pathToUrl) in bulk and for comparer..
266
  elseif ($is_multi_site && ! $is_main_site && 0 === strpos($filepath, dirname(dirname($uploads['basedir']))) )
267
  {
 
268
  $url = str_replace( dirname(dirname($uploads['basedir'])), dirname(dirname($uploads['baseurl'])), $filepath );
 
 
 
 
 
 
 
 
269
 
270
  } elseif ( false !== strpos( $filepath, 'wp-content/uploads' ) ) {
271
  // Get the directory name relative to the basedir (back compat for pre-2.7 uploads)
265
  // This is used by getting preview path ( backup pathToUrl) in bulk and for comparer..
266
  elseif ($is_multi_site && ! $is_main_site && 0 === strpos($filepath, dirname(dirname($uploads['basedir']))) )
267
  {
268
+
269
  $url = str_replace( dirname(dirname($uploads['basedir'])), dirname(dirname($uploads['baseurl'])), $filepath );
270
+ $homeUrl = home_url();
271
+
272
+ // The result didn't end in a full URL because URL might have less subdirs ( dirname dirname) .
273
+ // This happens when site has blogs.dir (sigh) on a subdomain . Try to substitue the ABSPATH root with the home_url
274
+ if (strpos($url, $homeUrl) === false)
275
+ {
276
+ $url = str_replace( trailingslashit(ABSPATH), trailingslashit($homeUrl), $filepath);
277
+ }
278
 
279
  } elseif ( false !== strpos( $filepath, 'wp-content/uploads' ) ) {
280
  // Get the directory name relative to the basedir (back compat for pre-2.7 uploads)
class/Controller/OptimizeController.php CHANGED
@@ -150,21 +150,23 @@ class OptimizeController
150
  return $json;
151
  }
152
 
153
- /** Check if item is in queue.
154
  * @param Object $mediaItem
155
  */
156
  public function isItemInQueue($mediaItem)
157
  {
 
 
 
158
  $type = $mediaItem->get('type');
159
- $q = $this->getQueue($type);
160
 
161
- $result = $q->getShortQ()->getItem($mediaItem->get('id'));
162
 
163
- if (is_object($result))
164
- return true;
165
- else
166
- return false;
167
 
 
 
 
168
  }
169
 
170
  /** Restores an item
@@ -179,6 +181,8 @@ class OptimizeController
179
  $json->status = 0;
180
  $json->result = new \stdClass;
181
 
 
 
182
  if (! is_object($mediaItem)) // something wrong
183
  {
184
 
@@ -189,13 +193,21 @@ class OptimizeController
189
  $json->result->is_done = true;
190
  $json->result->is_error = true;
191
 
192
- ResponseController::addData($item->item_id, 'message', $item->result->message);
 
 
193
 
194
- Log::addWarn('Item with id ' . $json->result->item_id . ' is not restorable,');
195
 
196
  return $json;
197
  }
198
 
 
 
 
 
 
 
199
  $item_id = $mediaItem->get('id');
200
 
201
  $json->result->item_id = $item_id;
@@ -209,7 +221,7 @@ class OptimizeController
209
  else
210
  {
211
  $result = false;
212
- $json->result->message = $mediaItem->getReason('restorable');
213
  }
214
 
215
  // Compat for ancient WP
@@ -238,10 +250,8 @@ class OptimizeController
238
  else
239
  {
240
 
241
- if (! property_exists($json->result, 'message'))
242
- {
243
- $json->result->message = __('Item is not restorable', 'shortpixel-image-optimiser');
244
- }
245
  $json->result->is_done = true;
246
  $json->fileStatus = ImageModel::FILE_STATUS_ERROR;
247
  $json->result->is_error = true;
@@ -308,8 +318,8 @@ class OptimizeController
308
  */
309
  public function processQueue($queueTypes = array())
310
  {
311
-
312
  $keyControl = ApiKeyController::getInstance();
 
313
  if ($keyControl->keyIsVerified() === false)
314
  {
315
  $json = $this->getJsonResponse();
@@ -323,11 +333,28 @@ class OptimizeController
323
  $quotaControl = QuotaController::getInstance();
324
  if ($quotaControl->hasQuota() === false)
325
  {
326
- $json = $this->getJsonResponse();
327
- $json->error = AjaxController::NOQUOTA;
328
- $json->status = false;
329
- $json->message = __('Quota Exceeded','shortpixel-image-optimiser');
330
- return $json;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
331
  }
332
 
333
  // @todo Here prevent bulk from running when running flag is off
@@ -495,7 +522,8 @@ class OptimizeController
495
  }
496
  else
497
  {
498
- $item->result->filename = $imageItem->getFileName();
 
499
  ResponseController::addData($item->item_id, 'fileName', $imageItem->getFileName());
500
  }
501
 
@@ -614,9 +642,6 @@ class OptimizeController
614
  $item->result->optimized = $fs->pathToUrl($showItem);
615
  }
616
 
617
-
618
-
619
-
620
  }
621
  // This was not a request process, just handle it and mark it as done.
622
  elseif ($result->apiStatus == ApiController::STATUS_NOT_API)
150
  return $json;
151
  }
152
 
153
+ /** Check if item is in queue. || Only checks the single queue!
154
  * @param Object $mediaItem
155
  */
156
  public function isItemInQueue($mediaItem)
157
  {
158
+ if (! is_null($mediaItem->is_in_queue))
159
+ return $mediaItem->is_in_queue;
160
+
161
  $type = $mediaItem->get('type');
 
162
 
163
+ $q = $this->getQueue($type);
164
 
165
+ $bool = $q->isItemInQueue($mediaItem->get('id'));
 
 
 
166
 
167
+ // Preventing double queries here
168
+ $mediaItem->is_in_queue = $bool;
169
+ return $bool;
170
  }
171
 
172
  /** Restores an item
181
  $json->status = 0;
182
  $json->result = new \stdClass;
183
 
184
+ $item_id = $mediaItem->get('id');
185
+
186
  if (! is_object($mediaItem)) // something wrong
187
  {
188
 
193
  $json->result->is_done = true;
194
  $json->result->is_error = true;
195
 
196
+ ResponseController::addData($item_id, 'is_error', true);
197
+ ResponseController::addData($item_id, 'is_done', true);
198
+ ResponseController::addData($item_id, 'message', $item->result->message);
199
 
200
+ Log::addWarn('Item with id ' . $item_id . ' is not restorable,');
201
 
202
  return $json;
203
  }
204
 
205
+ $data = array(
206
+ 'item_type' => $mediaItem->get('type'),
207
+ 'fileName' => $mediaItem->getFileName(),
208
+ );
209
+ ResponseController::addData($item_id, $data);
210
+
211
  $item_id = $mediaItem->get('id');
212
 
213
  $json->result->item_id = $item_id;
221
  else
222
  {
223
  $result = false;
224
+ $json->result->message = ResponseController::formatItem($mediaItem->get('id')); // $mediaItem->getReason('restorable');
225
  }
226
 
227
  // Compat for ancient WP
250
  else
251
  {
252
 
253
+ $json->result->message = ResponseController::formatItem($mediaItem->get('id'));
254
+
 
 
255
  $json->result->is_done = true;
256
  $json->fileStatus = ImageModel::FILE_STATUS_ERROR;
257
  $json->result->is_error = true;
318
  */
319
  public function processQueue($queueTypes = array())
320
  {
 
321
  $keyControl = ApiKeyController::getInstance();
322
+
323
  if ($keyControl->keyIsVerified() === false)
324
  {
325
  $json = $this->getJsonResponse();
333
  $quotaControl = QuotaController::getInstance();
334
  if ($quotaControl->hasQuota() === false)
335
  {
336
+ // If we are doing something special (restore, migrate etc), it should runs without credits, so we shouldn't be using any.
337
+ $isCustomOperation = false;
338
+ foreach($queueTypes as $qType)
339
+ {
340
+ $queue = $this->getQueue($qType);
341
+ if ($queue && true === $queue->isCustomOperation())
342
+ {
343
+ $isCustomOperation = true;
344
+ break;
345
+ }
346
+ }
347
+
348
+ // Break out of quota if we are on normal operations.
349
+ if (false === $isCustomOperation )
350
+ {
351
+ $quotaControl->forceCheckRemoteQuota(); // on next load check if something happenend when out and asking.
352
+ $json = $this->getJsonResponse();
353
+ $json->error = AjaxController::NOQUOTA;
354
+ $json->status = false;
355
+ $json->message = __('Quota Exceeded','shortpixel-image-optimiser');
356
+ return $json;
357
+ }
358
  }
359
 
360
  // @todo Here prevent bulk from running when running flag is off
522
  }
523
  else
524
  {
525
+ //$item->result->filename = $imageItem->getFileName();
526
+ // Used in WP-CLI
527
  ResponseController::addData($item->item_id, 'fileName', $imageItem->getFileName());
528
  }
529
 
642
  $item->result->optimized = $fs->pathToUrl($showItem);
643
  }
644
 
 
 
 
645
  }
646
  // This was not a request process, just handle it and mark it as done.
647
  elseif ($result->apiStatus == ApiController::STATUS_NOT_API)
class/Controller/Queue/Queue.php CHANGED
@@ -29,13 +29,6 @@ abstract class Queue
29
  const RESULT_UNKNOWN = -10;
30
 
31
 
32
- /* Result status (per item) to communicate back to frontend */
33
- /* const FILE_NOTEXISTS = -1;
34
- const FILE_ALREADYOPTIMIZED = -2;
35
- const FILE_OK = 1;
36
- const FILE_SUCCESS = 2;
37
- const FILE_WAIT = 3; */
38
-
39
  abstract protected function prepare();
40
  abstract public function getType();
41
 
@@ -328,6 +321,8 @@ abstract class Queue
328
  $stats->is_finished = (bool) $this->getStatus('finished');
329
  $stats->in_queue = (int) $this->getStatus('items');
330
  $stats->in_process = (int) $this->getStatus('in_process');
 
 
331
  $stats->errors = (int) $this->getStatus('errors');
332
  $stats->fatal_errors = (int) $this->getStatus('fatal_errors');
333
  $stats->done = (int) $this->getStatus('done');
@@ -373,7 +368,6 @@ abstract class Queue
373
  $count->images_basecount = $customData->baseCount;
374
  }
375
 
376
-
377
  return $count;
378
  }
379
 
@@ -407,6 +401,17 @@ abstract class Queue
407
  $this->getShortQ()->setStatus('custom_data', $customData);
408
  }
409
 
 
 
 
 
 
 
 
 
 
 
 
410
  public function getCustomDataItem($name)
411
  {
412
  $customData = $this->getStatus('custom_data');
@@ -603,6 +608,18 @@ abstract class Queue
603
 
604
  }
605
 
 
 
 
 
 
 
 
 
 
 
 
 
606
  public function itemFailed($item, $fatal = false)
607
  {
608
  if ($fatal)
29
  const RESULT_UNKNOWN = -10;
30
 
31
 
 
 
 
 
 
 
 
32
  abstract protected function prepare();
33
  abstract public function getType();
34
 
321
  $stats->is_finished = (bool) $this->getStatus('finished');
322
  $stats->in_queue = (int) $this->getStatus('items');
323
  $stats->in_process = (int) $this->getStatus('in_process');
324
+ $stats->awaiting = $stats->in_queue + $stats->in_process; // calculation used for WP-CLI.
325
+
326
  $stats->errors = (int) $this->getStatus('errors');
327
  $stats->fatal_errors = (int) $this->getStatus('fatal_errors');
328
  $stats->done = (int) $this->getStatus('done');
368
  $count->images_basecount = $customData->baseCount;
369
  }
370
 
 
371
  return $count;
372
  }
373
 
401
  $this->getShortQ()->setStatus('custom_data', $customData);
402
  }
403
 
404
+ // Return if this queue has any special operation outside of normal optimizing.
405
+ // Use to give the go processing when out of credits (ie)
406
+ public function isCustomOperation()
407
+ {
408
+ if ($this->getCustomDataItem('customOperation'))
409
+ {
410
+ return true;
411
+ }
412
+ return false;
413
+ }
414
+
415
  public function getCustomDataItem($name)
416
  {
417
  $customData = $this->getStatus('custom_data');
608
 
609
  }
610
 
611
+ // Check if item is in queue. Considered not in queue if status is done.
612
+ public function isItemInQueue($item_id)
613
+ {
614
+ $itemObj = $this->q->getItem($item_id);
615
+
616
+ if (is_object($itemObj) && intval($itemObj->status) <> ShortQ::QSTATUS_DONE)
617
+ {
618
+ return true;
619
+ }
620
+ return false;
621
+ }
622
+
623
  public function itemFailed($item, $fatal = false)
624
  {
625
  if ($fatal)
class/Controller/QuotaController.php CHANGED
@@ -76,7 +76,7 @@ class QuotaController
76
 
77
  $quota = (object) [
78
  'monthly' => (object) [
79
- 'text' => sprintf(__('%s/month', 'shortpixel-image-optimiser'), $quotaData['APICallsQuota']),
80
  'total' => $quotaData['APICallsQuotaNumeric'],
81
  'consumed' => $quotaData['APICallsMadeNumeric'],
82
  'remaining' => max($quotaData['APICallsQuotaNumeric'] - $quotaData['APICallsMadeNumeric'], 0),
@@ -302,10 +302,10 @@ class QuotaController
302
 
303
  $dataArray = array(
304
  "APIKeyValid" => true,
305
- "APICallsMade" => number_format($data->APICallsMade) . __(' images','shortpixel-image-optimiser'),
306
- "APICallsQuota" => number_format($data->APICallsQuota) . __(' images','shortpixel-image-optimiser'),
307
- "APICallsMadeOneTime" => number_format($data->APICallsMadeOneTime) . __(' images','shortpixel-image-optimiser'),
308
- "APICallsQuotaOneTime" => number_format($data->APICallsQuotaOneTime) . __(' images','shortpixel-image-optimiser'),
309
  "APICallsMadeNumeric" => (int) max($data->APICallsMade, 0),
310
  "APICallsQuotaNumeric" => (int) max($data->APICallsQuota, 0),
311
  "APICallsMadeOneTimeNumeric" => (int) max($data->APICallsMadeOneTime, 0),
76
 
77
  $quota = (object) [
78
  'monthly' => (object) [
79
+ 'text' => sprintf(__('%s/month', 'shortpixel-image-optimiser'), $quotaData['APICallsQuota']),
80
  'total' => $quotaData['APICallsQuotaNumeric'],
81
  'consumed' => $quotaData['APICallsMadeNumeric'],
82
  'remaining' => max($quotaData['APICallsQuotaNumeric'] - $quotaData['APICallsMadeNumeric'], 0),
302
 
303
  $dataArray = array(
304
  "APIKeyValid" => true,
305
+ "APICallsMade" => number_format($data->APICallsMade) . __(' credits','shortpixel-image-optimiser'),
306
+ "APICallsQuota" => number_format($data->APICallsQuota) . __(' credits','shortpixel-image-optimiser'),
307
+ "APICallsMadeOneTime" => number_format($data->APICallsMadeOneTime) . __(' credits','shortpixel-image-optimiser'),
308
+ "APICallsQuotaOneTime" => number_format($data->APICallsQuotaOneTime) . __(' credits','shortpixel-image-optimiser'),
309
  "APICallsMadeNumeric" => (int) max($data->APICallsMade, 0),
310
  "APICallsQuotaNumeric" => (int) max($data->APICallsQuota, 0),
311
  "APICallsMadeOneTimeNumeric" => (int) max($data->APICallsMadeOneTime, 0),
class/Controller/ResponseController.php CHANGED
@@ -5,6 +5,7 @@ use ShortPixel\ShortpixelLogger\ShortPixelLogger as Log;
5
  use ShortPixel\Model\ResponseModel as ResponseModel;
6
  use ShortPixel\Model\Image\ImageModel as ImageModel;
7
 
 
8
  class ResponseController
9
  {
10
 
@@ -31,8 +32,9 @@ class ResponseController
31
  const OUTPUT_CLI = 3; // Has no context, needs more information
32
 
33
 
34
- /**
35
  * @param Object QueueObject being used.
 
36
  */
37
  public static function setQ($q)
38
  {
@@ -56,14 +58,17 @@ class ResponseController
56
 
57
  public static function getResponseItem($item_id)
58
  {
59
- $itemType = self::$queueType;
60
- if (is_null($itemType)) // fail-safe
61
  $itemType = "Unknown";
 
 
 
 
62
 
63
  if (isset(self::$items[$itemType][$item_id]))
64
  {
65
  $item = self::$items[$itemType][$item_id];
66
-
67
  }
68
  else {
69
  $item = new ResponseModel($item_id, $itemType);
@@ -74,7 +79,7 @@ class ResponseController
74
 
75
  protected static function updateResponseItem($item)
76
  {
77
- $itemType = self::$queueType;
78
  self::$items[$itemType][$item->item_id] = $item;
79
  }
80
 
@@ -90,6 +95,14 @@ class ResponseController
90
  $data = $name;
91
  }
92
 
 
 
 
 
 
 
 
 
93
  $resp = self::getResponseItem($item_id); // responseModel
94
 
95
  foreach($data as $prop => $val)
@@ -137,6 +150,14 @@ class ResponseController
137
  break;
138
  }
139
 
 
 
 
 
 
 
 
 
140
  if (self::$screenOutput == self::OUTPUT_CLI)
141
  {
142
  $text = '(' . self::$queueName . ' : ' . $item->fileName . ') ' . $text . ' ';
5
  use ShortPixel\Model\ResponseModel as ResponseModel;
6
  use ShortPixel\Model\Image\ImageModel as ImageModel;
7
 
8
+
9
  class ResponseController
10
  {
11
 
32
  const OUTPUT_CLI = 3; // Has no context, needs more information
33
 
34
 
35
+ /** Correlates type of item with the queue being used. Be aware that usage *outside* the queue system needs to manually set type
36
  * @param Object QueueObject being used.
37
+ *
38
  */
39
  public static function setQ($q)
40
  {
58
 
59
  public static function getResponseItem($item_id)
60
  {
61
+ if (is_null(self::$queueType)) // fail-safe
62
+ {
63
  $itemType = "Unknown";
64
+ }
65
+ else {
66
+ $itemType = self::$queueType;
67
+ }
68
 
69
  if (isset(self::$items[$itemType][$item_id]))
70
  {
71
  $item = self::$items[$itemType][$item_id];
 
72
  }
73
  else {
74
  $item = new ResponseModel($item_id, $itemType);
79
 
80
  protected static function updateResponseItem($item)
81
  {
82
+ $itemType = $item->item_type;
83
  self::$items[$itemType][$item->item_id] = $item;
84
  }
85
 
95
  $data = $name;
96
  }
97
 
98
+
99
+ $item_type = (array_key_exists('item_type', $data)) ? $data['item_type'] : false;
100
+ // If no queue / queue type is set, set it if item type is passed to ResponseController. For items outside the queue system.
101
+ if ($item_type && is_null(self::$queueType))
102
+ {
103
+ self::$queueType = $item_type;
104
+ }
105
+
106
  $resp = self::getResponseItem($item_id); // responseModel
107
 
108
  foreach($data as $prop => $val)
150
  break;
151
  }
152
 
153
+ switch($item->apiStatus)
154
+ {
155
+ case ApiController::STATUS_FAIL:
156
+ $text .= sprintf(__('( %s %d ) ', 'shortpixel-image-optimizer'), (strtolower($item->item_type) == 'media') ? __('Attachment ID ') : __('Custom Type '), $item->item_id);
157
+ break;
158
+ }
159
+
160
+
161
  if (self::$screenOutput == self::OUTPUT_CLI)
162
  {
163
  $text = '(' . self::$queueName . ' : ' . $item->fileName . ') ' . $text . ' ';
class/Controller/SettingsController.php CHANGED
@@ -481,6 +481,7 @@ class SettingsController extends \ShortPixel\ViewController
481
 
482
  protected function loadStatistics()
483
  {
 
484
  $statsControl = StatsController::getInstance();
485
  $stats = new \stdClass;
486
 
@@ -496,7 +497,7 @@ class SettingsController extends \ShortPixel\ViewController
496
 
497
 
498
  $this->view->stats = $stats;
499
-
500
  }
501
 
502
  /** @todo Remove this check in Version 5.1 including all data on the old CF token */
481
 
482
  protected function loadStatistics()
483
  {
484
+ /*
485
  $statsControl = StatsController::getInstance();
486
  $stats = new \stdClass;
487
 
497
 
498
 
499
  $this->view->stats = $stats;
500
+ */
501
  }
502
 
503
  /** @todo Remove this check in Version 5.1 including all data on the old CF token */
class/Controller/View/BulkViewController.php CHANGED
@@ -103,10 +103,13 @@ class BulkViewController extends \ShortPixel\ViewController
103
 
104
  $approx->total->images = $approx->media->total + $approx->custom->images; // $sc->totalImagesToOptimize();
105
 
 
 
106
  // Prevent any guesses to go below zero.
107
  foreach($approx->media as $item => $value)
108
  {
109
- $approx->media->$item = max($value, 0);
 
110
  }
111
  return $approx;
112
 
103
 
104
  $approx->total->images = $approx->media->total + $approx->custom->images; // $sc->totalImagesToOptimize();
105
 
106
+ $approx->media->isLimited = $sc->find('media', 'isLimited');
107
+
108
  // Prevent any guesses to go below zero.
109
  foreach($approx->media as $item => $value)
110
  {
111
+ if (is_numeric($value))
112
+ $approx->media->$item = max($value, 0);
113
  }
114
  return $approx;
115
 
class/Controller/View/EditMediaViewController.php CHANGED
@@ -68,6 +68,7 @@ class EditMediaViewController extends \ShortPixel\ViewController
68
  return false;
69
  }
70
 
 
71
  $this->view->status_message = null;
72
 
73
  $this->view->text = UiHelper::getStatusText($this->imageModel);
@@ -259,7 +260,7 @@ class EditMediaViewController extends \ShortPixel\ViewController
259
  $url = $thumbObj->getURL(); //$fs->pathToURL($thumbObj); //wp_get_attachment_image_src($this->post_id, $size);
260
  $filename = $thumbObj->getFullPath();
261
  $backup = $thumbObj->hasBackup() ? $thumbObj->getBackupFile()->getFullPath() : 'n/a';
262
- // $debugMeta =// print_r($thumbObj->debugGetImageMeta(), true);
263
  $width = $thumbObj->get('width');
264
  $height = $thumbObj->get('height');
265
 
68
  return false;
69
  }
70
 
71
+
72
  $this->view->status_message = null;
73
 
74
  $this->view->text = UiHelper::getStatusText($this->imageModel);
260
  $url = $thumbObj->getURL(); //$fs->pathToURL($thumbObj); //wp_get_attachment_image_src($this->post_id, $size);
261
  $filename = $thumbObj->getFullPath();
262
  $backup = $thumbObj->hasBackup() ? $thumbObj->getBackupFile()->getFullPath() : 'n/a';
263
+
264
  $width = $thumbObj->get('width');
265
  $height = $thumbObj->get('height');
266
 
class/Controller/View/ListMediaViewController.php CHANGED
@@ -249,12 +249,17 @@ class ListMediaViewController extends \ShortPixel\ViewController
249
 
250
  if ($filter && $filter == 'optimized')
251
  {
252
- $sql = ' SELECT * FROM ' . $tableName;
 
 
 
 
 
253
  $sql .= ' INNER JOIN ' . $wpdb->posts . ' ON ' . $wpdb->posts . '.ID = ' . $tableName . '.attach_id ';
254
 
255
  $sql .= 'WHERE image_type = %d AND status = %d';
256
  $sql = $wpdb->prepare($sql, MediaLibraryModel::IMAGE_TYPE_MAIN, $fileStatus);
257
- $sql .= ' AND ' . $post_where; // glue back the orders, and the all.
258
  }
259
  if ($filter && $filter == 'unoptimized')
260
  {
249
 
250
  if ($filter && $filter == 'optimized')
251
  {
252
+ $where = " AND " . $wpdb->posts . '.ID in ( SELECT attach_id FROM ' . $tableName . " WHERE parent = %d and status = %d) ";
253
+ $where = $wpdb->prepare($where, MediaLibraryModel::IMAGE_TYPE_MAIN, ImageModel::FILE_STATUS_SUCCESS);
254
+
255
+ $sql = substr_replace($request, $where, ($post_pos + strlen($post_pos)) ,0);
256
+
257
+ /*$sql = ' SELECT SQL_CALC_FOUND_ROWS * FROM ' . $tableName;
258
  $sql .= ' INNER JOIN ' . $wpdb->posts . ' ON ' . $wpdb->posts . '.ID = ' . $tableName . '.attach_id ';
259
 
260
  $sql .= 'WHERE image_type = %d AND status = %d';
261
  $sql = $wpdb->prepare($sql, MediaLibraryModel::IMAGE_TYPE_MAIN, $fileStatus);
262
+ $sql .= ' AND ' . $post_where; // glue back the orders, and the all. */
263
  }
264
  if ($filter && $filter == 'unoptimized')
265
  {
class/Helper/InstallHelper.php CHANGED
@@ -152,18 +152,13 @@ class InstallHelper
152
  global $wpdb;
153
  require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
154
 
155
- if (self::checkTableExists('shortpixel_folders') === false)
156
- {
157
- dbDelta(self::getFolderTableSQL());
158
- }
159
- if (self::checkTableExists('shortpixel_meta') === false)
160
- {
161
- dbDelta(self::getMetaTableSQL());
162
- }
163
- if (self::checkTableExists('shortpixel_postmeta') === false)
164
- {
165
- dbDelta(self::getPostMetaSQL());
166
- }
167
 
168
  self::checkIndexes();
169
  }
@@ -291,7 +286,7 @@ class InstallHelper
291
  attach_id bigint unsigned NOT NULL,
292
  parent bigint unsigned NOT NULL,
293
  image_type tinyint default 0,
294
- size varchar(50),
295
  status tinyint default 0,
296
  compression_type tinyint,
297
  compressed_size int,
152
  global $wpdb;
153
  require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
154
 
155
+
156
+ dbDelta(self::getFolderTableSQL());
157
+
158
+ dbDelta(self::getMetaTableSQL());
159
+
160
+ dbDelta(self::getPostMetaSQL());
161
+
 
 
 
 
 
162
 
163
  self::checkIndexes();
164
  }
286
  attach_id bigint unsigned NOT NULL,
287
  parent bigint unsigned NOT NULL,
288
  image_type tinyint default 0,
289
+ size varchar(150),
290
  status tinyint default 0,
291
  compression_type tinyint,
292
  compressed_size int,
class/Helper/UiHelper.php CHANGED
@@ -202,9 +202,6 @@ class UiHelper
202
 
203
  }
204
 
205
-
206
-
207
-
208
  public static function compressionTypeToText($type)
209
  {
210
  if ($type == ImageModel::COMPRESSION_LOSSLESS )
@@ -241,7 +238,7 @@ class UiHelper
241
  if ($id === 0)
242
  return array();
243
 
244
- if ($mediaItem->isOptimized())
245
  {
246
  $optimizable = $mediaItem->getOptimizeURLS(true);
247
 
@@ -410,8 +407,8 @@ class UiHelper
410
  $text = __('This item is waiting to be processed', 'shortpixel-image-optimiser');
411
  }
412
 
413
- if ($mediaItem->isOptimizePrevented() !== false)
414
- {
415
 
416
  $retry = self::getAction('retry', $mediaItem->get('id'));
417
 
@@ -429,7 +426,7 @@ class UiHelper
429
  }
430
  }
431
 
432
- $text .= "<div class='shortpixel-image-error'>" . esc_html($mediaItem->isOptimizePrevented());
433
  $text .= "<span class='shortpixel-error-reset'>" . sprintf(__('After you have fixed this issue, you can %s click here to retry %s', 'shortpixel-image-optimiser'), '<a href="javascript:' . $retry['function'] . '">', '</a>');
434
 
435
  $text .= '</div>';
@@ -608,7 +605,18 @@ class UiHelper
608
 
609
  public static function formatNumber($number, $precision = 2)
610
  {
611
- return number_format_i18n( (int) $number, $precision);
 
 
 
 
 
 
 
 
 
 
 
612
  }
613
 
614
  protected static function convertImageTypeName($name, $type)
202
 
203
  }
204
 
 
 
 
205
  public static function compressionTypeToText($type)
206
  {
207
  if ($type == ImageModel::COMPRESSION_LOSSLESS )
238
  if ($id === 0)
239
  return array();
240
 
241
+ if ($mediaItem->isOptimized() )
242
  {
243
  $optimizable = $mediaItem->getOptimizeURLS(true);
244
 
407
  $text = __('This item is waiting to be processed', 'shortpixel-image-optimiser');
408
  }
409
 
410
+ if ($mediaItem->isOptimizePrevented() !== false)
411
+ {
412
 
413
  $retry = self::getAction('retry', $mediaItem->get('id'));
414
 
426
  }
427
  }
428
 
429
+ $text .= "<div class='shortpixel-image-error'>" . esc_html($mediaItem->getReason('processable'));
430
  $text .= "<span class='shortpixel-error-reset'>" . sprintf(__('After you have fixed this issue, you can %s click here to retry %s', 'shortpixel-image-optimiser'), '<a href="javascript:' . $retry['function'] . '">', '</a>');
431
 
432
  $text .= '</div>';
605
 
606
  public static function formatNumber($number, $precision = 2)
607
  {
608
+ global $wp_locale;
609
+ $decimalpoint = isset($wp_locale->number_format['decimal_point']) ? $wp_locale->number_format['decimal_point'] : false;
610
+ $number = number_format_i18n( (int) $number, $precision);
611
+
612
+ // Don't show trailing zeroes if number is a whole unbroken number.
613
+ if ($decimalpoint !== false && substr($number, strpos($number, $decimalpoint)) == 00)
614
+ {
615
+ $number = number_format_i18n($number, 0);
616
+ }
617
+ // Some locale's have no-breaking-space as thousands separator. This doesn't work well in JS / Cron Shell so replace with space.
618
+ $number = str_replace('&nbsp;', ' ', $number);
619
+ return $number;
620
  }
621
 
622
  protected static function convertImageTypeName($name, $type)
class/Model/EnvironmentModel.php CHANGED
@@ -184,7 +184,7 @@ class EnvironmentModel extends \ShortPixel\Model
184
  $use_screens = apply_filters('shortpixel/init/optimize_on_screens', $use_screens);
185
 
186
  $this->screen_id = $screen->id;
187
- if(in_array($screen->id, $use_screens)) {
188
  $this->is_screen_to_use = true;
189
  }
190
 
184
  $use_screens = apply_filters('shortpixel/init/optimize_on_screens', $use_screens);
185
 
186
  $this->screen_id = $screen->id;
187
+ if(is_array($use_screens) && in_array($screen->id, $use_screens)) {
188
  $this->is_screen_to_use = true;
189
  }
190
 
class/Model/Image/CustomImageModel.php CHANGED
@@ -204,10 +204,9 @@ class CustomImageModel extends \ShortPixel\Model\Image\ImageModel
204
  if ($bool)
205
  {
206
  $this->setMeta('status', ImageModel::FILE_STATUS_UNPROCESSED);
207
- $this->setMeta('compressed_size', 0);
208
- $this->setMeta('compression_type', null);
209
- $this->setMeta('backup', null);
210
- $this->setMeta('retries', 0);
211
 
212
  $this->saveMeta();
213
 
204
  if ($bool)
205
  {
206
  $this->setMeta('status', ImageModel::FILE_STATUS_UNPROCESSED);
207
+ $this->setMeta('compressedSize', 0);
208
+ $this->setMeta('compressionType', null);
209
+
 
210
 
211
  $this->saveMeta();
212
 
class/Model/Image/ImageModel.php CHANGED
@@ -66,6 +66,9 @@ abstract class ImageModel extends \ShortPixel\Model\File\FileModel
66
  protected $processable_status = 0;
67
  protected $restorable_status = 0;
68
 
 
 
 
69
  //protected $is_optimized = false;
70
  // protected $is_image = false;
71
 
@@ -112,8 +115,6 @@ abstract class ImageModel extends \ShortPixel\Model\File\FileModel
112
  /* Check if an image in theory could be processed. Check only exclusions, don't check status etc */
113
  public function isProcessable()
114
  {
115
- $this->processable_status = 0; // reset everytime.
116
-
117
  if ( $this->isOptimized() || ! $this->exists() || $this->isPathExcluded() || $this->isExtensionExcluded() || $this->isSizeExcluded() || (! $this->is_writable() && ! $this->is_virtual()) || $this->isOptimizePrevented() !== false )
118
  {
119
  if(! $this->is_writable() && $this->processable_status == 0)
@@ -124,7 +125,10 @@ abstract class ImageModel extends \ShortPixel\Model\File\FileModel
124
  return false;
125
  }
126
  else
 
 
127
  return true;
 
128
  }
129
 
130
  public function isProcessableFileType($type = 'webp')
@@ -190,7 +194,7 @@ abstract class ImageModel extends \ShortPixel\Model\File\FileModel
190
  $message = __('Image Size Excluded', 'shortpixel-image-optimiser');
191
  break;
192
  case self::P_EXCLUDE_PATH:
193
- $message = __('Image Path Excluded', 'shortpixel-image-optimiser');
194
  break;
195
  case self::P_IS_OPTIMIZED:
196
  $message = __('Image is already optimized', 'shortpixel-image-optimiser');
@@ -206,7 +210,10 @@ abstract class ImageModel extends \ShortPixel\Model\File\FileModel
206
  break;
207
  case self::P_OPTIMIZE_PREVENTED:
208
  $message = __('Fatal error preventing processing', 'shortpixel-image-optimiser');
 
 
209
  break;
 
210
  case self::P_RESTORABLE:
211
  $message = __('Image restorable', 'shortpixel-image-optimiser');
212
  break;
@@ -468,6 +475,7 @@ abstract class ImageModel extends \ShortPixel\Model\File\FileModel
468
  'is_error' => true,
469
  'issue_type' => ResponseController::ISSUE_BACKUP_CREATE,
470
  'message' => __('Could not create backup. Please check file permissions', 'shortpixel-image-optimiser'),
 
471
  );
472
 
473
  ResponseController::addData($this->get('id'), $response);
@@ -513,7 +521,7 @@ abstract class ImageModel extends \ShortPixel\Model\File\FileModel
513
 
514
  $optimizedSize = $tempFile->getFileSize();
515
  $this->setImageSize();
516
- }
517
 
518
  if ($copyok)
519
  {
@@ -580,6 +588,7 @@ abstract class ImageModel extends \ShortPixel\Model\File\FileModel
580
  'is_error' => true,
581
  'issue_type' => ResponseController::ISSUE_BACKUP_CREATE,
582
  'message' => __('Could not copy optimized image from temporary files. Check file permissions', 'shortpixel-image-optimiser'),
 
583
  );
584
 
585
  ResponseController::addData($this->get('id'), $response);;
@@ -597,6 +606,7 @@ abstract class ImageModel extends \ShortPixel\Model\File\FileModel
597
  'is_error' => true,
598
  'issue_type' => ResponseController::ISSUE_OPTIMIZED_NOFILE,
599
  'message' => __('Image is reporting as optimized, but file couldn\'t be found in the downloaded files', 'shortpixel-image-optimiser'),
 
600
 
601
  );
602
 
@@ -635,6 +645,7 @@ abstract class ImageModel extends \ShortPixel\Model\File\FileModel
635
 
636
  public function isRestorable()
637
  {
 
638
  if (! $this->isOptimized())
639
  {
640
  $this->restorable_status = self::P_NOT_OPTIMIZED;
@@ -873,6 +884,7 @@ abstract class ImageModel extends \ShortPixel\Model\File\FileModel
873
  if ($type == 'regex-name' || $type == 'regex-path')
874
  {
875
  $result = $this->matchExludeRegexPattern($target, $pattern);
 
876
  }
877
  else {
878
  $result = $this->matchExcludePattern($target, $pattern);
@@ -915,7 +927,9 @@ abstract class ImageModel extends \ShortPixel\Model\File\FileModel
915
  if(strlen($pattern) == 0) // can happen on faulty input in settings.
916
  return false;
917
 
918
- $m = preg_match($pattern, $target);
 
 
919
  if ($m !== false && $m > 0) // valid regex, more hits than zero
920
  {
921
  return true;
@@ -953,6 +967,11 @@ abstract class ImageModel extends \ShortPixel\Model\File\FileModel
953
 
954
  $this->error_message = __('Backup already exists, but image is recoverable and the plugin will rollback. Will retry to optimize again. ', 'shortpixel-image-optimiser');
955
  }
 
 
 
 
 
956
  else
957
  {
958
  $this->preventNextTry(__('Fatal Issue: The Backup file already exists. The backup seems not restorable, or the original file is bigger than the backup, indicating an error.', 'shortpixel-image-optimiser'));
66
  protected $processable_status = 0;
67
  protected $restorable_status = 0;
68
 
69
+ // Public var that can be set by OptimizeController to prevent double queries.
70
+ public $is_in_queue;
71
+
72
  //protected $is_optimized = false;
73
  // protected $is_image = false;
74
 
115
  /* Check if an image in theory could be processed. Check only exclusions, don't check status etc */
116
  public function isProcessable()
117
  {
 
 
118
  if ( $this->isOptimized() || ! $this->exists() || $this->isPathExcluded() || $this->isExtensionExcluded() || $this->isSizeExcluded() || (! $this->is_writable() && ! $this->is_virtual()) || $this->isOptimizePrevented() !== false )
119
  {
120
  if(! $this->is_writable() && $this->processable_status == 0)
125
  return false;
126
  }
127
  else
128
+ {
129
+ $this->processable_status = 0;
130
  return true;
131
+ }
132
  }
133
 
134
  public function isProcessableFileType($type = 'webp')
194
  $message = __('Image Size Excluded', 'shortpixel-image-optimiser');
195
  break;
196
  case self::P_EXCLUDE_PATH:
197
+ $message = __('Image Excluded', 'shortpixel-image-optimiser');
198
  break;
199
  case self::P_IS_OPTIMIZED:
200
  $message = __('Image is already optimized', 'shortpixel-image-optimiser');
210
  break;
211
  case self::P_OPTIMIZE_PREVENTED:
212
  $message = __('Fatal error preventing processing', 'shortpixel-image-optimiser');
213
+ if (property_exists($this, 'optimizePrevented'))
214
+ $message = $this->get('optimizePrevented');
215
  break;
216
+ // Restorable Reasons
217
  case self::P_RESTORABLE:
218
  $message = __('Image restorable', 'shortpixel-image-optimiser');
219
  break;
475
  'is_error' => true,
476
  'issue_type' => ResponseController::ISSUE_BACKUP_CREATE,
477
  'message' => __('Could not create backup. Please check file permissions', 'shortpixel-image-optimiser'),
478
+ 'fileName' => $this->getFileName(),
479
  );
480
 
481
  ResponseController::addData($this->get('id'), $response);
521
 
522
  $optimizedSize = $tempFile->getFileSize();
523
  $this->setImageSize();
524
+ } // else
525
 
526
  if ($copyok)
527
  {
588
  'is_error' => true,
589
  'issue_type' => ResponseController::ISSUE_BACKUP_CREATE,
590
  'message' => __('Could not copy optimized image from temporary files. Check file permissions', 'shortpixel-image-optimiser'),
591
+ 'fileName' => $this->getFileName(),
592
  );
593
 
594
  ResponseController::addData($this->get('id'), $response);;
606
  'is_error' => true,
607
  'issue_type' => ResponseController::ISSUE_OPTIMIZED_NOFILE,
608
  'message' => __('Image is reporting as optimized, but file couldn\'t be found in the downloaded files', 'shortpixel-image-optimiser'),
609
+ 'fileName' => $this->getFileName(),
610
 
611
  );
612
 
645
 
646
  public function isRestorable()
647
  {
648
+
649
  if (! $this->isOptimized())
650
  {
651
  $this->restorable_status = self::P_NOT_OPTIMIZED;
884
  if ($type == 'regex-name' || $type == 'regex-path')
885
  {
886
  $result = $this->matchExludeRegexPattern($target, $pattern);
887
+ Log::addTemp('Exclude RegeX result', $result);
888
  }
889
  else {
890
  $result = $this->matchExcludePattern($target, $pattern);
927
  if(strlen($pattern) == 0) // can happen on faulty input in settings.
928
  return false;
929
 
930
+ $matches = array();
931
+ $m = preg_match($pattern, $target, $matches);
932
+
933
  if ($m !== false && $m > 0) // valid regex, more hits than zero
934
  {
935
  return true;
967
 
968
  $this->error_message = __('Backup already exists, but image is recoverable and the plugin will rollback. Will retry to optimize again. ', 'shortpixel-image-optimiser');
969
  }
970
+ /* elseif ($backupFile->getFileSize() > $this->getFileSize() && ! $backupFile->is_virtual() ) // Where there is a backup and it's bigger, assume some hickup, but there is backup so hooray
971
+ {
972
+ Log::addWarn('Backup already exists. Backup file is bigger, so assume that all is good with backup and proceed');
973
+ return true; // ok it.
974
+ } */
975
  else
976
  {
977
  $this->preventNextTry(__('Fatal Issue: The Backup file already exists. The backup seems not restorable, or the original file is bigger than the backup, indicating an error.', 'shortpixel-image-optimiser'));
class/Model/Image/MediaLibraryModel.php CHANGED
@@ -13,7 +13,7 @@ class MediaLibraryModel extends \ShortPixel\Model\Image\MediaLibraryThumbnailMod
13
  {
14
 
15
  protected $thumbnails = array(); // thumbnails of this // MediaLibraryThumbnailModel .
16
- protected $retinas = array(); // retina files - MediaLibraryThumbnailModel (or retina / webp and move to thumbnail? )
17
  //protected $webps = array(); // webp files -
18
  protected $original_file = false; // the original instead of the possibly _scaled one created by WP 5.3
19
 
@@ -27,7 +27,7 @@ class MediaLibraryModel extends \ShortPixel\Model\Image\MediaLibraryThumbnailMod
27
 
28
  private static $unlistedChecked = array(); // limit checking unlisted.
29
 
30
- private $optimizePrevented; // cache if there is any reason to prevent optimizing
31
  private $justConverted = false; // check if conversion happened on same run, to prevent double runs.
32
 
33
  const IMAGE_TYPE_MAIN = 0;
@@ -110,14 +110,18 @@ class MediaLibraryModel extends \ShortPixel\Model\Image\MediaLibraryThumbnailMod
110
  }
111
 
112
  // @todo Check Retina's
113
- if ($settings->optimizeRetina)
114
- {
115
 
 
 
116
  foreach($this->retinas as $retinaObj)
117
  {
 
118
  $urls = array_merge($urls, $retinaObj->getOptimizeUrls($get_path));
119
  }
 
120
  }
 
 
121
  $urls = array_values(array_unique($urls));
122
  return $urls;
123
  }
@@ -190,6 +194,23 @@ class MediaLibraryModel extends \ShortPixel\Model\Image\MediaLibraryThumbnailMod
190
  }
191
  }
192
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
193
  return array_values(array_unique($toOptimize));
194
  //foreach($types as $index => $)
195
  }
@@ -287,9 +308,9 @@ class MediaLibraryModel extends \ShortPixel\Model\Image\MediaLibraryThumbnailMod
287
  $thumbObj = $this->getThumbnailModel($this->getFileDir() . $data['file'], $name);
288
 
289
  $meta = new ImageThumbnailMeta();
290
- $thumbObj->setName($name);
291
  $meta->originalWidth = (isset($data['width'])) ? $data['width'] : null; // get from WP
292
  $meta->originalHeight = (isset($data['height'])) ? $data['height'] : null;
 
293
  $thumbObj->setMetaObj($meta);
294
  $thumbnails[$name] = $thumbObj;
295
  }
@@ -301,31 +322,47 @@ class MediaLibraryModel extends \ShortPixel\Model\Image\MediaLibraryThumbnailMod
301
 
302
  protected function getRetinas()
303
  {
304
- if (! is_null($this->retinas))
305
- return $this->retinas;
 
 
306
 
307
- $retinas = array();
308
- $main = $this->getRetina();
309
 
310
- if ($main)
311
- $retinas[0] = $main; // on purpose not a string, but number to prevent any custom image sizes to get overwritten.
 
 
 
312
 
313
- if ($this->isScaled())
 
 
 
 
 
 
 
 
 
 
314
  {
315
  $retscaled = $this->original_file->getRetina();
316
  if ($retscaled)
317
- $retinas[1] = $retscaled; //see main
318
  }
319
 
320
  foreach ($this->thumbnails as $thumbname => $thumbObj)
321
  {
322
- $retinaObj = $thumbObj->getRetina();
323
- if ($retinaObj)
324
- $retinas[$thumbname] = $retinaObj;
 
 
 
325
  }
326
 
327
-
328
- return $retinas;
329
  }
330
 
331
  protected function getWebps()
@@ -342,6 +379,16 @@ class MediaLibraryModel extends \ShortPixel\Model\Image\MediaLibraryThumbnailMod
342
  if ($webp)
343
  $webps[$thumbname] = $webp;
344
  }
 
 
 
 
 
 
 
 
 
 
345
  if ($this->isScaled())
346
  {
347
  $webp = $this->original_file->getWebp();
@@ -366,6 +413,17 @@ class MediaLibraryModel extends \ShortPixel\Model\Image\MediaLibraryThumbnailMod
366
  if ($avif)
367
  $avifs[$thumbname] = $avif;
368
  }
 
 
 
 
 
 
 
 
 
 
 
369
  if ($this->isScaled())
370
  {
371
  $avif = $this->original_file->getAvif();
@@ -404,7 +462,6 @@ class MediaLibraryModel extends \ShortPixel\Model\Image\MediaLibraryThumbnailMod
404
  $return = true;
405
  $wpmeta = wp_get_attachment_metadata($this->get('id'));
406
 
407
-
408
  if (! $this->isOptimized() && isset($tempFiles[$this->getFileName()]) ) // main file might not be contained in results
409
  {
410
  if ($this->getExtension() == 'heic')
@@ -439,6 +496,7 @@ class MediaLibraryModel extends \ShortPixel\Model\Image\MediaLibraryThumbnailMod
439
  $compressionType = $this->getMeta('compressionType'); // CompressionType not set on subimages etc.
440
 
441
  // If thumbnails should not be optimized, they should not be in result Array.
 
442
  foreach($this->thumbnails as $thumbnail)
443
  {
444
  // Check if thumbnail is in the tempfiles return set. This might not always be the case
@@ -448,7 +506,6 @@ class MediaLibraryModel extends \ShortPixel\Model\Image\MediaLibraryThumbnailMod
448
  }
449
 
450
  $thumbnail->setMeta('compressionType', $compressionType);
451
-
452
  $thumbnail->handleOptimizedFileType($tempFiles); // check for webps /etc
453
 
454
  if ($thumbnail->isOptimized())
@@ -486,7 +543,6 @@ class MediaLibraryModel extends \ShortPixel\Model\Image\MediaLibraryThumbnailMod
486
  }
487
 
488
  $wpmeta['sizes'][$size]['filesize'] = $thumbnail->getFileSize();
489
-
490
  }
491
 
492
  if ($result)
@@ -500,6 +556,54 @@ class MediaLibraryModel extends \ShortPixel\Model\Image\MediaLibraryThumbnailMod
500
  }
501
  }
502
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
503
  if ($this->isScaled() )
504
  {
505
  $original_file = $this->getOriginalFile();
@@ -588,7 +692,8 @@ class MediaLibraryModel extends \ShortPixel\Model\Image\MediaLibraryThumbnailMod
588
  }
589
 
590
 
591
- /** @param String Full Path to the Thumbnail File
 
592
  * @return Object ThumbnailModel
593
  * */
594
  private function getThumbnailModel($path, $size)
@@ -649,7 +754,7 @@ class MediaLibraryModel extends \ShortPixel\Model\Image\MediaLibraryThumbnailMod
649
  }
650
  }
651
 
652
- // Load Thumbnails.
653
  if (property_exists($metadata,'thumbnails') && count($metadata->thumbnails) > 0) // unlisted in WordPress metadata sizes. Might be special unlisted one, one that was removed etc.
654
  {
655
  foreach($metadata->thumbnails as $name => $thumbMeta) // <!-- ThumbMeta is Object
@@ -678,7 +783,7 @@ class MediaLibraryModel extends \ShortPixel\Model\Image\MediaLibraryThumbnailMod
678
  }
679
  $this->thumbnails = $thumbnails;
680
 
681
- if (property_exists($metadata, 'retinas') && is_object($metadata->retinas))
682
  {
683
  $retinas = $this->getRetinas();
684
  foreach($metadata->retinas as $name => $retinaMeta)
@@ -690,6 +795,9 @@ class MediaLibraryModel extends \ShortPixel\Model\Image\MediaLibraryThumbnailMod
690
  $retMeta = new ImageThumbnailMeta();
691
  $retMeta->fromClass($retinaMeta);
692
  $retinaObj->setMetaObj($retMeta);
 
 
 
693
  $this->retinas[$name] = $retinaObj;
694
  }
695
  }
@@ -716,11 +824,7 @@ class MediaLibraryModel extends \ShortPixel\Model\Image\MediaLibraryThumbnailMod
716
  if (is_null($this->getMeta('originalWidth')))
717
  $this->setMeta('originalWidth', $this->get('width') );
718
 
719
- // Adds unlisted files to thumbnails array, if needed.
720
- // This is bound to be bad for performance and not good for big sites!
721
- // Moved this from isProcessable to be a bit more performance friendly.
722
- $this->addUnlisted();
723
-
724
  }
725
 
726
  protected function getDBMeta()
@@ -779,13 +883,10 @@ class MediaLibraryModel extends \ShortPixel\Model\Image\MediaLibraryThumbnailMod
779
  }
780
 
781
  // Thumbnails
782
- // $sql = 'SELECT * FROM ' . $wpdb->prefix . 'shortpixel_postmeta where parent = %d';
783
- // $sql = $wpdb->prepare($sql, $this->id);
784
 
785
  // Mimic the previous SPixel solution regarding the return Metadata Object needed, with all thunbnails there.
786
  $metadata = new \stdClass;
787
  $metadata->image_meta = new \stdClass;
788
- $metadata->thumbnails = new \stdClass;
789
  $metadata->thumbnails = array();
790
 
791
  //$metadata = new \stdClass; // main image
@@ -816,11 +917,15 @@ class MediaLibraryModel extends \ShortPixel\Model\Image\MediaLibraryThumbnailMod
816
  $data->$name = $val;
817
  }
818
 
819
- if ($record->parent == 0)
820
  {
821
  // Database ID should probably also be stored for the thumbnails, so updating / insert into the database will be easier. We have a free primary key, so why not use it?
822
  $metadata->image_meta = $data;
823
  }
 
 
 
 
824
  elseif($record->parent > 0) // Thumbnails
825
  {
826
  switch($record->image_type)
@@ -1050,13 +1155,17 @@ class MediaLibraryModel extends \ShortPixel\Model\Image\MediaLibraryThumbnailMod
1050
  $thumbnails[$thumbName] = $thumbObj->toClass();
1051
  }
1052
  }
1053
- foreach($this->retinas as $index => $retinaObj)
1054
- {
1055
- if ($retinaObj->getMeta('status') > 0)
1056
- {
1057
- $retinas[$index] = $retinaObj->toClass();
1058
- }
1059
- }
 
 
 
 
1060
 
1061
  if (count($thumbnails) > 0)
1062
  $metadata->thumbnails = $thumbnails;
@@ -1184,7 +1293,7 @@ class MediaLibraryModel extends \ShortPixel\Model\Image\MediaLibraryThumbnailMod
1184
  }
1185
 
1186
  // The exclude size on the main image - via regex - if fails, prevents the whole thing from optimization.
1187
- if ($this->processable_status == ImageModel::P_EXCLUDE_SIZE)
1188
  {
1189
  return $bool;
1190
  }
@@ -1210,6 +1319,18 @@ class MediaLibraryModel extends \ShortPixel\Model\Image\MediaLibraryThumbnailMod
1210
  }
1211
  }
1212
 
 
 
 
 
 
 
 
 
 
 
 
 
1213
  // Todo check if Webp / Avisf is active, check for unoptimized items
1214
  if ($this->isProcessableFileType('webp'))
1215
  {
@@ -1392,6 +1513,8 @@ class MediaLibraryModel extends \ShortPixel\Model\Image\MediaLibraryThumbnailMod
1392
  if (! $excludePatterns || ! is_array($excludePatterns) ) // no patterns, nothing excluded
1393
  return false;
1394
 
 
 
1395
  foreach($excludePatterns as $item) {
1396
  $type = trim($item["type"]);
1397
  if($type == "size") {
@@ -1399,23 +1522,23 @@ class MediaLibraryModel extends \ShortPixel\Model\Image\MediaLibraryThumbnailMod
1399
  $width = $this->get('width');
1400
  $height = $this->get('height');
1401
 
1402
-
1403
  if( $width && $height
1404
  && $this->isProcessableSize($width, $height, $item["value"]) === false){
1405
  $this->processable_status = self::P_EXCLUDE_SIZE;
1406
- return true;
1407
  }
1408
  else
1409
- return false;
1410
  }
1411
  }
1412
 
 
 
1413
  }
1414
 
1415
  private function isProcessableSize($width, $height, $excludePattern) {
1416
 
1417
  $ranges = preg_split("/(x|×|X)/",$excludePattern);
1418
-
1419
  $widthBounds = explode("-", $ranges[0]);
1420
  $minWidth = intval($widthBounds[0]);
1421
  $maxWidth = (!isset($widthBounds[1])) ? intval($widthBounds[0]) : intval($widthBounds[1]);
@@ -1559,7 +1682,7 @@ class MediaLibraryModel extends \ShortPixel\Model\Image\MediaLibraryThumbnailMod
1559
  {
1560
  $this->processable_status = self::P_OPTIMIZE_PREVENTED;
1561
  $this->optimizePrevented = $reason;
1562
- return $reason;
1563
  }
1564
  }
1565
 
@@ -1631,6 +1754,17 @@ class MediaLibraryModel extends \ShortPixel\Model\Image\MediaLibraryThumbnailMod
1631
  elseif ($thumbObj->isRestorable())
1632
  {
1633
  $bool = $thumbObj->restore(); // resets metadata
 
 
 
 
 
 
 
 
 
 
 
1634
  }
1635
 
1636
  if ($unlisted_file === null)
@@ -1645,16 +1779,38 @@ class MediaLibraryModel extends \ShortPixel\Model\Image\MediaLibraryThumbnailMod
1645
  $wpmeta['sizes'][$size]['filesize'] = $thumbObj->getFileSize();
1646
  }
1647
 
1648
- if (! $bool)
1649
- {
1650
- $cleanRestore = false;
1651
- }
1652
- else
 
 
 
 
 
 
 
1653
  {
1654
- $restored[$filebase] = true;
 
1655
  }
 
 
 
1656
 
1657
- }
 
 
 
 
 
 
 
 
 
 
 
1658
 
1659
  if ($this->isScaled() )
1660
  {
@@ -1725,6 +1881,28 @@ class MediaLibraryModel extends \ShortPixel\Model\Image\MediaLibraryThumbnailMod
1725
  return $bool;
1726
  }
1727
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1728
  /** New Setup of RestorePNG2JPG. Runs after copying backupfile back to uploads.
1729
  */
1730
  protected function restorePNG2JPG()
@@ -1863,6 +2041,15 @@ class MediaLibraryModel extends \ShortPixel\Model\Image\MediaLibraryThumbnailMod
1863
  }
1864
  }
1865
 
 
 
 
 
 
 
 
 
 
1866
  private function generateThumbnails()
1867
  {
1868
  $metadata = wp_generate_attachment_metadata($this->get('id'), $this->getFullPath());
@@ -1908,6 +2095,47 @@ class MediaLibraryModel extends \ShortPixel\Model\Image\MediaLibraryThumbnailMod
1908
 
1909
  delete_post_meta($this->id, '_shortpixel_was_converted');
1910
  $result = $this->checkLegacy();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1911
  if ($result)
1912
  {
1913
  $this->saveMeta();
@@ -1958,7 +2186,7 @@ class MediaLibraryModel extends \ShortPixel\Model\Image\MediaLibraryThumbnailMod
1958
  }
1959
 
1960
  $quotaController = QuotaController::getInstance();
1961
- if ($quotaController->hasQuota() === false)
1962
  {
1963
  $adminNotices = AdminNoticesController::getInstance();
1964
  $adminNotices->invokeLegacyNotice();
@@ -2127,38 +2355,52 @@ class MediaLibraryModel extends \ShortPixel\Model\Image\MediaLibraryThumbnailMod
2127
 
2128
  if (isset($data['retinasOpt']))
2129
  {
2130
- $count = $data['retinasOpt'];
 
2131
 
 
2132
  $retinas = $this->getRetinas();
2133
 
2134
  foreach($retinas as $index => $retinaObj) // Thumbnail Model
2135
  {
2136
-
2137
- $retinaObj->image_meta->status = $status;
2138
- $retinaObj->image_meta->compressionType = $type;
2139
- if ($status == self::FILE_STATUS_SUCCESS)
2140
- $retinaObj->image_meta->compressedSize = $retinaObj->getFileSize();
2141
- else
2142
- $retinaObj->image_meta->originalSize = $retinaObj->getFileSize();
2143
- // $retinaObj->image_meta->improvement = -1; // n/a
2144
- $retinaObj->image_meta->tsAdded = $tsAdded;
2145
- $retinaObj->image_meta->tsOptimized = $tsOptimized;
2146
- $retinaObj->image_meta->did_jpg2png = $did_jpg2png;
2147
- if ($retinaObj->hasBackup())
2148
- {
2149
- $retinaObj->has_backup = true;
2150
- if ($status == self::FILE_STATUS_SUCCESS)
2151
- $retinaObj->image_meta->originalSize = $retinaObj->getBackupFile()->getFileSize();
2152
- }
2153
-
2154
- $retinaObj->recordChanged(true);
2155
- $retinas[$index] = $retinaObj;
2156
- }
2157
- $this->retinas = $retinas;
2158
- if ($count !== count($retinas))
2159
- {
2160
- Log::addWarning("Conversion: $count retinas expected in legacy, " . count($retinas) . 'found', $retinas);
2161
- }
 
 
 
 
 
 
 
 
 
 
 
 
2162
  }
2163
 
2164
 
@@ -2345,11 +2587,21 @@ class MediaLibraryModel extends \ShortPixel\Model\Image\MediaLibraryThumbnailMod
2345
 
2346
  $currentFiles = array($this->getFileName());
2347
  foreach($this->thumbnails as $thumbObj)
2348
- $currentFiles[] = $thumbObj->getFileName();
 
 
2349
 
2350
  if ($this->isScaled())
2351
  $currentFiles[] = $this->getOriginalFile()->getFileName();
2352
 
 
 
 
 
 
 
 
 
2353
  $processFiles = array();
2354
  $unlisted = array();
2355
 
13
  {
14
 
15
  protected $thumbnails = array(); // thumbnails of this // MediaLibraryThumbnailModel .
16
+ protected $retinas; // retina files - MediaLibraryThumbnailModel (or retina / webp and move to thumbnail? )
17
  //protected $webps = array(); // webp files -
18
  protected $original_file = false; // the original instead of the possibly _scaled one created by WP 5.3
19
 
27
 
28
  private static $unlistedChecked = array(); // limit checking unlisted.
29
 
30
+ protected $optimizePrevented; // cache if there is any reason to prevent optimizing
31
  private $justConverted = false; // check if conversion happened on same run, to prevent double runs.
32
 
33
  const IMAGE_TYPE_MAIN = 0;
110
  }
111
 
112
  // @todo Check Retina's
 
 
113
 
114
+ if ($settings->optimizeRetina && ! is_null($this->retinas))
115
+ {
116
  foreach($this->retinas as $retinaObj)
117
  {
118
+ if ($retinaObj->isThumbnailProcessable())
119
  $urls = array_merge($urls, $retinaObj->getOptimizeUrls($get_path));
120
  }
121
+
122
  }
123
+
124
+
125
  $urls = array_values(array_unique($urls));
126
  return $urls;
127
  }
194
  }
195
  }
196
 
197
+ if (! is_null($this->retinas))
198
+ {
199
+ foreach($this->retinas as $retinaName => $retinaObj)
200
+ {
201
+ if ($retinaObj->getOptimizeFileType($type))
202
+ {
203
+ if (true === $get_path)
204
+ {
205
+ $toOptimize[] = $retinaObj->getFullPath();
206
+ }
207
+ else{
208
+ $toOptimize[] = $retinaObj->getURL(); //$fs->pathToUrl($thumbObj);
209
+ }
210
+ }
211
+ }
212
+ }
213
+
214
  return array_values(array_unique($toOptimize));
215
  //foreach($types as $index => $)
216
  }
308
  $thumbObj = $this->getThumbnailModel($this->getFileDir() . $data['file'], $name);
309
 
310
  $meta = new ImageThumbnailMeta();
 
311
  $meta->originalWidth = (isset($data['width'])) ? $data['width'] : null; // get from WP
312
  $meta->originalHeight = (isset($data['height'])) ? $data['height'] : null;
313
+ $thumbObj->setName($name); // name is size mostly
314
  $thumbObj->setMetaObj($meta);
315
  $thumbnails[$name] = $thumbObj;
316
  }
322
 
323
  protected function getRetinas()
324
  {
325
+ if (is_null($this->retinas))
326
+ {
327
+ $this->addRetinas();
328
+ }
329
 
330
+ return $this->retinas;
331
+ }
332
 
333
+ protected function addRetinas()
334
+ {
335
+ // Don't load retina's if option is off.
336
+ if (! \wpSPIO()->settings()->optimizeRetina)
337
+ return;
338
 
339
+ if (! isset($this->retinas[0]))
340
+ {
341
+ $main = $this->getRetina();
342
+
343
+ if ($main)
344
+ {
345
+ $this->retinas[0] = $main; // on purpose not a string, but number to prevent any custom image sizes to get overwritten.
346
+ }
347
+ }
348
+
349
+ if ($this->isScaled() && ! isset($this->retinas[1]))
350
  {
351
  $retscaled = $this->original_file->getRetina();
352
  if ($retscaled)
353
+ $this->retinas[1] = $retscaled; //see main
354
  }
355
 
356
  foreach ($this->thumbnails as $thumbname => $thumbObj)
357
  {
358
+ if (! isset($this->retinas[$thumbname]))
359
+ {
360
+ $retinaObj = $thumbObj->getRetina();
361
+ if ($retinaObj)
362
+ $this->retinas[$thumbname] = $retinaObj;
363
+ }
364
  }
365
 
 
 
366
  }
367
 
368
  protected function getWebps()
379
  if ($webp)
380
  $webps[$thumbname] = $webp;
381
  }
382
+
383
+ if (! is_null($this->retinas))
384
+ {
385
+ foreach ($this->retinas as $retinaName => $retinaObj)
386
+ {
387
+ $webp = $retinaObj->getWebp();
388
+ if ($webp)
389
+ $webps['retina-' . $retinaName] = $webp; // adding a prefix to make sure it will not overwrite thumbnames, they share the same name.
390
+ }
391
+ }
392
  if ($this->isScaled())
393
  {
394
  $webp = $this->original_file->getWebp();
413
  if ($avif)
414
  $avifs[$thumbname] = $avif;
415
  }
416
+
417
+ if (! is_null($this->retinas))
418
+ {
419
+ foreach ($this->retinas as $retinaName => $retinaObj)
420
+ {
421
+ $avif = $retinaObj->getAvif();
422
+ if ($avif)
423
+ $avifs['retina-' . $retinaName] = $avif; // adding a prefix to make sure it will not overwrite thumbnames, they share the same name.
424
+ }
425
+ }
426
+
427
  if ($this->isScaled())
428
  {
429
  $avif = $this->original_file->getAvif();
462
  $return = true;
463
  $wpmeta = wp_get_attachment_metadata($this->get('id'));
464
 
 
465
  if (! $this->isOptimized() && isset($tempFiles[$this->getFileName()]) ) // main file might not be contained in results
466
  {
467
  if ($this->getExtension() == 'heic')
496
  $compressionType = $this->getMeta('compressionType'); // CompressionType not set on subimages etc.
497
 
498
  // If thumbnails should not be optimized, they should not be in result Array.
499
+ // #### THUMBNAILS ####
500
  foreach($this->thumbnails as $thumbnail)
501
  {
502
  // Check if thumbnail is in the tempfiles return set. This might not always be the case
506
  }
507
 
508
  $thumbnail->setMeta('compressionType', $compressionType);
 
509
  $thumbnail->handleOptimizedFileType($tempFiles); // check for webps /etc
510
 
511
  if ($thumbnail->isOptimized())
543
  }
544
 
545
  $wpmeta['sizes'][$size]['filesize'] = $thumbnail->getFileSize();
 
546
  }
547
 
548
  if ($result)
556
  }
557
  }
558
 
559
+ /** #### RETINAS ***/
560
+ if (is_array($this->retinas))
561
+ {
562
+ foreach($this->retinas as $name => $retinaObj)
563
+ {
564
+ if (! isset($tempFiles[$retinaObj->getFileName()]) )
565
+ {
566
+ continue;
567
+ }
568
+
569
+ $retinaObj->setMeta('compressionType', $compressionType);
570
+ $retinaObj->handleOptimizedFileType($tempFiles); // check for webps /etc
571
+
572
+ if ($retinaObj->isOptimized())
573
+ {
574
+ continue;
575
+ }
576
+ if (!$retinaObj->isProcessable())
577
+ {
578
+ continue; // when excluded.
579
+ }
580
+ $filebase = $retinaObj->getFileBase();
581
+ $result = false;
582
+
583
+ if (isset($optimized[$filebase])) // double sizes.
584
+ {
585
+ $databaseID = $retinaObj->getMeta('databaseID');
586
+ $retinaObj->setMetaObj($optimized[$filebase]);
587
+ $retinaObj->setMeta('databaseID', $databaseID); // keep dbase id the same, otherwise it won't write this thumb to DB due to same ID.
588
+ $result = false;
589
+ }
590
+ else
591
+ {
592
+ $result = $retinaObj->handleOptimized($tempFiles);
593
+ }
594
+
595
+ if ($result)
596
+ {
597
+ $optimized[$filebase] = $retinaObj->getMetaObj();
598
+ }
599
+ elseif ($retinaObj->get('prevent_next_try') !== false) // in case of fatal issues.
600
+ {
601
+ $this->preventNextTry($retinaObj->get('prevent_next_try'));
602
+ $return = false; //failed
603
+ }
604
+ } // retinas loop
605
+ }
606
+
607
  if ($this->isScaled() )
608
  {
609
  $original_file = $this->getOriginalFile();
692
  }
693
 
694
 
695
+ /** Function to go from path -> thumbnail mode. This should be used for unlisted etc, but nothing that already is loaded in thumbnails.
696
+ * @param String Full Path to the Thumbnail File
697
  * @return Object ThumbnailModel
698
  * */
699
  private function getThumbnailModel($path, $size)
754
  }
755
  }
756
 
757
+ // Load Unlisted Thumbnails.
758
  if (property_exists($metadata,'thumbnails') && count($metadata->thumbnails) > 0) // unlisted in WordPress metadata sizes. Might be special unlisted one, one that was removed etc.
759
  {
760
  foreach($metadata->thumbnails as $name => $thumbMeta) // <!-- ThumbMeta is Object
783
  }
784
  $this->thumbnails = $thumbnails;
785
 
786
+ if (property_exists($metadata, 'retinas') && count($metadata->retinas) > 0 )
787
  {
788
  $retinas = $this->getRetinas();
789
  foreach($metadata->retinas as $name => $retinaMeta)
795
  $retMeta = new ImageThumbnailMeta();
796
  $retMeta->fromClass($retinaMeta);
797
  $retinaObj->setMetaObj($retMeta);
798
+ $retinaObj->setName($name);
799
+ $retinaObj->is_retina = true;
800
+
801
  $this->retinas[$name] = $retinaObj;
802
  }
803
  }
824
  if (is_null($this->getMeta('originalWidth')))
825
  $this->setMeta('originalWidth', $this->get('width') );
826
 
827
+ $this->loadLooseItems();
 
 
 
 
828
  }
829
 
830
  protected function getDBMeta()
883
  }
884
 
885
  // Thumbnails
 
 
886
 
887
  // Mimic the previous SPixel solution regarding the return Metadata Object needed, with all thunbnails there.
888
  $metadata = new \stdClass;
889
  $metadata->image_meta = new \stdClass;
 
890
  $metadata->thumbnails = array();
891
 
892
  //$metadata = new \stdClass; // main image
917
  $data->$name = $val;
918
  }
919
 
920
+ if ($record->parent == 0 && $record->image_type == self::IMAGE_TYPE_MAIN)
921
  {
922
  // Database ID should probably also be stored for the thumbnails, so updating / insert into the database will be easier. We have a free primary key, so why not use it?
923
  $metadata->image_meta = $data;
924
  }
925
+ elseif ($record->parent == 0 && $record->image_type = self::IMAGE_TYPE_RETINA)
926
+ {
927
+ $metadata->retinas[0] = $data;
928
+ }
929
  elseif($record->parent > 0) // Thumbnails
930
  {
931
  switch($record->image_type)
1155
  $thumbnails[$thumbName] = $thumbObj->toClass();
1156
  }
1157
  }
1158
+
1159
+ if (is_array($this->retinas))
1160
+ {
1161
+ foreach($this->retinas as $index => $retinaObj)
1162
+ {
1163
+ if ($retinaObj->getMeta('status') > 0)
1164
+ {
1165
+ $retinas[$index] = $retinaObj->toClass();
1166
+ }
1167
+ }
1168
+ }
1169
 
1170
  if (count($thumbnails) > 0)
1171
  $metadata->thumbnails = $thumbnails;
1293
  }
1294
 
1295
  // The exclude size on the main image - via regex - if fails, prevents the whole thing from optimization.
1296
+ if ($this->processable_status == ImageModel::P_EXCLUDE_SIZE || $this->processable_status == ImageModel::P_EXCLUDE_PATH)
1297
  {
1298
  return $bool;
1299
  }
1319
  }
1320
  }
1321
 
1322
+ if (! $bool && ! is_null($this->retinas) && count($this->retinas) > 0)
1323
+ {
1324
+ foreach($this->retinas as $name => $retinaObj)
1325
+ {
1326
+ if ($retinaObj->isThumbnailProcessable())
1327
+ {
1328
+ $bool = true;
1329
+ return true;
1330
+ }
1331
+ }
1332
+ }
1333
+
1334
  // Todo check if Webp / Avisf is active, check for unoptimized items
1335
  if ($this->isProcessableFileType('webp'))
1336
  {
1513
  if (! $excludePatterns || ! is_array($excludePatterns) ) // no patterns, nothing excluded
1514
  return false;
1515
 
1516
+ $bool = false;
1517
+
1518
  foreach($excludePatterns as $item) {
1519
  $type = trim($item["type"]);
1520
  if($type == "size") {
1522
  $width = $this->get('width');
1523
  $height = $this->get('height');
1524
 
 
1525
  if( $width && $height
1526
  && $this->isProcessableSize($width, $height, $item["value"]) === false){
1527
  $this->processable_status = self::P_EXCLUDE_SIZE;
1528
+ return true; // exit directly because we have our exclusion
1529
  }
1530
  else
1531
+ $bool = false; // continue and check all patterns, there might be multiple.
1532
  }
1533
  }
1534
 
1535
+ return $bool;
1536
+
1537
  }
1538
 
1539
  private function isProcessableSize($width, $height, $excludePattern) {
1540
 
1541
  $ranges = preg_split("/(x|×|X)/",$excludePattern);
 
1542
  $widthBounds = explode("-", $ranges[0]);
1543
  $minWidth = intval($widthBounds[0]);
1544
  $maxWidth = (!isset($widthBounds[1])) ? intval($widthBounds[0]) : intval($widthBounds[1]);
1682
  {
1683
  $this->processable_status = self::P_OPTIMIZE_PREVENTED;
1684
  $this->optimizePrevented = $reason;
1685
+ return true;
1686
  }
1687
  }
1688
 
1754
  elseif ($thumbObj->isRestorable())
1755
  {
1756
  $bool = $thumbObj->restore(); // resets metadata
1757
+ if (! $bool)
1758
+ {
1759
+ $cleanRestore = false;
1760
+ }
1761
+ else
1762
+ {
1763
+ $restored[$filebase] = true;
1764
+ }
1765
+ }
1766
+ else {
1767
+ Log::addWarn('Thumbnail not restorable ' . $size, $this->getReason('restorable'));
1768
  }
1769
 
1770
  if ($unlisted_file === null)
1779
  $wpmeta['sizes'][$size]['filesize'] = $thumbObj->getFileSize();
1780
  }
1781
 
1782
+ }
1783
+
1784
+ if (! is_null($this->retinas))
1785
+ {
1786
+ $restored = array();
1787
+
1788
+ foreach($this->retinas as $name => $retinaObj)
1789
+ {
1790
+ $filebase = $retinaObj->getFileBase();
1791
+ $size = $retinaObj->get('size');
1792
+
1793
+ if (isset($restored[$filebase]))
1794
  {
1795
+ $bool = true; // this filebase already restored. In case of duplicate sizes.
1796
+ $retinaObj->image_meta = new ImageThumbnailMeta();
1797
  }
1798
+ elseif ($retinaObj->isRestorable())
1799
+ {
1800
+ $bool = $retinaObj->restore();
1801
 
1802
+ if (! $bool)
1803
+ {
1804
+ $cleanRestore = false;
1805
+ }
1806
+ else
1807
+ {
1808
+ $restored[$filebase] = true;
1809
+ }
1810
+ }
1811
+
1812
+ }
1813
+ }
1814
 
1815
  if ($this->isScaled() )
1816
  {
1881
  return $bool;
1882
  }
1883
 
1884
+ // This is check for the mainFile.
1885
+ public function hasDBRecord()
1886
+ {
1887
+
1888
+ global $wpdb;
1889
+
1890
+ $sql = 'SELECT id FROM ' . $wpdb->prefix . 'shortpixel_postmeta WHERE attach_id = %d AND size IS NULL and image_type = %d';
1891
+ $sql = $wpdb->prepare($sql, $this->id, self::IMAGE_TYPE_MAIN);
1892
+
1893
+ $id = $wpdb->get_var($sql);
1894
+
1895
+ if (is_null($id))
1896
+ {
1897
+ return false;
1898
+ }
1899
+ elseif (is_numeric($id)) {
1900
+ return true;
1901
+ }
1902
+
1903
+ }
1904
+
1905
+
1906
  /** New Setup of RestorePNG2JPG. Runs after copying backupfile back to uploads.
1907
  */
1908
  protected function restorePNG2JPG()
2041
  }
2042
  }
2043
 
2044
+ // Load items that might be processable but not in WP metadata or other meta's .
2045
+ // used for IsProcessable ( check if we have something ) and handleOptimized ( to check against the optimized stuff )
2046
+ private function loadLooseItems()
2047
+ {
2048
+ // Load items that might be not recorded when loading.
2049
+ $this->addUnlisted();
2050
+ $this->addRetinas();
2051
+ }
2052
+
2053
  private function generateThumbnails()
2054
  {
2055
  $metadata = wp_generate_attachment_metadata($this->get('id'), $this->getFullPath());
2095
 
2096
  delete_post_meta($this->id, '_shortpixel_was_converted');
2097
  $result = $this->checkLegacy();
2098
+
2099
+ // Check the whole thing to find any images that have a backup, but are not marked as optimized, and just mark them.
2100
+ if (! $this->isOptimized() && $this->hasBackup() )
2101
+ {
2102
+ $this->setMeta('status', self::FILE_STATUS_SUCCESS);
2103
+ $result = true;
2104
+ }
2105
+ if ($this->hasOriginal())
2106
+ {
2107
+ $originalFile = $this->getOriginalFile();
2108
+ if (! $originalFile->isOptimized() && $originalFile->hasBackup() )
2109
+ {
2110
+ $originalFile->setMeta('status', self::FILE_STATUS_SUCCESS);
2111
+ $result = true;
2112
+ }
2113
+ }
2114
+ if (is_array($this->thumbnails) && count($this->thumbnails) > 0)
2115
+ {
2116
+ foreach($this->thumbnails as $thumbObj)
2117
+ {
2118
+ if (! $thumbObj->isOptimized() && $thumbObj->hasBackup())
2119
+ {
2120
+ $thumbObj->setMeta('status', self::FILE_STATUS_SUCCESS);
2121
+ $result = true;
2122
+ }
2123
+ }
2124
+ }
2125
+ if (is_array($this->retinas) && count($this->retinas) > 0)
2126
+ {
2127
+ foreach($this->retinas as $retinaObj)
2128
+ {
2129
+ if (! $retinaObj->isOptimized() && $retinaObj->hasBackup())
2130
+ {
2131
+ $retinaObj->setMeta('status', self::FILE_STATUS_SUCCESS);
2132
+ $result = true;
2133
+ }
2134
+
2135
+ }
2136
+ }
2137
+
2138
+
2139
  if ($result)
2140
  {
2141
  $this->saveMeta();
2186
  }
2187
 
2188
  $quotaController = QuotaController::getInstance();
2189
+ if ($quotaController->hasQuota() === true)
2190
  {
2191
  $adminNotices = AdminNoticesController::getInstance();
2192
  $adminNotices->invokeLegacyNotice();
2355
 
2356
  if (isset($data['retinasOpt']))
2357
  {
2358
+ $count = $data['retinasOpt']; // a number.
2359
+ $addedCounter = 0;
2360
 
2361
+ $retinasOpt = $data['retinasOpt'];
2362
  $retinas = $this->getRetinas();
2363
 
2364
  foreach($retinas as $index => $retinaObj) // Thumbnail Model
2365
  {
2366
+ if ($retinaObj->hasDBRecord() === true)
2367
+ {
2368
+ continue;
2369
+ }
2370
+
2371
+ // Check if thumbnail ('parent') is Optimized, if so, then retina probably should be optimized as well.
2372
+ if ( (isset($this->thumbnails[$index]) &&
2373
+ is_object($this->thumbnails[$index]) &&
2374
+ $this->thumbnails[$index]->isOptimized) || $retinaObj->hasBackup() )
2375
+ {
2376
+ $retinaObj->image_meta->status = $status;
2377
+ $retinaObj->image_meta->compressionType = $type;
2378
+ if ($status == self::FILE_STATUS_SUCCESS)
2379
+ $retinaObj->image_meta->compressedSize = $retinaObj->getFileSize();
2380
+ else
2381
+ $retinaObj->image_meta->originalSize = $retinaObj->getFileSize();
2382
+ // $retinaObj->image_meta->improvement = -1; // n/a
2383
+ $retinaObj->image_meta->tsAdded = $tsAdded;
2384
+ $retinaObj->image_meta->tsOptimized = $tsOptimized;
2385
+ $retinaObj->image_meta->did_jpg2png = $did_jpg2png;
2386
+ if ($retinaObj->hasBackup())
2387
+ {
2388
+ $retinaObj->has_backup = true;
2389
+ if ($status == self::FILE_STATUS_SUCCESS)
2390
+ $retinaObj->image_meta->originalSize = $retinaObj->getBackupFile()->getFileSize();
2391
+ }
2392
+
2393
+ $retinaObj->recordChanged(true);
2394
+ $retinas[$index] = $retinaObj;
2395
+ $addedCounter++;
2396
+ }
2397
+ } // foreach
2398
+
2399
+ $this->retinas = $retinas;
2400
+ if ($count !== $addedCounter)
2401
+ {
2402
+ Log::addWarning("Conversion: $count retinas expected in legacy, " . $addedCounter . 'found. This can be due to overlapping image sizes.');
2403
+ }
2404
  }
2405
 
2406
 
2587
 
2588
  $currentFiles = array($this->getFileName());
2589
  foreach($this->thumbnails as $thumbObj)
2590
+ {
2591
+ $currentFiles[] = $thumbObj->getFileName();
2592
+ }
2593
 
2594
  if ($this->isScaled())
2595
  $currentFiles[] = $this->getOriginalFile()->getFileName();
2596
 
2597
+ if (is_array($this->retinas))
2598
+ {
2599
+ foreach($this->retinas as $retinaObj)
2600
+ {
2601
+ $currentFiles[] = $retinaObj->getFileName();
2602
+ }
2603
+ }
2604
+
2605
  $processFiles = array();
2606
  $unlisted = array();
2607
 
class/Model/Image/MediaLibraryThumbnailModel.php CHANGED
@@ -18,6 +18,7 @@ class MediaLibraryThumbnailModel extends \ShortPixel\Model\Image\ImageModel
18
  public $mime; */
19
  protected $prevent_next_try = false;
20
  protected $is_main_file = false;
 
21
  protected $id; // this is the parent attachment id
22
  protected $size; // size of image in WP, if applicable.
23
 
@@ -47,6 +48,7 @@ class MediaLibraryThumbnailModel extends \ShortPixel\Model\Image\ImageModel
47
  'image_meta' => $this->image_meta,
48
  'name' => $this->name,
49
  'path' => $this->getFullPath(),
 
50
  'exists' => ($this->exists()) ? 'yes' : 'no',
51
 
52
  );
@@ -64,7 +66,9 @@ class MediaLibraryThumbnailModel extends \ShortPixel\Model\Image\ImageModel
64
  $filepath = (string) $this->getFileDir();
65
  $extension = $this->getExtension();
66
 
67
- $retina = new MediaLibraryThumbnailModel($filepath . $filebase . '@2x.' . $extension); // mind the dot in after 2x
 
 
68
 
69
  if ($retina->exists())
70
  return $retina;
@@ -153,7 +157,7 @@ class MediaLibraryThumbnailModel extends \ShortPixel\Model\Image\ImageModel
153
  {
154
  $fs = \wpSPIO()->filesystem();
155
 
156
- if ($this->size == 'original')
157
  {
158
  $url = wp_get_original_image_url($this->id);
159
  }
@@ -168,7 +172,7 @@ class MediaLibraryThumbnailModel extends \ShortPixel\Model\Image\ImageModel
168
  // https://app.asana.com/0/1200110778640816/1202589533659780
169
  $size_array = image_get_intermediate_size($this->id, $this->size);
170
 
171
- if ($size_array === false)
172
  {
173
  $url = $fs->pathToUrl($this);
174
  }
@@ -221,7 +225,10 @@ class MediaLibraryThumbnailModel extends \ShortPixel\Model\Image\ImageModel
221
  // if thumbnail processing is off, thumbs are never processable.
222
  // This is also used by main file, so check for that!
223
  if ( $this->excludeThumbnails() && $this->is_main_file === false)
 
 
224
  return false;
 
225
  else
226
  {
227
  $bool = parent::isProcessable();
@@ -246,14 +253,15 @@ class MediaLibraryThumbnailModel extends \ShortPixel\Model\Image\ImageModel
246
  // !Important . This doubles as checking excluded image sizes.
247
  protected function isSizeExcluded()
248
  {
 
249
  $excludeSizes = \wpSPIO()->settings()->excludeSizes;
250
  if (is_array($excludeSizes) && in_array($this->name, $excludeSizes))
 
 
251
  return true;
252
-
253
- return false;
254
- }
255
-
256
-
257
 
258
  protected function excludeThumbnails()
259
  {
@@ -292,18 +300,9 @@ class MediaLibraryThumbnailModel extends \ShortPixel\Model\Image\ImageModel
292
  {
293
  global $wpdb;
294
 
295
- $size = (! $this->is_main_file) ? $this->size : null;
296
-
297
- if (is_null($size))
298
- {
299
- $sql = 'SELECT id FROM ' . $wpdb->prefix . 'shortpixel_postmeta WHERE attach_id = %d AND size IS NULL';
300
- $sql = $wpdb->prepare($sql, $this->id);
301
- }
302
- else {
303
- $sql = 'SELECT id FROM ' . $wpdb->prefix . 'shortpixel_postmeta WHERE attach_id = %d AND size = %s';
304
- $sql = $wpdb->prepare($sql, $this->id, $size);
305
- }
306
 
 
 
307
 
308
  $id = $wpdb->get_var($sql);
309
 
18
  public $mime; */
19
  protected $prevent_next_try = false;
20
  protected $is_main_file = false;
21
+ protected $is_retina = false; // diffentiate from thumbnail / retina.
22
  protected $id; // this is the parent attachment id
23
  protected $size; // size of image in WP, if applicable.
24
 
48
  'image_meta' => $this->image_meta,
49
  'name' => $this->name,
50
  'path' => $this->getFullPath(),
51
+ 'size' => $this->size,
52
  'exists' => ($this->exists()) ? 'yes' : 'no',
53
 
54
  );
66
  $filepath = (string) $this->getFileDir();
67
  $extension = $this->getExtension();
68
 
69
+ $retina = new MediaLibraryThumbnailModel($filepath . $filebase . '@2x.' . $extension, $this->id, $this->size); // mind the dot in after 2x
70
+ $retina->setName($this->size);
71
+ $retina->is_retina = true;
72
 
73
  if ($retina->exists())
74
  return $retina;
157
  {
158
  $fs = \wpSPIO()->filesystem();
159
 
160
+ if ($this->size == 'original' && ! $this->get('is_retina'))
161
  {
162
  $url = wp_get_original_image_url($this->id);
163
  }
172
  // https://app.asana.com/0/1200110778640816/1202589533659780
173
  $size_array = image_get_intermediate_size($this->id, $this->size);
174
 
175
+ if ($size_array === false || ! isset($size_array['url']))
176
  {
177
  $url = $fs->pathToUrl($this);
178
  }
225
  // if thumbnail processing is off, thumbs are never processable.
226
  // This is also used by main file, so check for that!
227
  if ( $this->excludeThumbnails() && $this->is_main_file === false)
228
+ {
229
+ $this->processable_status = self::P_EXCLUDE_SIZE;
230
  return false;
231
+ }
232
  else
233
  {
234
  $bool = parent::isProcessable();
253
  // !Important . This doubles as checking excluded image sizes.
254
  protected function isSizeExcluded()
255
  {
256
+
257
  $excludeSizes = \wpSPIO()->settings()->excludeSizes;
258
  if (is_array($excludeSizes) && in_array($this->name, $excludeSizes))
259
+ {
260
+ $this->processable_status = self::P_EXCLUDE_SIZE;
261
  return true;
262
+ }
263
+ return false;
264
+ }
 
 
265
 
266
  protected function excludeThumbnails()
267
  {
300
  {
301
  global $wpdb;
302
 
 
 
 
 
 
 
 
 
 
 
 
303
 
304
+ $sql = 'SELECT id FROM ' . $wpdb->prefix . 'shortpixel_postmeta WHERE attach_id = %d AND size = %s';
305
+ $sql = $wpdb->prepare($sql, $this->id, $this->size);
306
 
307
  $id = $wpdb->get_var($sql);
308
 
class/Model/StatsModel.php CHANGED
@@ -30,6 +30,7 @@ class StatsModel
30
 
31
  protected $refreshStatTime;
32
 
 
33
  // Commented out stats were dropped.
34
  // Note: the difference in items / images including thumbs and the counts don't . This is due to technical difference in acquiring the data.
35
  protected $defaults = array(
@@ -38,6 +39,7 @@ class StatsModel
38
  'thumbs' => -1, // Optimized thumbs - SQL does thumbs, but queue doesn't. (imprecise query)
39
  'itemsTotal' => -1, // Total items in media ( sql )
40
  'thumbsTotal' => -1, // Total thumbs in media ( sql ) - imprecise query
 
41
  /* 'lossy' => 0, // processed x compression
42
  'lossy_thumbs' => 0, // main / thumbs
43
  'lossless' => 0, // main /thumbs
@@ -66,6 +68,7 @@ class StatsModel
66
  'itemsTotal' => -1,
67
  'thumbsTotal' => -1,
68
  ),
 
69
  /* 'total' => array('items' => 0, // total items found
70
  'images' => 0, // total images found
71
  ), */
@@ -215,6 +218,9 @@ class StatsModel
215
  case 'thumbsTotal':
216
  $data = $this->countMediaThumbnails();
217
  break;
 
 
 
218
  }
219
 
220
  if ($data >= 0)
@@ -291,6 +297,7 @@ class StatsModel
291
 
292
  $defaults = array(
293
  'optimizedOnly' => false,
 
294
  );
295
 
296
  $args = wp_parse_args($args,$defaults);
@@ -303,17 +310,27 @@ class StatsModel
303
  }
304
  else {
305
  // This query will return 2 positions after the thumbnail array declaration. Value can be up to two positions ( 0-100 thumbnails) . If positions is 1-10 intval will filter out the string part.
306
- $sql = "SELECT meta_id, post_id, substr(meta_value, instr(meta_value,'sizes')+9,2) as thumbcount, LOCATE('original_image', meta_value) as originalImage FROM " . $wpdb->postmeta . " WHERE meta_key = '_wp_attachment_metadata' ";
307
 
308
  $sql .= " AND post_id NOT IN ( SELECT post_id FROM " . $wpdb->postmeta . " where meta_key = '_shortpixel_prevent_optimize' )"; // exclude 'crashed items'
 
 
309
  }
310
 
 
311
  if (count($prepare) > 0)
312
  {
313
  $sql = $wpdb->prepare($sql, $prepare);
314
  }
315
 
316
  $results = $wpdb->get_results($sql);
 
 
 
 
 
 
 
317
  $thumbCount = 0;
318
 
319
  foreach($results as $row)
30
 
31
  protected $refreshStatTime;
32
 
33
+
34
  // Commented out stats were dropped.
35
  // Note: the difference in items / images including thumbs and the counts don't . This is due to technical difference in acquiring the data.
36
  protected $defaults = array(
39
  'thumbs' => -1, // Optimized thumbs - SQL does thumbs, but queue doesn't. (imprecise query)
40
  'itemsTotal' => -1, // Total items in media ( sql )
41
  'thumbsTotal' => -1, // Total thumbs in media ( sql ) - imprecise query
42
+ 'isLimited' => false,
43
  /* 'lossy' => 0, // processed x compression
44
  'lossy_thumbs' => 0, // main / thumbs
45
  'lossless' => 0, // main /thumbs
68
  'itemsTotal' => -1,
69
  'thumbsTotal' => -1,
70
  ),
71
+
72
  /* 'total' => array('items' => 0, // total items found
73
  'images' => 0, // total images found
74
  ), */
218
  case 'thumbsTotal':
219
  $data = $this->countMediaThumbnails();
220
  break;
221
+ case 'isLimited':
222
+ $data = $this->stats['media']['isLimited'];
223
+ break;
224
  }
225
 
226
  if ($data >= 0)
297
 
298
  $defaults = array(
299
  'optimizedOnly' => false,
300
+ 'limit' => 50000,
301
  );
302
 
303
  $args = wp_parse_args($args,$defaults);
310
  }
311
  else {
312
  // This query will return 2 positions after the thumbnail array declaration. Value can be up to two positions ( 0-100 thumbnails) . If positions is 1-10 intval will filter out the string part.
313
+ $sql = "SELECT meta_id, post_id, substr(meta_value, instr(meta_value,'sizes')+9,2) as thumbcount, LOCATE('original_image', meta_value) as originalImage FROM " . $wpdb->postmeta . " WHERE meta_key = '_wp_attachment_metadata' ";
314
 
315
  $sql .= " AND post_id NOT IN ( SELECT post_id FROM " . $wpdb->postmeta . " where meta_key = '_shortpixel_prevent_optimize' )"; // exclude 'crashed items'
316
+
317
+ $sql .= " limit 0," . $args['limit'];
318
  }
319
 
320
+
321
  if (count($prepare) > 0)
322
  {
323
  $sql = $wpdb->prepare($sql, $prepare);
324
  }
325
 
326
  $results = $wpdb->get_results($sql);
327
+
328
+ //og::addDebug('Limit and count results' . $args['limit'] . ' ' . count($results));
329
+ if ($args['limit'] <= count($results))
330
+ {
331
+ $this->stats['media']['isLimited']= true;
332
+ }
333
+
334
  $thumbCount = 0;
335
 
336
  foreach($results as $row)
class/external/cache.php ADDED
@@ -0,0 +1,153 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace ShortPixel;
3
+ use ShortPixel\ShortpixelLogger\ShortPixelLogger as Log;
4
+
5
+ class cacheRemover
6
+ {
7
+ protected $has_supercache = false; // supercache seems to replace quite fine, without our help. @todo Test if this is needed
8
+ protected $has_w3tc = false;
9
+ protected $has_wpengine = false;
10
+ protected $has_fastestcache = false;
11
+ protected $has_siteground = false;
12
+ protected $has_litespeed = false;
13
+
14
+ private static $instance;
15
+
16
+ public function __construct()
17
+ {
18
+ $this->addHooks();
19
+ }
20
+
21
+ public static function getInstance()
22
+ {
23
+ if (is_null(self::$instance))
24
+ self::$instance = new cacheRemover();
25
+
26
+ return self::$instance;
27
+ }
28
+
29
+ public function addHooks()
30
+ {
31
+ add_action('shortpixel/image/optimised', array($this, 'flushCache'));
32
+ }
33
+
34
+ /** Checks which cache plugins are active on the moment a flush is needed */
35
+ public function checkCaches()
36
+ {
37
+ if ( function_exists( 'w3tc_pgcache_flush' ) )
38
+ $this->has_w3tc = true;
39
+
40
+ if ( function_exists('wp_cache_clean_cache') )
41
+ $this->has_supercache = true;
42
+
43
+ if ( class_exists( 'WpeCommon' ) )
44
+ $this->has_wpengine = true;
45
+
46
+ global $wp_fastest_cache;
47
+ if ( method_exists( 'WpFastestCache', 'deleteCache' ) && !empty( $wp_fastest_cache ) )
48
+ $this->has_fastestcache = true;
49
+
50
+ // SG SuperCacher
51
+ if (function_exists('sg_cachepress_purge_cache')) {
52
+ $this->has_siteground = true;
53
+ }
54
+
55
+ if (defined( 'LSCWP_DIR' ))
56
+ {
57
+ $this->has_litespeed = true;
58
+ }
59
+
60
+ // @todo WpRocket?
61
+ // @todo BlueHost Caching?
62
+ }
63
+
64
+ /* Tries to flush cache there were we have issues
65
+ *
66
+ * @param Array $args Argument Array to provide data.
67
+ */
68
+ public function flushCache($imageItem)
69
+ {
70
+ if ($imageItem->get('type') == 'custom')
71
+ {
72
+ $post_id = 0;
73
+ }
74
+ else {
75
+ $post_id = $imageItem->get('id');
76
+ }
77
+
78
+ // important - first check the available cache plugins
79
+ $this->checkCaches();
80
+
81
+ // general WP
82
+ if ($post_id > 0)
83
+ clean_post_cache($post_id);
84
+ else
85
+ wp_cache_flush();
86
+
87
+ /* Verified working without.
88
+ if ($this->has_supercache)
89
+ $this->removeSuperCache();
90
+ */
91
+ if ($this->has_w3tc)
92
+ $this->removeW3tcCache();
93
+
94
+ if ($this->has_wpengine)
95
+ $this->removeWpeCache();
96
+
97
+ if ($this->has_siteground)
98
+ $this->removeSiteGround();
99
+
100
+ if ($this->has_fastestcache)
101
+ $this->removeFastestCache();
102
+
103
+ if ($this->has_litespeed)
104
+ $this->litespeedReset($post_id);
105
+
106
+ }
107
+
108
+ protected function removeSuperCache()
109
+ {
110
+ global $file_prefix, $supercachedir;
111
+ if ( empty( $supercachedir ) && function_exists( 'get_supercache_dir' ) ) {
112
+ $supercachedir = get_supercache_dir();
113
+ }
114
+ wp_cache_clean_cache( $file_prefix );
115
+ }
116
+
117
+ protected function removeW3tcCache()
118
+ {
119
+ w3tc_pgcache_flush();
120
+ }
121
+
122
+ protected function removeWpeCache()
123
+ {
124
+ if ( method_exists( 'WpeCommon', 'purge_memcached' ) ) {
125
+ \WpeCommon::purge_memcached();
126
+ }
127
+ if ( method_exists( 'WpeCommon', 'clear_maxcdn_cache' ) ) {
128
+ \WpeCommon::clear_maxcdn_cache();
129
+ }
130
+ if ( method_exists( 'WpeCommon', 'purge_varnish_cache' ) ) {
131
+ \WpeCommon::purge_varnish_cache();
132
+ }
133
+ }
134
+
135
+ protected function removeFastestCache()
136
+ {
137
+ global $wp_fastest_cache;
138
+ $wp_fastest_cache->deleteCache();
139
+ }
140
+
141
+ protected function removeSiteGround()
142
+ {
143
+ sg_cachepress_purge_cache();
144
+ }
145
+
146
+ protected function litespeedReset($post_id)
147
+ {
148
+ do_action('litespeed_media_reset', $post_id);
149
+ }
150
+
151
+ }
152
+
153
+ cacheRemover::getInstance();
class/external/gravityforms.php CHANGED
@@ -1,5 +1,7 @@
1
  <?php
2
  namespace ShortPixel;
 
 
3
 
4
  // Gravity Forms integrations.
5
  class gravityForms
@@ -7,7 +9,7 @@ class gravityForms
7
 
8
  public function __construct()
9
  {
10
- // @todo All this off, because it can only fatal error.
11
  // add_filter( 'gform_save_field_value', array($this,'shortPixelGravityForms'), 10, 5 );
12
  }
13
 
@@ -20,20 +22,33 @@ class gravityForms
20
 
21
  public function handleGravityFormsImageField($value) {
22
 
23
- $shortPixelObj = wpSPIO()->getShortPixel();
24
 
25
- if(!($folder = $shortPixelObj->getSpMetaDao()->getFolder(SHORTPIXEL_UPLOADS_BASE . '/gravity_forms'))) {
26
- return;
27
- }
 
 
 
 
 
 
 
 
28
  if(strpos($value , '|:|')) {
29
  $cleanup = explode('|:|', $value);
30
  $value = $cleanup[0];
31
  }
 
 
 
 
 
 
32
  //ShortPixel is monitoring the gravity forms folder, add the image to queue
33
- $uploadDir = wp_upload_dir();
34
- $localPath = str_replace($uploadDir['baseurl'], SHORTPIXEL_UPLOADS_BASE, $value);
35
 
36
- return $shortPixelObj->addPathToCustomFolder($localPath, $folder->getId(), 0);
37
  }
38
 
39
  } // class
1
  <?php
2
  namespace ShortPixel;
3
+ use ShortPixel\Controller\OtherMediaController as OtherMediaController;
4
+
5
 
6
  // Gravity Forms integrations.
7
  class gravityForms
9
 
10
  public function __construct()
11
  {
12
+ // @todo All this off, because it can only fatal error.
13
  // add_filter( 'gform_save_field_value', array($this,'shortPixelGravityForms'), 10, 5 );
14
  }
15
 
22
 
23
  public function handleGravityFormsImageField($value) {
24
 
 
25
 
26
+ $fs = \wpSPIO()->filesystem();
27
+ $otherMediaController = OtherMediaController::getInstance();
28
+ $uploadBase = $fs->getWPUploadBase();
29
+
30
+
31
+ $gravFolder = $otherMediaController->getFolderByPath($uploadBase->getPath() . 'gravity_forms');
32
+
33
+ if (! $gravFolder->exists())
34
+ return false;
35
+
36
+ /* no clue what this legacy is suppposed to be.
37
  if(strpos($value , '|:|')) {
38
  $cleanup = explode('|:|', $value);
39
  $value = $cleanup[0];
40
  }
41
+ */
42
+ if (! $gravFolder->get('in_db'))
43
+ {
44
+ $otherMediaController->addDirectory($gravFolder->getPath());
45
+ }
46
+
47
  //ShortPixel is monitoring the gravity forms folder, add the image to queue
48
+ // $uploadDir = wp_upload_dir();
49
+ //$localPath = str_replace($uploadDir['baseurl'], SHORTPIXEL_UPLOADS_BASE, $value);
50
 
51
+ //return $shortPixelObj->addPathToCustomFolder($localPath, $folder->getId(), 0);
52
  }
53
 
54
  } // class
class/external/wp-cli/wp-cli-base.php CHANGED
@@ -22,6 +22,10 @@ class WpCliController
22
 
23
  public function __construct()
24
  {
 
 
 
 
25
  $this->initCommands();
26
  }
27
 
@@ -30,6 +34,8 @@ class WpCliController
30
  if (is_null(self::$instance))
31
  self::$instance = new WpCliController();
32
 
 
 
33
  return self::$instance;
34
  }
35
 
@@ -52,12 +58,12 @@ class SpioCommandBase
52
 
53
  protected static $runs = 0;
54
  /**
55
- * Add a single item to the queue.
56
  *
57
  * ## OPTIONS
58
  *
59
  * <id>
60
- * : MediaLibrary ID
61
  *
62
  *
63
  * [--type=<type>]
@@ -70,12 +76,13 @@ class SpioCommandBase
70
  * ---
71
  *
72
  * [--halt]
73
- * : Stop (don't process the queue) after adding
74
- *
75
  *
76
  * ## EXAMPLES
77
  *
78
- * wp spio add 1
 
79
  *
80
  * @when after_wp_load
81
  */
@@ -126,35 +133,39 @@ class SpioCommandBase
126
 
127
 
128
  /**
129
- * Runs the current queue in manual mode. The queue will process amount of ticks ( send and receive images ) and then * stops. Use this if you regularly (every few minutes) want to run the script.
 
 
130
  *
131
- * Without defining ticks, the queue will run until all have been processed.
132
  *
133
  * ## OPTIONS
134
  *
135
  * [--ticks=<number>]
136
- * : How much times the queue runs
137
  * ---
138
  *
139
- * [--wait=<miliseconds>]
140
- * : How much miliseconds to wait for next tick.
141
  * ---
142
  * default: 3
143
  * ---
144
  *
145
- *
146
- *
147
  * [--queue=<name>]
148
- * : Either 'media' or 'custom' . Omit to run both.
149
  * ---
150
  * default: media,custom
151
  * ---
 
 
 
 
152
  *
153
  * ## EXAMPLES
154
  *
155
- * wp spio run | Complete all processes
156
- * wp spio run --ticks=20 --wait=3 | Ticks and wait time.
157
- * wp spio run --queue=media | Only run a specific queue.
158
  *
159
  *
160
  * @when after_wp_load
@@ -380,30 +391,30 @@ class SpioCommandBase
380
  protected function displayStatsLine($name, $stats)
381
  {
382
 
383
- $line = sprintf('Current Status for %s : (%d\%d) Done (%d%%), %d awaiting %d errors --', $name, $stats->done, $stats->total, $stats->percentage_done, ( $stats->in_process + $stats->in_queue ), $stats->fatal_errors);
384
 
385
  \WP_CLI::line($line);
386
  }
387
 
388
- /** Shows the current status of the queue
 
 
 
 
 
389
  *
390
- * [--show-debug]
391
- * : Dump more information for debugging
392
  *
 
393
  *
394
- * ---
395
- *
396
- * ## EXAMPLES
397
- *
398
- * wp spio status [--show-debug]
399
- *
400
  */
401
  public function status($args, $assoc)
402
  {
403
- $queue = $this->getQueueArgument($assoc);
404
 
 
405
  $startupData = $this->getStatus();
406
 
 
407
  $items = array();
408
  $fields = array('queue name', 'in queue', 'in process', 'fatal errors', 'done', 'total', 'preparing', 'running', 'finished');
409
 
@@ -436,14 +447,15 @@ class SpioCommandBase
436
  \WP_CLI\Utils\format_items('table', $items, $fields);
437
  }
438
 
439
- /** Shows Key setting that are applied when running via WP_CLI.
 
440
  *
441
  *
442
  * ---
443
  *
444
  * ## EXAMPLES
445
  *
446
- * wp settings
447
  *
448
  */
449
  public function settings()
@@ -464,17 +476,20 @@ class SpioCommandBase
464
  }
465
 
466
  /**
467
- * Clears the Queue(s)
468
  *
469
  *
470
  * [--queue=<name>]
471
- * : Either 'media' or 'custom' . Omit to run both.
472
  * ---
473
  * default: media,custom
474
  * options:
475
  * - media
476
  * - custom
477
  *
 
 
 
478
  */
479
  public function clear($args, $assoc)
480
  {
22
 
23
  public function __construct()
24
  {
25
+ $log = \ShortPixel\ShortPixelLogger\ShortPixelLogger::getInstance();
26
+ if (\ShortPixel\ShortPixelLogger\ShortPixelLogger::debugIsActive())
27
+ $log->setLogPath(SHORTPIXEL_BACKUP_FOLDER . "/shortpixel_log_wpcli");
28
+
29
  $this->initCommands();
30
  }
31
 
34
  if (is_null(self::$instance))
35
  self::$instance = new WpCliController();
36
 
37
+
38
+
39
  return self::$instance;
40
  }
41
 
58
 
59
  protected static $runs = 0;
60
  /**
61
+ * Adds a single item to the queue(s).
62
  *
63
  * ## OPTIONS
64
  *
65
  * <id>
66
+ * : Media Library ID or Custom Media ID
67
  *
68
  *
69
  * [--type=<type>]
76
  * ---
77
  *
78
  * [--halt]
79
+ * : Stops (does not process the queues) after the item is added.
80
+ *
81
  *
82
  * ## EXAMPLES
83
  *
84
+ * wp spio [bulk] add 123
85
+ * wp spio [bulk] add 21 --type=custom --halt
86
  *
87
  * @when after_wp_load
88
  */
133
 
134
 
135
  /**
136
+ * Starts processing what has been added to the processing queue(s), optionally stopping after a specified number of "ticks".
137
+ *
138
+ * A tick (or cycle) means a request sent to the API, either to send an image to be processed or to check if the API has completed processing. Use the ticks (cycles) if you want to run the script regularly (every few minutes) want to run the script.
139
  *
140
+ * If you do not define ticks, the queue will run until everything has been processed.
141
  *
142
  * ## OPTIONS
143
  *
144
  * [--ticks=<number>]
145
+ * : How often the queue runs (how many ticks/cycles)
146
  * ---
147
  *
148
+ * [--wait=<seconds>]
149
+ * : How many seconds the system waits for next tick (cycle).
150
  * ---
151
  * default: 3
152
  * ---
153
  *
 
 
154
  * [--queue=<name>]
155
+ * : Either 'media' or 'custom'. Omit the parameter to run both queues.
156
  * ---
157
  * default: media,custom
158
  * ---
159
+ * options:
160
+ * - media
161
+ * - custom
162
+ * ---
163
  *
164
  * ## EXAMPLES
165
  *
166
+ * wp spio [bulk] run | Complete all processes
167
+ * wp spio [bulk] run --ticks=20 --wait=3 | Ticks and wait time.
168
+ * wp spio [bulk] run --queue=media | Only run a specific queue.
169
  *
170
  *
171
  * @when after_wp_load
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
  }
398
 
399
+ /**
400
+ * Displays the current status of the processing queue(s)
401
+ *
402
+ * [--show-debug]
403
+ * : Dumps more information for debugging purposes
404
+ * ---
405
  *
406
+ * ## EXAMPLES
 
407
  *
408
+ * wp spio [bulk] status [--show-debug]
409
  *
 
 
 
 
 
 
410
  */
411
  public function status($args, $assoc)
412
  {
 
413
 
414
+ $queue = $this->getQueueArgument($assoc);
415
  $startupData = $this->getStatus();
416
 
417
+
418
  $items = array();
419
  $fields = array('queue name', 'in queue', 'in process', 'fatal errors', 'done', 'total', 'preparing', 'running', 'finished');
420
 
447
  \WP_CLI\Utils\format_items('table', $items, $fields);
448
  }
449
 
450
+ /**
451
+ * Displays the key settings that are applied when executing commands with WP-CLI.
452
  *
453
  *
454
  * ---
455
  *
456
  * ## EXAMPLES
457
  *
458
+ * wp spio [bulk] settings
459
  *
460
  */
461
  public function settings()
476
  }
477
 
478
  /**
479
+ * Clears the Queue(s)
480
  *
481
  *
482
  * [--queue=<name>]
483
+ * : Either 'media' or 'custom'. Omit the parameter to clear both queues.
484
  * ---
485
  * default: media,custom
486
  * options:
487
  * - media
488
  * - custom
489
  *
490
+ * ## EXAMPLES
491
+ *
492
+ * wp spio [bulk] clear
493
  */
494
  public function clear($args, $assoc)
495
  {
class/external/wp-cli/wp-cli-bulk.php CHANGED
@@ -8,29 +8,29 @@ use ShortPixel\Controller\Queue\Queue as Queue;
8
  use ShortPixel\Controller\ApiController as ApiController;
9
  use ShortPixel\Controller\ResponseController as ResponseController;
10
 
11
-
 
 
12
  class SpioBulk extends SpioCommandBase
13
  {
14
  /**
15
- * Starts prepared queue. The bulk needs an express command to start running.
16
- * After starting, the queue can be finished by using the run command.
17
  *
18
  * ## OPTIONS
19
 
20
  * [--queue=<name>]
21
- * : Either 'media' or 'custom' . Omit to run both.
22
  * ---
23
  * default: media,custom
24
  * options:
25
  * - media
26
  * - custom
27
- *
28
  * ---
29
  *
30
  * ## EXAMPLES
31
  *
32
- * wp spio start <ticks=20> <wait=3>
33
- * wp spio start
34
  *
35
  *
36
  * @when after_wp_load
@@ -54,13 +54,24 @@ class SpioBulk extends SpioCommandBase
54
  }
55
 
56
 
57
- /**
58
- * Automatically Bulk Process all that needs to be done
59
- *
60
- * [--queue=<name>]
61
- * : Either 'media' or 'custom' . Omit to run both.
62
- *
63
- */
 
 
 
 
 
 
 
 
 
 
 
64
  public function auto($args, $assoc)
65
  {
66
  $queue = $this->getQueueArgument($assoc);
@@ -100,7 +111,7 @@ class SpioBulk extends SpioCommandBase
100
  }
101
  elseif ($combined->is_finished)
102
  {
103
- if ($created) // means we already ran the whole thing once.
104
  {
105
  \WP_CLI::Line('[Auto Bulk] Seems finished and done running');
106
  $running = false;
@@ -127,18 +138,23 @@ class SpioBulk extends SpioCommandBase
127
  }
128
 
129
  /**
130
- * Enqueues the batch for bulk optimizing the media library
131
  *
132
  * ## OPTIONS
133
  *
134
  * [--queue=<name>]
135
- * : Either 'media' or 'custom' . Omit to run both.
 
 
 
 
 
 
136
  *
137
  * ## EXAMPLES
138
  *
139
- * wp spio bulk create
140
  *
141
-
142
  *
143
  * @when after_wp_load
144
  */
@@ -164,29 +180,28 @@ class SpioBulk extends SpioCommandBase
164
  return $stats;
165
  }
166
 
167
- /**
168
- * ## OPTIONS
169
- *
170
- * <start-id>
171
- * : ID to start restore
172
  *
173
  * <end-id>
174
  * : ID to stop restore
175
  *
176
- * [--type=<type>]
177
- * : Media | Custom
178
- * ---
179
- * default: media
180
- * options:
181
- * - media
182
- * - custom
183
- * ---
184
- *
185
  * ## EXAMPLES
186
  *
187
  * wp spio bulk restore 0 100
188
  *
189
-
190
  *
191
  * @when after_wp_load
192
  */
@@ -216,19 +231,24 @@ class SpioBulk extends SpioCommandBase
216
  return $optimizeController;
217
  }
218
 
219
- /**
220
- * Prepares items, similar to the run command. If will only run when a queue is in preparing stage and will run until everything is prepared.
221
- *
222
- *
223
- * [--queue=<name>]
224
- * : Either 'media' or 'custom' . Omit to run both.
225
- * ---
226
- * default: media,custom
227
- * options:
228
- * - media
229
- * - custom
230
- *
231
- */
 
 
 
 
 
232
  public function prepare($args, $assoc)
233
  {
234
  $queues = $this->getQueueArgument($assoc);
8
  use ShortPixel\Controller\ApiController as ApiController;
9
  use ShortPixel\Controller\ResponseController as ResponseController;
10
 
11
+ /**
12
+ * Actions for running bulk operations from WP-CLI
13
+ */
14
  class SpioBulk extends SpioCommandBase
15
  {
16
  /**
17
+ * Starts the prepared queue(s). The bulk needs an express command to start processing.
18
+ * Once started, the queue(s) can be processed and finished with the run command.
19
  *
20
  * ## OPTIONS
21
 
22
  * [--queue=<name>]
23
+ * : Either 'media' or 'custom'. Omit the parameter to start both queues.
24
  * ---
25
  * default: media,custom
26
  * options:
27
  * - media
28
  * - custom
 
29
  * ---
30
  *
31
  * ## EXAMPLES
32
  *
33
+ * wp spio bulk start
 
34
  *
35
  *
36
  * @when after_wp_load
54
  }
55
 
56
 
57
+ /**
58
+ * Automatically Bulk Processes everything that needs to be done.
59
+ *
60
+ * [--queue=<name>]
61
+ * : Either 'media' or 'custom'. Omit the parameter to process both queues.
62
+ * ---
63
+ * default: media,custom
64
+ * options:
65
+ * - media
66
+ * - custom
67
+ * ---
68
+ *
69
+ * ## EXAMPLES
70
+ *
71
+ * wp spio bulk auto
72
+ *
73
+ *
74
+ */
75
  public function auto($args, $assoc)
76
  {
77
  $queue = $this->getQueueArgument($assoc);
111
  }
112
  elseif ($combined->is_finished)
113
  {
114
+ if ($combined->done > 0 || $created == true) // means we already ran the whole thing once.
115
  {
116
  \WP_CLI::Line('[Auto Bulk] Seems finished and done running');
117
  $running = false;
138
  }
139
 
140
  /**
141
+ * Creates the queue(s) for bulk optimization of media library and/or custom media items.
142
  *
143
  * ## OPTIONS
144
  *
145
  * [--queue=<name>]
146
+ * : Either 'media' or 'custom'. Omit the parameter to create both queues.
147
+ * ---
148
+ * default: media,custom
149
+ * options:
150
+ * - media
151
+ * - custom
152
+ * ---
153
  *
154
  * ## EXAMPLES
155
  *
156
+ * wp spio bulk create
157
  *
 
158
  *
159
  * @when after_wp_load
160
  */
180
  return $stats;
181
  }
182
 
183
+ /**
184
+ * ## OPTIONS
185
+ *
186
+ * <start-id>
187
+ * : ID to start restore
188
  *
189
  * <end-id>
190
  * : ID to stop restore
191
  *
192
+ * [--type=<type>]
193
+ * : media or custom
194
+ * ---
195
+ * default: media
196
+ * options:
197
+ * - media
198
+ * - custom
199
+ * ---
200
+ *
201
  * ## EXAMPLES
202
  *
203
  * wp spio bulk restore 0 100
204
  *
 
205
  *
206
  * @when after_wp_load
207
  */
231
  return $optimizeController;
232
  }
233
 
234
+ /**
235
+ * Prepares the items by adding them to the queue(s). It runs only when the queue is in the preparing phase and finishes when everything is prepared.
236
+ *
237
+ *
238
+ * [--queue=<name>]
239
+ * : Either 'media' or 'custom'. Omit the parameter to run both queues.
240
+ * ---
241
+ * default: media,custom
242
+ * options:
243
+ * - media
244
+ * - custom
245
+ * ---
246
+ *
247
+ * ## EXAMPLES
248
+ *
249
+ * wp spio bulk prepare
250
+ *
251
+ */
252
  public function prepare($args, $assoc)
253
  {
254
  $queues = $this->getQueueArgument($assoc);
class/external/wp-cli/wp-cli-single.php CHANGED
@@ -8,19 +8,22 @@ use ShortPixel\Controller\Queue\Queue as Queue;
8
  use ShortPixel\Controller\ApiController as ApiController;
9
  use ShortPixel\Controller\ResponseController as ResponseController;
10
 
 
 
 
11
  class SpioSingle extends SpioCommandBase
12
  {
13
 
14
  /**
15
- * Restores optimized item to original ( if backups are active )
16
  *
17
  * ## OPTIONS
18
  *
19
  * <id>
20
- * : MediaLibrary ID
21
  *
22
  * [--type=<type>]
23
- * : Media | Custom
24
  * ---
25
  * default: media
26
  * options:
@@ -30,8 +33,8 @@ class SpioSingle extends SpioCommandBase
30
  *
31
  * ## EXAMPLES
32
  *
33
- * wp spio restore 1
34
- * wp spio restore 1 --type=custom
35
  *
36
  * @when after_wp_load
37
  */
8
  use ShortPixel\Controller\ApiController as ApiController;
9
  use ShortPixel\Controller\ResponseController as ResponseController;
10
 
11
+ /**
12
+ * Actions and operations for the ShortPixel Image Optimizer plugin
13
+ */
14
  class SpioSingle extends SpioCommandBase
15
  {
16
 
17
  /**
18
+ * Restores the optimized item to its original state (if backups are active).
19
  *
20
  * ## OPTIONS
21
  *
22
  * <id>
23
+ * : Media Library ID or Custom Media ID
24
  *
25
  * [--type=<type>]
26
+ * : media | custom
27
  * ---
28
  * default: media
29
  * options:
33
  *
34
  * ## EXAMPLES
35
  *
36
+ * wp spio restore 123
37
+ * wp spio restore 21 --type=custom
38
  *
39
  * @when after_wp_load
40
  */
class/front/img-to-picture-webp.php CHANGED
@@ -17,7 +17,6 @@ class ShortPixelImgToPictureWebp
17
  return $content; // . (isset($_GET['SHORTPIXEL_DEBUG']) ? '<!-- -->' : '');
18
  }
19
 
20
-
21
  $new_content = $this->testPictures($content);
22
  if ($new_content !== false)
23
  {
@@ -36,7 +35,7 @@ class ShortPixelImgToPictureWebp
36
  // [BS] No callback because we need preg_match_all
37
  $content = $this->testInlineStyle($content);
38
  // $content = preg_replace_callback('/background.*[^:]url\([\'|"](.*)[\'|"]\)[,;]/imU',array('self', 'convertInlineStyle'), $content);
39
- Log::addDebug('SPDBG WebP process done');
40
 
41
  return $content; // . (isset($_GET['SHORTPIXEL_DEBUG']) ? '<!-- SPDBG WebP converted -->' : '');
42
 
@@ -216,7 +215,7 @@ class ShortPixelImgToPictureWebp
216
  continue;
217
  $condition = isset($parts[1]) ? ' ' . $parts[1] : '';
218
 
219
- Log::addDebug('Running item - ' . $item, $fileurl);
220
 
221
  $fsFile = $fs->getFile($fileurl);
222
  $extension = $fsFile->getExtension(); // trigger setFileinfo, which will resolve URL -> Path
17
  return $content; // . (isset($_GET['SHORTPIXEL_DEBUG']) ? '<!-- -->' : '');
18
  }
19
 
 
20
  $new_content = $this->testPictures($content);
21
  if ($new_content !== false)
22
  {
35
  // [BS] No callback because we need preg_match_all
36
  $content = $this->testInlineStyle($content);
37
  // $content = preg_replace_callback('/background.*[^:]url\([\'|"](.*)[\'|"]\)[,;]/imU',array('self', 'convertInlineStyle'), $content);
38
+ // Log::addDebug('SPDBG WebP process done');
39
 
40
  return $content; // . (isset($_GET['SHORTPIXEL_DEBUG']) ? '<!-- SPDBG WebP converted -->' : '');
41
 
215
  continue;
216
  $condition = isset($parts[1]) ? ' ' . $parts[1] : '';
217
 
218
+ // Log::addDebug('Running item - ' . $item, $fileurl);
219
 
220
  $fsFile = $fs->getFile($fileurl);
221
  $extension = $fsFile->getExtension(); // trigger setFileinfo, which will resolve URL -> Path
class/plugin.json CHANGED
@@ -1 +1 @@
1
- {"name":"ShortPixel\/Plugin","description":"ShortPixel AutoLoader","type":"function","autoload":{"psr-4":{"ShortPixel":"class"},"files":["class\/wp-shortpixel-settings.php","class\/shortpixel-png2jpg.php","class\/front\/img-to-picture-webp.php","class\/external\/cloudflare.php","class\/external\/flywheel.php","class\/external\/nextgen\/nextGenController.php","class\/external\/nextgen\/nextGenViewController.php","class\/external\/visualcomposer.php","class\/external\/wp-offload-media.php","class\/external\/wp-cli\/wp-cli-base.php","class\/external\/wp-cli\/wp-cli-single.php","class\/external\/wp-cli\/wp-cli-bulk.php","class\/external\/custom-suffixes.php","class\/external\/pantheon.php","class\/external\/spai.php"]}}
1
+ {"name":"ShortPixel\/Plugin","description":"ShortPixel AutoLoader","type":"function","autoload":{"psr-4":{"ShortPixel":"class"},"files":["class\/wp-shortpixel-settings.php","class\/shortpixel-png2jpg.php","class\/front\/img-to-picture-webp.php","class\/external\/cloudflare.php","class\/external\/flywheel.php","class\/external\/nextgen\/nextGenController.php","class\/external\/nextgen\/nextGenViewController.php","class\/external\/visualcomposer.php","class\/external\/wp-offload-media.php","class\/external\/wp-cli\/wp-cli-base.php","class\/external\/wp-cli\/wp-cli-single.php","class\/external\/wp-cli\/wp-cli-bulk.php","class\/external\/custom-suffixes.php","class\/external\/pantheon.php","class\/external\/spai.php","class\/external\/cache.php"]}}
class/view/bulk/part-selection.php CHANGED
@@ -35,8 +35,14 @@ $approx = $this->view->approx;
35
  <h2><?php esc_html_e('Optimize:','shortpixel-image-optimiser'); ?> </h2>
36
  <p><?php printf(esc_html__('ShortPixel has %sestimated%s the number of images that can still be optimized. %sAfter you select the options, the plugin will calculate exactly how many images to optimize.','shortpixel-image-optimiser'), '<b>','</b>', '<br />'); ?></p>
37
 
 
 
 
 
 
38
  <div class="media-library optiongroup">
39
 
 
40
  <div class='switch_button'>
41
  <label>
42
  <input type="checkbox" class="switch" id="media_checkbox" checked>
@@ -50,6 +56,7 @@ $approx = $this->view->approx;
50
  <label><?php esc_html_e('Images (estimate)', 'shortpixel-image-optimiser'); ?></label>
51
  <span class="number" ><?php echo esc_html($approx->media->items) ?></span>
52
  </div>
 
53
  <?php if (\wpSPIO()->settings()->processThumbnails == 1): ?>
54
  <div class='option'>
55
  <label><?php esc_html_e('Thumbnails (estimate)','shortpixel-image-optimiser'); ?></label> <span class="number" ><?php echo esc_html($approx->media->thumbs) ?> </span>
@@ -106,7 +113,7 @@ $approx = $this->view->approx;
106
 
107
  </div>
108
  <h4><label for="webp_checkbox">
109
- <?php printf(esc_html__('Also create %s WebP %s versions of the images' ,'shortpixel-image-optimiser'), '<b>', '</b>' ); ?>
110
  </label></h4>
111
  <div class="option"><?php esc_html_e('The total number of WebP images will be calculated in the next step.','shortpixel-image-optimiser'); ?></div>
112
  </div>
@@ -121,7 +128,7 @@ $approx = $this->view->approx;
121
  </label>
122
 
123
  </div>
124
- <h4><label for="avif_checkbox"><?php esc_html_e('Also create AVIF> versions of the images','shortpixel-image-optimiser'); ?></label></h4>
125
  <div class="option"><?php esc_html_e('The total number of AVIF images will be calculated in the next step.','shortpixel-image-optimiser'); ?></div>
126
  </div>
127
  </div>
@@ -135,7 +142,7 @@ $approx = $this->view->approx;
135
  <h4 class='approx'><?php esc_html_e('An estimate of unoptimized images in this installation', 'shortpixel-image-optimiser'); ?> :
136
  <span data-check-approx-total><?php echo esc_html($approx->total->images) ?></span> </h4>
137
 
138
- <div><p><?php printf(esc_html_e('In the next step, the plugin will calculate the total number of images to be optimized, and your bulk process will be prepared. The processing %swill not start yet%s, but a summary of the images to be optimized will be displayed.', 'shortpixel-image-optimiser'),'<b>','</b>'); ?></p></div>
139
  </div>
140
 
141
  <nav>
35
  <h2><?php esc_html_e('Optimize:','shortpixel-image-optimiser'); ?> </h2>
36
  <p><?php printf(esc_html__('ShortPixel has %sestimated%s the number of images that can still be optimized. %sAfter you select the options, the plugin will calculate exactly how many images to optimize.','shortpixel-image-optimiser'), '<b>','</b>', '<br />'); ?></p>
37
 
38
+ <?php if ($approx->media->isLimited): ?>
39
+ <h4 class='count_limited'><?php esc_html_e('Shortpixel has detected a high number of images. This estimates are limited for performance reasons. On the next step an accurate count will be produced', 'shortpixel-image-optimiser'); ?></h4>
40
+ <?php endif; ?>
41
+
42
+
43
  <div class="media-library optiongroup">
44
 
45
+
46
  <div class='switch_button'>
47
  <label>
48
  <input type="checkbox" class="switch" id="media_checkbox" checked>
56
  <label><?php esc_html_e('Images (estimate)', 'shortpixel-image-optimiser'); ?></label>
57
  <span class="number" ><?php echo esc_html($approx->media->items) ?></span>
58
  </div>
59
+
60
  <?php if (\wpSPIO()->settings()->processThumbnails == 1): ?>
61
  <div class='option'>
62
  <label><?php esc_html_e('Thumbnails (estimate)','shortpixel-image-optimiser'); ?></label> <span class="number" ><?php echo esc_html($approx->media->thumbs) ?> </span>
113
 
114
  </div>
115
  <h4><label for="webp_checkbox">
116
+ <?php printf(esc_html__('Also create WebP versions of the images' ,'shortpixel-image-optimiser') ); ?>
117
  </label></h4>
118
  <div class="option"><?php esc_html_e('The total number of WebP images will be calculated in the next step.','shortpixel-image-optimiser'); ?></div>
119
  </div>
128
  </label>
129
 
130
  </div>
131
+ <h4><label for="avif_checkbox"><?php esc_html_e('Also create AVIF versions of the images','shortpixel-image-optimiser'); ?></label></h4>
132
  <div class="option"><?php esc_html_e('The total number of AVIF images will be calculated in the next step.','shortpixel-image-optimiser'); ?></div>
133
  </div>
134
  </div>
142
  <h4 class='approx'><?php esc_html_e('An estimate of unoptimized images in this installation', 'shortpixel-image-optimiser'); ?> :
143
  <span data-check-approx-total><?php echo esc_html($approx->total->images) ?></span> </h4>
144
 
145
+ <div><p><?php printf(__('In the next step, the plugin will calculate the total number of images to be optimized, and your bulk process will be prepared. The processing %s will not start yet %s, but a summary of the images to be optimized will be displayed.', 'shortpixel-image-optimiser'),'<b>','</b>'); ?></p></div>
146
  </div>
147
 
148
  <nav>
class/view/bulk/part-summary.php CHANGED
@@ -19,7 +19,7 @@ namespace ShortPixel;
19
  </h3>
20
  <div class="section-wrapper" data-check-visibility data-control="data-check-media-total">
21
  <h4><span class='dashicons dashicons-images-alt2'>&nbsp;</span>
22
- <?php esc_html_e('Media Library','shortpixel-image-optimiser'); ?> (<span data-stats-media="in_queue">0</span> <?php esc_html_e('items','shortpixel-image-optimiser'); ?></h4>
23
  <div class="list-table">
24
 
25
 
@@ -41,7 +41,7 @@ namespace ShortPixel;
41
  </div>
42
 
43
  <div class="section-wrapper" data-check-visibility data-control="data-check-custom-total">
44
- <h4><span class='dashicons dashicons-open-folder'>&nbsp;</span><?php esc_html_e('Custom Media', 'shortpixel-image-optimiser') ?> (<span data-stats-custom="in_queue">0</span> <?php esc_html_e('images','shortpixel-image-optimiser'); ?></h4>
45
  <div class="list-table">
46
 
47
  <div><span><?php esc_html_e('Images','shortpixel-image-optimiser'); ?></span>
19
  </h3>
20
  <div class="section-wrapper" data-check-visibility data-control="data-check-media-total">
21
  <h4><span class='dashicons dashicons-images-alt2'>&nbsp;</span>
22
+ <?php esc_html_e('Media Library','shortpixel-image-optimiser'); ?> (<span data-stats-media="in_queue">0</span> <?php esc_html_e('items','shortpixel-image-optimiser'); ?>)</h4>
23
  <div class="list-table">
24
 
25
 
41
  </div>
42
 
43
  <div class="section-wrapper" data-check-visibility data-control="data-check-custom-total">
44
+ <h4><span class='dashicons dashicons-open-folder'>&nbsp;</span><?php esc_html_e('Custom Media', 'shortpixel-image-optimiser') ?> (<span data-stats-custom="in_queue">0</span> <?php esc_html_e('items','shortpixel-image-optimiser'); ?>)</h4>
45
  <div class="list-table">
46
 
47
  <div><span><?php esc_html_e('Images','shortpixel-image-optimiser'); ?></span>
class/view/settings/part-advanced.php CHANGED
@@ -321,54 +321,70 @@ use \ShortPixel\Helper\UiHelper as UiHelper;
321
  <div class="option-content">
322
  <div class="spio-inline-help"><span class="dashicons dashicons-editor-help" title="Click for more info" data-link="https://shortpixel.com/knowledge-base/article/88-how-to-exclude-images-from-being-optimized"></span></div>
323
 
 
 
 
 
 
 
 
 
 
 
 
324
  <textarea name="excludePatterns" type="text" id="excludePatterns" placeholder="<?php
325
  esc_html_e('name:keepbig, path:/full/path/to/exclude/, regex-name:/valid_regex/, size:1000x2000','shortpixel-image-optimiser');?>" rows="4" cols="60"><?php echo esc_html( $excludePatterns );?></textarea>
326
 
327
  </div>
328
- <p class="settings-info">
329
- <?php
330
- // Hear you like strong, so I put some strong in your strong.
331
- printf(esc_html__('Add patterns separated by comma. A pattern consist of a %stype:value%s pair; the accepted types are
332
- %s"name"%s, %s"path"%s, %s"size"%s, %s"regex-name"%s and %s"regex-path"%s.
333
- A file is excluded if it matches any of the patterns. %s
334
-
335
- %s For a %s"name"%s pattern only the filename is matched, for %s"path"%s,
336
- the whole path will be matched (useful for excluding certain (sub)-directories altoghether).
337
- %s %s
338
- %s"regex-path"%s and %s"regex-name"%s work the same, except it requires a valid regular expression, contained between slashes. Special characters should be escaped by adding \ in front of them.
339
- %s %s
340
-
341
- For the %s"size"%s type, which applies only to Media Library images, %sthe main images (not thumbnails)%s that have the size in the specified range are excluded.
342
- The format for the "size" exclude is: %sminWidth%s- %smaxWidth%sx%sminHeight%s%s>maxHeight%s, for example %ssize:1000-1100x2000-2200%s. You can also specify a precise size, such as %s1000x2000%s.','shortpixel-image-optimiser'),
343
- '<strong>', '</strong>',
344
- '<strong>', '</strong>',
345
- '<strong>', '</strong>',
346
- '<strong>', '</strong>',
347
- '<strong>', '</strong>',
348
- '<strong>', '</strong>',
349
- '<br>',
350
- '<br>',
351
- '<strong>', '</strong>',
352
- '<strong>', '</strong>',
353
- '<strong>', '</strong>',
354
- '<strong>', '</strong>',
355
- '<br>',
356
- '<br>',
357
- '<strong>', '</strong>',
358
- '<strong>', '</strong>',
359
- '<br>',
360
- '<br>',
361
- '<strong>', '</strong>',
362
- '<strong>', '</strong>',
363
- '<strong>', '</strong>',
364
- '<strong>', '</strong>',
365
- '<strong>', '</strong>',
366
- '<strong>', '</strong>',
367
- '<strong>', '</strong>',
368
- '<strong>', '</strong>'
369
- );
370
- ?>
371
  </p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
372
  </td>
373
  </tr>
374
  <tr>
321
  <div class="option-content">
322
  <div class="spio-inline-help"><span class="dashicons dashicons-editor-help" title="Click for more info" data-link="https://shortpixel.com/knowledge-base/article/88-how-to-exclude-images-from-being-optimized"></span></div>
323
 
324
+ <p class="settings-info" data-toggle="exclude-settings-expanded">
325
+ <?php
326
+ printf(esc_html__('Use this section to exclude images based on patterns (separated by commas). A pattern consists of a %s type:value %s pair and the accepted types are %s "name", "path", "size", "regex-name" and "regex-path" %s. A file is excluded if it matches any of the patterns. Examples can be found in the collapsible area below the exclusion list.','shortpixel-image-optimiser'),
327
+ '<b>','</b>',
328
+ '<b>','</b>'
329
+ );
330
+ ?>
331
+ <br /><br />
332
+
333
+ </p>
334
+
335
  <textarea name="excludePatterns" type="text" id="excludePatterns" placeholder="<?php
336
  esc_html_e('name:keepbig, path:/full/path/to/exclude/, regex-name:/valid_regex/, size:1000x2000','shortpixel-image-optimiser');?>" rows="4" cols="60"><?php echo esc_html( $excludePatterns );?></textarea>
337
 
338
  </div>
339
+
340
+ <p class="settings-info">
341
+ <label><input type='checkbox' class='shortpixel-hide' data-toggle='exclude-settings-expanded'> >> <?php printf(esc_html__('See examples')); ?></label>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
342
  </p>
343
+
344
+ <div class='exclude-settings-expanded toggleTarget ' id="exclude-settings-expanded">
345
+ <p class="settings-info">
346
+ <?php
347
+ printf(esc_html__('For the pattern %s"name"%s, only the file name is matched, e.g. the pattern %sname:flower.jpg%s tells ShortPixel to exclude all JPEG images ending in “flower” (lowercase). At the same time, the pattern %sname:logo%s,excludes all images – PNG/JPEG/GIF – that contain the word “logo” in their name: “nicelogo.jpg”, “alllogos.png”, “logo.gif”.', 'shortpixel-image-optimiser'),
348
+ '<b>','</b>',
349
+ '<b>','</b>',
350
+ '<b>','</b>'
351
+ );
352
+ ?>
353
+
354
+ </p>
355
+ <br />
356
+ <p class="settings-info">
357
+ <?php
358
+ printf(esc_html__('For the %s"path"%s pattern, the entire path is matched (useful to exclude certain (sub)-directories altogether). For example, %spath:2022%s excludes all images uploaded in 2022, but also excludes images that contain 2022 in the filename (since this is also part of the path). If you want to exclude only the images uploaded in 2022, use %spath:/2022/%s instead.','shortpixel-image-optimiser'),
359
+ '<b>','</b>',
360
+ '<b>','</b>',
361
+ '<b>','</b>'
362
+ );
363
+ ?>
364
+ </p>
365
+ <br />
366
+ <p class="settings-info">
367
+ <?php
368
+ printf(esc_html__('%s"regex-path"%s and %s"regex-name"%s work the same way, but require a valid regular expression placed between slashes. Special characters should be escaped by prefixing them with \ . For example %sregex-name:/[0-9]+[^\/]*\.(PNG|png)/%s excludes all PNG images that have a numeric prefix.','shortpixel-image-optimiser'),
369
+ '<b>','</b>',
370
+ '<b>','</b>',
371
+ '<b>','</b>'
372
+ );
373
+ ?>
374
+ </p>
375
+ <br />
376
+ <p class="settings-info">
377
+ <?php
378
+ printf(esc_html__('The %s"size"%s type, which applies only to Media Library images, excludes the main images (not thumbnails) whose size is in the specified range. The format for the "size" exclusion type is: %sminWidth-maxWidthxminHeight-maxHeight%s, for example %ssize:1000-1100x2000-2200%s. You can also specify a exact size, for example, %s1000x2000%s.','shortpixel-image-optimiser'),
379
+ '<b>','</b>',
380
+ '<b>','</b>',
381
+ '<b>','</b>',
382
+ '<b>','</b>'
383
+ );
384
+ ?>
385
+ </p>
386
+
387
+ </div>
388
  </td>
389
  </tr>
390
  <tr>
class/view/settings/part-debug.php CHANGED
@@ -79,6 +79,7 @@ $env = \wpSPIO()->env();
79
  <span>Images</span><span><?php echo esc_html($statsControl->find('media', 'images')); ?></span>
80
  <span>ItemsTotal</span><span><?php echo esc_html($statsControl->find('media', 'itemsTotal')); ?></span>
81
  <span>ThumbsTotal</span><span><?php echo esc_html($statsControl->find('media', 'thumbsTotal')); ?></span>
 
82
  </div>
83
  <h4>Custom</h4>
84
  <div class='flex'>
79
  <span>Images</span><span><?php echo esc_html($statsControl->find('media', 'images')); ?></span>
80
  <span>ItemsTotal</span><span><?php echo esc_html($statsControl->find('media', 'itemsTotal')); ?></span>
81
  <span>ThumbsTotal</span><span><?php echo esc_html($statsControl->find('media', 'thumbsTotal')); ?></span>
82
+
83
  </div>
84
  <h4>Custom</h4>
85
  <div class='flex'>
class/wp-shortpixel-settings.php CHANGED
@@ -211,10 +211,9 @@ class WPShortPixelSettings extends \ShortPixel\Model {
211
 
212
  public static function onDeactivate() {
213
  delete_option('wp-short-pixel-activation-notice');
214
- delete_option( 'wp-short-pixel-bulk-last-status'); // legacy shizzle
215
- delete_option( 'wp-short-pixel-current-total-files');
216
  delete_option('wp-short-pixel-remove-settings-on-delete-plugin');
217
-
218
  }
219
 
220
 
@@ -249,11 +248,6 @@ class WPShortPixelSettings extends \ShortPixel\Model {
249
  $default = self::$_optionsMap[$key]['default']; // first do default do to overwrite.
250
  $key = self::$_optionsMap[$key]['key'];
251
  }
252
- if(get_option($key) === false) {
253
-
254
- add_option( $key, $default, '', 'no' );
255
-
256
- }
257
 
258
  $opt = get_option($key, $default);
259
  return $opt;
211
 
212
  public static function onDeactivate() {
213
  delete_option('wp-short-pixel-activation-notice');
214
+ delete_option('wp-short-pixel-bulk-last-status'); // legacy shizzle
215
+ delete_option('wp-short-pixel-current-total-files');
216
  delete_option('wp-short-pixel-remove-settings-on-delete-plugin');
 
217
  }
218
 
219
 
248
  $default = self::$_optionsMap[$key]['default']; // first do default do to overwrite.
249
  $key = self::$_optionsMap[$key]['key'];
250
  }
 
 
 
 
 
251
 
252
  $opt = get_option($key, $default);
253
  return $opt;
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.0
6
  Requires PHP: 5.6
7
- Stable tag: 5.0.7
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
@@ -32,25 +32,30 @@ Make an instant <a href="https://shortpixel.com/image-compression-test" target="
32
 
33
  * popular plugin with over 300,000 active installations - according to WordPress
34
  * compress JPG (and its variations JPEG, JPEG 2000, JPEG XR), PNG, GIF (still or animated) images and also PDF documents
35
- * option to convert any JPEG, PNG or GIF (even animated ones!) to **WebP** and **AVIF** for more Google love. <a href="https://blog.shortpixel.com/how-webp-images-can-speed-up-your-site/" target="_blank">How to enable WebP?</a>. <a href="https://blog.shortpixel.com/what-is-avif-and-why-is-it-good/" target="_blank">What is AVIF and why is it good?</a>.
 
 
36
  * option to automatically convert PNG to JPG if that will result in smaller images. Ideal for large images in PNG format
37
  * option to include the next generation images (WebP and AVIF) into the front-end pages by using the `<picture>` tag instead of `<img>`, independent from generating them through the plugin
38
- * compatible with WP Retina 2x - all **retina images** are automatically compressed. <a href="https://blog.shortpixel.com/how-to-use-optimized-retina-images-on-your-wordpress-site-for-best-user-experience-on-apple-devices/" target="_blank">How to benefit from Retina displays?</a>
39
  * optimize thumbnails as well as featured images. You can also **select individual thumbnails to exclude** from optimization
 
40
  * ability to optimize any image on your site including images in **NextGEN Gallery** and any other image galleries or sliders
41
  * option to scale images down, with 2 different options, which is very useful to automatically resize large images. This applies to the featured images and there is no need for additional plugins like Imsanity
42
  * CMYK to RGB conversion
43
  * skip already optimized images
44
  * **24h <a href="https://wordpress.org/support/plugin/shortpixel-image-optimiser/reviews/?filter=5" target="_blank">stellar support</a>** (24/7) directly from developers.
45
  * easily **test lossy/glossy/lossless** versions of the images with a single click in your Media Library
46
- * **great for photographers**: <a href="https://blog.shortpixel.com/how-much-smaller-can-be-images-without-exif-icc/" target="_blank">keep or remove EXIF</a> data from your images, compress photos with lossless option
47
  * works well with both HTTPS and HTTP websites
 
48
  * uses progressive JPEG for larger images in order to speed up the image display
49
  * you can run ShortPixel plugin on **multiple websites** or on a **multisite** with a **single API Key**
50
  * it is **safe to test** and use the plugin: all the original images are by default saved in a local backup that can be restored with a click, either one by one or in bulk
51
  * 'Bulk' optimize all the existing images in Media Library or in any gallery with one click
52
  * works great for **eCommerce websites using WooCommerce** or other plugins
53
  * works great with NextGEN gallery, Foo Gallery and any other galleries and sliders
 
54
  * compatible with WP Engine hosted websites and all the major hosting providers
55
  * compatible with WPML and WPML Media plugins
56
  * no file size limit
@@ -58,7 +63,7 @@ Make an instant <a href="https://shortpixel.com/image-compression-test" target="
58
  * compatible with watermarking plugins
59
  * option to deactivate auto-optimizing images on upload
60
  * no credits are used for the images that are optimised less that 5%
61
- * direct integration with CloudFlare, either by using an API Key or a Token
62
  * 30 days optimization report with all image details and overall statistics
63
  * We are GDPR compliant! <a href="https://shortpixel.com/privacy#gdpr" target="_blank">Read more.</a>
64
  * **free optimization credits for non-profits**, <a href="https://shortpixel.com/contact" target="_blank">contact us</a> for details
@@ -86,6 +91,7 @@ Help us spread the word by recommending ShortPixel to your friends and collect *
86
  * [reGenerate Thumbnails Advanced](https://wordpress.org/plugins/regenerate-thumbnails-advanced/) - Easily regenerate thumbnails
87
  * [Resize Image After Upload](https://wordpress.org/plugins/resize-image-after-upload/) - Automatically resize each uploaded image
88
  * [WP SVG Images](https://wordpress.org/plugins/wp-svg-images/) - Secure upload of SVG files to Media Library
 
89
 
90
  **Get in touch!**
91
 
@@ -96,13 +102,13 @@ Help us spread the word by recommending ShortPixel to your friends and collect *
96
 
97
  == Installation ==
98
 
99
- Let's get ShortPixel plugin running on your WordPress website:
100
 
101
 
102
  1. Sign up using your email at <a href="https://shortpixel.com/wp-apikey" target="_blank">https://shortpixel.com/wp-apikey</a>.
103
  2. You will receive your personal API key in a confirmation email, to the address you provided.
104
  3. Upload the ShortPixel plugin to the /wp-content/plugins/ directory
105
- 4. Use your unique API key to activate ShortPixel plugin in the 'Plugins' menu in WordPress.
106
  5. Uploaded images can be automatically optimized in the Media Library.
107
  6. Done!
108
 
@@ -309,6 +315,32 @@ Add HTTP basic authentication credentials by defining these constants in wp-conf
309
 
310
  == Changelog ==
311
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
312
  = 5.0.7 =
313
  Release date July 26th, 2022
314
  * Fix: the notification about credits used had some test data, resulting in wrong information (sorry again!);
4
  Requires at least: 4.8.0
5
  Tested up to: 6.0
6
  Requires PHP: 5.6
7
+ Stable tag: 5.0.8
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
32
 
33
  * popular plugin with over 300,000 active installations - according to WordPress
34
  * compress JPG (and its variations JPEG, JPEG 2000, JPEG XR), PNG, GIF (still or animated) images and also PDF documents
35
+ * option to convert any JPEG, PNG or GIF (even animated ones!) to **WebP** and **AVIF** for more Google love. <a href="https://shortpixel.com/blog/how-webp-images-can-speed-up-your-site/" target="_blank">How to enable WebP?</a>. <a href="https://shortpixel.com/blog/what-is-avif-and-why-is-it-good/" target="_blank">What is AVIF and why is it good?</a>.
36
+ * **New!:** full <a href="https://shortpixel.com/knowledge-base/article/537-wp-cli-support-for-shortpixel-image-optimizer" target="_blank">WP-CLI support</a> for background processing, useful especially for websites with a very large Media Library
37
+ * **New!:** Easily add <a href="https://shortpixel.com/knowledge-base/article/543-how-to-schedule-a-cron-event-to-run-shortpixel-image-optimizer" target="_blank">recurrent cron jobs</a> for background optimization. Useful if you have users uploading images via the front end of your website
38
  * option to automatically convert PNG to JPG if that will result in smaller images. Ideal for large images in PNG format
39
  * option to include the next generation images (WebP and AVIF) into the front-end pages by using the `<picture>` tag instead of `<img>`, independent from generating them through the plugin
40
+ * compatible with WP Retina 2x - all **retina images** are automatically compressed. <a href="https://shortpixel.com/blog/how-to-use-optimized-retina-images-on-your-wordpress-site-for-best-user-experience-on-apple-devices/" target="_blank">How to benefit from Retina displays?</a>
41
  * optimize thumbnails as well as featured images. You can also **select individual thumbnails to exclude** from optimization
42
+ * advanced exclusion options that allow excluding images based on filename, path, size or complex regex exclusions
43
  * ability to optimize any image on your site including images in **NextGEN Gallery** and any other image galleries or sliders
44
  * option to scale images down, with 2 different options, which is very useful to automatically resize large images. This applies to the featured images and there is no need for additional plugins like Imsanity
45
  * CMYK to RGB conversion
46
  * skip already optimized images
47
  * **24h <a href="https://wordpress.org/support/plugin/shortpixel-image-optimiser/reviews/?filter=5" target="_blank">stellar support</a>** (24/7) directly from developers.
48
  * easily **test lossy/glossy/lossless** versions of the images with a single click in your Media Library
49
+ * **great for photographers**: <a href="https://shortpixel.com/blog/how-much-smaller-can-be-images-without-exif-icc/" target="_blank">keep or remove EXIF</a> data from your images, compress photos with lossless option
50
  * works well with both HTTPS and HTTP websites
51
+ * fully compatible with any WordPress multisite install (either with sub-folders or sub-domains)
52
  * uses progressive JPEG for larger images in order to speed up the image display
53
  * you can run ShortPixel plugin on **multiple websites** or on a **multisite** with a **single API Key**
54
  * it is **safe to test** and use the plugin: all the original images are by default saved in a local backup that can be restored with a click, either one by one or in bulk
55
  * 'Bulk' optimize all the existing images in Media Library or in any gallery with one click
56
  * works great for **eCommerce websites using WooCommerce** or other plugins
57
  * works great with NextGEN gallery, Foo Gallery and any other galleries and sliders
58
+ * fully compatible with the <a href="https://wordpress.org/plugins/amazon-s3-and-cloudfront/" target="_blank">WP Offload Media</a> plugin
59
  * compatible with WP Engine hosted websites and all the major hosting providers
60
  * compatible with WPML and WPML Media plugins
61
  * no file size limit
63
  * compatible with watermarking plugins
64
  * option to deactivate auto-optimizing images on upload
65
  * no credits are used for the images that are optimised less that 5%
66
+ * direct integration with Cloudflare by using a Cloudflare Token
67
  * 30 days optimization report with all image details and overall statistics
68
  * We are GDPR compliant! <a href="https://shortpixel.com/privacy#gdpr" target="_blank">Read more.</a>
69
  * **free optimization credits for non-profits**, <a href="https://shortpixel.com/contact" target="_blank">contact us</a> for details
91
  * [reGenerate Thumbnails Advanced](https://wordpress.org/plugins/regenerate-thumbnails-advanced/) - Easily regenerate thumbnails
92
  * [Resize Image After Upload](https://wordpress.org/plugins/resize-image-after-upload/) - Automatically resize each uploaded image
93
  * [WP SVG Images](https://wordpress.org/plugins/wp-svg-images/) - Secure upload of SVG files to Media Library
94
+ * [ShortPixel Critical CSS](https://wordpress.org/plugins/shortpixel-critical-css/) - Automatically generate above-the-fold CSS for fatster loading times and better SEO scores
95
 
96
  **Get in touch!**
97
 
102
 
103
  == Installation ==
104
 
105
+ Let's get the ShortPixel plugin running on your WordPress website:
106
 
107
 
108
  1. Sign up using your email at <a href="https://shortpixel.com/wp-apikey" target="_blank">https://shortpixel.com/wp-apikey</a>.
109
  2. You will receive your personal API key in a confirmation email, to the address you provided.
110
  3. Upload the ShortPixel plugin to the /wp-content/plugins/ directory
111
+ 4. Use your unique API key to activate the ShortPixel plugin in the 'Plugins' menu in WordPress.
112
  5. Uploaded images can be automatically optimized in the Media Library.
113
  6. Done!
114
 
315
 
316
  == Changelog ==
317
 
318
+ = 5.0.8 =
319
+ Release date August 8th, 2022
320
+ * Fix: the `Previous Bulks` now displays the number of credits used instead of the number of Media Library items, to avoid confusion;
321
+ * Fix: the notification for migrating the old format of optimization information was not getting triggered anymore;
322
+ * Fix: excluded images and/or thumbnails can now be restored from the backup;
323
+ * Fix: added prevention for double database queries when checking if an item is already in the queue;
324
+ * Fix: the bulk restore and bulk migration of optimization data can now be done even if out of credits;
325
+ * Fix: reduced the number of database table checks done on wp-admin pages to the minimum possible;
326
+ * Fix: the out-of-quota message was not always showing up properly;
327
+ * Fix: the bulk migration of the optimization data now marks as optimized the images that have proper backups in place;
328
+ * Fix: the thousands separators are now displayed properly for all languages;
329
+ * Fix: the optimized/unoptimized Media Library filter has proper pagination and also works with WPML;
330
+ * Fix: in case the optimization percentage is an integer, drop the `.00` (83.00% -> 83%);
331
+ * Fix: improved the settings and bulk pages load time for sites with a huge number of items in the Media Library;
332
+ * Fix: properly save the optimization information even if the filename is huge;
333
+ * Fix: the `Optimize now` button wasn't showing up on Custom Media right after restoring an item from the backup;
334
+ * Fix: more fixes for multisite installs where the old `blogs.dir` folder structure is used;
335
+ * Fix: multiple fixes and improvements for WP-CLI, including more detailed embedded docs and examples;
336
+ * Fix: multiple fixes and improvements to the whole exclusions module;
337
+ * Fix: multiple fixes and improvements in handling how retina images are optimized;
338
+ * Fix: various small fixes and improvements to the debug mode of the plugin;
339
+ * Tweak: `CTRL+S` can now be used to save settings (you're welcome!);
340
+ * Tweak: added support for bulk processing via the processing hook;
341
+ * Tweak: various wording and text updates in the plugin and the readme file;
342
+ * Language: 10 new strings added, 8 updated, 0 fuzzed, and 2 obsoleted.
343
+
344
  = 5.0.7 =
345
  Release date July 26th, 2022
346
  * Fix: the notification about credits used had some test data, resulting in wrong information (sorry again!);
res/css/shortpixel-admin.css CHANGED
@@ -404,6 +404,10 @@ body.debug-model-active {
404
  display: none !important;
405
  }
406
 
 
 
 
 
407
  .switch_button {
408
  line-height: 12px;
409
  margin: 2px -5px 10px -5px;
404
  display: none !important;
405
  }
406
 
407
+ .button-primary.optimize {
408
+ margin-bottom: 16px;
409
+ }
410
+
411
  .switch_button {
412
  line-height: 12px;
413
  margin: 2px -5px 10px -5px;
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;;AAEK;EACI;EACT;EACA;;AACU;EAEG;EACA;EAEA;EACA;EACA;EACA;EACA;;AAEA;EACE;EACA;;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;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;;AAEK;EACI;EACT;EACA;;AACU;EAEG;EACA;EAEA;EACA;EACA;EACA;EACA;;AAEA;EACE;EACA;;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"}
res/css/shortpixel-bulk.css CHANGED
@@ -546,6 +546,9 @@
546
  .shortpixel-bulk-wrapper section.panel.selection .optiongroup .option .number {
547
  font-weight: 700;
548
  }
 
 
 
549
  .shortpixel-bulk-wrapper section.panel.summary .spio-progressbar .select .line {
550
  background: #1FBEC9;
551
  }
546
  .shortpixel-bulk-wrapper section.panel.selection .optiongroup .option .number {
547
  font-weight: 700;
548
  }
549
+ .shortpixel-bulk-wrapper section.panel.selection .count_limited {
550
+ color: #ff0000;
551
+ }
552
  .shortpixel-bulk-wrapper section.panel.summary .spio-progressbar .select .line {
553
  background: #1FBEC9;
554
  }
res/css/shortpixel-bulk.css.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sourceRoot":"","sources":["../scss/shortpixel-bulk.scss","../scss/elements/_colors.scss","../scss/elements/_animation.scss"],"names":[],"mappings":"AAAA;AAKE;AAqWF;AAoLI;AAqGF;;AA7nBE;EACE;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EAEI;EACA;;AAGN;EACE;;AAGF;EAEG;EAGA;;AAGL;EACC;EACA;EACA;EACA;EAEA;EACA;EACA,YC3CiB;ED4CjB,OC/CU;EDgDV;EACA;EACA;EACA;EACA;EACA;;AAEA;EAEC,YCzDS;ED0DT;EACA;;AAGD;EACC,cC/DS;EDgET,YChES;;ADkEV;EAEE;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;;AAID;EAEE,YCpFU;EDqFV;EACA;EACA;EACA;;AAGJ;EACE;EAED;EACA;;AACA;EAEE;;AAIH;EACG;;AAGD;EACE;;AAGJ;EACG;EACA;;AAGJ;EACG;IACG;;EAEH;IACG;;;AAIN;EAEE;EACA;;AAID;EAEE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AACC;EAEE;EACA;EACA;EACA;EACA;EACA;;AAEH;EAEE;EACD;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAED;EAEC;EACA;EACA;;AACA;EACC;;AACA;EAAW;;AACR;EAAS;EAA+B;;AAE3C;EAAQ;;AACR;EACE;EACD;;AAGF;EAAI;EAAuB;;AAK5B;EAEI;EACA;EACA;EACA;;AAGA;EAGG;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGA;EAEE;EACA;EACA;EACN;EACA;;AAGG;EACI;EACA;EACA;EACA;EACA;EACA;;AACA;EAAU;;AACV;EAEN;EACA;;AAMH;EAEG;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAEJ;;AAGI;EAEI;EACA;EACA;EACA;;AAGJ;EAEG;EAED;EACA;;AAKE;EAAK;;AACL;EACE;EACA;;AACA;EAAS;;AAGf;EACE;EACA;EAEA;EACL;EACK;EACA;EACA;EACA;EACA;EACL;EACA;EAEK;EACL;EACA;EACA;;AACA;EAAS;;AAMT;EAGE;EAGH;EACG;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AACA;EACE;;AAEF;EAEE;;AACA;EAEG;EACA;EACA;;AAGH;EAAiB;;AAIvB;EAEE;EACA;EAGA;EACA;EACA;EACA;EACA;EACA;;AACA;EACA;EACA;EACA;;AAEA;EAEC;EACA;EACC;;AASA;EAAa;;AAIb;EAEK;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AACA;EAEE;EACA;EACA;EAAS;;AAGX;EAEG;EAEA;EACA;EACA;EACA;EACP;EAEA;EACA;;AAEO;EAGP,YCnZQ;EDqZP;EACA;EAES;;AAKH;EACE;EACA;;AAEF;EAEN;;AAMF;EAEG;EACA;EACA;;AACA;EAAK;EAAwB;;AAC7B;EACE;;AACA;EAAS;EAAqB;;AAI9B;EACE;EACA;;AAKF;EACE;EACA;EAGA;EACA;;AAHA;EAAgB;;AAChB;EAAgB;;AAGhB;EACG;EACA;EACA;;AAYb;EAEI;;AACA;EAEE;EACA;EACA;EACA;;AAEA;EAEG;EACA;EACA;EACA;EACA;;AAGH;EAEE;;AAGF;EACE;EACA;EACA;EAEA;EACA;EACA;EACA;EACA;EACA;;AAGF;EAEE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACN;;AAEI;EAEE;EACA;EACA;EACA;EACN;;AAoBG;EATH;;AAUG;EAAe;;AACf;EAAQ;;AAEX;EAEG;EACJ;EACI;;AAKA;EACE;EACL;EACA;;AAKE;EAEG;EACL;;AAKG;EAEG;EACA;EACA;EACA;EACA;EACA;;AACN;EACC;;AACA;EAAI;;AAEC;EACE;;AAEF;EE9kBV;EACI;EACA;EACA;EACA;;AAEL;EACC;IAAM;IAA2B;;;AAGlC;EACC;IAAM;IAA8B;;;AAGrC;EACC;IAAM;IAA+B;;;AAGtC;EACC;IAAM;IAAmC;;;AAG1C;EACC;IAAM;IAAgC;;;AF6jBrC;EAEE;EACA;;AACA;EACE;EACD;;AAED;EAAI;;AAWA;EACG;;AAEH;EACG;EACA;EACA;EACA;;AAEH;EACE;EAEA;;AACA;EACI;EACA;;AAEJ;EACI;;AAcN;EAAQ;;AACR;EAAe;;AACf;EAAQ;;AAIR;EApHH;;AAqHG;EAAe;;AACf;EAAQ;;AAEX;EAEI;EACA;EACA;;AACA;EACE;EACA;EACA;EACA;EACA;EACA;;AACA;EACE;EACA;EACA;;AAKD;EACI;EACA;EACA;;AACA;EAEG;EACA;;AAIN;EAEG;EAEA;EACA;;AAEA;EACE;EACA;EACA;;AACA;EAEG;EACA;EACA;;AACA;EAEG;;AAIR;EAEG;EACA;EACA;EAEA;;AAOd;EAEE;EACA;EACA;EACA;;AAEA;EAAU;;AAGZ;EACI;EAEA;EAEL;;AACK;EAAM;;AACN;EACG;EACA;EACA;EACN;;AACM;EAAgB;EAAkB;;AACxC;EAAkB;;AAClB;EAAkB;;AAClB;EAAU;EAAc;;AAGrB;EACE;EACA;;AAIN;EAEG;EACA;EACA;EACA;EACA;EACA;;AACA;EACE;;AAEF;EACE;EACA;EACA;;AACA;EAAO;;AAET;EACE;EACA;EACA;EACA;EACA;EACA;;AAGL;EAEI;EACA;EACA;;AASD;EAAQ;;AACR;EAAe;;AACf;EAAQ;;AAIR;EAzQH;;AA0QG;EAAe;;AACf;EAAQ;;AAGX;EAEE;EACA;EACA;EACA;EACA;EACJ;EACA;;AAEI;EACE;EACA;EACL;EAGA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGG;EACI;EACA;EACA;;AAEA;EACE;;AAEF;EACE,QCz0BD;ED00BC;EACA;;AAEF;EAEE;EACA;EACA;EACA;EACA;;AAKR;EAEE;EACA;EACA;;AACA;EAAQ;;AACR;EACI;EACA;EACN;;AAEE;EACG;EACA;;AAEH;EAEE;EACA;EACA;EACA;EACA;EACL;;AAGK;EAEE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;AAIN;EAEE;;AAMJ;EACC;;AAIC;EACG;EACA;EACA;EACA;EACJ;;AAEA;EACG;EACD;EACA;EACA;EACA;EACA;EACA;EACA;;AAIC;EAEG;EACA;EACA;EACA;EACA;;AAGN;EAEC;EACA;;AAGK;EACI;EACA;EACA;;AAEA;EACE;;AAEF;EACE;EACA;EACA;;AAEF;EAEE;EACA;EACA;EACA;EACA;;AAKR;EAIH;EACA;EAGK;;AAEL;EAIC;EACA;EACA;;AAID;EAEC;EACC;EACD;EACA;EACA;EACA;EACA;;AAED;EAEE;;AAIF;EAGC;;AASI;EAEG;EACA;EACA;EACA;;AAEA;EACE;EACR;EACA;EASA;EACA;;AATA;EAEC;;AAED;EAEC;;AAKF;EACE;EACA;EACA;EACA;EACA;EACA;;AAGK;EACE;EACA;EACA;EACA;EACA;EACA;;AAGL;EAEG;;AAEH;EAEE;;AAKP;EACI;EACA;;AAYD;EAAQ;;AACR;EAAe;;AACf;EAAQ;;AAIR;EA9iBH;;AA+iBG;EAAe;;AACf;EAAQ;;AAGX;EACI;;AAEF;EAEI;EACA;EACA;EACA;EACA;EACA;;AACA;EACE;;AAOV;EAEG;EACA;EACA;EACA;EACA;;AAKL;EAEE;EAEA;;AACA;EAAK;EACH;EACA;;AAEA;EAEE;EACA;;AAIJ;EAAW;;AAEX;EAEC;EACA;;AAEK;EACG;;AAEH;EACG;EACA;EACA;EACA;EACN;;AAEG;EACE;EAEA;;AACA;EACI;EACA;;AAEJ;EACI;;AAGX;EAEE;EACA","file":"shortpixel-bulk.css"}
1
+ {"version":3,"sourceRoot":"","sources":["../scss/shortpixel-bulk.scss","../scss/elements/_colors.scss","../scss/elements/_animation.scss"],"names":[],"mappings":"AAAA;AAKE;AAqWF;AAoLI;AA2GF;;AAnoBE;EACE;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EAEI;EACA;;AAGN;EACE;;AAGF;EAEG;EAGA;;AAGL;EACC;EACA;EACA;EACA;EAEA;EACA;EACA,YC3CiB;ED4CjB,OC/CU;EDgDV;EACA;EACA;EACA;EACA;EACA;;AAEA;EAEC,YCzDS;ED0DT;EACA;;AAGD;EACC,cC/DS;EDgET,YChES;;ADkEV;EAEE;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;;AAID;EAEE,YCpFU;EDqFV;EACA;EACA;EACA;;AAGJ;EACE;EAED;EACA;;AACA;EAEE;;AAIH;EACG;;AAGD;EACE;;AAGJ;EACG;EACA;;AAGJ;EACG;IACG;;EAEH;IACG;;;AAIN;EAEE;EACA;;AAID;EAEE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AACC;EAEE;EACA;EACA;EACA;EACA;EACA;;AAEH;EAEE;EACD;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAED;EAEC;EACA;EACA;;AACA;EACC;;AACA;EAAW;;AACR;EAAS;EAA+B;;AAE3C;EAAQ;;AACR;EACE;EACD;;AAGF;EAAI;EAAuB;;AAK5B;EAEI;EACA;EACA;EACA;;AAGA;EAGG;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGA;EAEE;EACA;EACA;EACN;EACA;;AAGG;EACI;EACA;EACA;EACA;EACA;EACA;;AACA;EAAU;;AACV;EAEN;EACA;;AAMH;EAEG;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAEJ;;AAGI;EAEI;EACA;EACA;EACA;;AAGJ;EAEG;EAED;EACA;;AAKE;EAAK;;AACL;EACE;EACA;;AACA;EAAS;;AAGf;EACE;EACA;EAEA;EACL;EACK;EACA;EACA;EACA;EACA;EACL;EACA;EAEK;EACL;EACA;EACA;;AACA;EAAS;;AAMT;EAGE;EAGH;EACG;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AACA;EACE;;AAEF;EAEE;;AACA;EAEG;EACA;EACA;;AAGH;EAAiB;;AAIvB;EAEE;EACA;EAGA;EACA;EACA;EACA;EACA;EACA;;AACA;EACA;EACA;EACA;;AAEA;EAEC;EACA;EACC;;AASA;EAAa;;AAIb;EAEK;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AACA;EAEE;EACA;EACA;EAAS;;AAGX;EAEG;EAEA;EACA;EACA;EACA;EACP;EAEA;EACA;;AAEO;EAGP,YCnZQ;EDqZP;EACA;EAES;;AAKH;EACE;EACA;;AAEF;EAEN;;AAMF;EAEG;EACA;EACA;;AACA;EAAK;EAAwB;;AAC7B;EACE;;AACA;EAAS;EAAqB;;AAI9B;EACE;EACA;;AAKF;EACE;EACA;EAGA;EACA;;AAHA;EAAgB;;AAChB;EAAgB;;AAGhB;EACG;EACA;EACA;;AAYb;EAEI;;AACA;EAEE;EACA;EACA;EACA;;AAEA;EAEG;EACA;EACA;EACA;EACA;;AAGH;EAEE;;AAGF;EACE;EACA;EACA;EAEA;EACA;EACA;EACA;EACA;EACA;;AAGF;EAEE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACN;;AAEI;EAEE;EACA;EACA;EACA;EACN;;AAoBG;EATH;;AAUG;EAAe;;AACf;EAAQ;;AAEX;EAEG;EACJ;EACI;;AAKA;EACE;EACL;EACA;;AAKE;EAEG;EACL;;AAKG;EAEG;EACA;EACA;EACA;EACA;EACA;;AACN;EACC;;AACA;EAAI;;AAEC;EACE;;AAEF;EE9kBV;EACI;EACA;EACA;EACA;;AAEL;EACC;IAAM;IAA2B;;;AAGlC;EACC;IAAM;IAA8B;;;AAGrC;EACC;IAAM;IAA+B;;;AAGtC;EACC;IAAM;IAAmC;;;AAG1C;EACC;IAAM;IAAgC;;;AF6jBrC;EAEE;EACA;;AACA;EACE;EACD;;AAED;EAAI;;AAWA;EACG;;AAEH;EACG;EACA;EACA;EACA;;AAEH;EACE;EAEA;;AACA;EACI;EACA;;AAEJ;EACI;;AAMZ;EAEE;;AAYI;EAAQ;;AACR;EAAe;;AACf;EAAQ;;AAIR;EA1HH;;AA2HG;EAAe;;AACf;EAAQ;;AAEX;EAEI;EACA;EACA;;AACA;EACE;EACA;EACA;EACA;EACA;EACA;;AACA;EACE;EACA;EACA;;AAKD;EACI;EACA;EACA;;AACA;EAEG;EACA;;AAIN;EAEG;EAEA;EACA;;AAEA;EACE;EACA;EACA;;AACA;EAEG;EACA;EACA;;AACA;EAEG;;AAIR;EAEG;EACA;EACA;EAEA;;AAOd;EAEE;EACA;EACA;EACA;;AAEA;EAAU;;AAGZ;EACI;EAEA;EAEL;;AACK;EAAM;;AACN;EACG;EACA;EACA;EACN;;AACM;EAAgB;EAAkB;;AACxC;EAAkB;;AAClB;EAAkB;;AAClB;EAAU;EAAc;;AAGrB;EACE;EACA;;AAIN;EAEG;EACA;EACA;EACA;EACA;EACA;;AACA;EACE;;AAEF;EACE;EACA;EACA;;AACA;EAAO;;AAET;EACE;EACA;EACA;EACA;EACA;EACA;;AAGL;EAEI;EACA;EACA;;AASD;EAAQ;;AACR;EAAe;;AACf;EAAQ;;AAIR;EA/QH;;AAgRG;EAAe;;AACf;EAAQ;;AAGX;EAEE;EACA;EACA;EACA;EACA;EACJ;EACA;;AAEI;EACE;EACA;EACL;EAGA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGG;EACI;EACA;EACA;;AAEA;EACE;;AAEF;EACE,QC/0BD;EDg1BC;EACA;;AAEF;EAEE;EACA;EACA;EACA;EACA;;AAKR;EAEE;EACA;EACA;;AACA;EAAQ;;AACR;EACI;EACA;EACN;;AAEE;EACG;EACA;;AAEH;EAEE;EACA;EACA;EACA;EACA;EACL;;AAGK;EAEE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;AAIN;EAEE;;AAMJ;EACC;;AAIC;EACG;EACA;EACA;EACA;EACJ;;AAEA;EACG;EACD;EACA;EACA;EACA;EACA;EACA;EACA;;AAIC;EAEG;EACA;EACA;EACA;EACA;;AAGN;EAEC;EACA;;AAGK;EACI;EACA;EACA;;AAEA;EACE;;AAEF;EACE;EACA;EACA;;AAEF;EAEE;EACA;EACA;EACA;EACA;;AAKR;EAIH;EACA;EAGK;;AAEL;EAIC;EACA;EACA;;AAID;EAEC;EACC;EACD;EACA;EACA;EACA;EACA;;AAED;EAEE;;AAIF;EAGC;;AASI;EAEG;EACA;EACA;EACA;;AAEA;EACE;EACR;EACA;EASA;EACA;;AATA;EAEC;;AAED;EAEC;;AAKF;EACE;EACA;EACA;EACA;EACA;EACA;;AAGK;EACE;EACA;EACA;EACA;EACA;EACA;;AAGL;EAEG;;AAEH;EAEE;;AAKP;EACI;EACA;;AAYD;EAAQ;;AACR;EAAe;;AACf;EAAQ;;AAIR;EApjBH;;AAqjBG;EAAe;;AACf;EAAQ;;AAGX;EACI;;AAEF;EAEI;EACA;EACA;EACA;EACA;EACA;;AACA;EACE;;AAOV;EAEG;EACA;EACA;EACA;EACA;;AAKL;EAEE;EAEA;;AACA;EAAK;EACH;EACA;;AAEA;EAEE;EACA;;AAIJ;EAAW;;AAEX;EAEC;EACA;;AAEK;EACG;;AAEH;EACG;EACA;EACA;EACA;EACN;;AAEG;EACE;EAEA;;AACA;EACI;EACA;;AAEJ;EACI;;AAGX;EAEE;EACA","file":"shortpixel-bulk.css"}
res/css/shortpixel-othermedia.css CHANGED
@@ -70,6 +70,10 @@
70
  .shortpixel-other-media .list-overview .item:nth-child(odd) {
71
  background-color: #f9f9f9;
72
  }
 
 
 
 
73
  .shortpixel-other-media .list-overview .item:hover .row-actions {
74
  left: 0;
75
  color: #bbb;
@@ -126,7 +130,6 @@
126
  display: block;
127
  }
128
  .shortpixel-other-media .list-overview .item .sp-column-info {
129
- max-width: 400px;
130
  width: 100%;
131
  min-width: 250px;
132
  display: inline-block;
70
  .shortpixel-other-media .list-overview .item:nth-child(odd) {
71
  background-color: #f9f9f9;
72
  }
73
+ .shortpixel-other-media .list-overview .item span:last-child {
74
+ min-width: 400px;
75
+ max-width: 400px;
76
+ }
77
  .shortpixel-other-media .list-overview .item:hover .row-actions {
78
  left: 0;
79
  color: #bbb;
130
  display: block;
131
  }
132
  .shortpixel-other-media .list-overview .item .sp-column-info {
 
133
  width: 100%;
134
  min-width: 250px;
135
  display: inline-block;
res/css/shortpixel-othermedia.css.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sourceRoot":"","sources":["../scss/shortpixel-othermedia.scss"],"names":[],"mappings":"AAAA;EAEE;IAEE;;;AAIJ;EAEE;;AACA;EAEE;;AACA;EAEE;;AAGJ;EAEG;;AACD;EAEI;IAEG;IACA;;EAEH;IAEE;;;AAKP;EAEG;EACA;EACA;EACA;EACA;EACA;;AAEA;EAEE;;AAEA;EAEE;EACA;EACA;EACA;;AAGJ;EAEE;EACA;;AACA;EACE;EACA;EACA;;AACA;EAEE;;AAEF;EAEG;;AAID;EAEE;EACA;;AAEF;EAEE;;AAKN;EAEE;EACA;;AAKD;EACG;;AAID;EAEE;EACA;;AACA;EAGE;EACA;EACA;;AACA;EACG;;AAKT;EAEE;EACL;;AAEG;EAEE;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;EACA;;AAGJ;EAEE;;AAOF;EAEE;;AACA;EAEE;EACA;EACA;;AAGF;EAEE;;AAIJ;EAEE;EACA;;AACA;EAEE;EACA;;AACA;EAEE;;AAMN;EACE;EACL;EACK;EACA;EACL;;AAEK;EAPF;IAQM;;;AAET;EAEE;EACD;EACA;;AAID;EAII;IAAQ;;EAGP;IAAa;;EACb;IAAyB;IAAkB;IAAkB;;;AAIlE;EAIG;IAAQ;;EAKN;IAAQ;;;AAGb;EAEE;;AACA;EACE","file":"shortpixel-othermedia.css"}
1
+ {"version":3,"sourceRoot":"","sources":["../scss/shortpixel-othermedia.scss"],"names":[],"mappings":"AAAA;EAEE;IAEE;;;AAIJ;EAEE;;AACA;EAEE;;AACA;EAEE;;AAGJ;EAEG;;AACD;EAEI;IAEG;IACA;;EAEH;IAEE;;;AAKP;EAEG;EACA;EACA;EACA;EACA;EACA;;AAEA;EAEE;;AAEA;EAEE;EACA;EACA;EACA;;AAGJ;EAEE;EACA;;AACA;EACE;EACA;EACA;;AACA;EAEE;;AAEF;EAEG;;AAID;EAEE;EACA;;AAEF;EAEE;;AAKN;EAEE;EACA;;AAKD;EACG;;AAEP;EAEE;EACD;;AAIK;EAEE;EACA;;AACA;EAGE;EACA;EACA;;AACA;EACG;;AAKT;EAEE;EACL;;AAEG;EAEE;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;EACA;;AAGJ;EAEE;;AAOF;EAEE;;AACA;EAEE;EACA;EACA;;AAGF;EAEE;;AAIJ;EAEE;EACA;;AACA;EAEE;EACA;;AACA;EAEE;;AAMN;EAEH;EACK;EACA;EACL;;AAEK;EAPF;IAQM;;;AAET;EAEE;EACD;EACA;;AAID;EAII;IAAQ;;EAGP;IAAa;;EACb;IAAyB;IAAkB;IAAkB;;;AAIlE;EAIG;IAAQ;;EAKN;IAAQ;;;AAGb;EAEE;;AACA;EACE","file":"shortpixel-othermedia.css"}
res/js/screens/screen-bulk.js CHANGED
@@ -55,6 +55,8 @@ var ShortPixelScreen = function (MainScreen, processor)
55
  if (isPreparing)
56
  {
57
  this.SwitchPanel('selection');
 
 
58
  }
59
  else if (isRunning)
60
  {
@@ -582,7 +584,11 @@ console.log("Screen Init Done", initMedia, initCustom);
582
  else
583
  {
584
  if (value !== false)
585
- element.textContent = value;
 
 
 
 
586
  }
587
 
588
  });
@@ -618,9 +624,9 @@ console.log("Screen Init Done", initMedia, initCustom);
618
  }
619
 
620
  var error = this.processor.aStatusError[result.error];
621
-
622
  if (error == 'NOQUOTA')
623
  {
 
624
  this.ToggleOverQuotaNotice(true);
625
  }
626
 
55
  if (isPreparing)
56
  {
57
  this.SwitchPanel('selection');
58
+ this.UpdatePanelStatus('loading', 'selection');
59
+ this.PrepareBulk();
60
  }
61
  else if (isRunning)
62
  {
584
  else
585
  {
586
  if (value !== false)
587
+ {
588
+
589
+ element.textContent = value;
590
+
591
+ }
592
  }
593
 
594
  });
624
  }
625
 
626
  var error = this.processor.aStatusError[result.error];
 
627
  if (error == 'NOQUOTA')
628
  {
629
+
630
  this.ToggleOverQuotaNotice(true);
631
  }
632
 
res/js/shortpixel-processor.js CHANGED
@@ -300,7 +300,9 @@ window.ShortPixelProcessor =
300
  if (data.status == true && data.response) // data status is from shortpixel worker, not the response object
301
  {
302
  var response = data.response;
 
303
  this.workerErrors = 0;
 
304
  if ( response.callback)
305
  {
306
  console.log('Running callback : ' + response.callback);
@@ -312,11 +314,13 @@ window.ShortPixelProcessor =
312
  }
313
  if ( response.status == false)
314
  {
 
315
  // This is error status, or a usual shutdown, i.e. when process is in another browser.
316
  var error = this.aStatusError[response.error];
317
  if (error == 'PROCESSOR_ACTIVE')
318
  {
319
  this.Debug(response.message);
 
320
  this.StopProcess();
321
  }
322
  else if (error == 'NONCE_FAILED')
@@ -331,12 +335,18 @@ window.ShortPixelProcessor =
331
  this.screen.HandleError(response);
332
  this.Debug('No Quota - CheckResponse handler');
333
  this.PauseProcess();
 
334
  }
335
  else if (response.error < 0) // something happened.
336
  {
337
  this.StopProcess();
 
 
338
  }
339
- }
 
 
 
340
 
341
  // Check the screen if we are custom or media ( or bulk ) . Check the responses for each of those.
342
  if (typeof response.custom == 'object' && response.custom !== null)
300
  if (data.status == true && data.response) // data status is from shortpixel worker, not the response object
301
  {
302
  var response = data.response;
303
+ var handledError = false; // prevent passing to regular queueHandler is some action is taken.
304
  this.workerErrors = 0;
305
+
306
  if ( response.callback)
307
  {
308
  console.log('Running callback : ' + response.callback);
314
  }
315
  if ( response.status == false)
316
  {
317
+
318
  // This is error status, or a usual shutdown, i.e. when process is in another browser.
319
  var error = this.aStatusError[response.error];
320
  if (error == 'PROCESSOR_ACTIVE')
321
  {
322
  this.Debug(response.message);
323
+ handledError = true;
324
  this.StopProcess();
325
  }
326
  else if (error == 'NONCE_FAILED')
335
  this.screen.HandleError(response);
336
  this.Debug('No Quota - CheckResponse handler');
337
  this.PauseProcess();
338
+ handledError = true;
339
  }
340
  else if (response.error < 0) // something happened.
341
  {
342
  this.StopProcess();
343
+ handledError = true;
344
+ console.error('Some unknown error occured!', response.error, response);
345
  }
346
+
347
+ if (handledError == true)
348
+ return;
349
+ } // status false handler.
350
 
351
  // Check the screen if we are custom or media ( or bulk ) . Check the responses for each of those.
352
  if (typeof response.custom == 'object' && response.custom !== null)
res/js/shortpixel-settings.js CHANGED
@@ -6,8 +6,8 @@ var ShortPixelSettings = function()
6
 
7
  this.Init = function()
8
  {
9
- console.log('Init Settings');
10
  this.InitActions();
 
11
  }
12
 
13
  this.InitActions = function()
@@ -30,8 +30,11 @@ var ShortPixelSettings = function()
30
  modal.addEventListener('click', self.OpenModal.bind(self));
31
  });
32
 
 
 
33
  }
34
 
 
35
  this.DoToggleAction = function(event)
36
  {
37
  event.preventDefault();
@@ -47,6 +50,12 @@ var ShortPixelSettings = function()
47
  var checked = checkbox.checked;
48
  }
49
 
 
 
 
 
 
 
50
  if (checked)
51
  {
52
  // target.classList.add('is-visible');
@@ -191,9 +200,29 @@ this.ReceiveModal = function(elem)
191
 
192
  }
193
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
194
  this.Init();
195
  } // SPSettings
196
 
 
197
  document.addEventListener("DOMContentLoaded", function(){
198
  var s = new ShortPixelSettings();
199
  });
6
 
7
  this.Init = function()
8
  {
 
9
  this.InitActions();
10
+ this.SaveOnKey();
11
  }
12
 
13
  this.InitActions = function()
30
  modal.addEventListener('click', self.OpenModal.bind(self));
31
  });
32
 
33
+
34
+
35
  }
36
 
37
+
38
  this.DoToggleAction = function(event)
39
  {
40
  event.preventDefault();
50
  var checked = checkbox.checked;
51
  }
52
 
53
+ if (target === null)
54
+ {
55
+ console.error('Target element ID not found', checkbox);
56
+ return false;
57
+ }
58
+
59
  if (checked)
60
  {
61
  // target.classList.add('is-visible');
200
 
201
  }
202
 
203
+ this.SaveOnKey = function()
204
+ {
205
+ var saveForm = document.getElementById('wp_shortpixel_options');
206
+ if (saveForm === null)
207
+ return false; // no form no save.
208
+
209
+ window.addEventListener('keydown', function(event) {
210
+
211
+ if (! (event.key == 's' || event.key == 'S') || ! event.ctrlKey)
212
+ {
213
+ return true;
214
+ }
215
+ document.getElementById('wp_shortpixel_options').submit();
216
+ event.preventDefault();
217
+ return false;
218
+ });
219
+ }
220
+
221
+
222
  this.Init();
223
  } // SPSettings
224
 
225
+
226
  document.addEventListener("DOMContentLoaded", function(){
227
  var s = new ShortPixelSettings();
228
  });
res/js/shortpixel.js CHANGED
@@ -634,7 +634,7 @@ var ShortPixel = function() {
634
  },
635
  complete: function(response, status)
636
  {
637
- console.log(response, status);
638
 
639
  }
640
  });
634
  },
635
  complete: function(response, status)
636
  {
637
+ //console.log(response, status);
638
 
639
  }
640
  });
res/scss/shortpixel-admin.scss CHANGED
@@ -15,6 +15,11 @@
15
  display: none !important;
16
  }
17
 
 
 
 
 
 
18
 
19
  .switch_button
20
  {
15
  display: none !important;
16
  }
17
 
18
+ // Reserve some space for the processing text on bottom.
19
+ .button-primary.optimize
20
+ {
21
+ margin-bottom: 16px;
22
+ }
23
 
24
  .switch_button
25
  {
res/scss/shortpixel-bulk.scss CHANGED
@@ -639,6 +639,12 @@
639
 
640
  }
641
 
 
 
 
 
 
 
642
  } // panel
643
 
644
  /**************** SUMMARY ******/
639
 
640
  }
641
 
642
+ .count_limited
643
+ {
644
+ color: #ff0000;
645
+
646
+ }
647
+
648
  } // panel
649
 
650
  /**************** SUMMARY ******/
res/scss/shortpixel-othermedia.scss CHANGED
@@ -96,6 +96,11 @@
96
  &:nth-child(odd) {
97
  background-color: #f9f9f9;
98
  }
 
 
 
 
 
99
  &:hover
100
  {
101
  .row-actions
@@ -177,7 +182,7 @@
177
 
178
  }
179
  .sp-column-info {
180
- max-width: 400px;
181
  width: 100%;
182
  min-width: 250px;
183
  display: inline-block;
96
  &:nth-child(odd) {
97
  background-color: #f9f9f9;
98
  }
99
+ span:last-child
100
+ {
101
+ min-width: 400px;
102
+ max-width: 400px;
103
+ }
104
  &:hover
105
  {
106
  .row-actions
182
 
183
  }
184
  .sp-column-info {
185
+ // max-width: 400px;
186
  width: 100%;
187
  min-width: 250px;
188
  display: inline-block;
shortpixel-plugin.php CHANGED
@@ -494,16 +494,12 @@ class ShortPixelPlugin {
494
  global $plugin_page;
495
  $screen_id = $this->env()->screen_id;
496
 
497
- //var_dump(\wpSPIO()->env()->is_screen_to_use);
498
- //exit($screen_id);
499
 
500
  // $load = array();
501
  $load_processor = array( 'shortpixel', 'shortpixel-processor' ); // a whole suit needed for processing, not more. Always needs a screen as well!
502
  $load_bulk = array(); // the whole suit needed for bulking.
503
 
504
- if ( $this->env()->is_debug ) {
505
- $this->load_script( 'shortpixel-debug' );
506
- }
507
 
508
  if ( \wpSPIO()->env()->is_screen_to_use ) {
509
  $this->load_script( 'shortpixel-tooltip' );
@@ -535,6 +531,10 @@ class ShortPixelPlugin {
535
 
536
  $this->load_style( 'shortpixel-admin' );
537
  $this->load_style( 'shortpixel' );
 
 
 
 
538
 
539
  } elseif ( $plugin_page == 'wp-short-pixel-custom' ) {
540
  $this->load_style( 'shortpixel' );
494
  global $plugin_page;
495
  $screen_id = $this->env()->screen_id;
496
 
 
 
497
 
498
  // $load = array();
499
  $load_processor = array( 'shortpixel', 'shortpixel-processor' ); // a whole suit needed for processing, not more. Always needs a screen as well!
500
  $load_bulk = array(); // the whole suit needed for bulking.
501
 
502
+
 
 
503
 
504
  if ( \wpSPIO()->env()->is_screen_to_use ) {
505
  $this->load_script( 'shortpixel-tooltip' );
531
 
532
  $this->load_style( 'shortpixel-admin' );
533
  $this->load_style( 'shortpixel' );
534
+
535
+ if ( $this->env()->is_debug ) {
536
+ $this->load_script( 'shortpixel-debug' );
537
+ }
538
 
539
  } elseif ( $plugin_page == 'wp-short-pixel-custom' ) {
540
  $this->load_style( 'shortpixel' );
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.0.7
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.0.7");
35
 
36
  define('SHORTPIXEL_BACKUP', 'ShortpixelBackups');
37
  define('SHORTPIXEL_MAX_FAIL_RETRIES', 3);
@@ -62,6 +62,7 @@ define('SHORTPIXEL_UPLOADS_BASE', (file_exists($sp__uploads['basedir']) ? '' : A
62
  define('SHORTPIXEL_UPLOADS_NAME', basename(is_main_site() ? SHORTPIXEL_UPLOADS_BASE : dirname(dirname(SHORTPIXEL_UPLOADS_BASE))));
63
  $sp__backupBase = is_main_site() ? SHORTPIXEL_UPLOADS_BASE : dirname(dirname(SHORTPIXEL_UPLOADS_BASE));
64
  define('SHORTPIXEL_BACKUP_FOLDER', $sp__backupBase . '/' . SHORTPIXEL_BACKUP);
 
65
  define('SHORTPIXEL_BACKUP_URL',
66
  ((is_main_site() || (defined( 'SUBDOMAIN_INSTALL' ) && SUBDOMAIN_INSTALL))
67
  ? $sp__uploads['baseurl']
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.0.8
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.0.8");
35
 
36
  define('SHORTPIXEL_BACKUP', 'ShortpixelBackups');
37
  define('SHORTPIXEL_MAX_FAIL_RETRIES', 3);
62
  define('SHORTPIXEL_UPLOADS_NAME', basename(is_main_site() ? SHORTPIXEL_UPLOADS_BASE : dirname(dirname(SHORTPIXEL_UPLOADS_BASE))));
63
  $sp__backupBase = is_main_site() ? SHORTPIXEL_UPLOADS_BASE : dirname(dirname(SHORTPIXEL_UPLOADS_BASE));
64
  define('SHORTPIXEL_BACKUP_FOLDER', $sp__backupBase . '/' . SHORTPIXEL_BACKUP);
65
+ // @todo Backup URL not in use. Candidate for removal.
66
  define('SHORTPIXEL_BACKUP_URL',
67
  ((is_main_site() || (defined( 'SUBDOMAIN_INSTALL' ) && SUBDOMAIN_INSTALL))
68
  ? $sp__uploads['baseurl']