ShortPixel Image Optimizer - Version 4.14.6

Version Description

Release date: 9th October 2019 * Don't convert to the s with backgrounds. * Remove unused eval() call. * Restore the validate button next to API Key but change label to "Save and validate" * Fixed: PNGtoJPG issue with already uploaded images * Fixed: finding wrong unlisted thumbnails due to regex. * Fixed: fatal error when trying to delete crashed attachement ( without proper URL ) * Fix for S3 offload - PNG2JPG , doesn't remove old JPG files * Fixed: S3Offload will not offload anymore when 'Copy files to bucket' is off ( and object was not previously offloaded ) * S3Offload doesn't offload via optimiser anymore if this setting is off * Fixed: cutting out initial offload if optimization needs to be done, when autolibrary is on * Fix for PNG2JPG - JPG files remained in backupdir. * Small fix for remote download thumbnails * Fixed: notice in filemodel due meta-facade feeding array * Fixed: bug in File2Url in filesystemcontroller * Fixed: download issue in attempt to remote download * Language 0 new strings added, 0 updated, 0 fuzzied, and 0 obsoleted

Download this release

Release Info

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

Code changes from version 4.14.5 to 4.14.6

build/shortpixel/autoload.php CHANGED
@@ -1,5 +1,5 @@
1
  <?php
2
- require_once "PackageLoader.php";
3
  $loader = new ShortPixel\Build\PackageLoader();
4
  $loader->load(__DIR__);
5
 
1
  <?php
2
+ require_once (dirname(__FILE__) . "/PackageLoader.php");
3
  $loader = new ShortPixel\Build\PackageLoader();
4
  $loader->load(__DIR__);
5
 
class/controller/edit_media_controller.php ADDED
@@ -0,0 +1,252 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace ShortPixel;
3
+ use ShortPixel\ShortpixelLogger\ShortPixelLogger as Log;
4
+
5
+ // Future contoller for the edit media metabox view.
6
+ class editMediaController extends ShortPixelController
7
+ {
8
+ //$this->model = new
9
+ protected $template = 'view-edit-media';
10
+ protected $model = 'image';
11
+
12
+ private $post_id;
13
+ private $actions_allowed;
14
+
15
+ private $legacyViewObj;
16
+
17
+ public function __construct()
18
+ {
19
+
20
+ $this->loadModel($this->model);
21
+ parent::__construct();
22
+ }
23
+
24
+ // This data should be rendered by Image Model in the future.
25
+ public function setTempData($data)
26
+ {
27
+ $this->data = $data;
28
+ }
29
+
30
+ public function load($post_id)
31
+ {
32
+ $this->post_id = $post_id;
33
+
34
+ $this->imageModel = new ImageModel();
35
+ $this->imageModel->setByPostID($post_id);
36
+ $this->imageModel->reAcquire(); // single display mode - reset things.
37
+
38
+ $this->view->id = $post_id;
39
+ $this->view->status_message = null;
40
+
41
+ $this->actions_allowed = $this->checkUserPrivileges();
42
+
43
+ $this->view->status_message = $this->getStatusMessage();
44
+ $this->view->actions = $this->getActions();
45
+ $this->view->stats = $this->getStatistics();
46
+ $this->view->todo = $this->getTodo();
47
+ $this->view->debugInfo = $this->getDebugInfo();
48
+
49
+ $this->view->message = isset($this->data['message']) ? $this->data['message'] : '';
50
+ //$this->view->r
51
+ $this->loadView();
52
+
53
+ }
54
+
55
+
56
+ // The old view, we are trying to get rid of.
57
+ public function setLegacyView($legacyView)
58
+ {
59
+ $this->legacyViewObj = $legacyView;
60
+ }
61
+
62
+ protected function getStatusMessage()
63
+ {
64
+ if (! isset($this->data['status']))
65
+ return;
66
+
67
+ switch($this->data['status'])
68
+ {
69
+ case 'n/a':
70
+ return _e('Optimization N/A','shortpixel-image-optimiser');
71
+ break;
72
+ case 'notFound':
73
+ return _e('Image does not exist.','shortpixel-image-optimiser');
74
+ break;
75
+ case 'invalidKey':
76
+ return _e('Invalid API Key. <a href="options-general.php?page=wp-shortpixel-settings">Check your Settings</a>','shortpixel-image-optimiser');
77
+ break;
78
+ case 'quotaExceeded':
79
+ return __('Quota Exceeded','shortpixel-image-optimiser');
80
+ break;
81
+ }
82
+ }
83
+
84
+ protected function getActions()
85
+ {
86
+ $actions = array();
87
+ if (! $this->actions_allowed)
88
+ return $actions;
89
+
90
+ switch($this->data['status'])
91
+ {
92
+ case 'optimizeNow':
93
+ $actions[] = '<a class="button button-smaller button-primary" href="javascript:manualOptimization(' . $this->post_id . ',false)">
94
+ ' . __('Optimize now','shortpixel-image-optimiser') . '
95
+ </a>';
96
+ break;
97
+ case 'retry':
98
+ case 'waiting':
99
+ if (isset($this->data['cleanup']))
100
+ {
101
+ $actions[] = '<a class="button button-smaller button-primary" href="javascript:manualOptimization(' . $this->post_id . ', true)">' .
102
+ __('Cleanup&Retry','shortpixel-image-optimiser') . '</a>';
103
+ }
104
+ else {
105
+ if($this->data['status'] == 'retry' && (isset($this->data['backup']) && $this->data['backup']) ) {
106
+ $actions[] = '<a class="button button-smaller sp-action-restore"
107
+ href="admin.php?action=shortpixel_restore_backup&attachment_ID=' . $this->post_id . '" style="margin-left:5px;"
108
+ title="' . __('Restore Image from Backup', 'shortpixel-image-optimiser') . '">
109
+ ' . __('Cleanup','shortpixel-image-optimiser') . '</a>';
110
+
111
+ }
112
+ $actions[] = '<a class="button button-smaller button-primary" href="javascript:manualOptimization(' . $this->post_id . ', false)">' .
113
+ __('Retry','shortpixel-image-optimiser') . '</a>';
114
+ }
115
+ break;
116
+ }
117
+
118
+ return $actions;
119
+ }
120
+
121
+ protected function getStatistics()
122
+ {
123
+ $data = $this->data;
124
+
125
+ if ( $data['status'] != 'pdfOptimized' && $data['status'] != 'imgOptimized')
126
+ return array();
127
+
128
+ $stats = array();
129
+ if ($data['percent'] && $data['percent'] > 0)
130
+ {
131
+ $stats[] = array(__('Reduced by','shortpixel-image-optimiser'), '<strong>' . $data['percent'] . '% </strong>');
132
+ }
133
+
134
+ $stats[] = array(__('Type: ', 'shortpixel-image-optimiser'), $data['type']);
135
+ if ($data['bonus'])
136
+ $stats[] = array(__('Bonus processing','shortpixel-image-optimiser'), '');
137
+
138
+ if ($data['thumbsOpt'])
139
+ {
140
+ if ($data['thumbsTotal'] > $data['thumbsOpt'] )
141
+ $stats[] = array(sprintf(__('+%s of %s thumbnails optimized','shortpixel-image-optimiser'),$data['thumbsOpt'],$data['thumbsTotal']), '');
142
+ else
143
+ $stats[] = array(sprintf(__('+ %s thumbnails optimized','shortpixel-image-optimiser'),$data['thumbsOpt']), '');
144
+ }
145
+
146
+ if ($data['retinasOpt'])
147
+ {
148
+ $stats[] = array(sprintf(__('+%s Retina images optimized','shortpixel-image-optimiser') , $data['retinasOpt']), '');
149
+ }
150
+
151
+ if ($data['webpCount'])
152
+ {
153
+ $stats[] = array(__(" WebP images", 'shortpixel-image-optimiser'), $data['webpCount']);
154
+ }
155
+ if ($data['exifKept'])
156
+ $stats[] = array(__('EXIF kept', 'shortpixel-image-optimiser'), '');
157
+ else {
158
+ $stats[] = array(__('EXIF removed', 'shortpixel-image-optimiser'), '');
159
+ }
160
+
161
+ if ($data['png2jpg'])
162
+ {
163
+ $stats[] = array( __('Converted from PNG','shortpixel-image-optimiser'), '');
164
+ }
165
+
166
+ $stats[] = array(__("Optimized on", 'shortpixel-image-optimiser') . ": " . $data['date'], '');
167
+
168
+
169
+ /* $successText .= ($data['webpCount'] ? "<br>+" . $data['webpCount'] . __(" WebP images", 'shortpixel-image-optimiser') : "")
170
+ . "<br>EXIF: " . ($data['exifKept'] ? __('kept','shortpixel-image-optimiser') : __('removed','shortpixel-image-optimiser'))
171
+ . ($data['png2jpg'] ? '<br>' . __('Converted from PNG','shortpixel-image-optimiser'): '')
172
+ . "<br>" . __("Optimized on", 'shortpixel-image-optimiser') . ": " . $data['date']
173
+ . $todoSizes . $excludeSizes . $missingThumbs;
174
+ */
175
+ return $stats;
176
+ }
177
+
178
+ protected function getTodo()
179
+ {
180
+ $data = $this->data;
181
+ if ( $data['status'] != 'pdfOptimized' && $data['status'] != 'imgOptimized')
182
+ return array();
183
+
184
+ $excluded = (isset($data['excludeSizes']) ? count($data['excludeSizes']) : 0);
185
+ $todoSizes = $missingThumbs = $excludeSizes = '';
186
+
187
+ if(isset($data['thumbsToOptimizeList']) && count($data['thumbsToOptimizeList'])) {
188
+ $todoSizes .= "<br><span style='word-break: break-all;'> <span style='font-weight: bold;'>" . __("To optimize:", 'shortpixel-image-optimiser') . "</span>";
189
+ foreach($data['thumbsToOptimizeList'] as $todoItem) {
190
+ $todoSizes .= "<br> &#8226;&nbsp;" . $todoItem;
191
+ }
192
+ $todoSizes .= '</span>';
193
+ }
194
+ if(isset($data['excludeSizes']) && count($data['excludeSizes']) > 0 ) {
195
+ $excludeSizes .= "<br><span style='word-break: break-all;'> <span style='font-weight: bold;'>" . __("Excluded thumbnails:", 'shortpixel-image-optimiser') . "</span>";
196
+ foreach($data['excludeSizes'] as $excludedItem) {
197
+ $excludeSizes .= "<br> &#8226;&nbsp;" . $excludedItem;
198
+ }
199
+ $excludeSizes .= '</span>';
200
+ }
201
+ if(count($data['thumbsMissing'])) {
202
+ $missingThumbs .= "<br><span style='word-break: break-all;'> <span style='font-weight: bold;'>" . __("Missing thumbnails:", 'shortpixel-image-optimiser') . "</span>";
203
+ foreach($data['thumbsMissing'] as $miss) {
204
+ $missingThumbs .= "<br> &#8226&nbsp;" . $miss;
205
+ }
206
+ $missingThumbs .= '</span>';
207
+ }
208
+
209
+ return array($todoSizes, $excludeSizes, $missingThumbs);
210
+ }
211
+
212
+ protected function getDebugInfo()
213
+ {
214
+ if(! Log::debugIsActive())
215
+ {
216
+ return null;
217
+ }
218
+
219
+ $sizes = isset($this->data['sizes']) ? $this->data['sizes'] : array();
220
+
221
+ $debugInfo = array();
222
+ $debugInfo[] = array(__('URL', 'shortpixel_image_optiser'), wp_get_attachment_url($this->post_id));
223
+ $debugInfo[] = array(__('WPML Duplicates'), json_encode(\ShortPixelMetaFacade::getWPMLDuplicates($this->post_id)) );
224
+ $debugInfo[] = array(__('Data'), $this->data);
225
+ $debugInfo[] = array(__('Meta'), wp_get_attachment_metadata($this->post_id) );
226
+ $debugInfo[] = array(__('Backup Folder'), $this->shortPixel->getBackupFolderAny($this->imageModel->getFile()->getFullPath(), $sizes));
227
+ $debugInfo[] = array(__('Status'), $this->imageModel->getMeta()->getStatus() );
228
+
229
+ return $debugInfo;
230
+ }
231
+
232
+ protected function renderLegacyCell()
233
+ {
234
+
235
+ $data = $this->data;
236
+
237
+ if ( $data['status'] != 'pdfOptimized' && $data['status'] != 'imgOptimized')
238
+ return null;
239
+
240
+ $this->legacyViewObj->renderListCell($this->post_id, $data['status'], $data['showActions'], $data['thumbsToOptimize'],
241
+ $data['backup'], $data['type'], $data['invType'], '');
242
+ }
243
+
244
+ private function checkUserPrivileges()
245
+ {
246
+ if ((current_user_can( 'manage_options' ) || current_user_can( 'upload_files' ) || current_user_can( 'edit_posts' )))
247
+ return true;
248
+
249
+ return false;
250
+ }
251
+
252
+ } // controller .
class/controller/filesystem_controller.php CHANGED
@@ -87,22 +87,28 @@ Class FileSystemController extends ShortPixelController
87
  // stolen from wp_get_attachment_url
88
  if ( ( $uploads = wp_get_upload_dir() ) && false === $uploads['error'] ) {
89
  // Check that the upload base exists in the file location.
90
- if ( 0 === strpos( $file, $uploads['basedir'] ) ) {
91
  // Replace file location with url location.
92
  $url = str_replace( $uploads['basedir'], $uploads['baseurl'], $filepath );
93
- } elseif ( false !== strpos( $file, 'wp-content/uploads' ) ) {
94
  // Get the directory name relative to the basedir (back compat for pre-2.7 uploads)
95
- $url = trailingslashit( $uploads['baseurl'] . '/' . _wp_get_attachment_relative_path( $file ) ) . wp_basename( $filepath );
96
  } else {
97
  // It's a newly-uploaded file, therefore $file is relative to the basedir.
98
  $url = $uploads['baseurl'] . "/$filepath";
99
  }
100
  }
101
- return $url;
 
 
 
 
 
102
  }
103
 
104
 
105
 
106
 
107
 
 
108
  }
87
  // stolen from wp_get_attachment_url
88
  if ( ( $uploads = wp_get_upload_dir() ) && false === $uploads['error'] ) {
89
  // Check that the upload base exists in the file location.
90
+ if ( 0 === strpos( $filepath, $uploads['basedir'] ) ) {
91
  // Replace file location with url location.
92
  $url = str_replace( $uploads['basedir'], $uploads['baseurl'], $filepath );
93
+ } elseif ( false !== strpos( $filepath, 'wp-content/uploads' ) ) {
94
  // Get the directory name relative to the basedir (back compat for pre-2.7 uploads)
95
+ $url = trailingslashit( $uploads['baseurl'] . '/' . _wp_get_attachment_relative_path( $filepath ) ) . wp_basename( $filepath );
96
  } else {
97
  // It's a newly-uploaded file, therefore $file is relative to the basedir.
98
  $url = $uploads['baseurl'] . "/$filepath";
99
  }
100
  }
101
+
102
+ if (parse_url($url) !== false)
103
+ return $url;
104
+ else {
105
+ return false;
106
+ }
107
  }
108
 
109
 
110
 
111
 
112
 
113
+
114
  }
class/controller/settings.php CHANGED
@@ -94,6 +94,16 @@ class SettingsController extends shortPixelController
94
 
95
  }
96
 
 
 
 
 
 
 
 
 
 
 
97
  public function processSave()
98
  {
99
  Log::addDebug('after process postData', $this->postData);
94
 
95
  }
96
 
97
+ public function action_debug_medialibrary()
98
+ {
99
+ $this->loadEnv();
100
+ $this->loadModel('image');
101
+
102
+ \WpShortPixelMediaLbraryAdapter::reCountMediaLibraryItems();
103
+
104
+ $this->load();
105
+ }
106
+
107
  public function processSave()
108
  {
109
  Log::addDebug('after process postData', $this->postData);
class/db/shortpixel-custom-meta-dao.php CHANGED
@@ -479,7 +479,7 @@ class ShortPixelCustomMetaDao {
479
 
480
  public function update($meta) {
481
  $metaClass = get_class($meta);
482
- $tableSuffix = "";
483
  $tableSuffix = $metaClass::TABLE_SUFFIX;
484
  $prefix = $this->db->getPrefix();
485
 
@@ -507,9 +507,8 @@ class ShortPixelCustomMetaDao {
507
 
508
  public function delete($meta) {
509
  $metaClass = get_class($meta);
510
- $tableSuffix = "";
511
- // @todo Why O why
512
- eval( '$tableSuffix = ' . $metaClass . '::TABLE_SUFFIX;');
513
  $sql = "DELETE FROM {$this->db->getPrefix()}shortpixel_" . $tableSuffix . " WHERE id = %d";
514
  $this->db->query($sql, array($meta->getId()));
515
  }
479
 
480
  public function update($meta) {
481
  $metaClass = get_class($meta);
482
+ //$tableSuffix = "";
483
  $tableSuffix = $metaClass::TABLE_SUFFIX;
484
  $prefix = $this->db->getPrefix();
485
 
507
 
508
  public function delete($meta) {
509
  $metaClass = get_class($meta);
510
+ $tableSuffix = $metaClass::TABLE_SUFFIX;
511
+ //eval( '$tableSuffix = ' . $metaClass . '::TABLE_SUFFIX;');
 
512
  $sql = "DELETE FROM {$this->db->getPrefix()}shortpixel_" . $tableSuffix . " WHERE id = %d";
513
  $this->db->query($sql, array($meta->getId()));
514
  }
class/db/shortpixel-meta-facade.php CHANGED
@@ -101,7 +101,7 @@ class ShortPixelMetaFacade {
101
  return $rawMeta;
102
  }
103
 
104
- // @todo Find out the use of this function. Doesn't update_meta unless it's WPML.
105
  public function updateMeta($newMeta = null, $replaceThumbs = false) {
106
  if($newMeta) {
107
  $this->meta = $newMeta;
@@ -251,7 +251,7 @@ class ShortPixelMetaFacade {
251
  }
252
 
253
  // remove SPFoudnMeta from image. Dirty. @todo <--
254
- function removeSPFoundMeta()
255
  {
256
  if($this->type == ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE) {
257
  if(!isset($this->rawMeta)) {
@@ -378,6 +378,7 @@ class ShortPixelMetaFacade {
378
  */
379
  public static function safeGetAttachmentUrl($id) {
380
  $attURL = wp_get_attachment_url($id);
 
381
  if(!$attURL || !strlen($attURL)) {
382
  throw new Exception("Post metadata is corrupt (No attachment URL for $id)", ShortPixelAPI::ERR_POSTMETA_CORRUPT);
383
  }
@@ -405,33 +406,28 @@ class ShortPixelMetaFacade {
405
  $path = get_attached_file($this->ID);//get the full file PATH
406
  $fsFile = $fs->getFile($path);
407
  $mainExists = apply_filters('shortpixel_image_exists', file_exists($path), $path, $this->ID);
408
- $predownload_url = $url = self::safeGetAttachmentUrl($this->ID);
 
 
 
 
 
 
 
 
 
409
  $urlList = array(); $filePaths = array();
410
 
411
- Log::addDebug('attached file path: ' . $path );
412
 
413
  if(!$mainExists) {
414
- //try and download the image from the URL (images present only on CDN)
415
- $downloadTimeout = max(SHORTPIXEL_MAX_EXECUTION_TIME - 10, 15);
416
- //$tempOriginal = download_url($url, $downloadTimeout);
417
- $args_for_get = array(
418
- 'stream' => true,
419
- 'filename' => $path,
420
- );
421
- Log::addDebug('Downloading main file ' . $url );
422
- $response = wp_remote_get( $url, $args_for_get );
423
- if(is_wp_error( $response )) {
424
- Log::addError('Download Mailfile failed', array($response->get_error_messages()));
425
- }
426
- elseif ($fsFile->exists())
427
- {
428
- $mainExists = true;
429
- $fsUrl = $fs->pathToUrl($fsFile);
430
- if ($fsUrl !== false)
431
- $url = $fsUrl; // more secure way of getting url
432
-
433
- Log::addDebug('FSFILE TO URL -' . $fsUrl);
434
- }
435
  }
436
 
437
  if($mainExists) {
@@ -508,40 +504,23 @@ class ShortPixelMetaFacade {
508
  }
509
 
510
  if ( !$file_exists && !file_exists($tPath) ) {
511
- $tPath = SHORTPIXEL_UPLOADS_BASE . substr($origPath, strpos($origPath, $StichString) + strlen($StichString));
 
 
512
  }
513
 
514
  if ( !$file_exists && !file_exists($tPath) ) {
515
- $tPath = trailingslashit(SHORTPIXEL_UPLOADS_BASE) . $origPath;
 
 
516
  }
517
 
518
  if ( !$file_exists && !file_exists($tPath) ) {
519
  //try and download the image from the URL (images present only on CDN)
520
  // Log::addDebug('URLs and Paths - File didnt exists, trying to download', array($tUrl, $origPath));
521
  // $tempThumb = download_url($tUrl, $downloadTimeout);
522
- $args_for_get = array(
523
- 'stream' => true,
524
- 'filename' => $origFile->getFullPath(),
525
- 'timeout' => max(SHORTPIXEL_MAX_EXECUTION_TIME - 10, 15),
526
- );
527
-
528
- $response = wp_remote_get( $tUrl, $args_for_get );
529
- Log::addDebug('Thumb not found, trying to download: ' . $tUrl);
530
 
531
- if (is_wp_error($response))
532
- {
533
- Log::addError('Download Thumbnail failed', array($response->get_error_messages()));
534
- }
535
- elseif($origFile->exists())
536
- {
537
- $tPath = $origFile->getFullPath(); // download succesfull
538
- $fsUrl = $fs->pathToUrl($origFile);
539
- if ($fsUrl !== false) // this tranlation to domain url will not always hold to sendToProcessing when dealing w/ CDN and such.
540
- $tUrl = $fsUrl; // more secure way of getting url
541
- else {
542
- Log::addError('Download - Could not tranlate to URL', array($fsUrl, $tPath, $origFile));
543
- }
544
- }
545
 
546
  Log::addDebug('New TPath after download', array($tUrl, $tPath, $origPath, filesize($tPath)));
547
  }
@@ -575,10 +554,65 @@ class ShortPixelMetaFacade {
575
  array_walk($urlList, array( &$this, 'replacePlusChar') );
576
 
577
  $filePaths = ShortPixelAPI::CheckAndFixImagePaths($filePaths);//check for images to make sure they exist on disk
578
-
579
  return array("URLs" => $urlList, "PATHs" => $filePaths, "sizesMissing" => $sizesMissing);
580
  }
581
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
582
  protected function replacePlusChar(&$url) {
583
  $url = str_replace("+", "%2B", $url);
584
  }
101
  return $rawMeta;
102
  }
103
 
104
+ // Update MetaData of Image.
105
  public function updateMeta($newMeta = null, $replaceThumbs = false) {
106
  if($newMeta) {
107
  $this->meta = $newMeta;
251
  }
252
 
253
  // remove SPFoudnMeta from image. Dirty. @todo <--
254
+ public function removeSPFoundMeta()
255
  {
256
  if($this->type == ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE) {
257
  if(!isset($this->rawMeta)) {
378
  */
379
  public static function safeGetAttachmentUrl($id) {
380
  $attURL = wp_get_attachment_url($id);
381
+ Log::addDebug('Attachment URL - safeGotten - ' . $attURL);
382
  if(!$attURL || !strlen($attURL)) {
383
  throw new Exception("Post metadata is corrupt (No attachment URL for $id)", ShortPixelAPI::ERR_POSTMETA_CORRUPT);
384
  }
406
  $path = get_attached_file($this->ID);//get the full file PATH
407
  $fsFile = $fs->getFile($path);
408
  $mainExists = apply_filters('shortpixel_image_exists', file_exists($path), $path, $this->ID);
409
+ try
410
+ {
411
+ $predownload_url = $url = self::safeGetAttachmentUrl($this->ID); // This function *can* return an PHP error.
412
+ Log::addDebug('Resulting URL -- ' . $url);
413
+ }
414
+ catch(Exception $e)
415
+ {
416
+ Log::addWarn('Attachment seems corrupted', array($e->getMessage() ));
417
+ return array("URLs" => array(), "PATHs" => array(), "sizesMissing" => array());
418
+ }
419
  $urlList = array(); $filePaths = array();
420
 
421
+ Log::addDebug('attached file path: ' . $path, array( (string) $fsFile->getFileDir() ) );
422
 
423
  if(!$mainExists) {
424
+ list($url, $path) = $this->attemptRemoteDownload($url, $path, $this->ID);
425
+ $downloadFile = $fs->getFile($path);
426
+ if ($downloadFile->exists()) // check for success.
427
+ {
428
+ $mainExists = true;
429
+ $fsFile = $downloadFile; // overwrite.
430
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
431
  }
432
 
433
  if($mainExists) {
504
  }
505
 
506
  if ( !$file_exists && !file_exists($tPath) ) {
507
+ $try_path = SHORTPIXEL_UPLOADS_BASE . substr($origPath, strpos($origPath, $StichString) + strlen($StichString));
508
+ if (file_exists($try_path))
509
+ $tPath = $try_path; // found!
510
  }
511
 
512
  if ( !$file_exists && !file_exists($tPath) ) {
513
+ $try_path = trailingslashit(SHORTPIXEL_UPLOADS_BASE) . $origPath;
514
+ if (file_exists($try_path))
515
+ $tPath = $try_path; // found!
516
  }
517
 
518
  if ( !$file_exists && !file_exists($tPath) ) {
519
  //try and download the image from the URL (images present only on CDN)
520
  // Log::addDebug('URLs and Paths - File didnt exists, trying to download', array($tUrl, $origPath));
521
  // $tempThumb = download_url($tUrl, $downloadTimeout);
 
 
 
 
 
 
 
 
522
 
523
+ list($tUrl, $tPath) = $this->attemptRemoteDownload($tUrl, $tPath, $this->ID);
 
 
 
 
 
 
 
 
 
 
 
 
 
524
 
525
  Log::addDebug('New TPath after download', array($tUrl, $tPath, $origPath, filesize($tPath)));
526
  }
554
  array_walk($urlList, array( &$this, 'replacePlusChar') );
555
 
556
  $filePaths = ShortPixelAPI::CheckAndFixImagePaths($filePaths);//check for images to make sure they exist on disk
 
557
  return array("URLs" => $urlList, "PATHs" => $filePaths, "sizesMissing" => $sizesMissing);
558
  }
559
 
560
+ private function attemptRemoteDownload($url, $path, $attach_id)
561
+ {
562
+ $downloadTimeout = max(SHORTPIXEL_MAX_EXECUTION_TIME - 10, 15);
563
+ $fs = new \ShortPixel\FileSystemController();
564
+ $pathFile = $fs->getFile($path);
565
+
566
+ $args_for_get = array(
567
+ 'stream' => true,
568
+ 'filename' => $pathFile->getFullPath(),
569
+ );
570
+
571
+ $response = wp_remote_get( $url, $args_for_get );
572
+
573
+ if(is_wp_error( $response )) {
574
+ Log::addError('Download file failed', array($url, $response->get_error_messages(), $response->get_error_codes() ));
575
+
576
+ // Try to get it then via this way.
577
+ $response = download_url($url, $downloadTimeout);
578
+ if (!is_wp_error($response)) // response when alright is a tmp filepath. But given path can't be trusted since that can be reason for fail.
579
+ {
580
+ $tmpFile = $fs->getFile($response);
581
+ $post = get_post($attach_id);
582
+ $post_date = get_the_date('Y/m', $post); // get the date for the uploads tree.
583
+
584
+ $upload_dir = wp_upload_dir($post_date);
585
+ $upload_dir = $fs->getDirectory($upload_dir['path']); // get the upload dir.
586
+
587
+ $fixedFile = $fs->getFile($upload_dir->getPath() . $pathFile->getFileName() );
588
+ // try to move
589
+ $result = $tmpFile->move($fixedFile);
590
+
591
+ Log::addDebug('Fixed File', array($post_date, $fixedFile->getFullPath() ));
592
+
593
+ if ($result && $fixedFile->exists())
594
+ {
595
+ $path = $fixedFile->getFullPath(); // overwrite path with new fixed path.
596
+ $url = $fs->pathToUrl($fixedFile);
597
+ $pathFile = $fixedFile;
598
+ }
599
+ } // download_url ..
600
+ else {
601
+ Log::addError('Secondary download failed', array($url, $response->get_error_messages(), $response->get_error_codes() ));
602
+ }
603
+ }
604
+ else { // success
605
+ $pathFile = $fs->getFile($response['filename']);
606
+ }
607
+
608
+ $fsUrl = $fs->pathToUrl($pathFile);
609
+ if ($fsUrl !== false)
610
+ $url = $fsUrl; // more secure way of getting url
611
+
612
+ Log::addDebug('Remote Download attempt result', array($url, $path));
613
+ return array($url, $path);
614
+ }
615
+
616
  protected function replacePlusChar(&$url) {
617
  $url = str_replace("+", "%2B", $url);
618
  }
class/db/wp-shortpixel-media-library-adapter.php CHANGED
@@ -3,6 +3,246 @@ use ShortPixel\ShortpixelLogger\ShortPixelLogger as Log;
3
 
4
  class WpShortPixelMediaLbraryAdapter {
5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
  //count all the processable files in media library (while limiting the results to max 10000)
7
  public static function countAllProcessableFiles($settings = array(), $maxId = PHP_INT_MAX, $minId = 0){
8
  global $wpdb;
@@ -35,6 +275,7 @@ class WpShortPixelMediaLbraryAdapter {
35
  //count all the files, main and thumbs
36
  while ( 1 ) {
37
  $idInfo = self::getPostIdsChunk($minId, $maxId, $pointer, $limit);
 
38
  if($idInfo === null) {
39
  break; //we parsed all the results
40
  }
@@ -43,9 +284,12 @@ class WpShortPixelMediaLbraryAdapter {
43
  continue;
44
  }
45
 
46
- $filesList= $wpdb->get_results("SELECT * FROM " . $wpdb->prefix . "postmeta
47
  WHERE post_id IN (" . implode(',', $idInfo->ids) . ")
48
  AND ( meta_key = '_wp_attached_file' OR meta_key = '_wp_attachment_metadata' )");
 
 
 
49
 
50
  //in one case this query returned zero items but if fewer items in the IDs list, it worked so apply this workaround:
51
  if($limit > 1000 && count($filesList) == 0) {
@@ -70,7 +314,7 @@ class WpShortPixelMediaLbraryAdapter {
70
  }
71
  elseif ( $file->meta_key == "_wp_attachment_metadata" ) //_wp_attachment_metadata
72
  {
73
- $attachment = @unserialize($file->meta_value);
74
  $sizesCount = isset($attachment['sizes']) ? self::countSizesNotExcluded($attachment['sizes'], $settings->excludeSizes) : 0;
75
 
76
  // LA FIECARE 100 de imagini facem un test si daca findThumbs da diferit, sa dam o avertizare si eventual optiune
@@ -230,6 +474,7 @@ class WpShortPixelMediaLbraryAdapter {
230
  );
231
  }
232
 
 
233
  public static function getPostMetaSlice($startId, $endId, $limit) {
234
  global $wpdb;
235
  $time = microtime(true);
@@ -271,6 +516,62 @@ class WpShortPixelMediaLbraryAdapter {
271
  return $metaresult;
272
  }
273
  */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
274
  public static function getPostsJoinLessReverse($startId, $endId, $limit)
275
  {
276
  global $wpdb;
@@ -365,7 +666,7 @@ class WpShortPixelMediaLbraryAdapter {
365
 
366
  $base = $file->getFileBase();
367
  $ext = $file->getExtension();
368
- $pattern = '/' . preg_quote($base, '/') . '-\d+x\d+\.'. $ext .'/';
369
 
370
  $thumbs = array_merge($thumbs, self::getFilesByPattern($dirPath, $pattern));
371
 
@@ -392,7 +693,7 @@ class WpShortPixelMediaLbraryAdapter {
392
  {
393
  foreach ($suffixes as $suffix){
394
 
395
- $pattern = '/' . preg_quote($base, '/') . '-\d+x\d+'. $suffix . '\.'. $ext .'/';
396
  $thumbs = array_merge($thumbs, self::getFilesByPattern($dirPath, $pattern));
397
  /*foreach($thumbsCandidates as $th) {
398
  if(preg_match($pattern, $th)) {
@@ -408,7 +709,7 @@ class WpShortPixelMediaLbraryAdapter {
408
  {
409
  foreach ($infixes as $infix){
410
  //$thumbsCandidates = @glob($base . $infix . "-*." . $ext);
411
- $pattern = '/' . preg_quote($base, '/') . $infix . '-\d+x\d+' . '\.'. $ext .'/';
412
  $thumbs = array_merge($thumbs, self::getFilesByPattern($dirPath, $pattern));
413
 
414
  /*foreach($thumbsCandidates as $th) {
@@ -449,7 +750,7 @@ class WpShortPixelMediaLbraryAdapter {
449
  }
450
  catch(\Exception $e)
451
  {
452
- Log::addWarn('GetFilesbyPattern issue with directory. ', $e->message());
453
  return array();
454
  }
455
 
@@ -485,13 +786,27 @@ class WpShortPixelMediaLbraryAdapter {
485
  }
486
  }
487
 
488
- protected static function getPostIdsChunk($minId, $maxId, $pointer, $limit) {
489
  global $wpdb;
490
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
491
  $ids = $idDates = array();
492
- $idList = $wpdb->get_results("SELECT ID, post_mime_type, post_date FROM " . $wpdb->prefix . "posts
493
- WHERE ( ID <= $maxId AND ID > $minId )
494
- LIMIT $pointer,$limit");
495
  if ( empty($idList) ) {
496
  return null;
497
  }
@@ -501,7 +816,46 @@ class WpShortPixelMediaLbraryAdapter {
501
  $idDates[$item->ID] = $item->post_date;
502
  }
503
  }
504
- return (object)array('ids' => $ids, 'idDates' => $idDates);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
505
  }
506
 
507
  }
3
 
4
  class WpShortPixelMediaLbraryAdapter {
5
 
6
+ // Testing is this is better / faster than previous function.
7
+ public static function countAllProcessable($settings, $maxId = PHP_INT_MAX, $minId = 0)
8
+ {
9
+ global $wpdb;
10
+
11
+ $totalFiles = $mainFiles = $processedMainFiles = $processedTotalFiles = $totalFilesM1 = $totalFilesM2 = $totalFilesM3 = $totalFilesM4 =
12
+ $procGlossyMainFiles = $procGlossyTotalFiles = $procLossyMainFiles = $procLossyTotalFiles = $procLosslessMainFiles = $procLosslessTotalFiles = $procUndefMainFiles = $procUndefTotalFiles = $mainUnprocessedThumbs = 0;
13
+ $filesMap = $processedFilesMap = array();
14
+ $limit = self::getOptimalChunkSize();
15
+ $pointer = 0;
16
+ $filesWithErrors = array(); $moreFilesWithErrors = 0;
17
+ $run = true;
18
+ $excludePatterns = WPShortPixelSettings::getOpt("excludePatterns");
19
+ //idInfo = self::getPostIdsChunk($minId, $maxId, $pointer, $limit, true);
20
+
21
+ $foundUnlistedThumbs = false;
22
+ $counter = 0;
23
+
24
+ $filesWithErrors = array(); $moreFilesWithErrors = 0;
25
+ $excludePatterns = WPShortPixelSettings::getOpt("excludePatterns");
26
+
27
+ if (version_compare(PHP_VERSION, '5.3.0') >= 0) {
28
+ $month1 = new DateTime();
29
+ $month2 = new DateTime();
30
+ $month3 = new DateTime();
31
+ $month4 = new DateTime();
32
+ $mi1 = new DateInterval('P1M');
33
+ $mi2 = new DateInterval('P2M');
34
+ $mi3 = new DateInterval('P3M');
35
+ $mi4 = new DateInterval('P4M');
36
+ $month1->sub($mi1);
37
+ $month2->sub($mi2);
38
+ $month3->sub($mi3);
39
+ $month4->sub($mi4);
40
+ }
41
+
42
+ while ( $run == true ) {
43
+ $idInfo = self::getPostIdsChunk($minId, $maxId, $pointer, $limit, true);
44
+ $minId = isset($idInfo->last_id) ? $idInfo->last_id : -1;
45
+
46
+ if($idInfo === null) {
47
+ break; //we parsed all the results
48
+ }
49
+ elseif(count($idInfo->ids) == 0) {
50
+ //$minId += $limit; // This is a no results case.
51
+ continue;
52
+ }
53
+
54
+ $filesList= $wpdb->get_results("SELECT post_id, meta_key, meta_value FROM " . $wpdb->prefix . "postmeta
55
+ WHERE post_id IN (" . implode(',', $idInfo->ids) . ")
56
+ AND ( meta_key = '_wp_attached_file' OR meta_key = '_wp_attachment_metadata' )");
57
+ /* $filesList= $wpdb->get_results("SELECT post_id, meta_key, meta_value FROM " . $wpdb->prefix . "postmeta
58
+ WHERE post_id >= $minId and post_id <= $maxId
59
+ AND ( meta_key = '_wp_attached_file' OR meta_key = '_wp_attachment_metadata' )"); */
60
+
61
+ //$minId = $idInfo->ids[0];
62
+ //$minId = $idInfo->ids[count($idInfo->ids) - 1];
63
+
64
+ //in one case this query returned zero items but if fewer items in the IDs list, it worked so apply this workaround:
65
+ if($limit > 1000 && count($filesList) == 0) {
66
+ $limit = 1000;
67
+ continue;
68
+ }
69
+
70
+ foreach ( $filesList as $file )
71
+ {
72
+ $totalFilesThis = $processedFilesThis = 0;
73
+
74
+ if ( $file->meta_key == "_wp_attached_file" )
75
+ {//count pdf files only
76
+ $extension = substr($file->meta_value, strrpos($file->meta_value,".") + 1 );
77
+ if ( $extension == "pdf" && $settings->optimizePdfs && !isset($filesMap[$file->meta_value]))
78
+ {
79
+ $totalFiles++;
80
+ $totalFilesThis++;
81
+ $mainFiles++;
82
+ $filesMap[$file->meta_value] = 1;
83
+ }
84
+ }
85
+ elseif ( $file->meta_key == "_wp_attachment_metadata" ) //_wp_attachment_metadata
86
+ {
87
+ $attachment = maybe_unserialize($file->meta_value);
88
+ $sizesCount = isset($attachment['sizes']) ? self::countSizesNotExcluded($attachment['sizes'], $settings->excludeSizes) : 0;
89
+
90
+ // LA FIECARE 100 de imagini facem un test si daca findThumbs da diferit, sa dam o avertizare si eventual optiune
91
+ $dismissed = $settings->dismissedNotices ? $settings->dismissedNotices : array();
92
+ if( $foundUnlistedThumbs === false && $maxId == PHP_INT_MAX && !isset($dismissed['unlisted'])
93
+ && ( in_array($counter, array(2,4,6,8)) || floor($counter/100) == 0 && $counter%10 == 0
94
+ || floor($counter/1000) == 0 && $counter%100 == 0 || floor($counter/10000) == 0 && $counter%1000 == 0))
95
+ {
96
+ $filePath = isset($attachment['file']) ? trailingslashit(SHORTPIXEL_UPLOADS_BASE).$attachment['file'] : false;
97
+ if ($filePath && file_exists($filePath) && isset($attachment['sizes']) &&
98
+ ( !isset($attachment['ShortPixelImprovement']) || $attachment['ShortPixelImprovement'] === 0
99
+ || $attachment['ShortPixelImprovement'] === 0.0 || $attachment['ShortPixelImprovement'] === "0"))
100
+ {
101
+ $foundThumbs = WpShortPixelMediaLbraryAdapter::findThumbs($filePath);
102
+
103
+ $foundCount = count($foundThumbs);
104
+
105
+ if(count($foundThumbs) > $sizesCount) {
106
+ $unlisted = array();
107
+ foreach($foundThumbs as $found) {
108
+ $match = ShortPixelTools::findItem(wp_basename($found), $attachment['sizes'], 'file');
109
+ if(!$match) {
110
+ $unlisted[] = wp_basename($found);
111
+ }
112
+ }
113
+ $foundUnlistedThumbs = (object)array("id" => $file->post_id, "name" => wp_basename($attachment['file']), "unlisted" => $unlisted);
114
+ }
115
+ } else {
116
+ $counter--; // will take the next one
117
+ $realSizesCount = $sizesCount;
118
+ }
119
+ }
120
+ //processable
121
+ $isProcessable = false;
122
+ $isProcessed = isset($attachment['ShortPixelImprovement'])
123
+ && ($attachment['ShortPixelImprovement'] > 0 || $attachment['ShortPixelImprovement'] === 0.0 || $attachment['ShortPixelImprovement'] === "0")
124
+ //for PDFs there is no file field so just let it pass.
125
+ && (!isset($attachment['file']) || !isset($processedFilesMap[$attachment['file']]));
126
+
127
+ if( isset($attachment['file']) && !isset($filesMap[$attachment['file']])
128
+ && WPShortPixel::_isProcessablePath($attachment['file'], array(), $excludePatterns)){
129
+ $isProcessable = true;
130
+ $totalFiles += $sizesCount;
131
+ $totalFilesThis += $sizesCount;
132
+ if ( isset($attachment['file']) )
133
+ {
134
+ $totalFiles++;
135
+ $totalFilesThis++;
136
+ $mainFiles++;
137
+ $filesMap[$attachment['file']] = 1;
138
+ }
139
+ }
140
+ //processed
141
+ if ($isProcessed) {
142
+ //add main file to counts
143
+ $processedMainFiles++;
144
+ $processedTotalFiles++;
145
+ $processedFilesThis++;
146
+ $type = isset($attachment['ShortPixel']['type']) ? $attachment['ShortPixel']['type'] : null;
147
+ switch($type) {
148
+ case 'lossy' :
149
+ $procLossyMainFiles++;
150
+ $procLossyTotalFiles++;
151
+ break;
152
+ case 'glossy':
153
+ $procGlossyMainFiles++;
154
+ $procGlossyTotalFiles++;
155
+ break;
156
+ case 'lossless':
157
+ $procLosslessMainFiles++;
158
+ $procLosslessTotalFiles++;
159
+ break;
160
+ default:
161
+ $procUndefMainFiles++;
162
+ $procUndefTotalFiles++;
163
+ }
164
+
165
+ //get the thumbs processed for that attachment
166
+ $thumbs = $allThumbs = 0;
167
+ if ( isset($attachment['ShortPixel']['thumbsOpt']) ) {
168
+ $thumbs = $attachment['ShortPixel']['thumbsOpt'];
169
+ }
170
+ elseif ( isset($attachment['sizes']) ) {
171
+ $thumbs = $sizesCount;
172
+ }
173
+ if(!isset($attachment['file'])) { //for the pdfs that have thumbs, have to add the thumbs too (not added above )
174
+ $totalFiles += $thumbs;
175
+ $totalFilesThis += $thumbs;
176
+ }
177
+ $thumbsMissing = isset($attachment['ShortPixel']['thumbsMissing']) ? $attachment['ShortPixel']['thumbsMissing'] : array();
178
+
179
+ if ( isset($attachment['sizes']) && $sizesCount > $thumbs + count($thumbsMissing)) {
180
+ $mainUnprocessedThumbs++;
181
+ }
182
+
183
+ //increment with thumbs processed
184
+ $processedTotalFiles += $thumbs;
185
+ $processedFilesThis += $thumbs;
186
+ if($type == 'glossy') {
187
+ $procGlossyTotalFiles += $thumbs;
188
+ } elseif ($type == 'lossy') {
189
+ $procLossyTotalFiles += $thumbs;
190
+ } else {
191
+ $procLosslessTotalFiles += $thumbs;
192
+ }
193
+
194
+ if ( isset($attachment['file']) ) {
195
+ $processedFilesMap[$attachment['file']] = 1;
196
+ }
197
+ }
198
+ elseif($isProcessable && isset($attachment['ShortPixelImprovement'])) {
199
+ if(count($filesWithErrors) < 50) {
200
+ $filePath = explode("/", $attachment["file"]);
201
+ $name = is_array($filePath)? $filePath[count($filePath) - 1] : $file->post_id;
202
+ $filesWithErrors[$file->post_id] = array('Id' => $file->post_id, 'Name' => $name, 'Message' => $attachment['ShortPixelImprovement']);
203
+ } else {
204
+ $moreFilesWithErrors++;
205
+ }
206
+ }
207
+
208
+ }
209
+
210
+ if (version_compare(PHP_VERSION, '5.3.0') >= 0) {
211
+ $dt = new DateTime($idInfo->idDates[$file->post_id]);
212
+ if ($dt > $month1) {
213
+ $totalFilesM1 += $totalFilesThis;
214
+ } else if ($dt > $month2) {
215
+ $totalFilesM2 += $totalFilesThis;
216
+ } else if ($dt > $month3) {
217
+ $totalFilesM3 += $totalFilesThis;
218
+ } else if ($dt > $month4) {
219
+ $totalFilesM4 += $totalFilesThis;
220
+ }
221
+ }
222
+ }
223
+ unset($filesList);
224
+ $pointer += $limit;
225
+ $counter++;
226
+ }//end while
227
+
228
+ return array("totalFiles" => $totalFiles, "mainFiles" => $mainFiles,
229
+ "totalProcessedFiles" => $processedTotalFiles, "mainProcessedFiles" => $processedMainFiles,
230
+ "totalProcLossyFiles" => $procLossyTotalFiles, "mainProcLossyFiles" => $procLossyMainFiles,
231
+ "totalProcGlossyFiles" => $procGlossyTotalFiles, "mainProcGlossyFiles" => $procGlossyMainFiles,
232
+ "totalProcLosslessFiles" => $procLosslessTotalFiles, "mainProcLosslessFiles" => $procLosslessMainFiles,
233
+ "totalMlFiles" => $totalFiles, "mainMlFiles" => $mainFiles,
234
+ "totalProcessedMlFiles" => $processedTotalFiles, "mainProcessedMlFiles" => $processedMainFiles,
235
+ "totalProcLossyMlFiles" => $procLossyTotalFiles, "mainProcLossyMlFiles" => $procLossyMainFiles,
236
+ "totalProcGlossyMlFiles" => $procGlossyTotalFiles, "mainProcGlossyMlFiles" => $procGlossyMainFiles,
237
+ "totalProcLosslessMlFiles" => $procLosslessTotalFiles, "mainProcLosslessMlFiles" => $procLosslessMainFiles,
238
+ "totalProcUndefMlFiles" => $procUndefTotalFiles, "mainProcUndefMlFiles" => $procUndefMainFiles,
239
+ "mainUnprocessedThumbs" => $mainUnprocessedThumbs, "totalM1" => $totalFilesM1, "totalM2" => $totalFilesM2, "totalM3" => $totalFilesM3, "totalM4" => $totalFilesM4,
240
+ "filesWithErrors" => $filesWithErrors,
241
+ "moreFilesWithErrors" => $moreFilesWithErrors,
242
+ "foundUnlistedThumbs" => $foundUnlistedThumbs
243
+ );
244
+ }
245
+
246
  //count all the processable files in media library (while limiting the results to max 10000)
247
  public static function countAllProcessableFiles($settings = array(), $maxId = PHP_INT_MAX, $minId = 0){
248
  global $wpdb;
275
  //count all the files, main and thumbs
276
  while ( 1 ) {
277
  $idInfo = self::getPostIdsChunk($minId, $maxId, $pointer, $limit);
278
+
279
  if($idInfo === null) {
280
  break; //we parsed all the results
281
  }
284
  continue;
285
  }
286
 
287
+ $filesList= $wpdb->get_results("SELECT post_id, meta_key, meta_value FROM " . $wpdb->prefix . "postmeta
288
  WHERE post_id IN (" . implode(',', $idInfo->ids) . ")
289
  AND ( meta_key = '_wp_attached_file' OR meta_key = '_wp_attachment_metadata' )");
290
+ /* $filesList= $wpdb->get_results("SELECT post_id, meta_key, meta_value FROM " . $wpdb->prefix . "postmeta
291
+ WHERE post_id >= $minId and post_id <= $maxId
292
+ AND ( meta_key = '_wp_attached_file' OR meta_key = '_wp_attachment_metadata' )"); */
293
 
294
  //in one case this query returned zero items but if fewer items in the IDs list, it worked so apply this workaround:
295
  if($limit > 1000 && count($filesList) == 0) {
314
  }
315
  elseif ( $file->meta_key == "_wp_attachment_metadata" ) //_wp_attachment_metadata
316
  {
317
+ $attachment = maybe_unserialize($file->meta_value);
318
  $sizesCount = isset($attachment['sizes']) ? self::countSizesNotExcluded($attachment['sizes'], $settings->excludeSizes) : 0;
319
 
320
  // LA FIECARE 100 de imagini facem un test si daca findThumbs da diferit, sa dam o avertizare si eventual optiune
474
  );
475
  }
476
 
477
+
478
  public static function getPostMetaSlice($startId, $endId, $limit) {
479
  global $wpdb;
480
  $time = microtime(true);
516
  return $metaresult;
517
  }
518
  */
519
+
520
+ public static function getThumbsToOptimize($data, $filepath)
521
+ {
522
+ // @todo weak call. See how in future settings might come via central provider.
523
+ $settings = new \WPShortPixelSettings();
524
+
525
+ $fs = new \ShortPixel\FileSystemController();
526
+ $mainfile = $fs->getFile($filepath);
527
+
528
+ $sizesCount = isset($data['sizes']) ? WpShortPixelMediaLbraryAdapter::countSizesNotExcluded($data['sizes']) : 0;
529
+ $basedir = $mainfile->getFileDir()->getPath();
530
+ $thumbsOptList = isset($data['ShortPixel']['thumbsOptList']) ? $data['ShortPixel']['thumbsOptList'] : array();
531
+ $thumbsToOptimizeList = array(); // is returned, so should be defined before if.
532
+
533
+ if($sizesCount && $settings->processThumbnails) {
534
+
535
+ // findThumbs returns fullfilepath.
536
+ $found = $settings->optimizeUnlisted ? WpShortPixelMediaLbraryAdapter::findThumbs($mainfile->getFullPath()) : array();
537
+
538
+ $exclude = $settings->excludeSizes;
539
+ $exclude = is_array($exclude) ? $exclude : array();
540
+ foreach($data['sizes'] as $size => $sizeData) {
541
+ unset($found[\array_search($basedir . $sizeData['file'], $found)]); // @todo what is this intended to do?
542
+
543
+ // sizeData['file'] is *only* filename *but* can be wrong data, URL due to plugins. So check first, only get filename ( since it is supposed to fail with only a filename path ) and then reload.
544
+ $sizeFileCheck = $fs->getFile($sizeData['file']);
545
+ $file = $fs->getFile($basedir . $sizeFileCheck->getFileName());
546
+
547
+ if ($file->getExtension() !== $mainfile->getExtension())
548
+ {
549
+ continue;
550
+ }
551
+
552
+ if(!in_array($size, $exclude) && !in_array($file->getFileName(), $thumbsOptList)) {
553
+ $thumbsToOptimizeList[] = $file->getFileName();
554
+ }
555
+ }
556
+ //$found = array_diff($found, $thumbsOptList); // Wrong comparison. Found is full file path, thumbsOptList is not.
557
+ foreach($found as $path) {
558
+ $file = $fs->getFile($path);
559
+
560
+ // prevent Webp and what not from showing up.
561
+ if ($file->getExtension() !== $mainfile->getExtension())
562
+ {
563
+ continue;
564
+ }
565
+ // thumbs can already be in findThumbs.
566
+ if (! in_array($file->getFileName(), $thumbsToOptimizeList) && ! in_array($file->getFileName(), $thumbsOptList) )
567
+ {
568
+ $thumbsToOptimizeList[] = $file->getFileName();
569
+ }
570
+ }
571
+ }
572
+ return array($thumbsToOptimizeList, $sizesCount);
573
+ }
574
+
575
  public static function getPostsJoinLessReverse($startId, $endId, $limit)
576
  {
577
  global $wpdb;
666
 
667
  $base = $file->getFileBase();
668
  $ext = $file->getExtension();
669
+ $pattern = '/^' . preg_quote($base, '/') . '-\d+x\d+\.'. $ext .'/';
670
 
671
  $thumbs = array_merge($thumbs, self::getFilesByPattern($dirPath, $pattern));
672
 
693
  {
694
  foreach ($suffixes as $suffix){
695
 
696
+ $pattern = '/^' . preg_quote($base, '/') . '-\d+x\d+'. $suffix . '\.'. $ext .'/';
697
  $thumbs = array_merge($thumbs, self::getFilesByPattern($dirPath, $pattern));
698
  /*foreach($thumbsCandidates as $th) {
699
  if(preg_match($pattern, $th)) {
709
  {
710
  foreach ($infixes as $infix){
711
  //$thumbsCandidates = @glob($base . $infix . "-*." . $ext);
712
+ $pattern = '/^' . preg_quote($base, '/') . $infix . '-\d+x\d+' . '\.'. $ext .'/';
713
  $thumbs = array_merge($thumbs, self::getFilesByPattern($dirPath, $pattern));
714
 
715
  /*foreach($thumbsCandidates as $th) {
750
  }
751
  catch(\Exception $e)
752
  {
753
+ Log::addWarn('GetFilesbyPattern issue with directory. ', $e->getMessage());
754
  return array();
755
  }
756
 
786
  }
787
  }
788
 
789
+ protected static function getPostIdsChunk($minId, $maxId, $pointer, $limit, $byMinMax = false) {
790
  global $wpdb;
791
 
792
+ // min/max : the function feeds proper Min and MaxId to function so offset pointer is not needed.
793
+ if ($byMinMax)
794
+ {
795
+ $pointer = 0;
796
+ $sql = "SELECT ID, post_mime_type, post_date FROM " . $wpdb->prefix . "posts
797
+ WHERE ( ID > $minId )
798
+ and post_mime_type <> ''
799
+ LIMIT $limit";
800
+ }
801
+ else {
802
+ $sql = "SELECT ID, post_mime_type, post_date FROM " . $wpdb->prefix . "posts
803
+ WHERE ( ID <= $maxId AND ID > $minId )
804
+ LIMIT $pointer,$limit";
805
+ }
806
+
807
  $ids = $idDates = array();
808
+ $idList = $wpdb->get_results($sql);
809
+
 
810
  if ( empty($idList) ) {
811
  return null;
812
  }
816
  $idDates[$item->ID] = $item->post_date;
817
  }
818
  }
819
+
820
+ return (object)array('ids' => $ids, 'idDates' => $idDates, 'last_id' => $ids[count($ids)-1] );
821
+ }
822
+
823
+ /* Recount images from the media library when something went wrong badly */
824
+ public static function reCountMediaLibraryItems()
825
+ {
826
+ $limit = self::getOptimalChunkSize();
827
+ $run = true;
828
+ $minId = 0;
829
+ $maxId = -1; // not in use
830
+ $pointer = -1; // not in use.
831
+
832
+ $timeout = get_transient('shortpixel_debug_media');
833
+ if ($timeout !== false)
834
+ $minId = $timeout;
835
+
836
+ while ( $run == true ) {
837
+ if ($minId == -1)
838
+ exit('Hanging Loop Detected');
839
+ $idInfo = self::getPostIdsChunk($minId, $maxId, $pointer, $limit, true);
840
+ $minId = isset($idInfo->last_id) ? $idInfo->last_id : -1;
841
+
842
+ if($idInfo === null) {
843
+ break; //we parsed all the results
844
+ }
845
+ elseif(count($idInfo->ids) == 0) {
846
+ //$minId += $limit; // This is a no results case.
847
+ continue;
848
+ }
849
+ foreach($idInfo->ids as $post_id)
850
+ {
851
+ $imageModel = new \ShortPixel\ImageModel();
852
+ $imageModel->setByPostID($post_id);
853
+ $imageModel->reAcquire();
854
+ Log::addDebug('Reacquired: ' . $post_id );
855
+ }
856
+
857
+ set_transient('shortpixel_debug_media', $post_id, 20 * MINUTE_IN_SECONDS);
858
+ }
859
  }
860
 
861
  }
class/external/wp-offload-media.php CHANGED
@@ -8,6 +8,8 @@ class wpOffload
8
  protected $as3cf;
9
  protected $active = false;
10
 
 
 
11
  public function __construct()
12
  {
13
  // This must be called before WordPress' init.
@@ -17,21 +19,27 @@ class wpOffload
17
  public function init($as3cf)
18
  {
19
 
 
 
20
  $this->as3cf = $as3cf;
21
  $this->active = true;
22
 
23
  add_action('shortpixel_image_optimised', array($this, 'image_upload'));
24
  add_action('shortpixel_after_restore_image', array($this, 'image_restore')); // hit this when restoring.
25
  add_action('shortpixel/image/convertpng2jpg_after', array($this, 'image_converted'));
 
26
  add_action('shortpixel/image/convertpng2jpg_before', array($this, 'remove_remote'));
27
  add_filter('as3cf_attachment_file_paths', array($this, 'add_webp_paths'));
28
  add_filter('as3cf_remove_attachment_paths', array($this, 'remove_webp_paths'));
29
 
30
  add_filter('shortpixel/restore/targetfile', array($this, 'returnOriginalFile'),10,2);
31
 
 
 
32
  add_filter('get_attached_file', function($file, $id)
33
  {
34
- if (strpos($file, 's3:/') !== false)
 
35
  {
36
  return get_attached_file($id, true);
37
  }
@@ -108,10 +116,30 @@ class wpOffload
108
 
109
  public function image_upload($id)
110
  {
 
 
 
 
 
 
 
111
  Log::addDebug('Uploading New Attachment');
112
  $this->as3cf->upload_attachment($id);
113
  }
114
 
 
 
 
 
 
 
 
 
 
 
 
 
 
115
 
116
  private function getWebpPaths($paths, $check_exists = true)
117
  {
8
  protected $as3cf;
9
  protected $active = false;
10
 
11
+ protected $settings;
12
+
13
  public function __construct()
14
  {
15
  // This must be called before WordPress' init.
19
  public function init($as3cf)
20
  {
21
 
22
+
23
+
24
  $this->as3cf = $as3cf;
25
  $this->active = true;
26
 
27
  add_action('shortpixel_image_optimised', array($this, 'image_upload'));
28
  add_action('shortpixel_after_restore_image', array($this, 'image_restore')); // hit this when restoring.
29
  add_action('shortpixel/image/convertpng2jpg_after', array($this, 'image_converted'));
30
+ add_action('shortpixel_before_restore_image', array($this, 'remove_remote')); // not optimal, when backup fails this will cause issues.
31
  add_action('shortpixel/image/convertpng2jpg_before', array($this, 'remove_remote'));
32
  add_filter('as3cf_attachment_file_paths', array($this, 'add_webp_paths'));
33
  add_filter('as3cf_remove_attachment_paths', array($this, 'remove_webp_paths'));
34
 
35
  add_filter('shortpixel/restore/targetfile', array($this, 'returnOriginalFile'),10,2);
36
 
37
+ add_filter('as3cf_pre_update_attachment_metadata', array($this, 'preventInitialUpload'), 10,4);
38
+
39
  add_filter('get_attached_file', function($file, $id)
40
  {
41
+ $scheme = parse_url($file, PHP_URL_SCHEME);
42
+ if ($scheme !== false && strpos($scheme, 's3') !== false)
43
  {
44
  return get_attached_file($id, true);
45
  }
116
 
117
  public function image_upload($id)
118
  {
119
+ //$this->as3cf->get_setting( 'copy-to-s3' )
120
+ if ( ! ( $old_provider_object = $this->as3cf->get_attachment_provider_info( $id ) ) && ! $this->as3cf->get_setting( 'copy-to-s3' ) ) {
121
+ // abort if not already uploaded to provider and the copy setting is off
122
+ Log::addDebug('As3cf image upload is off and object not previously uploaded');
123
+ return false;
124
+ }
125
+
126
  Log::addDebug('Uploading New Attachment');
127
  $this->as3cf->upload_attachment($id);
128
  }
129
 
130
+ /** This function will cut out the initial upload to S3Offload and rely solely on the image_upload function provided here, after shortpixel optimize.
131
+ * Function will only work when plugin is set to auto-optimize new entries to the media library */
132
+ public function preventInitialUpload($bool, $data, $post_id, $old_provider_object)
133
+ {
134
+ // @todo weak call. See how in future settings might come via central provider.
135
+ $settings = new \WPShortPixelSettings();
136
+
137
+ if ($settings->autoMediaLibrary)
138
+ {
139
+ return true;
140
+ }
141
+ return $bool;
142
+ }
143
 
144
  private function getWebpPaths($paths, $check_exists = true)
145
  {
class/front/img-to-picture-webp.php CHANGED
@@ -112,6 +112,10 @@ class ShortPixelImgToPictureWebp
112
  }
113
 
114
  $img = self::get_attributes($match[0]);
 
 
 
 
115
  // [BS] Can return false in case of Module fail. Escape in that case with unmodified image
116
  if ($img === false)
117
  return $match[0];
112
  }
113
 
114
  $img = self::get_attributes($match[0]);
115
+ if(isset($img['style']) && strpos($img['style'], 'background') !== false) {
116
+ //don't replace for <img>'s that have background
117
+ return $match[0];
118
+ }
119
  // [BS] Can return false in case of Module fail. Escape in that case with unmodified image
120
  if ($img === false)
121
  return $match[0];
class/model/directory_model.php CHANGED
@@ -148,7 +148,7 @@ class DirectoryModel extends ShortPixelModel
148
  private function constructUsualDirectories($path)
149
  {
150
  $pathar = array_values(array_filter(explode('/', $path))); // array value to reset index
151
- $test_path = false;
152
  if ( ($key = array_search('wp-content', $pathar)) !== false)
153
  {
154
  $testpath = implode('/', array_slice($pathar, $key));
148
  private function constructUsualDirectories($path)
149
  {
150
  $pathar = array_values(array_filter(explode('/', $path))); // array value to reset index
151
+ $testpath = false;
152
  if ( ($key = array_search('wp-content', $pathar)) !== false)
153
  {
154
  $testpath = implode('/', array_slice($pathar, $key));
class/model/file_model.php CHANGED
@@ -26,6 +26,8 @@ class FileModel extends ShortPixelModel
26
  protected $exists = false;
27
  protected $is_writable = false;
28
  protected $is_readable = false;
 
 
29
  protected $status;
30
 
31
  protected $backupDirectory;
@@ -246,6 +248,7 @@ class FileModel extends ShortPixelModel
246
  */
247
  protected function processPath($path)
248
  {
 
249
  $original_path = $path;
250
  $path = trim($path);
251
 
26
  protected $exists = false;
27
  protected $is_writable = false;
28
  protected $is_readable = false;
29
+
30
+
31
  protected $status;
32
 
33
  protected $backupDirectory;
248
  */
249
  protected function processPath($path)
250
  {
251
+
252
  $original_path = $path;
253
  $path = trim($path);
254
 
class/model/image_model.php ADDED
@@ -0,0 +1,194 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace ShortPixel;
3
+ use ShortPixel\ShortpixelLogger\ShortPixelLogger as Log;
4
+
5
+ /* ImageModel class.
6
+ *
7
+ *
8
+ * - Represents a -single- image *not file*.
9
+ * - Can be either MediaLibrary, or Custom .
10
+ * - Not a replacement of Meta, but might be.
11
+ * - Goal: Structural ONE method calls of image related information, and combining information. Same task is now done on many places.
12
+ * -- Shortpixel Class should be able to blindly call model for information, correct metadata and such.
13
+ */
14
+ class ImageModel extends ShortPixelModel
15
+ {
16
+
17
+ private $file; // the file representation
18
+ private $meta; // metadata of the image.
19
+ private $facade; // ShortPixelMetaFacade
20
+
21
+ protected $thumbsnails = array(); // thumbnails of this
22
+
23
+
24
+ public function __construct()
25
+ {
26
+
27
+ }
28
+
29
+ public function setByPostID($post_id)
30
+ {
31
+ // Set Meta
32
+ $fs = new FileSystemController();
33
+ $this->facade = new \ShortPixelMetaFacade($post_id);
34
+ $this->meta = $this->facade->getMeta();
35
+
36
+ $file = get_attached_file($post_id);
37
+ $this->file = $fs->getFile($file);
38
+
39
+ }
40
+
41
+ public function getMeta()
42
+ {
43
+ return $this->meta;
44
+ }
45
+
46
+ public function getFile()
47
+ {
48
+ return $this->file;
49
+ }
50
+
51
+ /* Sanity check in process. Should only be called upon special request, or with single image displays. Should check and recheck stats, thumbs, unlistedthumbs and all assumptions of data that might corrupt or change outside of this plugin */
52
+ public function reAcquire()
53
+ {
54
+ $this->addUnlistedThumbs();
55
+ $this->reCheckThumbnails();
56
+
57
+ // $this->recount();
58
+ }
59
+
60
+ // Rebuild the ThumbsOptList and others to fix old info, wrong builds.
61
+ private function reCheckThumbnails()
62
+ {
63
+ // Redo only on non-processed images.
64
+ if ($this->meta->getStatus() != \ShortPixelMeta::FILE_STATUS_SUCCESS)
65
+ {
66
+ return;
67
+ }
68
+ $data = $this->facade->getRawMeta();
69
+ $oldList = array();
70
+ if (isset($data['ShortPixel']['thumbsOptList']))
71
+ {
72
+ $oldList = $data['ShortPixel']['thumbsOptList'];
73
+ unset($data['ShortPixel']['thumbsOptList']); // reset the thumbsOptList, so unset to get what the function thinks should be there.
74
+ }
75
+ list($includedSizes, $thumbsCount) = \WpShortPixelMediaLbraryAdapter::getThumbsToOptimize($data, $this->file->getFullPath() );
76
+
77
+ // When identical, save the check and the Dbase update.
78
+ if ($oldList === $includedSizes)
79
+ {
80
+ return;
81
+ }
82
+
83
+ $newList = array();
84
+ foreach($this->meta->getThumbsOptList() as $index => $item)
85
+ {
86
+ if ( in_array($item, $includedSizes))
87
+ {
88
+ $newList[] = $item;
89
+ }
90
+ }
91
+
92
+ $this->meta->setThumbsOptList($newList);
93
+ $this->facade->updateMeta($this->meta);
94
+
95
+ }
96
+
97
+ private function addUnlistedThumbs()
98
+ {
99
+ // @todo weak call. See how in future settings might come via central provider.
100
+ $settings = new \WPShortPixelSettings();
101
+
102
+ // must be media library, setting must be on.
103
+ if($this->facade->getType() != \ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE
104
+ || ! $settings->optimizeUnlisted) {
105
+ return 0;
106
+ }
107
+
108
+ $this->facade->removeSPFoundMeta(); // remove all found meta. If will be re-added here every time.
109
+ $meta = $this->meta; //$itemHandler->getMeta();
110
+
111
+ Log::addDebug('Finding Thumbs on path' . $meta->getPath());
112
+ $thumbs = \WpShortPixelMediaLbraryAdapter::findThumbs($meta->getPath());
113
+
114
+ $fs = new FileSystemController();
115
+ $mainFile = $this->file;
116
+
117
+ // Find Thumbs returns *full file path*
118
+ $foundThumbs = \WpShortPixelMediaLbraryAdapter::findThumbs($mainFile->getFullPath());
119
+
120
+ // no thumbs, then done.
121
+ if (count($foundThumbs) == 0)
122
+ {
123
+ return 0;
124
+ }
125
+ //first identify which thumbs are not in the sizes
126
+ $sizes = $meta->getThumbs();
127
+ $mimeType = false;
128
+
129
+ $allSizes = array();
130
+ $basepath = $mainFile->getFileDir()->getPath();
131
+
132
+ foreach($sizes as $size) {
133
+ // Thumbs should have filename only. This is shortpixel-meta ! Not metadata!
134
+ // Provided filename can be unexpected (URL, fullpath), so first do check, get filename, then check the full path
135
+ $sizeFileCheck = $fs->getFile($size['file']);
136
+ $sizeFilePath = $basepath . $sizeFileCheck->getFileName();
137
+ $sizeFile = $fs->getFile($sizeFilePath);
138
+
139
+ //get the mime-type from one of the thumbs metas
140
+ if(isset($size['mime-type'])) { //situation from support case #9351 Ramesh Mehay
141
+ $mimeType = $size['mime-type'];
142
+ }
143
+ $allSizes[] = $sizeFile;
144
+ }
145
+
146
+ foreach($foundThumbs as $id => $found) {
147
+ $foundFile = $fs->getFile($found);
148
+
149
+ foreach($allSizes as $sizeFile) {
150
+ if ($sizeFile->getExtension() !== $foundFile->getExtension())
151
+ {
152
+ $foundThumbs[$id] = false;
153
+ }
154
+ elseif ($sizeFile->getFileName() === $foundFile->getFileName())
155
+ {
156
+ $foundThumbs[$id] = false;
157
+ }
158
+ }
159
+ }
160
+ // add the unfound ones to the sizes array
161
+ $ind = 1;
162
+ $counter = 0;
163
+ // Assumption:: there is no point in adding to this array since findThumbs should find *all* thumbs that are relevant to this image.
164
+ /*while (isset($sizes[ShortPixelMeta::FOUND_THUMB_PREFIX . str_pad("".$start, 2, '0', STR_PAD_LEFT)]))
165
+ {
166
+ $start++;
167
+ } */
168
+ // $start = $ind;
169
+
170
+ foreach($foundThumbs as $found) {
171
+ if($found !== false) {
172
+ Log::addDebug('Adding File to sizes -> ' . $found);
173
+ $size = getimagesize($found);
174
+ Log::addDebug('Add Unlisted, add size' . $found );
175
+
176
+ $sizes[\ShortPixelMeta::FOUND_THUMB_PREFIX . str_pad("".$ind, 2, '0', STR_PAD_LEFT)]= array( // it's a file that has no corresponding thumb so it's the WEBP for the main file
177
+ 'file' => \ShortPixelAPI::MB_basename($found),
178
+ 'width' => $size[0],
179
+ 'height' => $size[1],
180
+ 'mime-type' => $mimeType
181
+ );
182
+ $ind++;
183
+ $counter++;
184
+ }
185
+ }
186
+ if($ind > 1) { // at least one thumbnail added, update
187
+ $meta->setThumbs($sizes);
188
+ $this->facade->updateMeta($meta);
189
+ }
190
+
191
+ return $counter;
192
+ }
193
+
194
+ } // model
class/shortpixel-png2jpg.php CHANGED
@@ -25,7 +25,11 @@ class ShortPixelPng2Jpg {
25
 
26
  //WPShortPixel::log("PNG2JPG SHELL EXEC: " . shell_exec('convert ' . $image . ' -format "%[opaque]" info:'));
27
 
28
- if (!file_exists($image) || ord(file_get_contents($image, false, null, 25, 1)) & 4) {
 
 
 
 
29
  $transparent = 1;
30
  } else {
31
  $contents = file_get_contents($image);
@@ -110,8 +114,9 @@ class ShortPixelPng2Jpg {
110
  WPShortPixel::log("PNG2JPG doConvert created JPEG at $newPath");
111
  $newSize = filesize($newPath);
112
  $origSize = filesize($image);
113
- if($newSize > $origSize * 0.95) {
114
  //if the image is not 5% smaller, don't bother.
 
115
  WPShortPixel::log("PNG2JPG converted image is larger ($newSize vs. $origSize), keeping the PNG");
116
  unlink($newPath);
117
  return (object)array("params" => $params, "unlink" => false);
@@ -217,6 +222,8 @@ class ShortPixelPng2Jpg {
217
 
218
  $meta = $itemHandler->getRawMeta();
219
  $ID = $itemHandler->getId();
 
 
220
  if(!$this->_settings->png2jpg || !isset($meta['file']) || strtolower(substr($meta['file'], -4)) !== '.png') {
221
  return ;
222
  }
@@ -224,8 +231,8 @@ class ShortPixelPng2Jpg {
224
 
225
  WPShortPixel::log("Send to processing: Convert Media PNG to JPG #{$ID} META: " . json_encode($meta));
226
 
227
- $image = $meta['file'];
228
- $imagePath = get_attached_file($ID);
229
  $basePath = trailingslashit(str_replace($image, "", $imagePath));
230
  $imageUrl = wp_get_attachment_url($ID);
231
  $baseUrl = self::removeUrlProtocol(trailingslashit(str_replace($image, "", $imageUrl))); //make the base url protocol agnostic if it's not already
@@ -248,7 +255,7 @@ class ShortPixelPng2Jpg {
248
  if($this->_settings->png2jpg == 2) {
249
  $doConvert = true;
250
  } else {
251
- $retC = $this->canConvertPng2Jpg($image);
252
  $doConvert = $retC['notTransparent'];
253
  }
254
  if (!$doConvert) {
25
 
26
  //WPShortPixel::log("PNG2JPG SHELL EXEC: " . shell_exec('convert ' . $image . ' -format "%[opaque]" info:'));
27
 
28
+ if (!file_exists($image)) {
29
+ WPShortPixel::log("PNG2JPG FILE MISSING: " . $image);
30
+ $transparent = 1;
31
+ } elseif(ord(file_get_contents($image, false, null, 25, 1)) & 4) {
32
+ WPShortPixel::log("PNG2JPG: 25th byte has thrid bit 1 - transparency");
33
  $transparent = 1;
34
  } else {
35
  $contents = file_get_contents($image);
114
  WPShortPixel::log("PNG2JPG doConvert created JPEG at $newPath");
115
  $newSize = filesize($newPath);
116
  $origSize = filesize($image);
117
+ if($newSize > $origSize * 0.95 || $newSize == 0) {
118
  //if the image is not 5% smaller, don't bother.
119
+ //if the size is 0, a conversion (or disk write) problem happened, go on with the PNG
120
  WPShortPixel::log("PNG2JPG converted image is larger ($newSize vs. $origSize), keeping the PNG");
121
  unlink($newPath);
122
  return (object)array("params" => $params, "unlink" => false);
222
 
223
  $meta = $itemHandler->getRawMeta();
224
  $ID = $itemHandler->getId();
225
+ $fs = new \Shortpixel\FileSystemController;
226
+
227
  if(!$this->_settings->png2jpg || !isset($meta['file']) || strtolower(substr($meta['file'], -4)) !== '.png') {
228
  return ;
229
  }
231
 
232
  WPShortPixel::log("Send to processing: Convert Media PNG to JPG #{$ID} META: " . json_encode($meta));
233
 
234
+ $image = $meta['file']; // This is not a full path!
235
+ $imagePath = get_attached_file($ID); // This is a full path.
236
  $basePath = trailingslashit(str_replace($image, "", $imagePath));
237
  $imageUrl = wp_get_attachment_url($ID);
238
  $baseUrl = self::removeUrlProtocol(trailingslashit(str_replace($image, "", $imageUrl))); //make the base url protocol agnostic if it's not already
255
  if($this->_settings->png2jpg == 2) {
256
  $doConvert = true;
257
  } else {
258
+ $retC = $this->canConvertPng2Jpg($imagePath);
259
  $doConvert = $retC['notTransparent'];
260
  }
261
  if (!$doConvert) {
class/view/settings/part-debug.php CHANGED
@@ -36,5 +36,13 @@ namespace ShortPixel;
36
  <pre><?php var_export($this->quotaData); ?></pre>
37
  </div>
38
 
 
 
 
 
 
 
 
 
39
  </div> <!-- tab-content -->
40
  </section>
36
  <pre><?php var_export($this->quotaData); ?></pre>
37
  </div>
38
 
39
+ <h3>Tools</h3>
40
+ <div class='debug-images'>
41
+ <form method="POST" action="<?php echo add_query_arg(array('sp-action' => 'action_debug_medialibrary')) ?>"
42
+ id="shortpixel-form-debug-medialib">
43
+ <button class='button' type='submit'>Reacquire Thumbnails on Media Library</button>
44
+ </form>
45
+ </div>
46
+
47
  </div> <!-- tab-content -->
48
  </section>
class/view/settings/part-general.php CHANGED
@@ -28,7 +28,7 @@
28
  if($showApiKey) {
29
  $canValidate = true;?>
30
  <input name="key" type="text" id="key" value="<?php echo( $view->data->apiKey );?>"
31
- class="regular-text" <?php echo($editApiKey ? "" : 'disabled') ?> >
32
  <?php
33
  }
34
  elseif(defined("SHORTPIXEL_API_KEY")) {
@@ -43,10 +43,10 @@
43
  <?php } ?>
44
  <input type="hidden" name="validate" id="valid" value=""/>
45
  <span class="spinner" id="pluginemail_spinner" style="float:none;"></span>
46
- <!-- <button type="button" id="validate" class="button button-primary" title="<?php _e('Validate the provided API key','shortpixel-image-optimiser');?>"
47
  onclick="ShortPixel.validateKey(this)" <?php echo $canValidate ? "" : "disabled"?> <?php echo $this->is_verifiedkey ? 'style="display:none;"' : '' ?>>
48
- <?php _e('Validate','shortpixel-image-optimiser');?>
49
- </button> -->
50
  <span class="shortpixel-key-valid" <?php echo $this->is_verifiedkey ? '' : 'style="display:none;"' ?>>
51
  <span class="dashicons dashicons-yes"></span><?php _e('Your API key is valid.','shortpixel-image-optimiser');?>
52
  </span>
28
  if($showApiKey) {
29
  $canValidate = true;?>
30
  <input name="key" type="text" id="key" value="<?php echo( $view->data->apiKey );?>"
31
+ class="regular-text" <?php echo($editApiKey ? "" : 'disabled') ?> <?php echo $this->is_verifiedkey ? 'onkeyup="ShortPixel.apiKeyChanged()"' : '' ?>>
32
  <?php
33
  }
34
  elseif(defined("SHORTPIXEL_API_KEY")) {
43
  <?php } ?>
44
  <input type="hidden" name="validate" id="valid" value=""/>
45
  <span class="spinner" id="pluginemail_spinner" style="float:none;"></span>
46
+ <button type="button" id="validate" class="button button-primary" title="<?php _e('Validate the provided API key','shortpixel-image-optimiser');?>"
47
  onclick="ShortPixel.validateKey(this)" <?php echo $canValidate ? "" : "disabled"?> <?php echo $this->is_verifiedkey ? 'style="display:none;"' : '' ?>>
48
+ <?php _e('Save settings & validate','shortpixel-image-optimiser');?>
49
+ </button>
50
  <span class="shortpixel-key-valid" <?php echo $this->is_verifiedkey ? '' : 'style="display:none;"' ?>>
51
  <span class="dashicons dashicons-yes"></span><?php _e('Your API key is valid.','shortpixel-image-optimiser');?>
52
  </span>
class/view/shortpixel_view.php CHANGED
@@ -1662,6 +1662,16 @@ class ShortPixelView {
1662
  }
1663
 
1664
  public function renderCustomColumn($id, $data, $extended = false){ ?>
 
 
 
 
 
 
 
 
 
 
1665
  <div id='sp-msg-<?php echo($id);?>' class='column-wp-shortPixel'>
1666
 
1667
  <?php switch($data['status']) {
@@ -1720,13 +1730,13 @@ class ShortPixelView {
1720
  $excluded = (isset($data['excludeSizes']) ? count($data['excludeSizes']) : 0);
1721
  $successText = $this->getSuccessText($data['percent'],$data['bonus'],$data['type'],$data['thumbsOpt'],$data['thumbsTotal'], $data['retinasOpt'], $data['excludeSizes']);
1722
  $todoSizes = $missingThumbs = $excludeSizes = '';
1723
- if($extended) {
1724
  if(isset($data['thumbsToOptimizeList']) && count($data['thumbsToOptimizeList'])) {
1725
  $todoSizes .= "<br><span style='word-break: break-all;'> <span style='font-weight: bold;'>" . __("To optimize:", 'shortpixel-image-optimiser') . "</span>";
1726
  foreach($data['thumbsToOptimizeList'] as $todoItem) {
1727
  $todoSizes .= "<br> &#8226;&nbsp;" . $todoItem;
1728
  }
1729
- $excludeSizes .= '</span>';
1730
  }
1731
  if(isset($data['excludeSizes'])) {
1732
  $excludeSizes .= "<br><span style='word-break: break-all;'> <span style='font-weight: bold;'>" . __("Excluded thumbnails:", 'shortpixel-image-optimiser') . "</span>";
@@ -1747,7 +1757,7 @@ class ShortPixelView {
1747
  . ($data['png2jpg'] ? '<br>' . __('Converted from PNG','shortpixel-image-optimiser'): '')
1748
  . "<br>" . __("Optimized on", 'shortpixel-image-optimiser') . ": " . $data['date']
1749
  . $todoSizes . $excludeSizes . $missingThumbs;
1750
- }
1751
  $this->renderListCell($id, $data['status'], $data['showActions'], $data['thumbsToOptimize'],
1752
  $data['backup'], $data['type'], $data['invType'], $successText);
1753
 
1662
  }
1663
 
1664
  public function renderCustomColumn($id, $data, $extended = false){ ?>
1665
+ <?php if ($extended) // extended ( edit-media ) moved to it's own view.
1666
+ {
1667
+ $controller = new \ShortPixel\editMediaController();
1668
+ $controller->setTempData($data);
1669
+ $controller->setLegacyView($this);
1670
+ $controller->setShortPixel($this->ctrl);
1671
+ $controller->load($id);
1672
+ return;
1673
+ }
1674
+ ?>
1675
  <div id='sp-msg-<?php echo($id);?>' class='column-wp-shortPixel'>
1676
 
1677
  <?php switch($data['status']) {
1730
  $excluded = (isset($data['excludeSizes']) ? count($data['excludeSizes']) : 0);
1731
  $successText = $this->getSuccessText($data['percent'],$data['bonus'],$data['type'],$data['thumbsOpt'],$data['thumbsTotal'], $data['retinasOpt'], $data['excludeSizes']);
1732
  $todoSizes = $missingThumbs = $excludeSizes = '';
1733
+ /*if($extended) {
1734
  if(isset($data['thumbsToOptimizeList']) && count($data['thumbsToOptimizeList'])) {
1735
  $todoSizes .= "<br><span style='word-break: break-all;'> <span style='font-weight: bold;'>" . __("To optimize:", 'shortpixel-image-optimiser') . "</span>";
1736
  foreach($data['thumbsToOptimizeList'] as $todoItem) {
1737
  $todoSizes .= "<br> &#8226;&nbsp;" . $todoItem;
1738
  }
1739
+ $todoSizes .= '</span>';
1740
  }
1741
  if(isset($data['excludeSizes'])) {
1742
  $excludeSizes .= "<br><span style='word-break: break-all;'> <span style='font-weight: bold;'>" . __("Excluded thumbnails:", 'shortpixel-image-optimiser') . "</span>";
1757
  . ($data['png2jpg'] ? '<br>' . __('Converted from PNG','shortpixel-image-optimiser'): '')
1758
  . "<br>" . __("Optimized on", 'shortpixel-image-optimiser') . ": " . $data['date']
1759
  . $todoSizes . $excludeSizes . $missingThumbs;
1760
+ } */
1761
  $this->renderListCell($id, $data['status'], $data['showActions'], $data['thumbsToOptimize'],
1762
  $data['backup'], $data['type'], $data['invType'], $successText);
1763
 
class/view/view-edit-media.php ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace ShortPixel;
3
+ use ShortPixel\ShortpixelLogger\ShortPixelLogger as Log;
4
+
5
+ ?>
6
+
7
+ <div id='sp-msg-<?php echo($view->id);?>' class='column-wp-shortPixel view-edit-media'>
8
+ <?php // Debug Data
9
+ if (! is_null($view->debugInfo)): ?>
10
+ <div class='debugInfo'>
11
+ <ul>
12
+ <?php foreach($view->debugInfo as $item): ?>
13
+ <li><strong><?php echo $item[0]; ?></strong>
14
+ <?php
15
+ if (is_array($item[1]) || is_object($item[1]))
16
+ echo "<PRE>" . print_r($item[1], true) . "</PRE>";
17
+ else
18
+ echo $item[1];
19
+ ?>
20
+ </li>
21
+ <?php endforeach; ?>
22
+ </ul>
23
+
24
+ </div>
25
+ <?php endif; ?>
26
+
27
+ <?php if (! is_null($view->status_message)): ?>
28
+ <h5><?php echo $view->status_message; ?></h5>
29
+ <?php endif; ?>
30
+
31
+ <p><?php echo $view->message; ?></p>
32
+
33
+ <?php if (count($view->stats) > 0): ?>
34
+ <div class='sp-column-stats'>
35
+ <?php $this->renderLegacyCell(); ?>
36
+ <ul class='edit-media-stats'>
37
+ <?php foreach($view->stats as $index => $data)
38
+ { ?>
39
+ <li><span><?php echo $data[0] ?></span> <span><?php echo $data[1] ?></span></li>
40
+ <?php } ?>
41
+ </ul>
42
+ </div>
43
+ <?php endif; ?>
44
+
45
+ <?php foreach($view->todo as $item)
46
+ echo $item ;
47
+ ?>
48
+
49
+ <div class='main-actions'>
50
+ <?php foreach($view->actions as $action)
51
+ echo $action;
52
+ ?>
53
+ </div>
54
+
55
+
56
+
57
+ </div>
class/wp-short-pixel.php CHANGED
@@ -70,7 +70,7 @@ class WPShortPixel {
70
  add_filter( 'request', array( &$this, 'columnOrderFilterBy') );
71
  add_action('restrict_manage_posts', array( &$this, 'mediaAddFilterDropdown'));
72
  //Edit media meta box
73
- add_action( 'add_meta_boxes', array( &$this, 'shortpixelInfoBox') );
74
  //for cleaning up the WebP images when an attachment is deleted
75
  add_action( 'delete_attachment', array( &$this, 'onDeleteImage') );
76
 
@@ -1499,7 +1499,14 @@ class WPShortPixel {
1499
  //$urlPath = implode("/", array_slice($filePath, 0, count($filePath) - 1));
1500
  $thumb = $uploadsUrl . $urlPath . $thumb;
1501
  } else {
 
1502
  $mainUrl = ShortPixelMetaFacade::safeGetAttachmentUrl($itemHandler->getId());
 
 
 
 
 
 
1503
  $thumb = dirname($mainUrl) . '/' . $thumb;
1504
  }
1505
  }
@@ -1624,6 +1631,7 @@ class WPShortPixel {
1624
  * Will update meta. if any are found.
1625
  * @param ShortPixelMetaFacade $itemHandler ShortpixelMetaFacade item handler.
1626
  * @return int Number of additions to the sizes Metadata.
 
1627
  */
1628
  private function addUnlistedThumbs($itemHandler)
1629
  {
@@ -1729,14 +1737,13 @@ class WPShortPixel {
1729
  }
1730
  }
1731
 
1732
- $meta = $itemHandler->getMeta();
1733
-
1734
  //WpShortPixelMediaLbraryAdapter::cleanupFoundThumbs($itemHandler);
1735
  $URLsAndPATHs = $this->getURLsAndPATHs($itemHandler, NULL, $onlyThumbs);
1736
  Log::addDebug('Send to PRocessing - URLS -', array($URLsAndPATHs) );
1737
 
1738
  //find thumbs that are not listed in the metadata and add them in the sizes array
1739
  $this->addUnlistedThumbs($itemHandler);
 
1740
 
1741
  //find any missing thumbs files and mark them as such
1742
  $miss = $meta->getThumbsMissing();
@@ -2086,23 +2093,37 @@ class WPShortPixel {
2086
 
2087
  $baseUrl = str_replace($fsFile->getFileName(), '', $imageUrl); // remove *only* filename from URL
2088
  $baseUrl = ShortPixelPng2Jpg::removeUrlProtocol($baseUrl); // @todo parse_url with a util helper / model should be better here
 
 
 
 
 
2089
 
2090
  // $baseUrl = ShortPixelPng2Jpg::removeUrlProtocol(trailingslashit(str_replace($image, "", $imageUrl))); //make the base url protocol agnostic if it's not already
2091
 
2092
  // not needed, we don't do this weird remove anymore.
2093
  $baseRelPath = ''; // trailingslashit(dirname($image)); // @todo Replace this (string) $fsFile->getFileDir();
2094
 
 
2095
  $toReplace[ShortPixelPng2Jpg::removeUrlProtocol($imageUrl)] = $baseUrl . $baseRelPath . wp_basename($png2jpgMain);
2096
  foreach($sizes as $key => $size) {
2097
  if(isset($png2jpgSizes[$key])) {
2098
  $toReplace[$baseUrl . $baseRelPath . $size['file']] = $baseUrl . $baseRelPath . wp_basename($png2jpgSizes[$key]['file']);
2099
  }
 
 
 
 
 
 
 
2100
  }
2101
 
2102
  //$file = $png2jpgMain;
2103
  $sizes = $png2jpgSizes;
2104
 
2105
- $fsFile = $fs->getFile($png2jpgMain); // original is non-existing at this time.
 
2106
 
2107
  }
2108
 
@@ -2134,7 +2155,6 @@ class WPShortPixel {
2134
  //$dest = $pathInfo['dirname'] . '/' . $imageData['file'];
2135
  $destination = $fs->getFile($filePath . $imageData['file']);
2136
  $source = $fs->getFile($bkFolder->getPath() . $imageData['file']); //trailingslashit($bkFolder) . $imageData['file'];
2137
-
2138
  if(! $source->exists() ) continue; // if thumbs were not optimized, then the backups will not be there.
2139
  if(! $source->is_readable() || ($destination->exists() && !$destination->is_writable() )) {
2140
  $failedFile = ($destination->is_writable() ? $source->getFullPath() : $destination->getFullPath());
@@ -2177,9 +2197,6 @@ class WPShortPixel {
2177
  Log::addError('DoRestore failed restoring retina backup', array($retinaBK->getFullPath(), $retinaDest->getFullPath() ));
2178
  }
2179
  }
2180
-
2181
- //@rename($bkFile, $file);
2182
- //@rename($this->retinaName($bkFile), $this->retinaName($file));
2183
  }
2184
  //getSize to update meta if image was resized by ShortPixel
2185
  if($fsFile->exists()) {
@@ -2189,7 +2206,6 @@ class WPShortPixel {
2189
  }
2190
 
2191
  //overwriting thumbnails
2192
-
2193
  foreach($thumbsPaths as $index => $data) {
2194
  $source = $data['source'];
2195
  $destination = $data['destination'];
@@ -2251,10 +2267,13 @@ class WPShortPixel {
2251
  $spPng2Jpg = new ShortPixelPng2Jpg($this->_settings);
2252
  $spPng2Jpg->png2JpgUpdateUrls(array(), $toReplace);
2253
  }
 
2254
  if(isset($toUnlink['PATHs'])) foreach($toUnlink['PATHs'] as $unlink) {
2255
  if($png2jpgMain) {
2256
  WPShortPixel::log("PNG2JPG unlink $unlink");
2257
- @unlink($unlink);
 
 
2258
  }
2259
  //try also the .webp
2260
  $unlinkWebpSymlink = trailingslashit(dirname($unlink)) . wp_basename($unlink, '.' . pathinfo($unlink, PATHINFO_EXTENSION)) . '.webp';
@@ -2614,7 +2633,7 @@ class WPShortPixel {
2614
  {
2615
  return $this->_settings->currentStats;
2616
  } else {
2617
- $imageCount = WpShortPixelMediaLbraryAdapter::countAllProcessableFiles($this->_settings);
2618
  $quotaData['time'] = time();
2619
  $quotaData['optimizePdfs'] = $this->_settings->optimizePdfs;
2620
  //$quotaData['quotaData'] = $quotaData;
@@ -2832,7 +2851,7 @@ class WPShortPixel {
2832
  }//resume was clicked
2833
 
2834
  //figure out the files that are left to be processed
2835
- $qry_left = "SELECT count(*) FilesLeftToBeProcessed FROM " . $wpdb->prefix . "postmeta
2836
  WHERE meta_key = '_wp_attached_file' AND post_id <= " . (0 + $this->prioQ->getStartBulkId());
2837
  $filesLeft = $wpdb->get_results($qry_left);
2838
 
@@ -3486,7 +3505,7 @@ class WPShortPixel {
3486
  * @todo Move this to custom media controller
3487
  */
3488
  public function generateCustomColumn( $column_name, $id, $extended = false ) {
3489
- if( 'wp-shortPixel' == $column_name ) {
3490
 
3491
  if(!$this->isProcessable($id)) {
3492
  $renderData['status'] = 'n/a';
@@ -3499,19 +3518,6 @@ class WPShortPixel {
3499
  $itemHandler = new ShortPixelMetaFacade($id);
3500
  $meta = $itemHandler->getMeta();
3501
 
3502
- if($extended && Log::debugIsActive()) {
3503
- // var_dump($data);
3504
- $sizes = isset($data['sizes']) ? $data['sizes'] : array();
3505
- echo "<PRE style='font-size:11px; overflow:hidden; white-space:pre-wrap'>";
3506
- echo "<strong>URL: </strong>"; print_r(wp_get_attachment_url($id));
3507
- echo('<br><br>' . json_encode(ShortPixelMetaFacade::getWPMLDuplicates($id)));
3508
- echo('<br><br><span class="array">'); print_r($data); echo ''; //json_encode($data))
3509
- echo('</span><br><br>');
3510
- echo '<p><strong>Backup Folder: </strong>' . $this->getBackupFolderAny($file, $sizes) . '</p>';
3511
- echo '<p><strong>Status</strong>: ' . $meta->getStatus() . '</p>';
3512
- echo "</PRE>";
3513
- }
3514
-
3515
  $fileExtension = strtolower(pathinfo($file, PATHINFO_EXTENSION));
3516
  $invalidKey = !$this->_settings->verifiedKey;
3517
  $quotaExceeded = $this->_settings->quotaExceeded;
@@ -3634,54 +3640,9 @@ class WPShortPixel {
3634
  * @return array Array of Thumbs to Optimize - only the filename - , and count of sizes not excluded ...
3635
  */
3636
  function getThumbsToOptimize($data, $filepath) {
3637
- $fs = new \ShortPixel\FileSystemController();
3638
- $mainfile = $fs->getFile($filepath);
3639
-
3640
- $sizesCount = isset($data['sizes']) ? WpShortPixelMediaLbraryAdapter::countSizesNotExcluded($data['sizes']) : 0;
3641
- $basedir = $mainfile->getFileDir()->getPath();
3642
- $thumbsOptList = isset($data['ShortPixel']['thumbsOptList']) ? $data['ShortPixel']['thumbsOptList'] : array();
3643
- $thumbsToOptimizeList = array(); // is returned, so should be defined before if.
3644
-
3645
- if($sizesCount && $this->_settings->processThumbnails) {
3646
 
3647
- // findThumbs returns fullfilepath.
3648
- $found = $this->_settings->optimizeUnlisted ? WpShortPixelMediaLbraryAdapter::findThumbs($mainfile->getFullPath()) : array();
3649
-
3650
- $exclude = $this->_settings->excludeSizes;
3651
- $exclude = is_array($exclude) ? $exclude : array();
3652
- foreach($data['sizes'] as $size => $sizeData) {
3653
- unset($found[\array_search($basedir . $sizeData['file'], $found)]); // @todo what is this intended to do?
3654
-
3655
- // sizeData['file'] is *only* filename *but* can be wrong data, URL due to plugins. So check first, only get filename ( since it is supposed to fail with only a filename path ) and then reload.
3656
- $sizeFileCheck = $fs->getFile($sizeData['file']);
3657
- $file = $fs->getFile($basedir . $sizeFileCheck->getFileName());
3658
-
3659
- if ($file->getExtension() !== $mainfile->getExtension())
3660
- {
3661
- continue;
3662
- }
3663
-
3664
- if(!in_array($size, $exclude) && !in_array($file->getFileName(), $thumbsOptList)) {
3665
- $thumbsToOptimizeList[] = $file->getFileName();
3666
- }
3667
- }
3668
- //$found = array_diff($found, $thumbsOptList); // Wrong comparison. Found is full file path, thumbsOptList is not.
3669
- foreach($found as $path) {
3670
- $file = $fs->getFile($path);
3671
-
3672
- // prevent Webp and what not from showing up.
3673
- if ($file->getExtension() !== $mainfile->getExtension())
3674
- {
3675
- continue;
3676
- }
3677
- // thumbs can already be in findThumbs.
3678
- if (! in_array($file->getFileName(), $thumbsToOptimizeList) && ! in_array($file->getFileName(), $thumbsOptList) )
3679
- {
3680
- $thumbsToOptimizeList[] = $file->getFileName();
3681
- }
3682
- }
3683
- }
3684
- return array($thumbsToOptimizeList, $sizesCount);
3685
  }
3686
 
3687
  /** Make columns sortable in Media Library
70
  add_filter( 'request', array( &$this, 'columnOrderFilterBy') );
71
  add_action('restrict_manage_posts', array( &$this, 'mediaAddFilterDropdown'));
72
  //Edit media meta box
73
+ add_action( 'add_meta_boxes', array( &$this, 'shortpixelInfoBox') ); // the info box in edit-media
74
  //for cleaning up the WebP images when an attachment is deleted
75
  add_action( 'delete_attachment', array( &$this, 'onDeleteImage') );
76
 
1499
  //$urlPath = implode("/", array_slice($filePath, 0, count($filePath) - 1));
1500
  $thumb = $uploadsUrl . $urlPath . $thumb;
1501
  } else {
1502
+ try {
1503
  $mainUrl = ShortPixelMetaFacade::safeGetAttachmentUrl($itemHandler->getId());
1504
+ }
1505
+ catch(Exception $e)
1506
+ {
1507
+ Log::addError('Attachment seems corrupted!', array($e->getMessage() ));
1508
+ $mainUrl = null; // error state.
1509
+ }
1510
  $thumb = dirname($mainUrl) . '/' . $thumb;
1511
  }
1512
  }
1631
  * Will update meta. if any are found.
1632
  * @param ShortPixelMetaFacade $itemHandler ShortpixelMetaFacade item handler.
1633
  * @return int Number of additions to the sizes Metadata.
1634
+ * @todo This function should Dis/pear. addUnlistedThumbs is now part of image model, to be called via proper controller.
1635
  */
1636
  private function addUnlistedThumbs($itemHandler)
1637
  {
1737
  }
1738
  }
1739
 
 
 
1740
  //WpShortPixelMediaLbraryAdapter::cleanupFoundThumbs($itemHandler);
1741
  $URLsAndPATHs = $this->getURLsAndPATHs($itemHandler, NULL, $onlyThumbs);
1742
  Log::addDebug('Send to PRocessing - URLS -', array($URLsAndPATHs) );
1743
 
1744
  //find thumbs that are not listed in the metadata and add them in the sizes array
1745
  $this->addUnlistedThumbs($itemHandler);
1746
+ $meta = $itemHandler->getMeta();
1747
 
1748
  //find any missing thumbs files and mark them as such
1749
  $miss = $meta->getThumbsMissing();
2093
 
2094
  $baseUrl = str_replace($fsFile->getFileName(), '', $imageUrl); // remove *only* filename from URL
2095
  $baseUrl = ShortPixelPng2Jpg::removeUrlProtocol($baseUrl); // @todo parse_url with a util helper / model should be better here
2096
+ $backupFileDir = $bkFile->getFileDir(); // directory of the backups.
2097
+
2098
+ // find the jpg optimized image in backups, and mark to remove
2099
+ if ($bkFile->exists())
2100
+ $toUnlink['PATHs'][] = $bkFile->getFullPath();
2101
 
2102
  // $baseUrl = ShortPixelPng2Jpg::removeUrlProtocol(trailingslashit(str_replace($image, "", $imageUrl))); //make the base url protocol agnostic if it's not already
2103
 
2104
  // not needed, we don't do this weird remove anymore.
2105
  $baseRelPath = ''; // trailingslashit(dirname($image)); // @todo Replace this (string) $fsFile->getFileDir();
2106
 
2107
+
2108
  $toReplace[ShortPixelPng2Jpg::removeUrlProtocol($imageUrl)] = $baseUrl . $baseRelPath . wp_basename($png2jpgMain);
2109
  foreach($sizes as $key => $size) {
2110
  if(isset($png2jpgSizes[$key])) {
2111
  $toReplace[$baseUrl . $baseRelPath . $size['file']] = $baseUrl . $baseRelPath . wp_basename($png2jpgSizes[$key]['file']);
2112
  }
2113
+
2114
+ $backuppedSize = $fs->getFile($backupFileDir . $size['file'] );
2115
+ Log::addDebug('Find optimized JPGEG backupFile Thing', array( $backuppedSize->getFullPath() ));
2116
+ if ($backuppedSize->exists())
2117
+ {
2118
+ $toUnlink['PATHs'][] = $backuppedSize ->getFullPath();
2119
+ }
2120
  }
2121
 
2122
  //$file = $png2jpgMain;
2123
  $sizes = $png2jpgSizes;
2124
 
2125
+ $fsFile = $fs->getFile($png2jpgMain); // original is non-existing at this time. :: Target
2126
+ $bkFile = $fs->getFile($bkFolder->getPath() . $fsFile->getFileName()); // Update this, because of filename (extension)
2127
 
2128
  }
2129
 
2155
  //$dest = $pathInfo['dirname'] . '/' . $imageData['file'];
2156
  $destination = $fs->getFile($filePath . $imageData['file']);
2157
  $source = $fs->getFile($bkFolder->getPath() . $imageData['file']); //trailingslashit($bkFolder) . $imageData['file'];
 
2158
  if(! $source->exists() ) continue; // if thumbs were not optimized, then the backups will not be there.
2159
  if(! $source->is_readable() || ($destination->exists() && !$destination->is_writable() )) {
2160
  $failedFile = ($destination->is_writable() ? $source->getFullPath() : $destination->getFullPath());
2197
  Log::addError('DoRestore failed restoring retina backup', array($retinaBK->getFullPath(), $retinaDest->getFullPath() ));
2198
  }
2199
  }
 
 
 
2200
  }
2201
  //getSize to update meta if image was resized by ShortPixel
2202
  if($fsFile->exists()) {
2206
  }
2207
 
2208
  //overwriting thumbnails
 
2209
  foreach($thumbsPaths as $index => $data) {
2210
  $source = $data['source'];
2211
  $destination = $data['destination'];
2267
  $spPng2Jpg = new ShortPixelPng2Jpg($this->_settings);
2268
  $spPng2Jpg->png2JpgUpdateUrls(array(), $toReplace);
2269
  }
2270
+ Log::addDebug('DoRestore, Unlinking', array($toUnlink) );
2271
  if(isset($toUnlink['PATHs'])) foreach($toUnlink['PATHs'] as $unlink) {
2272
  if($png2jpgMain) {
2273
  WPShortPixel::log("PNG2JPG unlink $unlink");
2274
+ $unlinkFile = $fs->getFile($unlink);
2275
+ $unlinkFile->delete();
2276
+ // @unlink($unlink);
2277
  }
2278
  //try also the .webp
2279
  $unlinkWebpSymlink = trailingslashit(dirname($unlink)) . wp_basename($unlink, '.' . pathinfo($unlink, PATHINFO_EXTENSION)) . '.webp';
2633
  {
2634
  return $this->_settings->currentStats;
2635
  } else {
2636
+ $imageCount = WpShortPixelMediaLbraryAdapter::countAllProcessable($this->_settings);
2637
  $quotaData['time'] = time();
2638
  $quotaData['optimizePdfs'] = $this->_settings->optimizePdfs;
2639
  //$quotaData['quotaData'] = $quotaData;
2851
  }//resume was clicked
2852
 
2853
  //figure out the files that are left to be processed
2854
+ $qry_left = "SELECT count(meta_id) FilesLeftToBeProcessed FROM " . $wpdb->prefix . "postmeta
2855
  WHERE meta_key = '_wp_attached_file' AND post_id <= " . (0 + $this->prioQ->getStartBulkId());
2856
  $filesLeft = $wpdb->get_results($qry_left);
2857
 
3505
  * @todo Move this to custom media controller
3506
  */
3507
  public function generateCustomColumn( $column_name, $id, $extended = false ) {
3508
+ if( 'wp-shortPixel' == $column_name ) {
3509
 
3510
  if(!$this->isProcessable($id)) {
3511
  $renderData['status'] = 'n/a';
3518
  $itemHandler = new ShortPixelMetaFacade($id);
3519
  $meta = $itemHandler->getMeta();
3520
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3521
  $fileExtension = strtolower(pathinfo($file, PATHINFO_EXTENSION));
3522
  $invalidKey = !$this->_settings->verifiedKey;
3523
  $quotaExceeded = $this->_settings->quotaExceeded;
3640
  * @return array Array of Thumbs to Optimize - only the filename - , and count of sizes not excluded ...
3641
  */
3642
  function getThumbsToOptimize($data, $filepath) {
3643
+ // This function moved, but lack of other destination.
3644
+ return WpShortPixelMediaLbraryAdapter::getThumbsToOptimize($data, $filepath);
 
 
 
 
 
 
 
3645
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3646
  }
3647
 
3648
  /** Make columns sortable in Media Library
readme.txt CHANGED
@@ -4,7 +4,7 @@ Tags: compressor, image, compression, optimize, image optimizer, image optimiser
4
  Requires at least: 3.2.0
5
  Tested up to: 5.2
6
  Requires PHP: 5.3
7
- Stable tag: 4.14.5
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
@@ -246,6 +246,25 @@ define('SHORTPIXEL_CUSTOM_THUMB_INFIXES', '-uae'); will handle custom thumbnails
246
 
247
  == Changelog ==
248
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
249
  = 4.14.5 =
250
  Release date: 29th August 2019
251
  * If constant SHORTPIXEL_USE_DOUBLE_WEBP_EXTENSION is defined as true, use double extension for WebP (.jpg.webp)
4
  Requires at least: 3.2.0
5
  Tested up to: 5.2
6
  Requires PHP: 5.3
7
+ Stable tag: 4.14.6
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
246
 
247
  == Changelog ==
248
 
249
+ = 4.14.6 =
250
+ Release date: 9th October 2019
251
+ * Don't convert to <picture> the <img>s with backgrounds.
252
+ * Remove unused eval() call.
253
+ * Restore the validate button next to API Key but change label to "Save and validate"
254
+ * Fixed: PNGtoJPG issue with already uploaded images
255
+ * Fixed: finding wrong unlisted thumbnails due to regex.
256
+ * Fixed: fatal error when trying to delete crashed attachement ( without proper URL )
257
+ * Fix for S3 offload - PNG2JPG , doesn't remove old JPG files
258
+ * Fixed: S3Offload will not offload anymore when 'Copy files to bucket' is off ( and object was not previously offloaded )
259
+ * S3Offload doesn't offload via optimiser anymore if this setting is off
260
+ * Fixed: cutting out initial offload if optimization needs to be done, when autolibrary is on
261
+ * Fix for PNG2JPG - JPG files remained in backupdir.
262
+ * Small fix for remote download thumbnails
263
+ * Fixed: notice in filemodel due meta-facade feeding array
264
+ * Fixed: bug in File2Url in filesystemcontroller
265
+ * Fixed: download issue in attempt to remote download
266
+ * Language – 0 new strings added, 0 updated, 0 fuzzied, and 0 obsoleted
267
+
268
  = 4.14.5 =
269
  Release date: 29th August 2019
270
  * If constant SHORTPIXEL_USE_DOUBLE_WEBP_EXTENSION is defined as true, use double extension for WebP (.jpg.webp)
res/css/shortpixel-admin.css CHANGED
@@ -109,3 +109,24 @@
109
  .settings_page_wp-shortpixel-settings section#tab-debug .env .flex span {
110
  width: 45%;
111
  padding: 4px; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
109
  .settings_page_wp-shortpixel-settings section#tab-debug .env .flex span {
110
  width: 45%;
111
  padding: 4px; }
112
+
113
+ .view-edit-media .debugInfo pre {
114
+ font-size: 11px; }
115
+ .view-edit-media .sp-column-stats {
116
+ position: relative; }
117
+ .view-edit-media .sp-column-stats .sp-column-actions {
118
+ margin-right: 5px;
119
+ margin-top: 16px; }
120
+ .view-edit-media .sp-column-stats .edit-media-stats {
121
+ border: 1px solid #ccc;
122
+ padding: 16px; }
123
+ .view-edit-media .sp-column-stats .edit-media-stats li {
124
+ margin: 0;
125
+ line-height: 20px; }
126
+ .view-edit-media .main-actions {
127
+ display: inline-block;
128
+ width: 100%; }
129
+ .view-edit-media .main-actions .button.button-smaller {
130
+ padding: 6px 15px;
131
+ height: auto;
132
+ float: none; }
res/js/shortpixel.js CHANGED
@@ -63,13 +63,12 @@ var ShortPixel = function() {
63
  jQuery('#request_key').attr('href', jQuery('#request_key').attr('href').split('?')[0] + '?pluginemail=' + email);
64
  }
65
 
66
- /* Can be removed.
67
  function validateKey(button){
68
  console.log('validate');
69
  jQuery('#valid').val('validate');
70
 
71
  jQuery(button).parents('form').submit();
72
- } */
73
 
74
  jQuery("#key").keypress(function(e) {
75
  if(e.which == 13) {
@@ -256,7 +255,7 @@ var ShortPixel = function() {
256
  ShortPixel.adjustSettingsTabs();
257
  jQuery(section).find('.wp-shortpixel-tab-content').fadeIn(50);
258
  }
259
- if(typeof HS.beacon.suggest !== 'undefined' ){
260
  switch(tab){
261
  case "settings":
262
  beacon = shortpixel_suggestions_settings;
@@ -794,7 +793,7 @@ var ShortPixel = function() {
794
  setOptions : setOptions,
795
  isEmailValid : isEmailValid,
796
  updateSignupEmail : updateSignupEmail,
797
- //validateKey : validateKey,
798
  enableResize : enableResize,
799
  setupGeneralTab : setupGeneralTab,
800
  apiKeyChanged : apiKeyChanged,
63
  jQuery('#request_key').attr('href', jQuery('#request_key').attr('href').split('?')[0] + '?pluginemail=' + email);
64
  }
65
 
 
66
  function validateKey(button){
67
  console.log('validate');
68
  jQuery('#valid').val('validate');
69
 
70
  jQuery(button).parents('form').submit();
71
+ }
72
 
73
  jQuery("#key").keypress(function(e) {
74
  if(e.which == 13) {
255
  ShortPixel.adjustSettingsTabs();
256
  jQuery(section).find('.wp-shortpixel-tab-content').fadeIn(50);
257
  }
258
+ if(typeof HS !== 'undefined' && typeof HS.beacon.suggest !== 'undefined' ){
259
  switch(tab){
260
  case "settings":
261
  beacon = shortpixel_suggestions_settings;
793
  setOptions : setOptions,
794
  isEmailValid : isEmailValid,
795
  updateSignupEmail : updateSignupEmail,
796
+ validateKey : validateKey,
797
  enableResize : enableResize,
798
  setupGeneralTab : setupGeneralTab,
799
  apiKeyChanged : apiKeyChanged,
res/js/shortpixel.min.js CHANGED
@@ -1 +1 @@
1
- function showToolBarAlert(e,r,t){var s=jQuery("li.shortpixel-toolbar-processing");switch(e){case ShortPixel.STATUS_QUOTA_EXCEEDED:if(window.location.href.search("wp-short-pixel-bulk")>0&&0==jQuery(".sp-quota-exceeded-alert").length)return void location.reload();s.addClass("shortpixel-alert"),s.addClass("shortpixel-quota-exceeded"),jQuery("a",s).attr("href","options-general.php?page=wp-shortpixel-settings"),jQuery("a div",s).attr("title","ShortPixel quota exceeded. Click for details.");break;case ShortPixel.STATUS_SKIP:case ShortPixel.STATUS_FAIL:s.addClass("shortpixel-alert shortpixel-processing"),jQuery("a div",s).attr("title",r),void 0!==t&&jQuery("a",s).attr("href","post.php?post="+t+"&action=edit");break;case ShortPixel.STATUS_NO_KEY:s.addClass("shortpixel-alert"),s.addClass("shortpixel-quota-exceeded"),jQuery("a",s).attr("href","options-general.php?page=wp-shortpixel-settings"),jQuery("a div",s).attr("title","Get API Key");break;case ShortPixel.STATUS_SUCCESS:case ShortPixel.STATUS_RETRY:s.addClass("shortpixel-processing"),s.removeClass("shortpixel-alert"),jQuery("a",s).removeAttr("target"),jQuery("a",s).attr("href",jQuery("a img",s).attr("success-url"))}s.removeClass("shortpixel-hide")}function hideToolBarAlert(){jQuery("li.shortpixel-toolbar-processing.shortpixel-processing").addClass("shortpixel-hide")}function hideQuotaExceededToolBarAlert(){jQuery("li.shortpixel-toolbar-processing.shortpixel-quota-exceeded").addClass("shortpixel-hide")}function checkQuotaExceededAlert(){"undefined"!=typeof shortPixelQuotaExceeded&&(1==shortPixelQuotaExceeded?showToolBarAlert(ShortPixel.STATUS_QUOTA_EXCEEDED):hideQuotaExceededToolBarAlert())}function checkBulkProgress(){var e=function(e){return r?"/":(r=!0,e)},r=!1,t=window.location.href.toLowerCase().replace(/\/\//g,e);r=!1;var s=ShortPixel.WP_ADMIN_URL.toLowerCase().replace(/\/\//g,e);t.search(s)<0&&(t=ShortPixel.convertPunycode(t),s=ShortPixel.convertPunycode(s)),t.search(s+"upload.php")<0&&t.search(s+"edit.php")<0&&t.search(s+"edit-tags.php")<0&&t.search(s+"post-new.php")<0&&t.search(s+"post.php")<0&&t.search("page=nggallery-manage-gallery")<0&&(0==ShortPixel.FRONT_BOOTSTRAP||0==t.search(s))?hideToolBarAlert():(1==ShortPixel.bulkProcessor&&window.location.href.search("wp-short-pixel-bulk")<0&&void 0!==localStorage.bulkPage&&localStorage.bulkPage>0&&(ShortPixel.bulkProcessor=!1),window.location.href.search("wp-short-pixel-bulk")>=0&&(ShortPixel.bulkProcessor=!0,localStorage.bulkTime=Math.floor(Date.now()/1e3),localStorage.bulkPage=1),1==ShortPixel.bulkProcessor||void 0===localStorage.bulkTime||Math.floor(Date.now()/1e3)-localStorage.bulkTime>90?(ShortPixel.bulkProcessor=!0,localStorage.bulkPage=window.location.href.search("wp-short-pixel-bulk")>=0?1:0,localStorage.bulkTime=Math.floor(Date.now()/1e3),console.log(localStorage.bulkTime),checkBulkProcessingCallApi()):setTimeout(checkBulkProgress,5e3))}function checkBulkProcessingCallApi(){jQuery.ajax({type:"POST",url:ShortPixel.AJAX_URL,data:{action:"shortpixel_image_processing"},success:function(e){if(e.length>0){r=null;try{var r=JSON.parse(e)}catch(e){return void ShortPixel.retry(e.message)}ShortPixel.retries=0;var t=r.ImageID,s=jQuery("div.short-pixel-bulk-page").length>0;switch(r.Status&&r.Status!=ShortPixel.STATUS_SEARCHING&&(ShortPixel.returnedStatusSearching>=2&&jQuery(".bulk-notice-msg.bulk-searching").hide(),ShortPixel.returnedStatusSearching=0),r.Status){case ShortPixel.STATUS_NO_KEY:setCellMessage(t,r.Message,"<a class='button button-smaller button-primary' href=\"https://shortpixel.com/wp-apikey"+ShortPixel.AFFILIATE+'" target="_blank">'+_spTr.getApiKey+"</a>"),showToolBarAlert(ShortPixel.STATUS_NO_KEY);break;case ShortPixel.STATUS_QUOTA_EXCEEDED:setCellMessage(t,r.Message,"<a class='button button-smaller button-primary' href=\"https://shortpixel.com/login/"+ShortPixel.API_KEY+'" target="_blank">'+_spTr.extendQuota+"</a><a class='button button-smaller' href='admin.php?action=shortpixel_check_quota'>"+_spTr.check__Quota+"</a>"),showToolBarAlert(ShortPixel.STATUS_QUOTA_EXCEEDED),0==r.Stop&&setTimeout(checkBulkProgress,5e3),ShortPixel.otherMediaUpdateActions(t,["quota","view"]);break;case ShortPixel.STATUS_FAIL:setCellMessage(t,r.Message,"<a class='button button-smaller button-primary' href=\"javascript:manualOptimization('"+t+"', false)\">"+_spTr.retry+"</a>"),showToolBarAlert(ShortPixel.STATUS_FAIL,r.Message,t),s&&(ShortPixel.bulkShowError(t,r.Message,r.Filename,r.CustomImageLink),r.BulkPercent&&progressUpdate(r.BulkPercent,r.BulkMsg),ShortPixel.otherMediaUpdateActions(t,["retry","view"])),console.log(r.Message),setTimeout(checkBulkProgress,5e3);break;case ShortPixel.STATUS_EMPTY_QUEUE:console.log(r.Message),clearBulkProcessor(),hideToolBarAlert();var o=jQuery("#bulk-progress");s&&o.length&&"2"!=r.BulkStatus&&(progressUpdate(100,"Bulk finished!"),jQuery("a.bulk-cancel").attr("disabled","disabled"),hideSlider(),setTimeout(function(){window.location.reload()},3e3));break;case ShortPixel.STATUS_SUCCESS:s&&(ShortPixel.bulkHideLengthyMsg(),ShortPixel.bulkHideMaintenanceMsg());var i=r.PercentImprovement;showToolBarAlert(ShortPixel.STATUS_SUCCESS,"");var a=ShortPixel.isCustomImageId(t)?"":ShortPixel.successActions(t,r.Type,r.ThumbsCount,r.ThumbsTotal,r.BackupEnabled,r.Filename);setCellMessage(t,ShortPixel.successMsg(t,i,r.Type,r.ThumbsCount,r.RetinasCount),a),jQuery("#post-"+t).length>0&&jQuery("#post-"+t).find(".filename").text(r.Filename),jQuery(".misc-pub-filename strong").length>0&&jQuery(".misc-pub-filename strong").text(r.Filename),ShortPixel.isCustomImageId(t)&&r.TsOptimized&&r.TsOptimized.length>0&&(console.log(t),jQuery(".date-"+t).text(r.TsOptimized));var l=jQuery(["restore","view","redolossy","redoglossy","redolossless"]).not(["redo"+r.Type]).get();ShortPixel.otherMediaUpdateActions(t,l);new PercentageAnimator("#sp-msg-"+t+" span.percent",i).animate(i),s&&void 0!==r.Thumb&&(r.BulkPercent&&progressUpdate(r.BulkPercent,r.BulkMsg),r.Thumb.length>0&&(sliderUpdate(t,r.Thumb,r.BkThumb,r.PercentImprovement,r.Filename),void 0!==r.AverageCompression&&0+r.AverageCompression>0&&(jQuery("#sp-avg-optimization").html('<input type="text" class="dial" value="'+Math.round(r.AverageCompression)+'"/>'),ShortPixel.percentDial("#sp-avg-optimization .dial",60)))),console.log("Server response: "+e),s&&void 0!==r.BulkPercent&&progressUpdate(r.BulkPercent,r.BulkMsg),setTimeout(checkBulkProgress,5e3);break;case ShortPixel.STATUS_SKIP:1!==r.Silent&&ShortPixel.bulkShowError(t,r.Message,r.Filename,r.CustomImageLink);case ShortPixel.STATUS_ERROR:void 0!==r.Message&&(showToolBarAlert(ShortPixel.STATUS_SKIP,r.Message+" Image ID: "+t),setCellMessage(t,r.Message,"")),ShortPixel.otherMediaUpdateActions(t,["retry","view"]);case ShortPixel.STATUS_RETRY:console.log("Server response: "+e),showToolBarAlert(ShortPixel.STATUS_RETRY,""),s&&void 0!==r.BulkPercent&&progressUpdate(r.BulkPercent,r.BulkMsg),s&&r.Count>3&&ShortPixel.bulkShowLengthyMsg(t,r.Filename,r.CustomImageLink),setTimeout(checkBulkProgress,5e3);break;case ShortPixel.STATUS_SEARCHING:console.log("Server response: "+e),ShortPixel.returnedStatusSearching++,ShortPixel.returnedStatusSearching>=2&&jQuery(".bulk-notice-msg.bulk-searching").show(),setTimeout(checkBulkProgress,2500);break;case ShortPixel.STATUS_MAINTENANCE:ShortPixel.bulkShowMaintenanceMsg("maintenance"),setTimeout(checkBulkProgress,6e4);break;case ShortPixel.STATUS_QUEUE_FULL:ShortPixel.bulkShowMaintenanceMsg("queue-full"),setTimeout(checkBulkProgress,6e4);break;default:ShortPixel.retry("Unknown status "+r.Status+". Retrying...")}}},error:function(e){ShortPixel.retry(e.statusText)}})}function clearBulkProcessor(){ShortPixel.bulkProcessor=!1,localStorage.bulkTime=0,window.location.href.search("wp-short-pixel-bulk")>=0&&(localStorage.bulkPage=0)}function setCellMessage(e,r,t){var s=jQuery("#sp-msg-"+e);s.length>0&&(s.html("<div class='sp-column-actions'>"+t+"</div><div class='sp-column-info'>"+r+"</div>"),s.css("color","")),(s=jQuery("#sp-cust-msg-"+e)).length>0&&s.html("<div class='sp-column-info'>"+r+"</div>")}function manualOptimization(e,r){setCellMessage(e,"<img src='"+ShortPixel.WP_PLUGIN_URL+"/res/img/loading.gif' class='sp-loading-small'>Image waiting to be processed",""),jQuery("li.shortpixel-toolbar-processing").removeClass("shortpixel-hide"),jQuery("li.shortpixel-toolbar-processing").removeClass("shortpixel-alert"),jQuery("li.shortpixel-toolbar-processing").addClass("shortpixel-processing");var t={action:"shortpixel_manual_optimization",image_id:e,cleanup:r};jQuery.ajax({type:"GET",url:ShortPixel.AJAX_URL,data:t,success:function(r){var t=JSON.parse(r);t.Status==ShortPixel.STATUS_SUCCESS?setTimeout(checkBulkProgress,2e3):setCellMessage(e,void 0!==t.Message?t.Message:_spTr.thisContentNotProcessable,"")},error:function(r){t.action="shortpixel_check_status",jQuery.ajax({type:"GET",url:ShortPixel.AJAX_URL,data:t,success:function(r){var t=JSON.parse(r);t.Status!==ShortPixel.STATUS_SUCCESS&&setCellMessage(e,void 0!==t.Message?t.Message:_spTr.thisContentNotProcessable,"")}})}})}function reoptimize(e,r){setCellMessage(e,"<img src='"+ShortPixel.WP_PLUGIN_URL+"/res/img/loading.gif' class='sp-loading-small'>Image waiting to be reprocessed",""),jQuery("li.shortpixel-toolbar-processing").removeClass("shortpixel-hide"),jQuery("li.shortpixel-toolbar-processing").addClass("shortpixel-processing");var t={action:"shortpixel_redo",attachment_ID:e,type:r};jQuery.get(ShortPixel.AJAX_URL,t,function(r){(t=JSON.parse(r)).Status==ShortPixel.STATUS_SUCCESS?setTimeout(checkBulkProgress,2e3):($msg=void 0!==t.Message?t.Message:_spTr.thisContentNotProcessable,setCellMessage(e,$msg,""),showToolBarAlert(ShortPixel.STATUS_FAIL,$msg))})}function optimizeThumbs(e){setCellMessage(e,"<img src='"+ShortPixel.WP_PLUGIN_URL+"/res/img/loading.gif' class='sp-loading-small'>"+_spTr.imageWaitOptThumbs,""),jQuery("li.shortpixel-toolbar-processing").removeClass("shortpixel-hide"),jQuery("li.shortpixel-toolbar-processing").addClass("shortpixel-processing");var r={action:"shortpixel_optimize_thumbs",attachment_ID:e};jQuery.get(ShortPixel.AJAX_URL,r,function(t){(r=JSON.parse(t)).Status==ShortPixel.STATUS_SUCCESS?setTimeout(checkBulkProgress,2e3):setCellMessage(e,void 0!==r.Message?r.Message:_spTr.thisContentNotProcessable,"")})}function dismissShortPixelNoticeExceed(e){jQuery("#wp-admin-bar-shortpixel_processing").hide();var r={action:"shortpixel_dismiss_notice",notice_id:"exceed"};jQuery.get(ShortPixel.AJAX_URL,r,function(e){(r=JSON.parse(e)).Status==ShortPixel.STATUS_SUCCESS&&console.log("dismissed")}),e.preventDefault()}function dismissShortPixelNotice(e){jQuery("#short-pixel-notice-"+e).hide();var r={action:"shortpixel_dismiss_notice",notice_id:e};jQuery.get(ShortPixel.AJAX_URL,r,function(e){(r=JSON.parse(e)).Status==ShortPixel.STATUS_SUCCESS&&console.log("dismissed")})}function PercentageAnimator(e,r){this.animationSpeed=10,this.increment=2,this.curPercentage=0,this.targetPercentage=r,this.outputSelector=e,this.animate=function(e){this.targetPercentage=e,setTimeout(PercentageTimer.bind(null,this),this.animationSpeed)}}function PercentageTimer(e){e.curPercentage-e.targetPercentage<-e.increment?e.curPercentage+=e.increment:e.curPercentage-e.targetPercentage>e.increment?e.curPercentage-=e.increment:e.curPercentage=e.targetPercentage,jQuery(e.outputSelector).text(e.curPercentage+"%"),e.curPercentage!=e.targetPercentage&&setTimeout(PercentageTimer.bind(null,e),e.animationSpeed)}function progressUpdate(e,r){var t=jQuery("#bulk-progress");t.length&&(jQuery(".progress-left",t).css("width",e+"%"),jQuery(".progress-img",t).css("left",e+"%"),e>24?(jQuery(".progress-img span",t).html(""),jQuery(".progress-left",t).html(e+"%")):(jQuery(".progress-img span",t).html(e+"%"),jQuery(".progress-left",t).html("")),jQuery(".bulk-estimate").html(r))}function sliderUpdate(e,r,t,s,o){var i=jQuery(".bulk-slider div.bulk-slide:first-child");if(0!==i.length){"empty-slide"!=i.attr("id")&&i.hide(),i.css("z-index",1e3),jQuery(".bulk-img-opt",i).attr("src",""),void 0===t&&(t=""),t.length>0&&jQuery(".bulk-img-orig",i).attr("src","");var a=i.clone();a.attr("id","slide-"+e),jQuery(".bulk-img-opt",a).attr("src",r),t.length>0?(jQuery(".img-original",a).css("display","inline-block"),jQuery(".bulk-img-orig",a).attr("src",t)):jQuery(".img-original",a).css("display","none"),jQuery(".bulk-opt-percent",a).html('<input type="text" class="dial" value="'+s+'"/>'),jQuery(".bulk-slider").append(a),ShortPixel.percentDial("#"+a.attr("id")+" .dial",100),jQuery(".bulk-slider-container span.filename").html("&nbsp;&nbsp;"+o),"empty-slide"==i.attr("id")?(i.remove(),jQuery(".bulk-slider-container").css("display","block")):i.animate({left:i.width()+i.position().left},"slow","swing",function(){i.remove(),a.fadeIn("slow")})}}function hideSlider(){jQuery(".bulk-slider-container").css("display","none")}function showStats(){jQuery(".bulk-stats").length}function SPstringFormat(){var e=Array.prototype.slice.call(arguments);if(0!==e.length){var r=e.shift();for(i=0;i<e.length;i++)r=r.replace(new RegExp("\\{"+i+"\\}","gm"),e[i]);return r}}jQuery(document).ready(function(){ShortPixel.init()});var ShortPixel=function(){function e(e){jQuery(e).is(":checked")?jQuery("#width,#height").removeAttr("disabled"):jQuery("#width,#height").attr("disabled","disabled")}function r(){jQuery("#shortpixel-hs-button-blind").remove(),jQuery("#shortpixel-hs-tools").remove(),jQuery("#hs-beacon").remove(),jQuery("#botbutton").remove(),jQuery("#shortpixel-hs-blind").remove()}return jQuery("#key").keypress(function(e){13==e.which&&jQuery("#valid").val("validate")}),{init:function(){void 0===ShortPixel.API_KEY&&(jQuery("table.wp-list-table.media").length>0&&jQuery('select[name^="action"] option:last-child').before('<option value="short-pixel-bulk">'+_spTr.optimizeWithSP+'</option><option value="short-pixel-bulk-lossy"> → '+_spTr.redoLossy+'</option><option value="short-pixel-bulk-glossy"> → '+_spTr.redoGlossy+'</option><option value="short-pixel-bulk-lossless"> → '+_spTr.redoLossless+'</option><option value="short-pixel-bulk-restore"> → '+_spTr.restoreOriginal+"</option>"),ShortPixel.setOptions(ShortPixelConstants[0]),jQuery("#backup-folder-size").length&&jQuery("#backup-folder-size").html(ShortPixel.getBackupSize()),"todo"==ShortPixel.MEDIA_ALERT&&jQuery("div.media-frame.mode-grid").length>0&&jQuery("div.media-frame.mode-grid").before('<div id="short-pixel-media-alert" class="notice notice-warning"><p>'+SPstringFormat(_spTr.changeMLToListMode,'<a href="upload.php?mode=list" class="view-list"><span class="screen-reader-text">'," </span>",'</a><a class="alignright" href="javascript:ShortPixel.dismissMediaAlert();">',"</a>")+"</p></div>"),jQuery(window).on("beforeunload",function(){1==ShortPixel.bulkProcessor&&clearBulkProcessor()}),checkQuotaExceededAlert(),checkBulkProgress())},setOptions:function(e){for(var r in e)ShortPixel[r]=e[r]},isEmailValid:function(e){return/^\w+([\.+-]?\w+)*@\w+([\.-]?\w+)*(\.\w{1,63})+$/.test(e)},updateSignupEmail:function(){var e=jQuery("#pluginemail").val();ShortPixel.isEmailValid(e)&&jQuery("#request_key").removeClass("disabled"),jQuery("#request_key").attr("href",jQuery("#request_key").attr("href").split("?")[0]+"?pluginemail="+e)},enableResize:e,setupGeneralTab:function(){var r=0;void 0!==document.wp_shortpixel_options&&(r=document.wp_shortpixel_options.compressionType);for(var t=0,s=null;t<r.length;t++)r[t].onclick=function(){this!==s&&(s=this),void 0===ShortPixel.setupGeneralTabAlert&&(alert(_spTr.alertOnlyAppliesToNewImages),ShortPixel.setupGeneralTabAlert=1)};ShortPixel.enableResize("#resize"),jQuery("#resize").change(function(){e(this)}),jQuery(".resize-sizes").blur(function(e){var r=jQuery(e.target);if(ShortPixel.resizeSizesAlert!=r.val()){ShortPixel.resizeSizesAlert=r.val();var t=jQuery("#min-"+r.attr("name")).val(),s=jQuery("#min-"+r.attr("name")).data("nicename");r.val()<Math.min(t,1024)?(t>1024?alert(SPstringFormat(_spTr.pleaseDoNotSetLesser1024,s)):alert(SPstringFormat(_spTr.pleaseDoNotSetLesserSize,s,s,t)),e.preventDefault(),r.focus()):this.defaultValue=r.val()}}),jQuery(".shortpixel-confirm").click(function(e){return!!confirm(e.target.getAttribute("data-confirm"))||(e.preventDefault(),!1)}),jQuery('input[name="removeExif"], input[name="png2jpg"]').on("change",function(){ShortPixel.checkExifWarning()}),ShortPixel.checkExifWarning()},apiKeyChanged:function(){jQuery(".wp-shortpixel-options .shortpixel-key-valid").css("display","none"),jQuery(".wp-shortpixel-options button#validate").css("display","inline-block")},setupAdvancedTab:function(){jQuery("input.remove-folder-button").click(function(){var e=jQuery(this).data("value");1==confirm(SPstringFormat(_spTr.areYouSureStopOptimizing,e))&&(jQuery("#removeFolder").val(e),jQuery("#wp_shortpixel_options").submit())}),jQuery("input.recheck-folder-button").click(function(){var e=jQuery(this).data("value");1==confirm(SPstringFormat(_spTr.areYouSureStopOptimizing,e))&&(jQuery("#recheckFolder").val(e),jQuery("#wp_shortpixel_options").submit())})},checkThumbsUpdTotal:function(e){var r=jQuery("#"+(e.checked?"total":"main")+"ToProcess").val();jQuery("div.bulk-play span.total").text(r),jQuery("#displayTotal").text(r)},initSettings:function(){ShortPixel.adjustSettingsTabs(),ShortPixel.setupGeneralTab(),jQuery(window).resize(function(){ShortPixel.adjustSettingsTabs()}),jQuery("article.sp-tabs a.tab-link").click(function(e){var r=jQuery(e.target).data("id");ShortPixel.switchSettingsTab(r)}),jQuery("input[type=radio][name=deliverWebpType]").change(function(){"deliverWebpAltered"==this.value?window.confirm(_spTr.alertDeliverWebPAltered)?0==jQuery("input[type=radio][name=deliverWebpAlteringType]:checked").length&&jQuery("#deliverWebpAlteredWP").prop("checked",!0):jQuery(this).prop("checked",!1):"deliverWebpUnaltered"==this.value&&window.alert(_spTr.alertDeliverWebPUnaltered)})},switchSettingsTab:function(e){var r=e.replace("tab-",""),t="",s=jQuery("section#"+e);jQuery('input[name="display_part"]').val(r);var o=window.location.href.toString();if(o.indexOf("?")>0){var i=o.substring(0,o.indexOf("?"));i+="?"+jQuery.param({page:"wp-shortpixel-settings",part:r}),window.history.replaceState({},document.title,i)}if(s.length>0&&(jQuery("section").removeClass("sel-tab"),jQuery("section .wp-shortpixel-tab-content").fadeOut(50),jQuery(s).addClass("sel-tab"),ShortPixel.adjustSettingsTabs(),jQuery(s).find(".wp-shortpixel-tab-content").fadeIn(50)),void 0!==HS.beacon.suggest){switch(r){case"settings":t=shortpixel_suggestions_settings;break;case"adv-settings":t=shortpixel_suggestions_adv_settings;break;case"cloudflare":case"stats":t=shortpixel_suggestions_cloudflare}HS.beacon.suggest(t)}},adjustSettingsTabs:function(){var e=jQuery("section.sel-tab").height()+90;jQuery(".section-wrapper").css("height",e)},onBulkThumbsCheck:function(e){e.checked?(jQuery("#with-thumbs").css("display","inherit"),jQuery("#without-thumbs").css("display","none")):(jQuery("#without-thumbs").css("display","inherit"),jQuery("#with-thumbs").css("display","none"))},dismissMediaAlert:function(){var e={action:"shortpixel_dismiss_media_alert"};jQuery.get(ShortPixel.AJAX_URL,e,function(r){"success"==(e=JSON.parse(r)).Status&&jQuery("#short-pixel-media-alert").hide()})},closeHelpPane:r,dismissHelpPane:function(){r(),dismissShortPixelNotice("help")},checkQuota:function(){jQuery.get(ShortPixel.AJAX_URL,{action:"shortpixel_check_quota"},function(){console.log("quota refreshed")})},percentDial:function(e,r){jQuery(e).knob({readOnly:!0,width:r,height:r,fgColor:"#1CAECB",format:function(e){return e+"%"}})},successMsg:function(e,r,t,s,o){return(r>0?"<div class='sp-column-info'>"+_spTr.reducedBy+" <strong><span class='percent'>"+r+"%</span></strong> ":"")+(r>0&&r<5?"<br>":"")+(r<5?_spTr.bonusProcessing:"")+(t.length>0?" ("+t+")":"")+(0+s>0?"<br>"+SPstringFormat(_spTr.plusXthumbsOpt,s):"")+(0+o>0?"<br>"+SPstringFormat(_spTr.plusXretinasOpt,o):"")+"</div>"},successActions:function(e,r,t,s,o,i){if(1==o){var a=jQuery(".sp-column-actions-template").clone();if(!a.length)return!1;var l;return l=0==r.length?["lossy","lossless"]:["lossy","glossy","lossless"].filter(function(e){return!(e==r)}),a.html(a.html().replace(/__SP_ID__/g,e)),"pdf"==i.substr(i.lastIndexOf(".")+1).toLowerCase()&&jQuery(".sp-action-compare",a).remove(),0==t&&s>0?a.html(a.html().replace("__SP_THUMBS_TOTAL__",s)):(jQuery(".sp-action-optimize-thumbs",a).remove(),jQuery(".sp-dropbtn",a).removeClass("button-primary")),a.html(a.html().replace(/__SP_FIRST_TYPE__/g,l[0])),a.html(a.html().replace(/__SP_SECOND_TYPE__/g,l[1])),a.html()}return""},otherMediaUpdateActions:function(e,r){if(e=e.substring(2),jQuery(".shortpixel-other-media").length){for(var t=["optimize","retry","restore","redo","quota","view"],s=0,o=t.length;s<o;s++)jQuery("#"+t[s]+"_"+e).css("display","none");for(var s=0,o=r.length;s<o;s++)jQuery("#"+r[s]+"_"+e).css("display","")}},retry:function(e){ShortPixel.retries++,isNaN(ShortPixel.retries)&&(ShortPixel.retries=1),ShortPixel.retries<6?(console.log("Invalid response from server (Error: "+e+"). Retrying pass "+(ShortPixel.retries+1)+"..."),setTimeout(checkBulkProgress,5e3)):(ShortPixel.bulkShowError(-1,"Invalid response from server received 6 times. Please retry later by reloading this page, or <a href='https://shortpixel.com/contact' target='_blank'>contact support</a>. (Error: "+e+")",""),console.log("Invalid response from server 6 times. Giving up."))},initFolderSelector:function(){jQuery(".select-folder-button").click(function(){jQuery(".sp-folder-picker-shade").fadeIn(100),jQuery(".shortpixel-modal.modal-folder-picker").show();var e=jQuery(".sp-folder-picker");e.parent().css("margin-left",-e.width()/2),e.fileTree({script:ShortPixel.browseContent,multiFolder:!1})}),jQuery(".shortpixel-modal input.select-folder-cancel, .sp-folder-picker-shade").click(function(){jQuery(".sp-folder-picker-shade").fadeOut(100),jQuery(".shortpixel-modal.modal-folder-picker").hide()}),jQuery(".shortpixel-modal input.select-folder").click(function(e){if(r=jQuery("UL.jqueryFileTree LI.directory.selected"),0==jQuery(r).length)var r=jQuery("UL.jqueryFileTree LI.selected").parents(".directory");var t=jQuery(r).children("a").attr("rel");if(void 0!==t)if(t=t.trim()){var s=jQuery("#customFolderBase").val()+t;"/"==s.slice(-1)&&(s=s.slice(0,-1)),jQuery("#addCustomFolder").val(s),jQuery("#addCustomFolderView").val(s),jQuery(".sp-folder-picker-shade").fadeOut(100),jQuery(".shortpixel-modal.modal-folder-picker").css("display","none"),jQuery("#saveAdvAddFolder").removeClass("hidden")}else alert("Please select a folder from the list.")})},browseContent:function(e){e.action="shortpixel_browse_content";var r="";return jQuery.ajax({type:"POST",url:ShortPixel.AJAX_URL,data:e,success:function(e){r=e},async:!1}),r},getBackupSize:function(){var e="";return jQuery.ajax({type:"POST",url:ShortPixel.AJAX_URL,data:{action:"shortpixel_get_backup_size"},success:function(r){e=r},async:!1}),e},newApiKey:function(e){if(!jQuery("#tos").is(":checked"))return e.preventDefault(),jQuery("#tos-robo").fadeIn(400,function(){jQuery("#tos-hand").fadeIn()}),void jQuery("#tos").click(function(){jQuery("#tos-robo").css("display","none"),jQuery("#tos-hand").css("display","none")});if(jQuery("#request_key").addClass("disabled"),jQuery("#pluginemail_spinner").addClass("is-active"),ShortPixel.updateSignupEmail(),ShortPixel.isEmailValid(jQuery("#pluginemail").val())){jQuery("#pluginemail-error").css("display","none");var r={action:"shortpixel_new_api_key",email:jQuery("#pluginemail").val()};jQuery.ajax({type:"POST",async:!1,url:ShortPixel.AJAX_URL,data:r,success:function(r){data=JSON.parse(r),"success"==data.Status?(e.preventDefault(),window.location.reload()):"invalid"==data.Status&&(jQuery("#pluginemail-error").html("<b>"+data.Details+"</b>"),jQuery("#pluginemail-error").css("display",""),jQuery("#pluginemail-info").css("display","none"),e.preventDefault())}}),jQuery("#request_key").removeAttr("onclick")}else jQuery("#pluginemail-error").css("display",""),jQuery("#pluginemail-info").css("display","none"),e.preventDefault();jQuery("#request_key").removeClass("disabled"),jQuery("#pluginemail_spinner").removeClass("is-active")},proposeUpgrade:function(){jQuery("#shortPixelProposeUpgrade .sp-modal-body").addClass("sptw-modal-spinner"),jQuery("#shortPixelProposeUpgrade .sp-modal-body").html(""),jQuery("#shortPixelProposeUpgradeShade").css("display","block"),jQuery("#shortPixelProposeUpgrade").removeClass("shortpixel-hide"),jQuery.ajax({type:"POST",url:ShortPixel.AJAX_URL,data:{action:"shortpixel_propose_upgrade"},success:function(e){jQuery("#shortPixelProposeUpgrade .sp-modal-body").removeClass("sptw-modal-spinner"),jQuery("#shortPixelProposeUpgrade .sp-modal-body").html(e)}})},closeProposeUpgrade:function(){jQuery("#shortPixelProposeUpgradeShade").css("display","none"),jQuery("#shortPixelProposeUpgrade").addClass("shortpixel-hide"),ShortPixel.toRefresh&&ShortPixel.recheckQuota()},includeUnlisted:function(){jQuery("#short-pixel-notice-unlisted").hide(),jQuery("#optimizeUnlisted").prop("checked",!0);var e={action:"shortpixel_dismiss_notice",notice_id:"unlisted",notice_data:"true"};jQuery.get(ShortPixel.AJAX_URL,e,function(r){(e=JSON.parse(r)).Status==ShortPixel.STATUS_SUCCESS&&console.log("dismissed")})},bulkShowLengthyMsg:function(e,r,t){var s=jQuery(".bulk-notice-msg.bulk-lengthy");if(0!=s.length){var o=jQuery("a",s);o.text(r),t?o.attr("href",t):o.attr("href",o.data("href").replace("__ID__",e)),s.css("display","block")}},bulkHideLengthyMsg:function(){jQuery(".bulk-notice-msg.bulk-lengthy").css("display","none")},bulkShowMaintenanceMsg:function(e){var r=jQuery(".bulk-notice-msg.bulk-"+e);0!=r.length&&r.css("display","block")},bulkHideMaintenanceMsg:function(e){jQuery(".bulk-notice-msg.bulk-"+e).css("display","none")},bulkShowError:function(e,r,t,s){var o=jQuery("#bulk-error-template");if(0!=o.length){var i=o.clone();i.attr("id","bulk-error-"+e),-1==e?(jQuery("span.sp-err-title",i).remove(),i.addClass("bulk-error-fatal")):(jQuery("img",i).remove(),jQuery("#bulk-error-".id).remove()),jQuery("span.sp-err-content",i).html(r);var a=jQuery("a.sp-post-link",i);s?a.attr("href",s):a.attr("href",a.attr("href").replace("__ID__",e)),a.text(t),o.after(i),i.css("display","block")}},confirmBulkAction:function(e,r){return!!confirm(_spTr["confirmBulk"+e])||(r.stopPropagation(),r.preventDefault(),!1)},checkRandomAnswer:function(e){var r=jQuery(e.target).val(),t=jQuery('input[name="random_answer"]').val(),s=jQuery('input[name="random_answer"]').data("target");r==t?(jQuery(s).removeClass("disabled").prop("disabled",!1),jQuery(s).removeAttr("aria-disabled")):jQuery(s).addClass("disabled").prop("disabled",!0)},removeBulkMsg:function(e){jQuery(e).parent().parent().remove()},isCustomImageId:function(e){return"C-"==e.substring(0,2)},recheckQuota:function(){var e=window.location.href.split("#");window.location.href=e[0]+(e[0].indexOf("?")>0?"&":"?")+"checkquota=1"+(void 0===e[1]?"":"#"+e[1])},openImageMenu:function(e){e.preventDefault(),this.menuCloseEvent||(jQuery(window).click(function(e){e.target.matches(".sp-dropbtn")||jQuery(".sp-dropdown.sp-show").removeClass("sp-show")}),this.menuCloseEvent=!0);var r=e.target.parentElement.classList.contains("sp-show");jQuery(".sp-dropdown.sp-show").removeClass("sp-show"),r||e.target.parentElement.classList.add("sp-show")},menuCloseEvent:!1,loadComparer:function(e){this.comparerData.origUrl=!1,!1===this.comparerData.cssLoaded&&(jQuery("<link>").appendTo("head").attr({type:"text/css",rel:"stylesheet",href:this.WP_PLUGIN_URL+"/res/css/twentytwenty.min.css"}),this.comparerData.cssLoaded=2),!1===this.comparerData.jsLoaded&&(jQuery.getScript(this.WP_PLUGIN_URL+"/res/js/jquery.twentytwenty.min.js",function(){ShortPixel.comparerData.jsLoaded=2,ShortPixel.comparerData.origUrl.length>0&&ShortPixel.displayComparerPopup(ShortPixel.comparerData.width,ShortPixel.comparerData.height,ShortPixel.comparerData.origUrl,ShortPixel.comparerData.optUrl)}),this.comparerData.jsLoaded=1),!1===this.comparerData.origUrl&&(jQuery.ajax({type:"POST",url:ShortPixel.AJAX_URL,data:{action:"shortpixel_get_comparer_data",id:e},success:function(e){data=JSON.parse(e),jQuery.extend(ShortPixel.comparerData,data),2==ShortPixel.comparerData.jsLoaded&&ShortPixel.displayComparerPopup(ShortPixel.comparerData.width,ShortPixel.comparerData.height,ShortPixel.comparerData.origUrl,ShortPixel.comparerData.optUrl)}}),this.comparerData.origUrl="")},displayComparerPopup:function(e,r,t,s){var o=e,i=r<150||e<350,a=jQuery(i?"#spUploadCompareSideBySide":"#spUploadCompare"),l=jQuery(".sp-modal-shade");i||jQuery("#spCompareSlider").html('<img class="spUploadCompareOriginal"/><img class="spUploadCompareOptimized"/>'),e=Math.max(350,Math.min(800,e<350?2*(e+25):r<150?e+25:e)),r=Math.max(150,i?o>350?2*(r+45):r+45:r*e/o);var n="-"+Math.round(e/2);jQuery(".sp-modal-body",a).css("width",e),jQuery(".shortpixel-slider",a).css("width",e),a.css("width",e),a.css("marginLeft",n+"px"),jQuery(".sp-modal-body",a).css("height",r),a.show(),l.show(),i||jQuery("#spCompareSlider").twentytwenty({slider_move:"mousemove"}),jQuery(".sp-close-button").on("click",ShortPixel.closeComparerPopup),jQuery(document).on("keyup.sp_modal_active",ShortPixel.closeComparerPopup),jQuery(".sp-modal-shade").on("click",ShortPixel.closeComparerPopup);var u=jQuery(".spUploadCompareOptimized",a);jQuery(".spUploadCompareOriginal",a).attr("src",t),setTimeout(function(){jQuery(window).trigger("resize")},1e3),u.load(function(){jQuery(window).trigger("resize")}),u.attr("src",s)},closeComparerPopup:function(e){jQuery("#spUploadCompareSideBySide").hide(),jQuery("#spUploadCompare").hide(),jQuery(".sp-modal-shade").hide(),jQuery(document).unbind("keyup.sp_modal_active"),jQuery(".sp-modal-shade").off("click"),jQuery(".sp-close-button").off("click")},convertPunycode:function(e){var r=document.createElement("a");return r.href=e,e.indexOf(r.protocol+"//"+r.hostname)<0?r.href:e.replace(r.protocol+"//"+r.hostname,r.protocol+"//"+r.hostname.split(".").map(function(e){return sp_punycode.toASCII(e)}).join("."))},checkExifWarning:function(){!jQuery('input[name="removeExif"]').is(":checked")&&jQuery('input[name="png2jpg"]').is(":checked")?jQuery(".exif_warning").fadeIn():jQuery(".exif_warning").fadeOut()},comparerData:{cssLoaded:!1,jsLoaded:!1,origUrl:!1,optUrl:!1,width:0,height:0},toRefresh:!1,resizeSizesAlert:!1,returnedStatusSearching:0}}();
1
+ jQuery(document).ready(function(){ShortPixel.init()});var ShortPixel=function(){function N(){if(typeof ShortPixel.API_KEY!=="undefined"){return}if(jQuery("table.wp-list-table.media").length>0){jQuery('select[name^="action"] option:last-child').before('<option value="short-pixel-bulk">'+_spTr.optimizeWithSP+'</option><option value="short-pixel-bulk-lossy"> → '+_spTr.redoLossy+'</option><option value="short-pixel-bulk-glossy"> → '+_spTr.redoGlossy+'</option><option value="short-pixel-bulk-lossless"> → '+_spTr.redoLossless+'</option><option value="short-pixel-bulk-restore"> → '+_spTr.restoreOriginal+"</option>")}ShortPixel.setOptions(ShortPixelConstants[0]);if(jQuery("#backup-folder-size").length){jQuery("#backup-folder-size").html(ShortPixel.getBackupSize())}if(ShortPixel.MEDIA_ALERT=="todo"&&jQuery("div.media-frame.mode-grid").length>0){jQuery("div.media-frame.mode-grid").before('<div id="short-pixel-media-alert" class="notice notice-warning"><p>'+SPstringFormat(_spTr.changeMLToListMode,'<a href="upload.php?mode=list" class="view-list"><span class="screen-reader-text">'," </span>",'</a><a class="alignright" href="javascript:ShortPixel.dismissMediaAlert();">',"</a>")+"</p></div>")}jQuery(window).on("beforeunload",function(){if(ShortPixel.bulkProcessor==true){clearBulkProcessor()}});checkQuotaExceededAlert();checkBulkProgress()}function o(V){for(var W in V){ShortPixel[W]=V[W]}}function x(V){return/^\w+([\.+-]?\w+)*@\w+([\.-]?\w+)*(\.\w{1,63})+$/.test(V)}function p(){var V=jQuery("#pluginemail").val();if(ShortPixel.isEmailValid(V)){jQuery("#request_key").removeClass("disabled")}jQuery("#request_key").attr("href",jQuery("#request_key").attr("href").split("?")[0]+"?pluginemail="+V)}function a(V){console.log("validate");jQuery("#valid").val("validate");jQuery(V).parents("form").submit()}jQuery("#key").keypress(function(V){if(V.which==13){jQuery("#valid").val("validate")}});function Q(V){if(jQuery(V).is(":checked")){jQuery("#width,#height").removeAttr("disabled")}else{jQuery("#width,#height").attr("disabled","disabled")}}function k(){if(!jQuery('input[name="removeExif"]').is(":checked")&&jQuery('input[name="png2jpg"]').is(":checked")){jQuery(".exif_warning").fadeIn()}else{jQuery(".exif_warning").fadeOut()}}function e(){var V=0;if(typeof document.wp_shortpixel_options!=="undefined"){V=document.wp_shortpixel_options.compressionType}for(var W=0,X=null;W<V.length;W++){V[W].onclick=function(){if(this!==X){X=this}if(typeof ShortPixel.setupGeneralTabAlert!=="undefined"){return}alert(_spTr.alertOnlyAppliesToNewImages);ShortPixel.setupGeneralTabAlert=1}}ShortPixel.enableResize("#resize");jQuery("#resize").change(function(){Q(this)});jQuery(".resize-sizes").blur(function(aa){var ab=jQuery(aa.target);if(ShortPixel.resizeSizesAlert==ab.val()){return}ShortPixel.resizeSizesAlert=ab.val();var Z=jQuery("#min-"+ab.attr("name")).val();var Y=jQuery("#min-"+ab.attr("name")).data("nicename");if(ab.val()<Math.min(Z,1024)){if(Z>1024){alert(SPstringFormat(_spTr.pleaseDoNotSetLesser1024,Y))}else{alert(SPstringFormat(_spTr.pleaseDoNotSetLesserSize,Y,Y,Z))}aa.preventDefault();ab.focus()}else{this.defaultValue=ab.val()}});jQuery(".shortpixel-confirm").click(function(Z){var Y=confirm(Z.target.getAttribute("data-confirm"));if(!Y){Z.preventDefault();return false}return true});jQuery('input[name="removeExif"], input[name="png2jpg"]').on("change",function(){ShortPixel.checkExifWarning()});ShortPixel.checkExifWarning()}function H(){jQuery(".wp-shortpixel-options .shortpixel-key-valid").css("display","none");jQuery(".wp-shortpixel-options button#validate").css("display","inline-block")}function y(){jQuery("input.remove-folder-button").click(function(){var W=jQuery(this).data("value");var V=confirm(SPstringFormat(_spTr.areYouSureStopOptimizing,W));if(V==true){jQuery("#removeFolder").val(W);jQuery("#wp_shortpixel_options").submit()}});jQuery("input.recheck-folder-button").click(function(){var W=jQuery(this).data("value");var V=confirm(SPstringFormat(_spTr.areYouSureStopOptimizing,W));if(V==true){jQuery("#recheckFolder").val(W);jQuery("#wp_shortpixel_options").submit()}})}function P(V){var W=jQuery("#"+(V.checked?"total":"main")+"ToProcess").val();jQuery("div.bulk-play span.total").text(W);jQuery("#displayTotal").text(W)}function g(){ShortPixel.adjustSettingsTabs();ShortPixel.setupGeneralTab();jQuery(window).resize(function(){ShortPixel.adjustSettingsTabs()});jQuery("article.sp-tabs a.tab-link").click(function(W){var V=jQuery(W.target).data("id");ShortPixel.switchSettingsTab(V)});jQuery("input[type=radio][name=deliverWebpType]").change(function(){if(this.value=="deliverWebpAltered"){if(window.confirm(_spTr.alertDeliverWebPAltered)){var V=jQuery("input[type=radio][name=deliverWebpAlteringType]:checked").length;if(V==0){jQuery("#deliverWebpAlteredWP").prop("checked",true)}}else{jQuery(this).prop("checked",false)}}else{if(this.value=="deliverWebpUnaltered"){window.alert(_spTr.alertDeliverWebPUnaltered)}}})}function C(aa){var X=aa.replace("tab-",""),V="",Z=jQuery("section#"+aa);jQuery('input[name="display_part"]').val(X);var Y=window.location.href.toString();if(Y.indexOf("?")>0){var W=Y.substring(0,Y.indexOf("?"));W+="?"+jQuery.param({page:"wp-shortpixel-settings",part:X});window.history.replaceState({},document.title,W)}if(Z.length>0){jQuery("section").removeClass("sel-tab");jQuery("section .wp-shortpixel-tab-content").fadeOut(50);jQuery(Z).addClass("sel-tab");ShortPixel.adjustSettingsTabs();jQuery(Z).find(".wp-shortpixel-tab-content").fadeIn(50)}if(typeof HS!=="undefined"&&typeof HS.beacon.suggest!=="undefined"){switch(X){case"settings":V=shortpixel_suggestions_settings;break;case"adv-settings":V=shortpixel_suggestions_adv_settings;break;case"cloudflare":case"stats":V=shortpixel_suggestions_cloudflare;break;default:break}HS.beacon.suggest(V)}}function D(){var V=jQuery("section.sel-tab").height()+90;jQuery(".section-wrapper").css("height",V)}function R(){var V={action:"shortpixel_dismiss_media_alert"};jQuery.get(ShortPixel.AJAX_URL,V,function(W){V=JSON.parse(W);if(V.Status=="success"){jQuery("#short-pixel-media-alert").hide()}})}function w(){jQuery("#shortpixel-hs-button-blind").remove();jQuery("#shortpixel-hs-tools").remove();jQuery("#hs-beacon").remove();jQuery("#botbutton").remove();jQuery("#shortpixel-hs-blind").remove()}function q(){w();dismissShortPixelNotice("help")}function m(){var V={action:"shortpixel_check_quota"};jQuery.get(ShortPixel.AJAX_URL,V,function(){console.log("quota refreshed")})}function G(V){if(V.checked){jQuery("#with-thumbs").css("display","inherit");jQuery("#without-thumbs").css("display","none")}else{jQuery("#without-thumbs").css("display","inherit");jQuery("#with-thumbs").css("display","none")}}function b(Z,X,W,Y,V){return(X>0?"<div class='sp-column-info'>"+_spTr.reducedBy+" <strong><span class='percent'>"+X+"%</span></strong> ":"")+(X>0&&X<5?"<br>":"")+(X<5?_spTr.bonusProcessing:"")+(W.length>0?" ("+W+")":"")+(0+Y>0?"<br>"+SPstringFormat(_spTr.plusXthumbsOpt,Y):"")+(0+V>0?"<br>"+SPstringFormat(_spTr.plusXretinasOpt,V):"")+"</div>"}function s(W,V){jQuery(W).knob({readOnly:true,width:V,height:V,fgColor:"#1CAECB",format:function(X){return X+"%"}})}function c(ac,X,aa,Z,W,ab){if(W==1){var Y=jQuery(".sp-column-actions-template").clone();if(!Y.length){return false}var V;if(X.length==0){V=["lossy","lossless"]}else{V=["lossy","glossy","lossless"].filter(function(ad){return !(ad==X)})}Y.html(Y.html().replace(/__SP_ID__/g,ac));if(ab.substr(ab.lastIndexOf(".")+1).toLowerCase()=="pdf"){jQuery(".sp-action-compare",Y).remove()}if(aa==0&&Z>0){Y.html(Y.html().replace("__SP_THUMBS_TOTAL__",Z))}else{jQuery(".sp-action-optimize-thumbs",Y).remove();jQuery(".sp-dropbtn",Y).removeClass("button-primary")}Y.html(Y.html().replace(/__SP_FIRST_TYPE__/g,V[0]));Y.html(Y.html().replace(/__SP_SECOND_TYPE__/g,V[1]));return Y.html()}return""}function j(Z,Y){Z=Z.substring(2);if(jQuery(".shortpixel-other-media").length){var X=["optimize","retry","restore","redo","quota","view"];for(var W=0,V=X.length;W<V;W++){jQuery("#"+X[W]+"_"+Z).css("display","none")}for(var W=0,V=Y.length;W<V;W++){jQuery("#"+Y[W]+"_"+Z).css("display","")}}}function l(V){ShortPixel.retries++;if(isNaN(ShortPixel.retries)){ShortPixel.retries=1}if(ShortPixel.retries<6){console.log("Invalid response from server (Error: "+V+"). Retrying pass "+(ShortPixel.retries+1)+"...");setTimeout(checkBulkProgress,5000)}else{ShortPixel.bulkShowError(-1,"Invalid response from server received 6 times. Please retry later by reloading this page, or <a href='https://shortpixel.com/contact' target='_blank'>contact support</a>. (Error: "+V+")","");console.log("Invalid response from server 6 times. Giving up.")}}function n(V){V.action="shortpixel_browse_content";var W="";jQuery.ajax({type:"POST",url:ShortPixel.AJAX_URL,data:V,success:function(X){W=X},async:false});return W}function d(){var V={action:"shortpixel_get_backup_size"};var W="";jQuery.ajax({type:"POST",url:ShortPixel.AJAX_URL,data:V,success:function(X){W=X},async:false});return W}function f(W){if(!jQuery("#tos").is(":checked")){W.preventDefault();jQuery("#tos-robo").fadeIn(400,function(){jQuery("#tos-hand").fadeIn()});jQuery("#tos").click(function(){jQuery("#tos-robo").css("display","none");jQuery("#tos-hand").css("display","none")});return}jQuery("#request_key").addClass("disabled");jQuery("#pluginemail_spinner").addClass("is-active");ShortPixel.updateSignupEmail();if(ShortPixel.isEmailValid(jQuery("#pluginemail").val())){jQuery("#pluginemail-error").css("display","none");var V={action:"shortpixel_new_api_key",email:jQuery("#pluginemail").val()};jQuery.ajax({type:"POST",async:false,url:ShortPixel.AJAX_URL,data:V,success:function(X){data=JSON.parse(X);if(data.Status=="success"){W.preventDefault();window.location.reload()}else{if(data.Status=="invalid"){jQuery("#pluginemail-error").html("<b>"+data.Details+"</b>");jQuery("#pluginemail-error").css("display","");jQuery("#pluginemail-info").css("display","none");W.preventDefault()}else{}}}});jQuery("#request_key").removeAttr("onclick")}else{jQuery("#pluginemail-error").css("display","");jQuery("#pluginemail-info").css("display","none");W.preventDefault()}jQuery("#request_key").removeClass("disabled");jQuery("#pluginemail_spinner").removeClass("is-active")}function S(){jQuery("#shortPixelProposeUpgrade .sp-modal-body").addClass("sptw-modal-spinner");jQuery("#shortPixelProposeUpgrade .sp-modal-body").html("");jQuery("#shortPixelProposeUpgradeShade").css("display","block");jQuery("#shortPixelProposeUpgrade").removeClass("shortpixel-hide");var V={action:"shortpixel_propose_upgrade"};jQuery.ajax({type:"POST",url:ShortPixel.AJAX_URL,data:V,success:function(W){jQuery("#shortPixelProposeUpgrade .sp-modal-body").removeClass("sptw-modal-spinner");jQuery("#shortPixelProposeUpgrade .sp-modal-body").html(W)}})}function L(){jQuery("#shortPixelProposeUpgradeShade").css("display","none");jQuery("#shortPixelProposeUpgrade").addClass("shortpixel-hide");if(ShortPixel.toRefresh){ShortPixel.recheckQuota()}}function z(){jQuery("#short-pixel-notice-unlisted").hide();jQuery("#optimizeUnlisted").prop("checked",true);var V={action:"shortpixel_dismiss_notice",notice_id:"unlisted",notice_data:"true"};jQuery.get(ShortPixel.AJAX_URL,V,function(W){V=JSON.parse(W);if(V.Status==ShortPixel.STATUS_SUCCESS){console.log("dismissed")}})}function r(){jQuery(".select-folder-button").click(function(){jQuery(".sp-folder-picker-shade").fadeIn(100);jQuery(".shortpixel-modal.modal-folder-picker").show();var V=jQuery(".sp-folder-picker");V.parent().css("margin-left",-V.width()/2);V.fileTree({script:ShortPixel.browseContent,multiFolder:false})});jQuery(".shortpixel-modal input.select-folder-cancel, .sp-folder-picker-shade").click(function(){jQuery(".sp-folder-picker-shade").fadeOut(100);jQuery(".shortpixel-modal.modal-folder-picker").hide()});jQuery(".shortpixel-modal input.select-folder").click(function(Y){var X=jQuery("UL.jqueryFileTree LI.directory.selected");if(jQuery(X).length==0){var X=jQuery("UL.jqueryFileTree LI.selected").parents(".directory")}var V=jQuery(X).children("a").attr("rel");if(typeof V==="undefined"){return}V=V.trim();if(V){var W=jQuery("#customFolderBase").val()+V;if(W.slice(-1)=="/"){W=W.slice(0,-1)}jQuery("#addCustomFolder").val(W);jQuery("#addCustomFolderView").val(W);jQuery(".sp-folder-picker-shade").fadeOut(100);jQuery(".shortpixel-modal.modal-folder-picker").css("display","none");jQuery("#saveAdvAddFolder").removeClass("hidden")}else{alert("Please select a folder from the list.")}})}function K(Z,Y,X){var W=jQuery(".bulk-notice-msg.bulk-lengthy");if(W.length==0){return}var V=jQuery("a",W);V.text(Y);if(X){V.attr("href",X)}else{V.attr("href",V.data("href").replace("__ID__",Z))}W.css("display","block")}function F(){jQuery(".bulk-notice-msg.bulk-lengthy").css("display","none")}function A(V){var W=jQuery(".bulk-notice-msg.bulk-"+V);if(W.length==0){return}W.css("display","block")}function T(V){jQuery(".bulk-notice-msg.bulk-"+V).css("display","none")}function v(ab,Z,aa,Y){var V=jQuery("#bulk-error-template");if(V.length==0){return}var X=V.clone();X.attr("id","bulk-error-"+ab);if(ab==-1){jQuery("span.sp-err-title",X).remove();X.addClass("bulk-error-fatal")}else{jQuery("img",X).remove();jQuery("#bulk-error-".id).remove()}jQuery("span.sp-err-content",X).html(Z);var W=jQuery("a.sp-post-link",X);if(Y){W.attr("href",Y)}else{W.attr("href",W.attr("href").replace("__ID__",ab))}W.text(aa);V.after(X);X.css("display","block")}function I(V,W){if(!confirm(_spTr["confirmBulk"+V])){W.stopPropagation();W.preventDefault();return false}return true}function B(Y){var W=jQuery(Y.target).val();var V=jQuery('input[name="random_answer"]').val();var X=jQuery('input[name="random_answer"]').data("target");if(W==V){jQuery(X).removeClass("disabled").prop("disabled",false);jQuery(X).removeAttr("aria-disabled")}else{jQuery(X).addClass("disabled").prop("disabled",true)}}function u(V){jQuery(V).parent().parent().remove()}function M(V){return V.substring(0,2)=="C-"}function O(){var V=window.location.href.split("#");window.location.href=V[0]+(V[0].indexOf("?")>0?"&":"?")+"checkquota=1"+(typeof V[1]==="undefined"?"":"#"+V[1])}function h(W){W.preventDefault();if(!this.menuCloseEvent){jQuery(window).click(function(X){if(!X.target.matches(".sp-dropbtn")){jQuery(".sp-dropdown.sp-show").removeClass("sp-show")}});this.menuCloseEvent=true}var V=W.target.parentElement.classList.contains("sp-show");jQuery(".sp-dropdown.sp-show").removeClass("sp-show");if(!V){W.target.parentElement.classList.add("sp-show")}}function U(V){this.comparerData.origUrl=false;if(this.comparerData.cssLoaded===false){jQuery("<link>").appendTo("head").attr({type:"text/css",rel:"stylesheet",href:this.WP_PLUGIN_URL+"/res/css/twentytwenty.min.css"});this.comparerData.cssLoaded=2}if(this.comparerData.jsLoaded===false){jQuery.getScript(this.WP_PLUGIN_URL+"/res/js/jquery.twentytwenty.min.js",function(){ShortPixel.comparerData.jsLoaded=2;if(ShortPixel.comparerData.origUrl.length>0){ShortPixel.displayComparerPopup(ShortPixel.comparerData.width,ShortPixel.comparerData.height,ShortPixel.comparerData.origUrl,ShortPixel.comparerData.optUrl)}});this.comparerData.jsLoaded=1}if(this.comparerData.origUrl===false){jQuery.ajax({type:"POST",url:ShortPixel.AJAX_URL,data:{action:"shortpixel_get_comparer_data",id:V},success:function(W){data=JSON.parse(W);jQuery.extend(ShortPixel.comparerData,data);if(ShortPixel.comparerData.jsLoaded==2){ShortPixel.displayComparerPopup(ShortPixel.comparerData.width,ShortPixel.comparerData.height,ShortPixel.comparerData.origUrl,ShortPixel.comparerData.optUrl)}}});this.comparerData.origUrl=""}}function J(X,ad,ae,Y){var ac=X;var W=(ad<150||X<350);var ab=jQuery(W?"#spUploadCompareSideBySide":"#spUploadCompare");var Z=jQuery(".sp-modal-shade");if(!W){jQuery("#spCompareSlider").html('<img class="spUploadCompareOriginal"/><img class="spUploadCompareOptimized"/>')}X=Math.max(350,Math.min(800,(X<350?(X+25)*2:(ad<150?X+25:X))));ad=Math.max(150,(W?(ac>350?2*(ad+45):ad+45):ad*X/ac));var aa="-"+Math.round(X/2);jQuery(".sp-modal-body",ab).css("width",X);jQuery(".shortpixel-slider",ab).css("width",X);ab.css("width",X);ab.css("marginLeft",aa+"px");jQuery(".sp-modal-body",ab).css("height",ad);ab.show();Z.show();if(!W){jQuery("#spCompareSlider").twentytwenty({slider_move:"mousemove"})}jQuery(".sp-close-button").on("click",ShortPixel.closeComparerPopup);jQuery(document).on("keyup.sp_modal_active",ShortPixel.closeComparerPopup);jQuery(".sp-modal-shade").on("click",ShortPixel.closeComparerPopup);var V=jQuery(".spUploadCompareOptimized",ab);jQuery(".spUploadCompareOriginal",ab).attr("src",ae);setTimeout(function(){jQuery(window).trigger("resize")},1000);V.load(function(){jQuery(window).trigger("resize")});V.attr("src",Y)}function t(V){jQuery("#spUploadCompareSideBySide").hide();jQuery("#spUploadCompare").hide();jQuery(".sp-modal-shade").hide();jQuery(document).unbind("keyup.sp_modal_active");jQuery(".sp-modal-shade").off("click");jQuery(".sp-close-button").off("click")}function E(V){var W=document.createElement("a");W.href=V;if(V.indexOf(W.protocol+"//"+W.hostname)<0){return W.href}return V.replace(W.protocol+"//"+W.hostname,W.protocol+"//"+W.hostname.split(".").map(function(X){return sp_punycode.toASCII(X)}).join("."))}return{init:N,setOptions:o,isEmailValid:x,updateSignupEmail:p,validateKey:a,enableResize:Q,setupGeneralTab:e,apiKeyChanged:H,setupAdvancedTab:y,checkThumbsUpdTotal:P,initSettings:g,switchSettingsTab:C,adjustSettingsTabs:D,onBulkThumbsCheck:G,dismissMediaAlert:R,closeHelpPane:w,dismissHelpPane:q,checkQuota:m,percentDial:s,successMsg:b,successActions:c,otherMediaUpdateActions:j,retry:l,initFolderSelector:r,browseContent:n,getBackupSize:d,newApiKey:f,proposeUpgrade:S,closeProposeUpgrade:L,includeUnlisted:z,bulkShowLengthyMsg:K,bulkHideLengthyMsg:F,bulkShowMaintenanceMsg:A,bulkHideMaintenanceMsg:T,bulkShowError:v,confirmBulkAction:I,checkRandomAnswer:B,removeBulkMsg:u,isCustomImageId:M,recheckQuota:O,openImageMenu:h,menuCloseEvent:false,loadComparer:U,displayComparerPopup:J,closeComparerPopup:t,convertPunycode:E,checkExifWarning:k,comparerData:{cssLoaded:false,jsLoaded:false,origUrl:false,optUrl:false,width:0,height:0},toRefresh:false,resizeSizesAlert:false,returnedStatusSearching:0}}();function showToolBarAlert(c,b,d){var a=jQuery("li.shortpixel-toolbar-processing");switch(c){case ShortPixel.STATUS_QUOTA_EXCEEDED:if(window.location.href.search("wp-short-pixel-bulk")>0&&jQuery(".sp-quota-exceeded-alert").length==0){location.reload();return}a.addClass("shortpixel-alert");a.addClass("shortpixel-quota-exceeded");jQuery("a",a).attr("href","options-general.php?page=wp-shortpixel-settings");jQuery("a div",a).attr("title","ShortPixel quota exceeded. Click for details.");break;case ShortPixel.STATUS_SKIP:case ShortPixel.STATUS_FAIL:a.addClass("shortpixel-alert shortpixel-processing");jQuery("a div",a).attr("title",b);if(typeof d!=="undefined"){jQuery("a",a).attr("href","post.php?post="+d+"&action=edit")}break;case ShortPixel.STATUS_NO_KEY:a.addClass("shortpixel-alert");a.addClass("shortpixel-quota-exceeded");jQuery("a",a).attr("href","options-general.php?page=wp-shortpixel-settings");jQuery("a div",a).attr("title","Get API Key");break;case ShortPixel.STATUS_SUCCESS:case ShortPixel.STATUS_RETRY:a.addClass("shortpixel-processing");a.removeClass("shortpixel-alert");jQuery("a",a).removeAttr("target");jQuery("a",a).attr("href",jQuery("a img",a).attr("success-url"))}a.removeClass("shortpixel-hide")}function hideToolBarAlert(){jQuery("li.shortpixel-toolbar-processing.shortpixel-processing").addClass("shortpixel-hide")}function hideQuotaExceededToolBarAlert(){jQuery("li.shortpixel-toolbar-processing.shortpixel-quota-exceeded").addClass("shortpixel-hide")}function checkQuotaExceededAlert(){if(typeof shortPixelQuotaExceeded!="undefined"){if(shortPixelQuotaExceeded==1){showToolBarAlert(ShortPixel.STATUS_QUOTA_EXCEEDED)}else{hideQuotaExceededToolBarAlert()}}}function checkBulkProgress(){var b=function(e){if(!d){d=true;return e}return"/"};var d=false;var a=window.location.href.toLowerCase().replace(/\/\//g,b);d=false;var c=ShortPixel.WP_ADMIN_URL.toLowerCase().replace(/\/\//g,b);if(a.search(c)<0){a=ShortPixel.convertPunycode(a);c=ShortPixel.convertPunycode(c)}if(a.search(c+"upload.php")<0&&a.search(c+"edit.php")<0&&a.search(c+"edit-tags.php")<0&&a.search(c+"post-new.php")<0&&a.search(c+"post.php")<0&&a.search("page=nggallery-manage-gallery")<0&&(ShortPixel.FRONT_BOOTSTRAP==0||a.search(c)==0)){hideToolBarAlert();return}if(ShortPixel.bulkProcessor==true&&window.location.href.search("wp-short-pixel-bulk")<0&&typeof localStorage.bulkPage!=="undefined"&&localStorage.bulkPage>0){ShortPixel.bulkProcessor=false}if(window.location.href.search("wp-short-pixel-bulk")>=0){ShortPixel.bulkProcessor=true;localStorage.bulkTime=Math.floor(Date.now()/1000);localStorage.bulkPage=1}if(ShortPixel.bulkProcessor==true||typeof localStorage.bulkTime=="undefined"||Math.floor(Date.now()/1000)-localStorage.bulkTime>90){ShortPixel.bulkProcessor=true;localStorage.bulkPage=(window.location.href.search("wp-short-pixel-bulk")>=0?1:0);localStorage.bulkTime=Math.floor(Date.now()/1000);console.log(localStorage.bulkTime);checkBulkProcessingCallApi()}else{setTimeout(checkBulkProgress,5000)}}function checkBulkProcessingCallApi(){var a={action:"shortpixel_image_processing"};jQuery.ajax({type:"POST",url:ShortPixel.AJAX_URL,data:a,success:function(g){if(g.length>0){var j=null;try{var j=JSON.parse(g)}catch(l){ShortPixel.retry(l.message);return}ShortPixel.retries=0;var d=j.ImageID;var k=(jQuery("div.short-pixel-bulk-page").length>0);if(j.Status&&j.Status!=ShortPixel.STATUS_SEARCHING){if(ShortPixel.returnedStatusSearching>=2){jQuery(".bulk-notice-msg.bulk-searching").hide()}ShortPixel.returnedStatusSearching=0}switch(j.Status){case ShortPixel.STATUS_NO_KEY:setCellMessage(d,j.Message,"<a class='button button-smaller button-primary' href=\"https://shortpixel.com/wp-apikey"+ShortPixel.AFFILIATE+'" target="_blank">'+_spTr.getApiKey+"</a>");showToolBarAlert(ShortPixel.STATUS_NO_KEY);break;case ShortPixel.STATUS_QUOTA_EXCEEDED:setCellMessage(d,j.Message,"<a class='button button-smaller button-primary' href=\"https://shortpixel.com/login/"+ShortPixel.API_KEY+'" target="_blank">'+_spTr.extendQuota+"</a><a class='button button-smaller' href='admin.php?action=shortpixel_check_quota'>"+_spTr.check__Quota+"</a>");showToolBarAlert(ShortPixel.STATUS_QUOTA_EXCEEDED);if(j.Stop==false){setTimeout(checkBulkProgress,5000)}ShortPixel.otherMediaUpdateActions(d,["quota","view"]);break;case ShortPixel.STATUS_FAIL:setCellMessage(d,j.Message,"<a class='button button-smaller button-primary' href=\"javascript:manualOptimization('"+d+"', false)\">"+_spTr.retry+"</a>");showToolBarAlert(ShortPixel.STATUS_FAIL,j.Message,d);if(k){ShortPixel.bulkShowError(d,j.Message,j.Filename,j.CustomImageLink);if(j.BulkPercent){progressUpdate(j.BulkPercent,j.BulkMsg)}ShortPixel.otherMediaUpdateActions(d,["retry","view"])}console.log(j.Message);setTimeout(checkBulkProgress,5000);break;case ShortPixel.STATUS_EMPTY_QUEUE:console.log(j.Message);clearBulkProcessor();hideToolBarAlert();var c=jQuery("#bulk-progress");if(k&&c.length&&j.BulkStatus!="2"){progressUpdate(100,"Bulk finished!");jQuery("a.bulk-cancel").attr("disabled","disabled");hideSlider();setTimeout(function(){window.location.reload()},3000)}break;case ShortPixel.STATUS_SUCCESS:if(k){ShortPixel.bulkHideLengthyMsg();ShortPixel.bulkHideMaintenanceMsg()}var m=j.PercentImprovement;showToolBarAlert(ShortPixel.STATUS_SUCCESS,"");var b=ShortPixel.isCustomImageId(d)?"":ShortPixel.successActions(d,j.Type,j.ThumbsCount,j.ThumbsTotal,j.BackupEnabled,j.Filename);setCellMessage(d,ShortPixel.successMsg(d,m,j.Type,j.ThumbsCount,j.RetinasCount),b);if(jQuery("#post-"+d).length>0){jQuery("#post-"+d).find(".filename").text(j.Filename)}if(jQuery(".misc-pub-filename strong").length>0){jQuery(".misc-pub-filename strong").text(j.Filename)}if(ShortPixel.isCustomImageId(d)&&j.TsOptimized&&j.TsOptimized.length>0){console.log(d);jQuery(".date-"+d).text(j.TsOptimized)}var h=jQuery(["restore","view","redolossy","redoglossy","redolossless"]).not(["redo"+j.Type]).get();ShortPixel.otherMediaUpdateActions(d,h);var f=new PercentageAnimator("#sp-msg-"+d+" span.percent",m);f.animate(m);if(k&&typeof j.Thumb!=="undefined"){if(j.BulkPercent){progressUpdate(j.BulkPercent,j.BulkMsg)}if(j.Thumb.length>0){sliderUpdate(d,j.Thumb,j.BkThumb,j.PercentImprovement,j.Filename);if(typeof j.AverageCompression!=="undefined"&&0+j.AverageCompression>0){jQuery("#sp-avg-optimization").html('<input type="text" class="dial" value="'+Math.round(j.AverageCompression)+'"/>');ShortPixel.percentDial("#sp-avg-optimization .dial",60)}}}console.log("Server response: "+g);if(k&&typeof j.BulkPercent!=="undefined"){progressUpdate(j.BulkPercent,j.BulkMsg)}setTimeout(checkBulkProgress,5000);break;case ShortPixel.STATUS_SKIP:if(j.Silent!==1){ShortPixel.bulkShowError(d,j.Message,j.Filename,j.CustomImageLink)}case ShortPixel.STATUS_ERROR:if(typeof j.Message!=="undefined"){showToolBarAlert(ShortPixel.STATUS_SKIP,j.Message+" Image ID: "+d);setCellMessage(d,j.Message,"")}ShortPixel.otherMediaUpdateActions(d,["retry","view"]);case ShortPixel.STATUS_RETRY:console.log("Server response: "+g);showToolBarAlert(ShortPixel.STATUS_RETRY,"");if(k&&typeof j.BulkPercent!=="undefined"){progressUpdate(j.BulkPercent,j.BulkMsg)}if(k&&j.Count>3){ShortPixel.bulkShowLengthyMsg(d,j.Filename,j.CustomImageLink)}setTimeout(checkBulkProgress,5000);break;case ShortPixel.STATUS_SEARCHING:console.log("Server response: "+g);ShortPixel.returnedStatusSearching++;if(ShortPixel.returnedStatusSearching>=2){jQuery(".bulk-notice-msg.bulk-searching").show()}setTimeout(checkBulkProgress,2500);break;case ShortPixel.STATUS_MAINTENANCE:ShortPixel.bulkShowMaintenanceMsg("maintenance");setTimeout(checkBulkProgress,60000);break;case ShortPixel.STATUS_QUEUE_FULL:ShortPixel.bulkShowMaintenanceMsg("queue-full");setTimeout(checkBulkProgress,60000);break;default:ShortPixel.retry("Unknown status "+j.Status+". Retrying...");break}}},error:function(b){ShortPixel.retry(b.statusText)}})}function clearBulkProcessor(){ShortPixel.bulkProcessor=false;localStorage.bulkTime=0;if(window.location.href.search("wp-short-pixel-bulk")>=0){localStorage.bulkPage=0}}function setCellMessage(d,a,c){var b=jQuery("#sp-msg-"+d);if(b.length>0){b.html("<div class='sp-column-actions'>"+c+"</div><div class='sp-column-info'>"+a+"</div>");b.css("color","")}b=jQuery("#sp-cust-msg-"+d);if(b.length>0){b.html("<div class='sp-column-info'>"+a+"</div>")}}function manualOptimization(c,a){setCellMessage(c,"<img src='"+ShortPixel.WP_PLUGIN_URL+"/res/img/loading.gif' class='sp-loading-small'>Image waiting to be processed","");jQuery("li.shortpixel-toolbar-processing").removeClass("shortpixel-hide");jQuery("li.shortpixel-toolbar-processing").removeClass("shortpixel-alert");jQuery("li.shortpixel-toolbar-processing").addClass("shortpixel-processing");var b={action:"shortpixel_manual_optimization",image_id:c,cleanup:a};jQuery.ajax({type:"GET",url:ShortPixel.AJAX_URL,data:b,success:function(d){var e=JSON.parse(d);if(e.Status==ShortPixel.STATUS_SUCCESS){setTimeout(checkBulkProgress,2000)}else{setCellMessage(c,typeof e.Message!=="undefined"?e.Message:_spTr.thisContentNotProcessable,"")}},error:function(d){b.action="shortpixel_check_status";jQuery.ajax({type:"GET",url:ShortPixel.AJAX_URL,data:b,success:function(e){var f=JSON.parse(e);if(f.Status!==ShortPixel.STATUS_SUCCESS){setCellMessage(c,typeof f.Message!=="undefined"?f.Message:_spTr.thisContentNotProcessable,"")}}})}})}function reoptimize(c,a){setCellMessage(c,"<img src='"+ShortPixel.WP_PLUGIN_URL+"/res/img/loading.gif' class='sp-loading-small'>Image waiting to be reprocessed","");jQuery("li.shortpixel-toolbar-processing").removeClass("shortpixel-hide");jQuery("li.shortpixel-toolbar-processing").addClass("shortpixel-processing");var b={action:"shortpixel_redo",attachment_ID:c,type:a};jQuery.get(ShortPixel.AJAX_URL,b,function(d){b=JSON.parse(d);if(b.Status==ShortPixel.STATUS_SUCCESS){setTimeout(checkBulkProgress,2000)}else{$msg=typeof b.Message!=="undefined"?b.Message:_spTr.thisContentNotProcessable;setCellMessage(c,$msg,"");showToolBarAlert(ShortPixel.STATUS_FAIL,$msg)}})}function optimizeThumbs(b){setCellMessage(b,"<img src='"+ShortPixel.WP_PLUGIN_URL+"/res/img/loading.gif' class='sp-loading-small'>"+_spTr.imageWaitOptThumbs,"");jQuery("li.shortpixel-toolbar-processing").removeClass("shortpixel-hide");jQuery("li.shortpixel-toolbar-processing").addClass("shortpixel-processing");var a={action:"shortpixel_optimize_thumbs",attachment_ID:b};jQuery.get(ShortPixel.AJAX_URL,a,function(c){a=JSON.parse(c);if(a.Status==ShortPixel.STATUS_SUCCESS){setTimeout(checkBulkProgress,2000)}else{setCellMessage(b,typeof a.Message!=="undefined"?a.Message:_spTr.thisContentNotProcessable,"")}})}function dismissShortPixelNoticeExceed(b){jQuery("#wp-admin-bar-shortpixel_processing").hide();var a={action:"shortpixel_dismiss_notice",notice_id:"exceed"};jQuery.get(ShortPixel.AJAX_URL,a,function(c){a=JSON.parse(c);if(a.Status==ShortPixel.STATUS_SUCCESS){console.log("dismissed")}});b.preventDefault()}function dismissShortPixelNotice(b){jQuery("#short-pixel-notice-"+b).hide();var a={action:"shortpixel_dismiss_notice",notice_id:b};jQuery.get(ShortPixel.AJAX_URL,a,function(c){a=JSON.parse(c);if(a.Status==ShortPixel.STATUS_SUCCESS){console.log("dismissed")}})}function PercentageAnimator(b,a){this.animationSpeed=10;this.increment=2;this.curPercentage=0;this.targetPercentage=a;this.outputSelector=b;this.animate=function(c){this.targetPercentage=c;setTimeout(PercentageTimer.bind(null,this),this.animationSpeed)}}function PercentageTimer(a){if(a.curPercentage-a.targetPercentage<-a.increment){a.curPercentage+=a.increment}else{if(a.curPercentage-a.targetPercentage>a.increment){a.curPercentage-=a.increment}else{a.curPercentage=a.targetPercentage}}jQuery(a.outputSelector).text(a.curPercentage+"%");if(a.curPercentage!=a.targetPercentage){setTimeout(PercentageTimer.bind(null,a),a.animationSpeed)}}function progressUpdate(c,b){var a=jQuery("#bulk-progress");if(a.length){jQuery(".progress-left",a).css("width",c+"%");jQuery(".progress-img",a).css("left",c+"%");if(c>24){jQuery(".progress-img span",a).html("");jQuery(".progress-left",a).html(c+"%")}else{jQuery(".progress-img span",a).html(c+"%");jQuery(".progress-left",a).html("")}jQuery(".bulk-estimate").html(b)}}function sliderUpdate(g,c,d,e,b){var f=jQuery(".bulk-slider div.bulk-slide:first-child");if(f.length===0){return}if(f.attr("id")!="empty-slide"){f.hide()}f.css("z-index",1000);jQuery(".bulk-img-opt",f).attr("src","");if(typeof d==="undefined"){d=""}if(d.length>0){jQuery(".bulk-img-orig",f).attr("src","")}var a=f.clone();a.attr("id","slide-"+g);jQuery(".bulk-img-opt",a).attr("src",c);if(d.length>0){jQuery(".img-original",a).css("display","inline-block");jQuery(".bulk-img-orig",a).attr("src",d)}else{jQuery(".img-original",a).css("display","none")}jQuery(".bulk-opt-percent",a).html('<input type="text" class="dial" value="'+e+'"/>');jQuery(".bulk-slider").append(a);ShortPixel.percentDial("#"+a.attr("id")+" .dial",100);jQuery(".bulk-slider-container span.filename").html("&nbsp;&nbsp;"+b);if(f.attr("id")=="empty-slide"){f.remove();jQuery(".bulk-slider-container").css("display","block")}else{f.animate({left:f.width()+f.position().left},"slow","swing",function(){f.remove();a.fadeIn("slow")})}}function hideSlider(){jQuery(".bulk-slider-container").css("display","none")}function showStats(){var a=jQuery(".bulk-stats");if(a.length>0){}}function SPstringFormat(){var b=Array.prototype.slice.call(arguments);if(b.length===0){return}var a=b.shift();for(i=0;i<b.length;i++){a=a.replace(new RegExp("\\{"+i+"\\}","gm"),b[i])}return a};
res/scss/shortpixel-admin.scss CHANGED
@@ -1,6 +1,7 @@
1
 
2
  @import 'utils/notices';
3
  @import 'view/bulk-restore-all';
4
- @import 'view/bulk_dashboard';
5
  @import 'view/settings-advanced';
6
  @import 'view/settings';
 
1
 
2
  @import 'utils/notices';
3
  @import 'view/bulk-restore-all';
4
+ @import 'view/bulk_dashboard';
5
  @import 'view/settings-advanced';
6
  @import 'view/settings';
7
+ @import 'view/edit-media';
res/scss/view/_edit-media.scss ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+
3
+ .view-edit-media
4
+ {
5
+ .debugInfo
6
+ {
7
+ pre
8
+ {
9
+ font-size: 11px;
10
+ // overflow: hidden;
11
+ }
12
+ }
13
+ .sp-column-stats
14
+ {
15
+ position: relative;
16
+
17
+ .sp-column-actions
18
+ {
19
+ margin-right: 5px;
20
+ margin-top: 16px;
21
+ }
22
+ .edit-media-stats
23
+ {
24
+ border: 1px solid #ccc;
25
+ padding: 16px;
26
+
27
+ li
28
+ {
29
+ margin: 0;
30
+ line-height: 20px;
31
+ }
32
+ }
33
+ }
34
+ .main-actions
35
+ {
36
+ display: inline-block;
37
+ width: 100%;
38
+ //text-align: center;
39
+ .button.button-smaller
40
+ {
41
+ //float: none;
42
+ padding: 6px 15px;
43
+ height: auto;
44
+ float: none;
45
+ }
46
+ }
47
+
48
+ } // view-edit-media
shortpixel_api.php CHANGED
@@ -467,6 +467,8 @@ class ShortPixelAPI {
467
  return array("Status" => self::STATUS_SUCCESS);
468
  }
469
 
 
 
470
  //$fullSubDir = str_replace(wp_normalize_path(get_home_path()), "", wp_normalize_path(dirname($itemHandler->getMeta()->getPath()))) . '/';
471
  //$SubDir = ShortPixelMetaFacade::returnSubDir($itemHandler->getMeta()->getPath(), $itemHandler->getType());
472
  $fullSubDir = ShortPixelMetaFacade::returnSubDir($mainPath);
467
  return array("Status" => self::STATUS_SUCCESS);
468
  }
469
 
470
+ Log::addDebug('Backing The Up', array($mainPath, $PATHs));
471
+
472
  //$fullSubDir = str_replace(wp_normalize_path(get_home_path()), "", wp_normalize_path(dirname($itemHandler->getMeta()->getPath()))) . '/';
473
  //$SubDir = ShortPixelMetaFacade::returnSubDir($itemHandler->getMeta()->getPath(), $itemHandler->getType());
474
  $fullSubDir = ShortPixelMetaFacade::returnSubDir($mainPath);
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="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: 4.14.5
7
  * Author: ShortPixel
8
  * Author URI: https://shortpixel.com
9
  * Text Domain: shortpixel-image-optimiser
@@ -19,7 +19,7 @@ define('SHORTPIXEL_PLUGIN_DIR', __DIR__);
19
 
20
  //define('SHORTPIXEL_AFFILIATE_CODE', '');
21
 
22
- define('SHORTPIXEL_IMAGE_OPTIMISER_VERSION', "4.14.5");
23
  define('SHORTPIXEL_MAX_TIMEOUT', 10);
24
  define('SHORTPIXEL_VALIDATE_MAX_TIMEOUT', 15);
25
  define('SHORTPIXEL_BACKUP', 'ShortpixelBackups');
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="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: 4.14.6
7
  * Author: ShortPixel
8
  * Author URI: https://shortpixel.com
9
  * Text Domain: shortpixel-image-optimiser
19
 
20
  //define('SHORTPIXEL_AFFILIATE_CODE', '');
21
 
22
+ define('SHORTPIXEL_IMAGE_OPTIMISER_VERSION', "4.14.6");
23
  define('SHORTPIXEL_MAX_TIMEOUT', 10);
24
  define('SHORTPIXEL_VALIDATE_MAX_TIMEOUT', 15);
25
  define('SHORTPIXEL_BACKUP', 'ShortpixelBackups');