ShortPixel Image Optimizer - Version 3.1.9

Version Description

  • option to keep the EXIF data and ICC profile.
  • more explanations on settings. *
Download this release

Release Info

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

Code changes from version 3.1.8 to 3.1.9

js/short-pixel.js CHANGED
@@ -106,7 +106,7 @@ function checkQuotaExceededAlert() {
106
  * calls itself until receives an Empty queue message
107
  */
108
  function checkBulkProgress() {
109
- if(window.location.href.search("wp-admin/upload.php") < 0
110
  && window.location.href.search("wp-admin/edit.php") < 0
111
  && window.location.href.search("wp-admin/edit-tags.php") < 0
112
  && window.location.href.search("wp-admin/post-new.php") < 0
@@ -201,7 +201,7 @@ function checkBulkProcessingCallApi(){
201
  case ShortPixel.STATUS_SUCCESS:
202
  var percent = data["PercentImprovement"];
203
  var cellMsg = "Reduced by <span class='percent'>" + percent + "%</span> "
204
- + (data["BackupEnabled"] == 1 ? "| <a href=\"admin.php?action=shortpixel_restore_backup&attachment_ID=" + id + ")\">Restore backup</a>" : "");
205
  if(0 + data['ThumbsCount'] > 0) {
206
  cellMsg += "<br>+" + data['ThumbsCount'] + " thumbnails optimized";
207
  }
106
  * calls itself until receives an Empty queue message
107
  */
108
  function checkBulkProgress() {
109
+ if( window.location.href.search("wp-admin/upload.php") < 0
110
  && window.location.href.search("wp-admin/edit.php") < 0
111
  && window.location.href.search("wp-admin/edit-tags.php") < 0
112
  && window.location.href.search("wp-admin/post-new.php") < 0
201
  case ShortPixel.STATUS_SUCCESS:
202
  var percent = data["PercentImprovement"];
203
  var cellMsg = "Reduced by <span class='percent'>" + percent + "%</span> "
204
+ + (data["BackupEnabled"] == 1 ? "<a class='button button-smaller' href=\"admin.php?action=shortpixel_restore_backup&attachment_ID=" + id + ")\">Restore backup</a>" : "");
205
  if(0 + data['ThumbsCount'] > 0) {
206
  cellMsg += "<br>+" + data['ThumbsCount'] + " thumbnails optimized";
207
  }
readme.txt CHANGED
@@ -3,9 +3,9 @@
3
  Contributors: AlexSP
4
  Tags: picture, optimization, image editor, pngout, upload speed, shortpixel, compression, jpegmini, webp, lossless, cwebp, media, jpegtran, image, image optimisation, image optimization, shrink, picture, photo, optimize photos, compress, performance, tinypng, crunch, pngquant, attachment, optimize, pictures, fast, images, image files, image quality, lossy, upload, kraken, resize, seo, smushit, optipng, kraken image optimizer, ewww, photo optimization, gifsicle, image optimizer, images, krakenio, png, gmagick, image optimize, pdf, pdf optimisation, pdf optimization, optimize pdf, optimise pdf, shrink pdf, jpg, jpeg, jpg optimisation, jpg optimization, optimize jpg, optimise jpg, shrink jpg, gif, animated gif, optimize gif, optimise gif, optimizer, optimiser, compresion, optimization, cruncher, image cruncher, compress png, compress jpg, compress jpeg, compress pdf, faster loading times, image optimiser, improve pagerank, optimise, optimize animated gif, optimise jpeg, optimize jpeg, optimize png, optimise png, optimise pdf, optimize pdf, tinyjpg, short pixel, shortpixel, woocommerce compatible
5
 
6
- Requires at least: 3.0.1
7
  Tested up to: 4.4
8
- Stable tag: 3.1.8
9
  License: GPLv2 or later
10
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
11
 
@@ -168,6 +168,12 @@ The ShortPixel team is here to help. <a href="https://shortpixel.com/contact">Co
168
 
169
  == Changelog ==
170
 
 
 
 
 
 
 
171
  = 3.1.8 =
172
 
173
  * fix reloading bulk page on quota used up
3
  Contributors: AlexSP
4
  Tags: picture, optimization, image editor, pngout, upload speed, shortpixel, compression, jpegmini, webp, lossless, cwebp, media, jpegtran, image, image optimisation, image optimization, shrink, picture, photo, optimize photos, compress, performance, tinypng, crunch, pngquant, attachment, optimize, pictures, fast, images, image files, image quality, lossy, upload, kraken, resize, seo, smushit, optipng, kraken image optimizer, ewww, photo optimization, gifsicle, image optimizer, images, krakenio, png, gmagick, image optimize, pdf, pdf optimisation, pdf optimization, optimize pdf, optimise pdf, shrink pdf, jpg, jpeg, jpg optimisation, jpg optimization, optimize jpg, optimise jpg, shrink jpg, gif, animated gif, optimize gif, optimise gif, optimizer, optimiser, compresion, optimization, cruncher, image cruncher, compress png, compress jpg, compress jpeg, compress pdf, faster loading times, image optimiser, improve pagerank, optimise, optimize animated gif, optimise jpeg, optimize jpeg, optimize png, optimise png, optimise pdf, optimize pdf, tinyjpg, short pixel, shortpixel, woocommerce compatible
5
 
6
+ Requires at least: 3.2.0
7
  Tested up to: 4.4
8
+ Stable tag: 3.1.9
9
  License: GPLv2 or later
10
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
11
 
168
 
169
  == Changelog ==
170
 
171
+ = 3.1.9 =
172
+
173
+ * option to keep the EXIF data and ICC profile.
174
+ * more explanations on settings.
175
+ *
176
+
177
  = 3.1.8 =
178
 
179
  * fix reloading bulk page on quota used up
shortpixel_api.php CHANGED
@@ -1,444 +1,421 @@
1
- <?php
2
- if ( !function_exists( 'download_url' ) ) {
3
- require_once( ABSPATH . 'wp-admin/includes/file.php' );
4
- }
5
-
6
- class ShortPixelAPI {
7
-
8
- const STATUS_SUCCESS = 1;
9
- const STATUS_UNCHANGED = 0;
10
- const STATUS_ERROR = -1;
11
- const STATUS_FAIL = -2;
12
- const STATUS_QUOTA_EXCEEDED = -3;
13
- const STATUS_SKIP = -4;
14
- const STATUS_NOT_FOUND = -5;
15
- const STATUS_NO_KEY = -6;
16
- const STATUS_RETRY = -7;
17
-
18
- private $_apiKey = '';
19
- private $_compressionType = '';
20
- private $_CMYKtoRGBconversion = '';
21
- private $_maxAttempts = 10;
22
- private $_apiEndPoint = 'https://api.shortpixel.com/v2/reducer.php';
23
- private $_resizeImages;
24
- private $_resizeWidth;
25
- private $_resizeHeight;
26
-
27
- public function setCompressionType($compressionType) {
28
- $this->_compressionType = $compressionType;
29
- }
30
-
31
- public function setCMYKtoRGB($CMYK2RGB) {
32
- $this->_CMYKtoRGBconversion = $CMYK2RGB;
33
- }
34
- public function getCompressionType() {
35
- return $this->_compressionType;
36
- }
37
-
38
- public function setApiKey($apiKey) {
39
- $this->_apiKey = $apiKey;
40
- }
41
-
42
- public function getApiKey() {
43
- return $this->_apiKey;
44
- }
45
-
46
- public function __construct($apiKey, $compressionType, $CMYK2RGB, $resize, $width, $height) {
47
- $this->_apiKey = $apiKey;
48
- $this->setCompressionType($compressionType);
49
- $this->setCMYKtoRGB($CMYK2RGB);
50
- $this->_resizeImages = $resize;
51
- $this->_resizeWidth = $width;
52
- $this->_resizeHeight = $height;
53
- add_action('processImageAction', array(&$this, 'processImageAction'), 10, 4);
54
- }
55
-
56
- public function processImageAction($url, $filePaths, $ID, $time) {
57
- $this->processImage($URLs, $PATHs, $ID, $time);
58
- }
59
-
60
- public function doRequests($URLs, $Blocking, $ID) {
61
-
62
- $requestParameters = array(
63
- 'plugin_version' => PLUGIN_VERSION,
64
- 'key' => $this->_apiKey,
65
- 'lossy' => $this->_compressionType,
66
- 'cmyk2rgb' => $this->_CMYKtoRGBconversion,
67
- 'resize' => $this->_resizeImages,
68
- 'resize_width' => $this->_resizeWidth,
69
- 'resize_height' => $this->_resizeHeight,
70
- 'urllist' => $URLs
71
- );
72
- $arguments = array(
73
- 'method' => 'POST',
74
- 'timeout' => 45,
75
- 'redirection' => 3,
76
- 'sslverify' => false,
77
- 'httpversion' => '1.0',
78
- 'blocking' => $Blocking,
79
- 'headers' => array(),
80
- 'body' => json_encode($requestParameters),
81
- 'cookies' => array()
82
- );
83
-
84
- $response = wp_remote_post($this->_apiEndPoint, $arguments );
85
-
86
- //only if $Blocking is true analyze the response
87
- if ( $Blocking )
88
- {
89
- //there was an error, save this error inside file's SP optimization field
90
- if ( is_object($response) && get_class($response) == 'WP_Error' )
91
- {
92
- $errorMessage = $response->errors['http_request_failed'][0];
93
- $errorCode = 503;
94
- }
95
- elseif ( isset($response['response']['code']) && $response['response']['code'] <> 200 )
96
- {
97
- $errorMessage = $response['response']['code'] . " - " . $response['response']['message'];
98
- $errorCode = $response['response']['code'];
99
- }
100
-
101
- if ( isset($errorMessage) )
102
- {//set details inside file so user can know what happened
103
- $meta = wp_get_attachment_metadata($ID);
104
- $meta['ShortPixelImprovement'] = 'Error: <i>' . $errorMessage . '</i>';
105
- unset($meta['ShortPixel']['WaitingProcessing']);
106
- wp_update_attachment_metadata($ID, $meta);
107
- return array("response" => array("code" => $errorCode, "message" => $errorMessage ));
108
- }
109
-
110
- return $response;//this can be an error or a good response
111
- }
112
-
113
- return $response;
114
- }
115
-
116
- public function parseResponse($response) {
117
- $data = $response['body'];
118
- $data = $this->parseJSON($data);
119
- return (array)$data;
120
- }
121
-
122
- //handles the processing of the image using the ShortPixel API
123
- public function processImage($URLs, $PATHs, $ID = null, $startTime = 0)
124
- {
125
-
126
- $PATHs = self::CheckAndFixImagePaths($PATHs);//check for images to make sure they exist on disk
127
- if ( $PATHs === false )
128
- return array("Status" => self::STATUS_SKIP, "Message" => 'The file(s) do not exist on disk, Image #$ID');
129
-
130
- //tries multiple times (till timeout almost reached) to fetch images.
131
- if($startTime == 0) {
132
- $startTime = time();
133
- }
134
- $apiRetries = get_option('wp-short-pixel-api-retries');
135
- if( time() - $startTime > MAX_EXECUTION_TIME)
136
- {//keeps track of time
137
- if ( $apiRetries > MAX_API_RETRIES )//we tried to process this time too many times, giving up...
138
- {
139
- $meta = wp_get_attachment_metadata($ID);
140
- $meta['ShortPixelImprovement'] = 'Timed out while processing.';
141
- unset($meta['ShortPixel']['WaitingProcessing']);
142
- update_option('wp-short-pixel-api-retries', 0);//fai added to solve a bug?
143
- wp_update_attachment_metadata($ID, $meta);
144
- return array("Status" => self::STATUS_SKIP, "Message" => 'Skip this image, tries the next one.');
145
- }
146
- else
147
- {//we'll try again next time user visits a page on admin panel
148
- $apiRetries++;
149
- update_option('wp-short-pixel-api-retries', $apiRetries);
150
- return array("Status" => self::STATUS_RETRY, "Message" => 'Timed out while processing. (pass '.$apiRetries.')');
151
- }
152
- }
153
- $response = $this->doRequests($URLs, true, $ID);//send requests to API
154
-
155
- if($response['response']['code'] != 200)//response <> 200 -> there was an error apparently?
156
- return array("Status" => self::STATUS_FAIL, "Message" => "There was an error and your request was not processed.");
157
-
158
- $APIresponse = $this->parseResponse($response);//get the actual response from API, its an array
159
-
160
- if ( isset($APIresponse[0]) )//API returned image details
161
- {
162
- foreach ( $APIresponse as $imageObject )//this part makes sure that all the sizes were processed and ready to be downloaded
163
- {
164
- if ( $imageObject->Status->Code == 0 || $imageObject->Status->Code == 1 )
165
- {
166
- sleep(1);
167
- return $this->processImage($URLs, $PATHs, $ID, $startTime);
168
- }
169
- }
170
-
171
- $firstImage = $APIresponse[0];//extract as object first image
172
- switch($firstImage->Status->Code)
173
- {
174
- case 2:
175
- //handle image has been processed
176
- update_option( 'wp-short-pixel-quota-exceeded', 0);//reset the quota exceeded flag
177
- return $this->handleSuccess($APIresponse, $URLs, $PATHs, $ID);
178
- break;
179
- default:
180
- //handle error
181
- if ( !file_exists($PATHs[0]) )
182
- return array("Status" => self::STATUS_NOT_FOUND, "Message" => "File not found on disk.");
183
- elseif ( isset($APIresponse[0]->Status->Message) )
184
- return array("Status" => self::STATUS_FAIL, "Message" => "There was an error and your request was not processed (" . $APIresponse[0]->Status->Message . ").");
185
-
186
- return array("Status" => self::STATUS_FAIL, "Message" => "There was an error and your request was not processed");
187
- break;
188
- }
189
- }
190
-
191
- switch($APIresponse['Status']->Code)
192
- {
193
-
194
- case -403:
195
- @delete_option('bulkProcessingStatus');
196
- update_option( 'wp-short-pixel-quota-exceeded', 1);
197
- return array("Status" => self::STATUS_QUOTA_EXCEEDED, "Message" => "Quota exceeded.");
198
- break;
199
- }
200
-
201
- //sometimes the response array can be different
202
- if ( is_numeric($APIresponse['Status']->Code) )
203
- return array("Status" => self::STATUS_FAIL, "Message" => $APIresponse['Status']->Message);
204
- else
205
- return array("Status" => self::STATUS_FAIL, "Message" => $APIresponse[0]->Status->Message);
206
-
207
- }
208
-
209
- public function handleDownload($fileData,$counter){
210
- //var_dump($fileData);
211
- if($this->_compressionType)
212
- {
213
- $fileType = "LossyURL";
214
- $fileSize = "LossySize";
215
- }
216
- else
217
- {
218
- $fileType = "LosslessURL";
219
- $fileSize = "LoselessSize";
220
- }
221
-
222
- //if there is no improvement in size then we do not download this file
223
- if ( $fileData->OriginalSize == $fileData->$fileSize )
224
- return array("Status" => self::STATUS_UNCHANGED, "Message" => "File wasn't optimized so we do not download it.");
225
-
226
- $correctFileSize = $fileData->$fileSize;
227
- $tempFiles[$counter] = download_url(urldecode($fileData->$fileType));
228
- //var_dump($tempFiles);
229
-
230
- if(is_wp_error( $tempFiles[$counter] )) //also tries with http instead of https
231
- {
232
- $tempFiles[$counter] = download_url(str_replace('http://', 'https://', urldecode($fileData->$fileType)));
233
- }
234
- //on success we return this
235
- $returnMessage = array("Status" => self::STATUS_SUCCESS, "Message" => $tempFiles[$counter]);
236
-
237
- if ( is_wp_error( $tempFiles[$counter] ) ) {
238
- @unlink($tempFiles[$counter]);
239
- $returnMessage = array(
240
- "Status" => self::STATUS_ERROR,
241
- "Message" => "Error downloading file ({$fileData->$fileType}) " . $tempFiles[$counter]->get_error_message());
242
- }
243
- //check response so that download is OK
244
- elseif( filesize($tempFiles[$counter]) != $correctFileSize) {
245
- $size = filesize($tempFiles[$counter]);
246
- @unlink($tempFiles[$counter]);
247
- $returnMessage = array(
248
- "Status" => self::STATUS_ERROR,
249
- "Message" => "Error downloading file - incorrect file size (downloaded: {$size}, correct: {$correctFileSize} )");
250
- }
251
- elseif (!file_exists($tempFiles[$counter])) {
252
- $returnMessage = array("Status" => self::STATUS_ERROR, "Message" => "Unable to locate downloaded file " . $tempFiles[$counter]);
253
- }
254
- return $returnMessage;
255
- }
256
-
257
- public function handleSuccess($APIresponse, $URLs, $PATHs, $ID) {
258
- $counter = $savedSpace = $originalSpace = $optimizedSpace = $averageCompression = 0;
259
-
260
- //download each file from array and process it
261
- foreach ( $APIresponse as $fileData )
262
- {
263
- if ( $fileData->Status->Code == 2 ) //file was processed OK
264
- {
265
- if ( $counter == 0 )//save percent improvement for main file
266
- $percentImprovement = $fileData->PercentImprovement;
267
- else //count thumbnails only
268
- update_option( 'wp-short-pixel-thumbnail-count', get_option('wp-short-pixel-thumbnail-count') + 1 );
269
- $downloadResult = $this->handleDownload($fileData,$counter);
270
- //when the status is STATUS_UNCHANGED we just skip the array line for that one
271
- if ( $downloadResult['Status'] == self::STATUS_SUCCESS ) {
272
- $tempFiles[$counter] = $downloadResult['Message'];
273
- }
274
- elseif ( $downloadResult['Status'] <> self::STATUS_UNCHANGED )
275
- return array("Status" => $downloadResult['Status'], "Message" => $downloadResult['Message']);
276
- }
277
- else //there was an error while trying to download a file
278
- $tempFiles[$counter] = "";
279
-
280
- $counter++;
281
- }
282
-
283
- //figure out in what SubDir files should land
284
- $SubDir = $this->returnSubDir(get_attached_file($ID));
285
-
286
- //if backup is enabled - we try to save the images
287
- if( get_option('wp-short-backup_images') )
288
- {
289
- $uploadDir = wp_upload_dir();
290
- $source = $PATHs;//array with final paths for this files
291
-
292
- if( !file_exists(SP_BACKUP_FOLDER) && !@mkdir(SP_BACKUP_FOLDER, 0777, true) ) {//creates backup folder if it doesn't exist
293
- return array("Status" => self::STATUS_FAIL, "Message" => "Backup folder does not exist and it cannot be created");
294
- }
295
- //create subdir in backup folder if needed
296
- @mkdir( SP_BACKUP_FOLDER . DIRECTORY_SEPARATOR . $SubDir, 0777, true);
297
-
298
- foreach ( $source as $fileID => $filePATH )//create destination files array
299
- {
300
- $destination[$fileID] = SP_BACKUP_FOLDER . DIRECTORY_SEPARATOR . $SubDir . self::MB_basename($source[$fileID]);
301
- }
302
-
303
- //now that we have original files and where we should back them up we attempt to do just that
304
- if(is_writable(SP_BACKUP_FOLDER))
305
- {
306
- foreach ( $destination as $fileID => $filePATH )
307
- {
308
- if ( !file_exists($filePATH) )
309
- {
310
- if ( !@copy($source[$fileID], $destination[$fileID]) )
311
- {//file couldn't have been saved in backup folder
312
- ShortPixelAPI::SaveMessageinMetadata($ID, 'Cannot save file <i>' . self::MB_basename($source[$fileID]) . '</i> in backup directory');
313
- return array("Status" => self::STATUS_FAIL, "Message" => 'Cannot save file <i>' . self::MB_basename($source[$fileID]) . '</i> in backup directory');
314
- }
315
- }
316
- }
317
- } else {//cannot write to the backup dir, return with an error
318
- ShortPixelAPI::SaveMessageinMetadata($ID, 'Cannot save file in backup directory');
319
- return array("Status" => self::STATUS_FAIL, "Message" => 'Cannot save file in backup directory');
320
- }
321
-
322
- }//end backup section
323
-
324
-
325
- $writeFailed = 0;
326
-
327
- if ( !empty($tempFiles) )
328
- {
329
- //overwrite the original files with the optimized ones
330
- foreach ( $tempFiles as $tempFileID => $tempFilePATH )
331
- {
332
- if ( file_exists($tempFilePATH) && file_exists($PATHs[$tempFileID]) && is_writable($PATHs[$tempFileID]) ) {
333
- copy($tempFilePATH, $PATHs[$tempFileID]);
334
- } else {
335
- $writeFailed++;
336
- }
337
- @unlink($tempFilePATH);
338
-
339
- if ( $writeFailed > 0 )//there was an error
340
- {
341
- ShortPixelAPI::SaveMessageinMetadata($ID, 'Error: optimized version of ' . $writeFailed . ' file(s) couldn\'t be updated.');
342
- update_option('bulkProcessingStatus', "error");
343
- return array("Status" => self::STATUS_FAIL, "Code" =>"write-fail", "Message" => 'Error: optimized version of ' . $writeFailed . ' file(s) couldn\'t be updated.');
344
- }
345
- else
346
- {//all files were copied, optimization data regarding the savings locally in DB
347
- $fileType = ( $this->_compressionType ) ? "LossySize" : "LoselessSize";
348
- $savedSpace += $APIresponse[$tempFileID]->OriginalSize - $APIresponse[$tempFileID]->$fileType;
349
- $originalSpace += $APIresponse[$tempFileID]->OriginalSize;
350
- $optimizedSpace += $APIresponse[$tempFileID]->$fileType;
351
- $averageCompression += $fileData->PercentImprovement;
352
-
353
- //add the number of files with < 5% optimization
354
- if ( ( ( 1 - $APIresponse[$tempFileID]->$fileType/$APIresponse[$tempFileID]->OriginalSize ) * 100 ) < 5 )
355
- update_option( 'wp-short-pixel-files-under-5-percent', get_option('wp-short-pixel-files-under-5-percent') + 1);
356
-
357
- }
358
- }
359
- }
360
- //old average counting
361
- update_option('wp-short-pixel-savedSpace', get_option('wp-short-pixel-savedSpace') + $savedSpace);
362
- $averageCompression = get_option('wp-short-pixel-averageCompression') * get_option('wp-short-pixel-fileCount');
363
- $averageCompression = $averageCompression / (get_option('wp-short-pixel-fileCount') + count($APIresponse));
364
- update_option('wp-short-pixel-averageCompression', $averageCompression);
365
- update_option('wp-short-pixel-fileCount', get_option('wp-short-pixel-fileCount') + count($APIresponse));
366
- //new average counting
367
- update_option('wp-short-pixel-total-original', get_option('wp-short-pixel-total-original') + $originalSpace);
368
- update_option('wp-short-pixel-total-optimized', get_option('wp-short-pixel-total-optimized') + $optimizedSpace);
369
- //update metadata for this file
370
- $meta = wp_get_attachment_metadata($ID);
371
- $meta['ShortPixelImprovement'] = round($percentImprovement,2);
372
- wp_update_attachment_metadata($ID, $meta);
373
- //we reset the retry counter in case of success
374
- update_option('wp-short-pixel-api-retries', 0);
375
-
376
- return array("Status" => self::STATUS_SUCCESS, "Message" => 'Success: No pixels remained unsqueezed :-)', "PercentImprovement" => $percentImprovement);
377
- }//end handleSuccess
378
-
379
- static public function returnSubDir($file)//return subdir for that particular attached file
380
- {
381
- $Atoms = explode("/", $file);
382
- $Counter = count($Atoms);
383
- $SubDir = $Atoms[$Counter-3] . DIRECTORY_SEPARATOR . $Atoms[$Counter-2] . DIRECTORY_SEPARATOR;
384
-
385
- return $SubDir;
386
- }
387
-
388
- //a basename alternative that deals OK with multibyte charsets (e.g. Arabic)
389
- static public function MB_basename($Path){
390
- $Separator = " qq ";
391
- $Path = preg_replace("/[^ ]/u", $Separator."\$0".$Separator, $Path);
392
- $Base = basename($Path);
393
- $Base = str_replace($Separator, "", $Base);
394
- return $Base;
395
- }
396
-
397
- //sometimes, the paths to the files as defined in metadata are wrong, we try to automatically correct them
398
- static public function CheckAndFixImagePaths($PATHs){
399
-
400
- $ErrorCount = 0;
401
- $uploadDir = wp_upload_dir();
402
- $Tmp = explode("/", $uploadDir['basedir']);
403
- $TmpCount = count($Tmp);
404
- $StichString = $Tmp[$TmpCount-2] . "/" . $Tmp[$TmpCount-1];
405
- //files exist on disk?
406
- foreach ( $PATHs as $Id => $File )
407
- {
408
- //we try again with a different path
409
- if ( !file_exists($File) ){
410
- $NewFile = $uploadDir['basedir'] . substr($File,strpos($File, $StichString)+strlen($StichString));
411
- if ( file_exists($NewFile) )
412
- $PATHs[$Id] = $NewFile;
413
- else
414
- $ErrorCount++;
415
- }
416
- }
417
-
418
- if ( $ErrorCount > 0 )
419
- return false;
420
- else
421
- return $PATHs;
422
-
423
- }
424
-
425
-
426
- static private function SaveMessageinMetadata($ID, $Message)
427
- {
428
- $meta = wp_get_attachment_metadata($ID);
429
- $meta['ShortPixelImprovement'] = $Message;
430
- unset($meta['ShortPixel']['WaitingProcessing']);
431
- wp_update_attachment_metadata($ID, $meta);
432
- }
433
-
434
- public function parseJSON($data) {
435
- if ( function_exists('json_decode') ) {
436
- $data = json_decode( $data );
437
- } else {
438
- require_once( 'JSON/JSON.php' );
439
- $json = new Services_JSON( );
440
- $data = $json->decode( $data );
441
- }
442
- return $data;
443
- }
444
- }
1
+ <?php
2
+ if ( !function_exists( 'download_url' ) ) {
3
+ require_once( ABSPATH . 'wp-admin/includes/file.php' );
4
+ }
5
+
6
+ class ShortPixelAPI {
7
+
8
+ const STATUS_SUCCESS = 1;
9
+ const STATUS_UNCHANGED = 0;
10
+ const STATUS_ERROR = -1;
11
+ const STATUS_FAIL = -2;
12
+ const STATUS_QUOTA_EXCEEDED = -3;
13
+ const STATUS_SKIP = -4;
14
+ const STATUS_NOT_FOUND = -5;
15
+ const STATUS_NO_KEY = -6;
16
+ const STATUS_RETRY = -7;
17
+
18
+ private $_settings;
19
+ private $_maxAttempts = 10;
20
+ private $_apiEndPoint = 'https://api.shortpixel.com/v2/reducer_dev.php';
21
+
22
+
23
+ public function __construct($settings) {
24
+ $this->_settings = $settings;
25
+ add_action('processImageAction', array(&$this, 'processImageAction'), 10, 4);
26
+ }
27
+
28
+ public function processImageAction($url, $filePaths, $ID, $time) {
29
+ $this->processImage($URLs, $PATHs, $ID, $time);
30
+ }
31
+
32
+ public function doRequests($URLs, $Blocking, $ID) {
33
+
34
+ $requestParameters = array(
35
+ 'plugin_version' => PLUGIN_VERSION,
36
+ 'key' => $this->_settings->apiKey,
37
+ 'lossy' => $this->_settings->compressionType,
38
+ 'cmyk2rgb' => $this->_settings->CMYKtoRGBconversion,
39
+ 'keep_exif' => ($this->_settings->keepExif ? "1" : "0"),
40
+ 'resize' => $this->_settings->resizeImages,
41
+ 'resize_width' => $this->_settings->resizeWidth,
42
+ 'resize_height' => $this->_settings->resizeHeight,
43
+ 'urllist' => $URLs
44
+ );
45
+ $arguments = array(
46
+ 'method' => 'POST',
47
+ 'timeout' => 45,
48
+ 'redirection' => 3,
49
+ 'sslverify' => false,
50
+ 'httpversion' => '1.0',
51
+ 'blocking' => $Blocking,
52
+ 'headers' => array(),
53
+ 'body' => json_encode($requestParameters),
54
+ 'cookies' => array()
55
+ );
56
+ //echo("URL:".$this->_apiEndPoint."ARGUMENTS:");var_dump($arguments);
57
+ $response = wp_remote_post($this->_apiEndPoint, $arguments );
58
+ //echo("RESPONSE:"); var_dump($response);
59
+
60
+ //only if $Blocking is true analyze the response
61
+ if ( $Blocking )
62
+ {
63
+ //there was an error, save this error inside file's SP optimization field
64
+ if ( is_object($response) && get_class($response) == 'WP_Error' )
65
+ {
66
+ $errorMessage = $response->errors['http_request_failed'][0];
67
+ $errorCode = 503;
68
+ }
69
+ elseif ( isset($response['response']['code']) && $response['response']['code'] <> 200 )
70
+ {
71
+ $errorMessage = $response['response']['code'] . " - " . $response['response']['message'];
72
+ $errorCode = $response['response']['code'];
73
+ }
74
+
75
+ if ( isset($errorMessage) )
76
+ {//set details inside file so user can know what happened
77
+ $meta = wp_get_attachment_metadata($ID);
78
+ $meta['ShortPixelImprovement'] = 'Error: <i>' . $errorMessage . '</i>';
79
+ unset($meta['ShortPixel']['WaitingProcessing']);
80
+ wp_update_attachment_metadata($ID, $meta);
81
+ return array("response" => array("code" => $errorCode, "message" => $errorMessage ));
82
+ }
83
+
84
+ return $response;//this can be an error or a good response
85
+ }
86
+
87
+ return $response;
88
+ }
89
+
90
+ public function parseResponse($response) {
91
+ $data = $response['body'];
92
+ $data = $this->parseJSON($data);
93
+ return (array)$data;
94
+ }
95
+
96
+ //handles the processing of the image using the ShortPixel API
97
+ public function processImage($URLs, $PATHs, $ID = null, $startTime = 0)
98
+ {
99
+
100
+ $PATHs = self::CheckAndFixImagePaths($PATHs);//check for images to make sure they exist on disk
101
+ if ( $PATHs === false )
102
+ return array("Status" => self::STATUS_SKIP, "Message" => 'The file(s) do not exist on disk, Image ID: ' .$ID);
103
+
104
+ //tries multiple times (till timeout almost reached) to fetch images.
105
+ if($startTime == 0) {
106
+ $startTime = time();
107
+ }
108
+ $apiRetries = get_option('wp-short-pixel-api-retries');
109
+ if( time() - $startTime > MAX_EXECUTION_TIME)
110
+ {//keeps track of time
111
+ if ( $apiRetries > MAX_API_RETRIES )//we tried to process this time too many times, giving up...
112
+ {
113
+ $meta = wp_get_attachment_metadata($ID);
114
+ $meta['ShortPixelImprovement'] = 'Timed out while processing.';
115
+ unset($meta['ShortPixel']['WaitingProcessing']);
116
+ update_option('wp-short-pixel-api-retries', 0);//fai added to solve a bug?
117
+ wp_update_attachment_metadata($ID, $meta);
118
+ return array("Status" => self::STATUS_SKIP, "Message" => 'Skip this image, tries the next one.');
119
+ }
120
+ else
121
+ {//we'll try again next time user visits a page on admin panel
122
+ $apiRetries++;
123
+ update_option('wp-short-pixel-api-retries', $apiRetries);
124
+ return array("Status" => self::STATUS_RETRY, "Message" => 'Timed out while processing. (pass '.$apiRetries.')');
125
+ }
126
+ }
127
+ $response = $this->doRequests($URLs, true, $ID);//send requests to API
128
+
129
+ if($response['response']['code'] != 200)//response <> 200 -> there was an error apparently?
130
+ return array("Status" => self::STATUS_FAIL, "Message" => "There was an error and your request was not processed.");
131
+
132
+ $APIresponse = $this->parseResponse($response);//get the actual response from API, its an array
133
+
134
+ if ( isset($APIresponse[0]) )//API returned image details
135
+ {
136
+ foreach ( $APIresponse as $imageObject )//this part makes sure that all the sizes were processed and ready to be downloaded
137
+ {
138
+ if ( $imageObject->Status->Code == 0 || $imageObject->Status->Code == 1 )
139
+ {
140
+ sleep(1);
141
+ return $this->processImage($URLs, $PATHs, $ID, $startTime);
142
+ }
143
+ }
144
+
145
+ $firstImage = $APIresponse[0];//extract as object first image
146
+ switch($firstImage->Status->Code)
147
+ {
148
+ case 2:
149
+ //handle image has been processed
150
+ update_option( 'wp-short-pixel-quota-exceeded', 0);//reset the quota exceeded flag
151
+ return $this->handleSuccess($APIresponse, $URLs, $PATHs, $ID);
152
+ break;
153
+ default:
154
+ //handle error
155
+ if ( !file_exists($PATHs[0]) )
156
+ return array("Status" => self::STATUS_NOT_FOUND, "Message" => "File not found on disk.");
157
+ elseif ( isset($APIresponse[0]->Status->Message) )
158
+ return array("Status" => self::STATUS_FAIL, "Message" => "There was an error and your request was not processed (" . $APIresponse[0]->Status->Message . ").");
159
+
160
+ return array("Status" => self::STATUS_FAIL, "Message" => "There was an error and your request was not processed");
161
+ break;
162
+ }
163
+ }
164
+
165
+ switch($APIresponse['Status']->Code)
166
+ {
167
+
168
+ case -403:
169
+ @delete_option('bulkProcessingStatus');
170
+ update_option( 'wp-short-pixel-quota-exceeded', 1);
171
+ return array("Status" => self::STATUS_QUOTA_EXCEEDED, "Message" => "Quota exceeded.");
172
+ break;
173
+ }
174
+
175
+ //sometimes the response array can be different
176
+ if ( is_numeric($APIresponse['Status']->Code) )
177
+ return array("Status" => self::STATUS_FAIL, "Message" => $APIresponse['Status']->Message);
178
+ else
179
+ return array("Status" => self::STATUS_FAIL, "Message" => $APIresponse[0]->Status->Message);
180
+
181
+ }
182
+
183
+ public function handleDownload($fileData,$counter){
184
+ //var_dump($fileData);
185
+ if($this->_settings->compressionType)
186
+ {
187
+ $fileType = "LossyURL";
188
+ $fileSize = "LossySize";
189
+ }
190
+ else
191
+ {
192
+ $fileType = "LosslessURL";
193
+ $fileSize = "LoselessSize";
194
+ }
195
+
196
+ //if there is no improvement in size then we do not download this file
197
+ if ( $fileData->OriginalSize == $fileData->$fileSize )
198
+ return array("Status" => self::STATUS_UNCHANGED, "Message" => "File wasn't optimized so we do not download it.");
199
+
200
+ $correctFileSize = $fileData->$fileSize;
201
+ $tempFiles[$counter] = download_url(urldecode($fileData->$fileType));
202
+ //var_dump($tempFiles);
203
+
204
+ if(is_wp_error( $tempFiles[$counter] )) //also tries with http instead of https
205
+ {
206
+ $tempFiles[$counter] = download_url(str_replace('http://', 'https://', urldecode($fileData->$fileType)));
207
+ }
208
+ //on success we return this
209
+ $returnMessage = array("Status" => self::STATUS_SUCCESS, "Message" => $tempFiles[$counter]);
210
+
211
+ if ( is_wp_error( $tempFiles[$counter] ) ) {
212
+ @unlink($tempFiles[$counter]);
213
+ $returnMessage = array(
214
+ "Status" => self::STATUS_ERROR,
215
+ "Message" => "Error downloading file ({$fileData->$fileType}) " . $tempFiles[$counter]->get_error_message());
216
+ }
217
+ //check response so that download is OK
218
+ elseif( filesize($tempFiles[$counter]) != $correctFileSize) {
219
+ $size = filesize($tempFiles[$counter]);
220
+ @unlink($tempFiles[$counter]);
221
+ $returnMessage = array(
222
+ "Status" => self::STATUS_ERROR,
223
+ "Message" => "Error downloading file - incorrect file size (downloaded: {$size}, correct: {$correctFileSize} )");
224
+ }
225
+ elseif (!file_exists($tempFiles[$counter])) {
226
+ $returnMessage = array("Status" => self::STATUS_ERROR, "Message" => "Unable to locate downloaded file " . $tempFiles[$counter]);
227
+ }
228
+ return $returnMessage;
229
+ }
230
+
231
+ public function handleSuccess($APIresponse, $URLs, $PATHs, $ID) {
232
+ $counter = $savedSpace = $originalSpace = $optimizedSpace = $averageCompression = 0;
233
+
234
+ //download each file from array and process it
235
+ foreach ( $APIresponse as $fileData )
236
+ {
237
+ if ( $fileData->Status->Code == 2 ) //file was processed OK
238
+ {
239
+ if ( $counter == 0 )//save percent improvement for main file
240
+ $percentImprovement = $fileData->PercentImprovement;
241
+ else //count thumbnails only
242
+ update_option( 'wp-short-pixel-thumbnail-count', get_option('wp-short-pixel-thumbnail-count') + 1 );
243
+ $downloadResult = $this->handleDownload($fileData,$counter);
244
+ //when the status is STATUS_UNCHANGED we just skip the array line for that one
245
+ if ( $downloadResult['Status'] == self::STATUS_SUCCESS ) {
246
+ $tempFiles[$counter] = $downloadResult['Message'];
247
+ }
248
+ elseif ( $downloadResult['Status'] <> self::STATUS_UNCHANGED )
249
+ return array("Status" => $downloadResult['Status'], "Message" => $downloadResult['Message']);
250
+ }
251
+ else //there was an error while trying to download a file
252
+ $tempFiles[$counter] = "";
253
+
254
+ $counter++;
255
+ }
256
+
257
+ //figure out in what SubDir files should land
258
+ $SubDir = $this->returnSubDir(get_attached_file($ID));
259
+
260
+ //if backup is enabled - we try to save the images
261
+ if( get_option('wp-short-backup_images') )
262
+ {
263
+ $uploadDir = wp_upload_dir();
264
+ $source = $PATHs;//array with final paths for this files
265
+
266
+ if( !file_exists(SP_BACKUP_FOLDER) && !@mkdir(SP_BACKUP_FOLDER, 0777, true) ) {//creates backup folder if it doesn't exist
267
+ return array("Status" => self::STATUS_FAIL, "Message" => "Backup folder does not exist and it cannot be created");
268
+ }
269
+ //create subdir in backup folder if needed
270
+ @mkdir( SP_BACKUP_FOLDER . DIRECTORY_SEPARATOR . $SubDir, 0777, true);
271
+
272
+ foreach ( $source as $fileID => $filePATH )//create destination files array
273
+ {
274
+ $destination[$fileID] = SP_BACKUP_FOLDER . DIRECTORY_SEPARATOR . $SubDir . self::MB_basename($source[$fileID]);
275
+ }
276
+
277
+ //now that we have original files and where we should back them up we attempt to do just that
278
+ if(is_writable(SP_BACKUP_FOLDER))
279
+ {
280
+ foreach ( $destination as $fileID => $filePATH )
281
+ {
282
+ if ( !file_exists($filePATH) )
283
+ {
284
+ if ( !@copy($source[$fileID], $destination[$fileID]) )
285
+ {//file couldn't have been saved in backup folder
286
+ ShortPixelAPI::SaveMessageinMetadata($ID, 'Cannot save file <i>' . self::MB_basename($source[$fileID]) . '</i> in backup directory');
287
+ return array("Status" => self::STATUS_FAIL, "Message" => 'Cannot save file <i>' . self::MB_basename($source[$fileID]) . '</i> in backup directory');
288
+ }
289
+ }
290
+ }
291
+ } else {//cannot write to the backup dir, return with an error
292
+ ShortPixelAPI::SaveMessageinMetadata($ID, 'Cannot save file in backup directory');
293
+ return array("Status" => self::STATUS_FAIL, "Message" => 'Cannot save file in backup directory');
294
+ }
295
+
296
+ }//end backup section
297
+
298
+
299
+ $writeFailed = 0;
300
+
301
+ if ( !empty($tempFiles) )
302
+ {
303
+ //overwrite the original files with the optimized ones
304
+ foreach ( $tempFiles as $tempFileID => $tempFilePATH )
305
+ {
306
+ if ( file_exists($tempFilePATH) && file_exists($PATHs[$tempFileID]) && is_writable($PATHs[$tempFileID]) ) {
307
+ copy($tempFilePATH, $PATHs[$tempFileID]);
308
+ } else {
309
+ $writeFailed++;
310
+ }
311
+ @unlink($tempFilePATH);
312
+
313
+ if ( $writeFailed > 0 )//there was an error
314
+ {
315
+ ShortPixelAPI::SaveMessageinMetadata($ID, 'Error: optimized version of ' . $writeFailed . ' file(s) couldn\'t be updated.');
316
+ update_option('bulkProcessingStatus', "error");
317
+ return array("Status" => self::STATUS_FAIL, "Code" =>"write-fail", "Message" => 'Error: optimized version of ' . $writeFailed . ' file(s) couldn\'t be updated.');
318
+ }
319
+ else
320
+ {//all files were copied, optimization data regarding the savings locally in DB
321
+ $fileType = ( $this->_settings->compressionType ) ? "LossySize" : "LoselessSize";
322
+ $savedSpace += $APIresponse[$tempFileID]->OriginalSize - $APIresponse[$tempFileID]->$fileType;
323
+ $originalSpace += $APIresponse[$tempFileID]->OriginalSize;
324
+ $optimizedSpace += $APIresponse[$tempFileID]->$fileType;
325
+ $averageCompression += $fileData->PercentImprovement;
326
+
327
+ //add the number of files with < 5% optimization
328
+ if ( ( ( 1 - $APIresponse[$tempFileID]->$fileType/$APIresponse[$tempFileID]->OriginalSize ) * 100 ) < 5 )
329
+ $this->_settings->under5Percent++;
330
+
331
+ }
332
+ }
333
+ }
334
+ //old average counting
335
+ $this->_settings->savedSpace += $savedSpace;
336
+ $averageCompression = $this->_settings->averageCompression * $this->_settings->fileCount;
337
+ $averageCompression = $averageCompression / ($this->_settings->fileCount + count($APIresponse));
338
+ $this->_settings->averageCompression = $averageCompression;
339
+ $this->_settings->fileCount += count($APIresponse);
340
+ //new average counting
341
+ $this->_settings->totalOriginal += $originalSpace;
342
+ $this->_settings->totalOptimized += $optimizedSpace;
343
+ //update metadata for this file
344
+ $meta = wp_get_attachment_metadata($ID);
345
+ $meta['ShortPixelImprovement'] = round($percentImprovement,2);
346
+ $meta['ShortPixel']['type'] = $this->_settings->compressionType == 1 ? 'lossy' : 'lossless';
347
+ $meta['ShortPixel']['thumbsOpt'] = $this->_settings->processThumbnails && isset($meta['sizes']) ? count($meta['sizes']) : 0;
348
+ wp_update_attachment_metadata($ID, $meta);
349
+ //we reset the retry counter in case of success
350
+ update_option('wp-short-pixel-api-retries', 0);
351
+
352
+ return array("Status" => self::STATUS_SUCCESS, "Message" => 'Success: No pixels remained unsqueezed :-)', "PercentImprovement" => $percentImprovement);
353
+ }//end handleSuccess
354
+
355
+ static public function returnSubDir($file)//return subdir for that particular attached file
356
+ {
357
+ $Atoms = explode("/", $file);
358
+ $Counter = count($Atoms);
359
+ $SubDir = $Atoms[$Counter-3] . DIRECTORY_SEPARATOR . $Atoms[$Counter-2] . DIRECTORY_SEPARATOR;
360
+
361
+ return $SubDir;
362
+ }
363
+
364
+ //a basename alternative that deals OK with multibyte charsets (e.g. Arabic)
365
+ static public function MB_basename($Path){
366
+ $Separator = " qq ";
367
+ $Path = preg_replace("/[^ ]/u", $Separator."\$0".$Separator, $Path);
368
+ $Base = basename($Path);
369
+ $Base = str_replace($Separator, "", $Base);
370
+ return $Base;
371
+ }
372
+
373
+ //sometimes, the paths to the files as defined in metadata are wrong, we try to automatically correct them
374
+ static public function CheckAndFixImagePaths($PATHs){
375
+
376
+ $ErrorCount = 0;
377
+ $uploadDir = wp_upload_dir();
378
+ $Tmp = explode("/", $uploadDir['basedir']);
379
+ $TmpCount = count($Tmp);
380
+ $StichString = $Tmp[$TmpCount-2] . "/" . $Tmp[$TmpCount-1];
381
+ //files exist on disk?
382
+ foreach ( $PATHs as $Id => $File )
383
+ {
384
+ //we try again with a different path
385
+ if ( !file_exists($File) ){
386
+ //$NewFile = $uploadDir['basedir'] . "/" . substr($File,strpos($File, $StichString));//+strlen($StichString));
387
+ $NewFile = $uploadDir['basedir'] . substr($File,strpos($File, $StichString)+strlen($StichString));
388
+ if ( file_exists($NewFile) )
389
+ $PATHs[$Id] = $NewFile;
390
+ else
391
+ $ErrorCount++;
392
+ }
393
+ }
394
+
395
+ if ( $ErrorCount > 0 )
396
+ return false;
397
+ else
398
+ return $PATHs;
399
+
400
+ }
401
+
402
+
403
+ static private function SaveMessageinMetadata($ID, $Message)
404
+ {
405
+ $meta = wp_get_attachment_metadata($ID);
406
+ $meta['ShortPixelImprovement'] = $Message;
407
+ unset($meta['ShortPixel']['WaitingProcessing']);
408
+ wp_update_attachment_metadata($ID, $meta);
409
+ }
410
+
411
+ public function parseJSON($data) {
412
+ if ( function_exists('json_decode') ) {
413
+ $data = json_decode( $data );
414
+ } else {
415
+ require_once( 'JSON/JSON.php' );
416
+ $json = new Services_JSON( );
417
+ $data = $json->decode( $data );
418
+ }
419
+ return $data;
420
+ }
421
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
shortpixel_queue.php CHANGED
@@ -2,7 +2,8 @@
2
 
3
  class ShortPixelQueue {
4
 
5
- private $ctrl;
 
6
  private $startBulkId;
7
  private $stopBulkId;
8
  private $bulkCount;
@@ -18,17 +19,13 @@ class ShortPixelQueue {
18
  const BULK_PAUSED = 2; //bulk is paused
19
  const BULK_FINISHED = 3; //bulk finished
20
 
21
- //handling older
22
- public function ShortPixelQueue($controller) {
23
- $this->__construct($controller);
24
- }
25
-
26
- public function __construct($controller) {
27
  $this->ctrl = $controller;
 
28
  //init the option if needed
29
  if(!isset($_SESSION["wp-short-pixel-priorityQueue"])) {
30
  //take the priority list from the options (we persist there the priority IDs from the previous session)
31
- $prioQueueOpt = WPShortPixel::getOpt( 'wp-short-pixel-priorityQueue', array());//here we save the IDs for the files that need to be processed after an image upload for example
32
  $_SESSION["wp-short-pixel-priorityQueue"] = array();
33
  foreach($prioQueueOpt as $ID) {
34
  $meta = wp_get_attachment_metadata($ID);
@@ -37,22 +34,27 @@ class ShortPixelQueue {
37
  $this->push($ID);
38
  }
39
  }
40
- update_option('wp-short-pixel-priorityQueue', $_SESSION["wp-short-pixel-priorityQueue"]);
41
  WPShortPixel::log("INIT: Session queue not found, updated from Options with "
42
  .json_encode($_SESSION["wp-short-pixel-priorityQueue"]));
43
  }
44
 
45
- $this->startBulkId = WPShortPixel::getOpt( 'wp-short-pixel-query-id-start', 0);//current query ID used for postmeta queries
46
- $this->stopBulkId = WPShortPixel::getOpt( 'wp-short-pixel-query-id-stop', 0);//min ID used for postmeta queries
47
- $this->bulkCount = WPShortPixel::getOpt( "wp-short-pixel-bulk-count", 0);
48
- $this->bulkPreviousPercent = WPShortPixel::getOpt( "wp-short-pixel-bulk-previous-percent", 0);
49
- $this->bulkCurrentlyProcessed = WPShortPixel::getOpt( "wp-short-pixel-bulk-processed-items", 0);
50
- $this->bulkAlreadyDoneCount = WPShortPixel::getOpt( "wp-short-pixel-bulk-done-count", 0);
51
- $this->lastBulkStartTime = WPShortPixel::getOpt( 'wp-short-pixel-last-bulk-start-time', 0);//time of the last start of the bulk.
52
- $this->lastBulkSuccessTime = WPShortPixel::getOpt( 'wp-short-pixel-last-bulk-success-time', 0);//time of the last start of the bulk.
53
- $this->bulkRunningTime = WPShortPixel::getOpt( 'wp-short-pixel-bulk-running-time', 0);//how long the bulk ran that far.
54
  }
55
 
 
 
 
 
 
56
  public function get() {
57
  return $_SESSION["wp-short-pixel-priorityQueue"];//get_option("wp-short-pixel-priorityQueue");
58
  }
@@ -65,7 +67,7 @@ class ShortPixelQueue {
65
  $prioQ = array_unique($priorityQueue);
66
  $_SESSION["wp-short-pixel-priorityQueue"] = $prioQ;
67
  //push also to the options queue, in case the session gets killed retrieve frm there
68
- update_option('wp-short-pixel-priorityQueue', $prioQ);
69
 
70
  WPShortPixel::log("PUSH: Updated: ".json_encode($_SESSION["wp-short-pixel-priorityQueue"]));//get_option("wp-short-pixel-priorityQueue")));
71
  }
@@ -90,31 +92,31 @@ class ShortPixelQueue {
90
  $found = true;
91
  }
92
  }
93
- //update_option("wp-short-pixel-priorityQueue", $newPriorityQueue);
94
  $_SESSION["wp-short-pixel-priorityQueue"] = $newPriorityQueue;
95
  WPShortPixel::log("REM: " . ($found ? "Updated: " : "Not found") . json_encode($_SESSION["wp-short-pixel-priorityQueue"]));//get_option("wp-short-pixel-priorityQueue")));
96
  return $found;
97
  }
98
 
99
  public function removeFromFailed($ID) {
100
- $failed = explode(",", WPShortPixel::getOpt('wp-short-pixel-failed-imgs',''));
101
  $key = array_search($ID, $failed);
102
  if($key !== false) {
103
  unset($failed[$key]);
104
  $failed = array_values($failed);
105
- update_option('wp-short-pixel-failed-imgs', implode(",", $failed) );
106
  }
107
  }
108
 
109
  public function addToFailed($ID) {
110
- $failed = WPShortPixel::getOpt('wp-short-pixel-failed-imgs','');
111
  if(!in_array($ID, explode(",", $failed))) {
112
- update_option('wp-short-pixel-failed-imgs', (strlen($failed) ? $failed . "," : "") . $ID );
113
  }
114
  }
115
 
116
  public function getFailed() {
117
- $failed = WPShortPixel::getOpt('wp-short-pixel-failed-imgs','');
118
  if(!strlen($failed)) return array();
119
  return explode(",", $failed);
120
  }
@@ -126,11 +128,11 @@ class ShortPixelQueue {
126
 
127
  public function bulkPaused() {
128
  WPShortPixel::log("Bulk Paused: " . get_option( 'wp-short-pixel-cancel-pointer'));
129
- return WPShortPixel::getOpt( 'wp-short-pixel-cancel-pointer', 0);
130
  }
131
 
132
  public function bulkRan() {
133
- return WPShortPixel::getOpt("wp-short-pixel-bulk-ever-ran", 0) != 0;
134
  }
135
 
136
  public function processing() {
@@ -139,7 +141,7 @@ class ShortPixelQueue {
139
  }
140
 
141
  public function getFlagBulkId() {
142
- return WPShortPixel::getOpt("wp-short-pixel-flag-id",0);
143
  }
144
 
145
  public function getStartBulkId() {
@@ -152,7 +154,7 @@ class ShortPixelQueue {
152
 
153
  public function setStartBulkId($start){
154
  $this->startBulkId = $start;
155
- update_option("wp-short-pixel-query-id-start", $this->startBulkId);
156
  }
157
 
158
  public function getStopBulkId() {
@@ -161,21 +163,21 @@ class ShortPixelQueue {
161
 
162
  public function resetStopBulkId() {
163
  $this->stopBulkId = $this->ctrl->getMinMediaId();
164
- update_option("wp-short-pixel-query-id-stop", $this->stopBulkId);
165
  }
166
 
167
  public function setBulkPreviousPercent() {
168
  //processable
169
  $res = $this->ctrl->countAllProcessableFiles($this->getFlagBulkId(), $this->stopBulkId);
170
  $this->bulkCount = $res["mainFiles"];
171
- update_option("wp-short-pixel-bulk-count", $this->bulkCount);
172
  //already processed
173
  $res = $this->ctrl->countAllProcessedFiles($this->getFlagBulkId(), $this->stopBulkId);
174
  $this->bulkAlreadyDoneCount = $res["mainFiles"];
175
- update_option("wp-short-pixel-bulk-done-count", $this->bulkAlreadyDoneCount);
176
  //percent already done
177
  $this->bulkPreviousPercent = round($this->bulkAlreadyDoneCount / $this->bulkCount *100);
178
- update_option("wp-short-pixel-bulk-previous-percent", $this->bulkPreviousPercent);
179
  }
180
 
181
  public function getBulkToProcess() {
@@ -183,7 +185,7 @@ class ShortPixelQueue {
183
  }
184
 
185
  public function flagBulkStart() {
186
- update_option("wp-short-pixel-flag-id", $this->startBulkId);
187
  delete_option('bulkProcessingStatus');
188
  add_option('bulkProcessingStatus', 'running');//set bulk flag
189
  }
@@ -194,13 +196,13 @@ class ShortPixelQueue {
194
  $this->flagBulkStart(); //we use this to detect new added files while bulk is running
195
  $this->setBulkPreviousPercent();
196
  $this->resetBulkCurrentlyProcessed();
197
- update_option( 'wp-short-pixel-bulk-ever-ran', 1);
198
  }
199
 
200
  public function pauseBulk() {
201
  $cancelPointer = $this->startBulkId;
202
  $bulkStartId = $this->getFlagBulkId();
203
- update_option( 'wp-short-pixel-cancel-pointer', $cancelPointer);//we save this so we can resume bulk processing
204
  WPShortPixel::log("PAUSE: Pointer = ".get_option( 'wp-short-pixel-cancel-pointer'));
205
  //remove the bulk items from prio queue
206
  foreach($this->get() as $qItem) {
@@ -214,18 +216,18 @@ class ShortPixelQueue {
214
  public function stopBulk() {
215
  $this->startBulkId = WPShortPixel::getMaxMediaId();
216
  $this->stopBulkId = $this->startBulkId;
217
- update_option("wp-short-pixel-query-id-start", $this->startBulkId);
218
- update_option("wp-short-pixel-query-id-stop", $this->stopBulkId);
219
  delete_option('bulkProcessingStatus');
220
- return WPShortPixel::getOpt('wp-short-pixel-bulk-ever-ran', 0);
221
  }
222
 
223
  public function resumeBulk() {
224
  $this->startBulkId = get_option( 'wp-short-pixel-cancel-pointer');
225
- update_option("wp-short-pixel-query-id-start", $this->startBulkId);//start downwards from the biggest item ID
226
  $this->stopBulkId = $this->ctrl->getMinMediaId();
227
- update_option("wp-short-pixel-query-id-stop", $this->stopBulkId);
228
- //update_option("wp-short-pixel-flag-id", $this->startBulkId);//we use to detect new added files while bulk is running
229
  add_option('bulkProcessingStatus', 'running');//set bulk flag
230
  delete_option( 'wp-short-pixel-cancel-pointer');
231
  WPShortPixel::log("Resumed: (pause says: " . $this->bulkPaused() . ") Start from: " . $this->startBulkId . " to " . $this->stopBulkId);
@@ -233,12 +235,12 @@ class ShortPixelQueue {
233
 
234
  public function resetBulkCurrentlyProcessed() {
235
  $this->bulkCurrentlyProcessed = 0;
236
- update_option( "wp-short-pixel-bulk-processed-items", $this->bulkCurrentlyProcessed);
237
  }
238
 
239
  public function incrementBulkCurrentlyProcessed() {
240
  $this->bulkCurrentlyProcessed++;
241
- update_option( "wp-short-pixel-bulk-processed-items", $this->bulkCurrentlyProcessed);
242
  }
243
 
244
  public function markBulkComplete() {
@@ -275,13 +277,13 @@ class ShortPixelQueue {
275
  $this->incrementBulkCurrentlyProcessed();
276
  if($t - $this->lastBulkSuccessTime > 120) { //if break longer than two minutes we mark a pause in the bulk
277
  $this->bulkRunningTime += ($this->lastBulkSuccessTime - $this->lastBulkStartTime);
278
- update_option('wp-short-pixel-bulk-running-time', $this->bulkRunningTime);
279
  $this->lastBulkStartTime = $this->lastBulkSuccessTime = $t;
280
- update_option('wp-short-pixel-last-bulk-start-time', $t);
281
- update_option('wp-short-pixel-last-bulk-success-time', $t);
282
  } else {
283
  $this->lastBulkSuccessTime = $t;
284
- update_option('wp-short-pixel-last-bulk-success-time', $t);
285
  }
286
  }
287
 
2
 
3
  class ShortPixelQueue {
4
 
5
+ private $ctrl;
6
+ private $settings;
7
  private $startBulkId;
8
  private $stopBulkId;
9
  private $bulkCount;
19
  const BULK_PAUSED = 2; //bulk is paused
20
  const BULK_FINISHED = 3; //bulk finished
21
 
22
+ public function __construct($controller, $settings) {
 
 
 
 
 
23
  $this->ctrl = $controller;
24
+ $this->settings = $settings;
25
  //init the option if needed
26
  if(!isset($_SESSION["wp-short-pixel-priorityQueue"])) {
27
  //take the priority list from the options (we persist there the priority IDs from the previous session)
28
+ $prioQueueOpt = $this->settings->getOpt( 'wp-short-pixel-priorityQueue', array());//here we save the IDs for the files that need to be processed after an image upload for example
29
  $_SESSION["wp-short-pixel-priorityQueue"] = array();
30
  foreach($prioQueueOpt as $ID) {
31
  $meta = wp_get_attachment_metadata($ID);
34
  $this->push($ID);
35
  }
36
  }
37
+ $this->settings->setOpt('wp-short-pixel-priorityQueue', $_SESSION["wp-short-pixel-priorityQueue"]);
38
  WPShortPixel::log("INIT: Session queue not found, updated from Options with "
39
  .json_encode($_SESSION["wp-short-pixel-priorityQueue"]));
40
  }
41
 
42
+ $this->startBulkId = $this->settings->getOpt( 'wp-short-pixel-query-id-start', 0);//current query ID used for postmeta queries
43
+ $this->stopBulkId = $this->settings->getOpt( 'wp-short-pixel-query-id-stop', 0);//min ID used for postmeta queries
44
+ $this->bulkCount = $this->settings->getOpt( "wp-short-pixel-bulk-count", 0);
45
+ $this->bulkPreviousPercent = $this->settings->getOpt( "wp-short-pixel-bulk-previous-percent", 0);
46
+ $this->bulkCurrentlyProcessed = $this->settings->getOpt( "wp-short-pixel-bulk-processed-items", 0);
47
+ $this->bulkAlreadyDoneCount = $this->settings->getOpt( "wp-short-pixel-bulk-done-count", 0);
48
+ $this->lastBulkStartTime = $this->settings->getOpt( 'wp-short-pixel-last-bulk-start-time', 0);//time of the last start of the bulk.
49
+ $this->lastBulkSuccessTime = $this->settings->getOpt( 'wp-short-pixel-last-bulk-success-time', 0);//time of the last start of the bulk.
50
+ $this->bulkRunningTime = $this->settings->getOpt( 'wp-short-pixel-bulk-running-time', 0);//how long the bulk ran that far.
51
  }
52
 
53
+ //handling older
54
+ public function ShortPixelQueue($controller) {
55
+ $this->__construct($controller);
56
+ }
57
+
58
  public function get() {
59
  return $_SESSION["wp-short-pixel-priorityQueue"];//get_option("wp-short-pixel-priorityQueue");
60
  }
67
  $prioQ = array_unique($priorityQueue);
68
  $_SESSION["wp-short-pixel-priorityQueue"] = $prioQ;
69
  //push also to the options queue, in case the session gets killed retrieve frm there
70
+ $this->settings->setOpt('wp-short-pixel-priorityQueue', $prioQ);
71
 
72
  WPShortPixel::log("PUSH: Updated: ".json_encode($_SESSION["wp-short-pixel-priorityQueue"]));//get_option("wp-short-pixel-priorityQueue")));
73
  }
92
  $found = true;
93
  }
94
  }
95
+ //$this->settings->setOpt("wp-short-pixel-priorityQueue", $newPriorityQueue);
96
  $_SESSION["wp-short-pixel-priorityQueue"] = $newPriorityQueue;
97
  WPShortPixel::log("REM: " . ($found ? "Updated: " : "Not found") . json_encode($_SESSION["wp-short-pixel-priorityQueue"]));//get_option("wp-short-pixel-priorityQueue")));
98
  return $found;
99
  }
100
 
101
  public function removeFromFailed($ID) {
102
+ $failed = explode(",", $this->settings->getOpt('wp-short-pixel-failed-imgs',''));
103
  $key = array_search($ID, $failed);
104
  if($key !== false) {
105
  unset($failed[$key]);
106
  $failed = array_values($failed);
107
+ $this->settings->setOpt('wp-short-pixel-failed-imgs', implode(",", $failed) );
108
  }
109
  }
110
 
111
  public function addToFailed($ID) {
112
+ $failed = $this->settings->getOpt('wp-short-pixel-failed-imgs','');
113
  if(!in_array($ID, explode(",", $failed))) {
114
+ $this->settings->setOpt('wp-short-pixel-failed-imgs', (strlen($failed) ? $failed . "," : "") . $ID );
115
  }
116
  }
117
 
118
  public function getFailed() {
119
+ $failed = $this->settings->getOpt('wp-short-pixel-failed-imgs','');
120
  if(!strlen($failed)) return array();
121
  return explode(",", $failed);
122
  }
128
 
129
  public function bulkPaused() {
130
  WPShortPixel::log("Bulk Paused: " . get_option( 'wp-short-pixel-cancel-pointer'));
131
+ return $this->settings->getOpt( 'wp-short-pixel-cancel-pointer', 0);
132
  }
133
 
134
  public function bulkRan() {
135
+ return $this->settings->getOpt("wp-short-pixel-bulk-ever-ran", 0) != 0;
136
  }
137
 
138
  public function processing() {
141
  }
142
 
143
  public function getFlagBulkId() {
144
+ return $this->settings->getOpt("wp-short-pixel-flag-id",0);
145
  }
146
 
147
  public function getStartBulkId() {
154
 
155
  public function setStartBulkId($start){
156
  $this->startBulkId = $start;
157
+ $this->settings->setOpt("wp-short-pixel-query-id-start", $this->startBulkId);
158
  }
159
 
160
  public function getStopBulkId() {
163
 
164
  public function resetStopBulkId() {
165
  $this->stopBulkId = $this->ctrl->getMinMediaId();
166
+ $this->settings->setOpt("wp-short-pixel-query-id-stop", $this->stopBulkId);
167
  }
168
 
169
  public function setBulkPreviousPercent() {
170
  //processable
171
  $res = $this->ctrl->countAllProcessableFiles($this->getFlagBulkId(), $this->stopBulkId);
172
  $this->bulkCount = $res["mainFiles"];
173
+ $this->settings->setOpt("wp-short-pixel-bulk-count", $this->bulkCount);
174
  //already processed
175
  $res = $this->ctrl->countAllProcessedFiles($this->getFlagBulkId(), $this->stopBulkId);
176
  $this->bulkAlreadyDoneCount = $res["mainFiles"];
177
+ $this->settings->setOpt("wp-short-pixel-bulk-done-count", $this->bulkAlreadyDoneCount);
178
  //percent already done
179
  $this->bulkPreviousPercent = round($this->bulkAlreadyDoneCount / $this->bulkCount *100);
180
+ $this->settings->setOpt("wp-short-pixel-bulk-previous-percent", $this->bulkPreviousPercent);
181
  }
182
 
183
  public function getBulkToProcess() {
185
  }
186
 
187
  public function flagBulkStart() {
188
+ $this->settings->setOpt("wp-short-pixel-flag-id", $this->startBulkId);
189
  delete_option('bulkProcessingStatus');
190
  add_option('bulkProcessingStatus', 'running');//set bulk flag
191
  }
196
  $this->flagBulkStart(); //we use this to detect new added files while bulk is running
197
  $this->setBulkPreviousPercent();
198
  $this->resetBulkCurrentlyProcessed();
199
+ $this->settings->setOpt( 'wp-short-pixel-bulk-ever-ran', 1);
200
  }
201
 
202
  public function pauseBulk() {
203
  $cancelPointer = $this->startBulkId;
204
  $bulkStartId = $this->getFlagBulkId();
205
+ $this->settings->setOpt( 'wp-short-pixel-cancel-pointer', $cancelPointer);//we save this so we can resume bulk processing
206
  WPShortPixel::log("PAUSE: Pointer = ".get_option( 'wp-short-pixel-cancel-pointer'));
207
  //remove the bulk items from prio queue
208
  foreach($this->get() as $qItem) {
216
  public function stopBulk() {
217
  $this->startBulkId = WPShortPixel::getMaxMediaId();
218
  $this->stopBulkId = $this->startBulkId;
219
+ $this->settings->setOpt("wp-short-pixel-query-id-start", $this->startBulkId);
220
+ $this->settings->setOpt("wp-short-pixel-query-id-stop", $this->stopBulkId);
221
  delete_option('bulkProcessingStatus');
222
+ return $this->settings->getOpt('wp-short-pixel-bulk-ever-ran', 0);
223
  }
224
 
225
  public function resumeBulk() {
226
  $this->startBulkId = get_option( 'wp-short-pixel-cancel-pointer');
227
+ $this->settings->setOpt("wp-short-pixel-query-id-start", $this->startBulkId);//start downwards from the biggest item ID
228
  $this->stopBulkId = $this->ctrl->getMinMediaId();
229
+ $this->settings->setOpt("wp-short-pixel-query-id-stop", $this->stopBulkId);
230
+ //$this->settings->setOpt("wp-short-pixel-flag-id", $this->startBulkId);//we use to detect new added files while bulk is running
231
  add_option('bulkProcessingStatus', 'running');//set bulk flag
232
  delete_option( 'wp-short-pixel-cancel-pointer');
233
  WPShortPixel::log("Resumed: (pause says: " . $this->bulkPaused() . ") Start from: " . $this->startBulkId . " to " . $this->stopBulkId);
235
 
236
  public function resetBulkCurrentlyProcessed() {
237
  $this->bulkCurrentlyProcessed = 0;
238
+ $this->settings->setOpt( "wp-short-pixel-bulk-processed-items", $this->bulkCurrentlyProcessed);
239
  }
240
 
241
  public function incrementBulkCurrentlyProcessed() {
242
  $this->bulkCurrentlyProcessed++;
243
+ $this->settings->setOpt( "wp-short-pixel-bulk-processed-items", $this->bulkCurrentlyProcessed);
244
  }
245
 
246
  public function markBulkComplete() {
277
  $this->incrementBulkCurrentlyProcessed();
278
  if($t - $this->lastBulkSuccessTime > 120) { //if break longer than two minutes we mark a pause in the bulk
279
  $this->bulkRunningTime += ($this->lastBulkSuccessTime - $this->lastBulkStartTime);
280
+ $this->settings->setOpt('wp-short-pixel-bulk-running-time', $this->bulkRunningTime);
281
  $this->lastBulkStartTime = $this->lastBulkSuccessTime = $t;
282
+ $this->settings->setOpt('wp-short-pixel-last-bulk-start-time', $t);
283
+ $this->settings->setOpt('wp-short-pixel-last-bulk-success-time', $t);
284
  } else {
285
  $this->lastBulkSuccessTime = $t;
286
+ $this->settings->setOpt('wp-short-pixel-last-bulk-success-time', $t);
287
  }
288
  }
289
 
shortpixel_view.php CHANGED
@@ -4,15 +4,15 @@ class ShortPixelView {
4
 
5
  private $ctrl;
6
 
 
 
 
 
7
  //handling older
8
  public function ShortPixelView($controller) {
9
  $this->__construct($controller);
10
  }
11
 
12
- public function __construct($controller) {
13
- $this->ctrl = $controller;
14
- }
15
-
16
  public function displayQuotaExceededAlert($quotaData)
17
  { ?>
18
  <br/>
@@ -327,9 +327,11 @@ class ShortPixelView {
327
  }
328
 
329
  public function displaySettingsForm($quotaData) {
 
330
  $checked = ($this->ctrl->processThumbnails() ? 'checked' : '');
331
  $checkedBackupImages = ($this->ctrl->backupImages() ? 'checked' : '');
332
  $cmyk2rgb = ($this->ctrl->getCMYKtoRGBconversion() ? 'checked' : '');
 
333
  $resize = ($this->ctrl->getResizeImages() ? 'checked' : '');
334
  $resizeDisabled = ($this->ctrl->getResizeImages() ? '' : 'disabled');
335
  $minSizes = $this->ctrl->getMaxIntermediateImageSize();
@@ -364,13 +366,13 @@ class ShortPixelView {
364
  <label for="compressionType">Compression type:</label>
365
  </th>
366
  <td>
367
- <input type="radio" name="compressionType" value="1" <?= $this->ctrl->getCompressionType() == 1 ? "checked" : "" ?>>Lossy</br>
368
- <p class="settings-info"> <b>Lossy compression: </b>lossy has a better compression rate than lossless compression.</br>The resulting image
369
- is not 100% identical with the original. Works well for photos taken with your camera.</p></br>
 
370
  <input type="radio" name="compressionType" value="0" <?= $this->ctrl->getCompressionType() != 1 ? "checked" : "" ?>>Lossless
371
- <p class="settings-info"><b>Lossless compression: </b> the shrunk image will be identical with the original and smaller in size.</br>Use this
372
- when you do not want to lose any of the original image's details. Works best for technical drawings,
373
- clip art and comics. </p>
374
  </td>
375
  </tr>
376
  </tbody>
@@ -381,27 +383,37 @@ class ShortPixelView {
381
  <th scope="row"><label for="thumbnails">Also include thumbnails:</label></th>
382
  <td><input name="thumbnails" type="checkbox" id="thumbnails" <?= $checked ?>> Apply compression also to
383
  <strong><?=$thumbnailsToProcess ? number_format($thumbnailsToProcess) : ""?> image thumbnails.</strong>
384
- <p class="settings-info">Thumbnails count up to your total quota, and should be optimized for best results of your website's speed.</p>
385
  </td>
386
  </tr>
387
  <tr>
388
  <th scope="row"><label for="backupImages">Image backup</label></th>
389
  <td>
390
  <input name="backupImages" type="checkbox" id="backupImages" <?= $checkedBackupImages ?>> Save and keep a backup of your original images in a separate folder.
 
391
  </td>
392
  </tr>
393
  <tr>
394
- <th scope="row"><label for="backupImages">CMYK to RGB conversion</label></th>
395
  <td>
396
  <input name="cmyk2rgb" type="checkbox" id="cmyk2rgb" <?= $cmyk2rgb ?>>Adjust your images for computer and mobile screen display.
397
  </td>
398
  </tr>
 
 
 
 
 
 
 
 
 
399
  <tr>
400
  <th scope="row"><label for="resize">Resize large images</label></th>
401
  <td>
402
  <input name="resize" type="checkbox" id="resize" <?= $resize ?>> to maximum
403
  <input type="text" name="width" id="width" style="width:70px" value="<?= max($this->ctrl->getResizeWidth(), min(1024, $minSizes['width'])) ?>" <?= $resizeDisabled ?>/> pixels wide &times;
404
- <input type="text" name="height" id="height" style="width:70px" value="<?= max($this->ctrl->getResizeHeight(), min(1024, $minSizes['height'])) ?>" <?= $resizeDisabled ?>/> pixels high
405
  <p class="settings-info"> Recommended for large photos, like the ones taken with your phone. Saved space can go up to 80% or more after resizing.<br/>
406
  The new resolution should not be less than your largest thumbnail size, which is <?=$minSizes['width']?> &times; <?=$minSizes['height']?> pixels.</p>
407
  </td>
4
 
5
  private $ctrl;
6
 
7
+ public function __construct($controller) {
8
+ $this->ctrl = $controller;
9
+ }
10
+
11
  //handling older
12
  public function ShortPixelView($controller) {
13
  $this->__construct($controller);
14
  }
15
 
 
 
 
 
16
  public function displayQuotaExceededAlert($quotaData)
17
  { ?>
18
  <br/>
327
  }
328
 
329
  public function displaySettingsForm($quotaData) {
330
+ $settings = $this->ctrl->getSettings();
331
  $checked = ($this->ctrl->processThumbnails() ? 'checked' : '');
332
  $checkedBackupImages = ($this->ctrl->backupImages() ? 'checked' : '');
333
  $cmyk2rgb = ($this->ctrl->getCMYKtoRGBconversion() ? 'checked' : '');
334
+ $removeExif = ($settings->keepExif ? '' : 'checked');
335
  $resize = ($this->ctrl->getResizeImages() ? 'checked' : '');
336
  $resizeDisabled = ($this->ctrl->getResizeImages() ? '' : 'disabled');
337
  $minSizes = $this->ctrl->getMaxIntermediateImageSize();
366
  <label for="compressionType">Compression type:</label>
367
  </th>
368
  <td>
369
+ <input type="radio" name="compressionType" value="1" <?= $this->ctrl->getCompressionType() == 1 ? "checked" : "" ?>>Lossy (recommended)</br>
370
+ <p class="settings-info"> <b>Lossy compression: </b>lossy has a better compression rate than lossless compression.</br>While the resulting image
371
+ is not 100% identical with the original, in the vast majority of cases the difference is not noticeable. You can
372
+ <a href="https://shortpixel.com/online-image-compression" target="_blank">freely test your images</a> for lossy optimization.</p></br>
373
  <input type="radio" name="compressionType" value="0" <?= $this->ctrl->getCompressionType() != 1 ? "checked" : "" ?>>Lossless
374
+ <p class="settings-info"><b>Lossless compression: </b> the shrunk image will be identical with the original and smaller in size.</br>In some rare cases you will need to use
375
+ this type of compression. Some technical drawings or images from vector graphics are possible situations.</p>
 
376
  </td>
377
  </tr>
378
  </tbody>
383
  <th scope="row"><label for="thumbnails">Also include thumbnails:</label></th>
384
  <td><input name="thumbnails" type="checkbox" id="thumbnails" <?= $checked ?>> Apply compression also to
385
  <strong><?=$thumbnailsToProcess ? number_format($thumbnailsToProcess) : ""?> image thumbnails.</strong>
386
+ <p class="settings-info">It is highly recommended that you optimize the thumbnails as they are usually the images most viewed by end users and can generate most traffic.<br>Please note that thumbnails count up to your total quota.</p>
387
  </td>
388
  </tr>
389
  <tr>
390
  <th scope="row"><label for="backupImages">Image backup</label></th>
391
  <td>
392
  <input name="backupImages" type="checkbox" id="backupImages" <?= $checkedBackupImages ?>> Save and keep a backup of your original images in a separate folder.
393
+ <p class="settings-info">Usually recommended for safety.</p>
394
  </td>
395
  </tr>
396
  <tr>
397
+ <th scope="row"><label for="cmyk2rgb">CMYK to RGB conversion</label></th>
398
  <td>
399
  <input name="cmyk2rgb" type="checkbox" id="cmyk2rgb" <?= $cmyk2rgb ?>>Adjust your images for computer and mobile screen display.
400
  </td>
401
  </tr>
402
+ <tr>
403
+ <th scope="row"><label for="removeExif">Remove EXIF</label></th>
404
+ <td>
405
+ <input name="removeExif" type="checkbox" id="removeExif" <?= $removeExif ?>>Remove the EXIF tag and ICC profile of the image (recommended).
406
+ <p class="settings-info"> EXIF is a set of various pieces of information that are automatically embedded into the image upon creation. This can include GPS position, camera manufacturer, date and time, etc.
407
+ ICC profile specifies the color profile that is used by the image.
408
+ Unless you really need that data to be kept we recommend you removing it as it can lead to <a href="http://blog.shortpixel.com/how-much-smaller-can-be-images-without-exif-icc" target="_blank">better compression rates</a>.</p></br>
409
+ </td>
410
+ </tr>
411
  <tr>
412
  <th scope="row"><label for="resize">Resize large images</label></th>
413
  <td>
414
  <input name="resize" type="checkbox" id="resize" <?= $resize ?>> to maximum
415
  <input type="text" name="width" id="width" style="width:70px" value="<?= max($this->ctrl->getResizeWidth(), min(1024, $minSizes['width'])) ?>" <?= $resizeDisabled ?>/> pixels wide &times;
416
+ <input type="text" name="height" id="height" style="width:70px" value="<?= max($this->ctrl->getResizeHeight(), min(1024, $minSizes['height'])) ?>" <?= $resizeDisabled ?>/> pixels high (original aspect ratio is preserved)
417
  <p class="settings-info"> Recommended for large photos, like the ones taken with your phone. Saved space can go up to 80% or more after resizing.<br/>
418
  The new resolution should not be less than your largest thumbnail size, which is <?=$minSizes['width']?> &times; <?=$minSizes['height']?> pixels.</p>
419
  </td>
wp-shortpixel-settings.php ADDED
@@ -0,0 +1,150 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class WPShortPixelSettings {
4
+ private $_apiKey = '';
5
+ private $_compressionType = 1;
6
+ private $_keepExif = 0;
7
+ private $_processThumbnails = 1;
8
+ private $_CMYKtoRGBconversion = 1;
9
+ private $_backupImages = 1;
10
+ private $_verifiedKey = false;
11
+
12
+ private $_resizeImages = false;
13
+ private $_resizeWidth = 0;
14
+ private $_resizeHeight = 0;
15
+
16
+ private static $_optionsMap = array(
17
+ 'apiKey' => 'wp-short-pixel-apiKey',
18
+ 'verifiedKey' => 'wp-short-pixel-verifiedKey',
19
+ 'compressionType' => 'wp-short-pixel-compression',
20
+ 'processThumbnails' => 'wp-short-process_thumbnails',
21
+ 'keepExif' => 'wp-short-pixel-keep-exif',
22
+ 'CMYKtoRGBconversion' => 'wp-short-pixel_cmyk2rgb',
23
+ 'backupImages' => 'wp-short-backup_images',
24
+ 'fileCount' => 'wp-short-pixel-fileCount',
25
+ 'thumbsCount' => 'wp-short-pixel-thumbnail-count',
26
+ 'under5Percent' => 'wp-short-pixel-files-under-5-percent',
27
+ 'savedSpace' => 'wp-short-pixel-savedSpace',
28
+ 'averageCompression' => 'wp-short-pixel-averageCompression',
29
+ 'apiRetries' => 'wp-short-pixel-api-retries',
30
+ 'resizeImages' => 'wp-short-pixel-resize-images',
31
+ 'resizeWidth' => 'wp-short-pixel-resize-width',
32
+ 'resizeHeight' => 'wp-short-pixel-resize-height',
33
+ 'totalOptimized' => 'wp-short-pixel-total-optimized',
34
+ 'totalOriginal' => 'wp-short-pixel-total-original',
35
+ 'quotaExceeded' => 'wp-short-pixel-quota-exceeded',
36
+ '' => '',
37
+ '' => '',
38
+ '' => '',
39
+ '' => '',
40
+ '' => '',
41
+ );
42
+
43
+ public function __construct() {
44
+ $this->populateOptions();
45
+ }
46
+
47
+ public function populateOptions() {
48
+
49
+ $this->_apiKey = self::getOpt('wp-short-pixel-apiKey', '');
50
+ $this->_verifiedKey = self::getOpt('wp-short-pixel-verifiedKey', $this->_verifiedKey);
51
+ $this->_compressionType = self::getOpt('wp-short-pixel-compression', $this->_compressionType);
52
+ $this->_processThumbnails = self::getOpt('wp-short-process_thumbnails', $this->_processThumbnails);
53
+ $this->_CMYKtoRGBconversion = self::getOpt('wp-short-pixel_cmyk2rgb', $this->_CMYKtoRGBconversion);
54
+ $this->_backupImages = self::getOpt('wp-short-backup_images', $this->_backupImages);
55
+ // the following practically set defaults for options if they're not set
56
+ self::getOpt( 'wp-short-pixel-fileCount', 0);
57
+ self::getOpt( 'wp-short-pixel-thumbnail-count', 0);//amount of optimized thumbnails
58
+ self::getOpt( 'wp-short-pixel-files-under-5-percent', 0);//amount of optimized thumbnails
59
+ self::getOpt( 'wp-short-pixel-savedSpace', 0);
60
+ self::getOpt( 'wp-short-pixel-api-retries', 0);//sometimes we need to retry processing/downloading a file multiple times
61
+ self::getOpt( 'wp-short-pixel-quota-exceeded', 0);
62
+ self::getOpt( 'wp-short-pixel-total-original', 0);//amount of original data
63
+ self::getOpt( 'wp-short-pixel-total-optimized', 0);//amount of optimized
64
+ self::getOpt( 'wp-short-pixel-protocol', 'https');
65
+
66
+ $this->_resizeImages = self::getOpt( 'wp-short-pixel-resize-images', 0);
67
+ $this->_resizeWidth = self::getOpt( 'wp-short-pixel-resize-width', 0);
68
+ $this->_resizeHeight = self::getOpt( 'wp-short-pixel-resize-height', 0);
69
+ }
70
+
71
+ public static function debugResetOptions() {
72
+ delete_option('wp-short-pixel-apiKey');
73
+ delete_option('wp-short-pixel-verifiedKey');
74
+ delete_option('wp-short-pixel-compression');
75
+ delete_option('wp-short-process_thumbnails');
76
+ delete_option('wp-short-pixel_cmyk2rgb');
77
+ delete_option('wp-short-pixel-keep-exif');
78
+ delete_option('wp-short-backup_images');
79
+ delete_option('wp-short-pixel-view-mode');
80
+ update_option( 'wp-short-pixel-thumbnail-count', 0);
81
+ update_option( 'wp-short-pixel-files-under-5-percent', 0);
82
+ update_option( 'wp-short-pixel-savedSpace', 0);
83
+ delete_option( 'wp-short-pixel-averageCompression');
84
+ delete_option( 'wp-short-pixel-fileCount');
85
+ delete_option( 'wp-short-pixel-total-original');
86
+ delete_option( 'wp-short-pixel-total-optimized');
87
+ update_option( 'wp-short-pixel-api-retries', 0);//sometimes we need to retry processing/downloading a file multiple times
88
+ update_option( 'wp-short-pixel-quota-exceeded', 0);
89
+ delete_option( 'wp-short-pixel-protocol');
90
+ update_option( 'wp-short-pixel-bulk-ever-ran', 0);
91
+ delete_option('wp-short-pixel-priorityQueue');
92
+ delete_option( 'wp-short-pixel-resize-images');
93
+ delete_option( 'wp-short-pixel-resize-width');
94
+ delete_option( 'wp-short-pixel-resize-height');
95
+ delete_option( 'wp-short-pixel-dismissed-notices');
96
+ if(isset($_SESSION["wp-short-pixel-priorityQueue"])) {
97
+ unset($_SESSION["wp-short-pixel-priorityQueue"]);
98
+ }
99
+ delete_option("wp-short-pixel-bulk-previous-percent");
100
+ }
101
+
102
+ public static function onActivate() {
103
+ if(!self::getOpt('wp-short-pixel-verifiedKey', false)) {
104
+ update_option('wp-short-pixel-activation-notice', true);
105
+ }
106
+ update_option( 'wp-short-pixel-activation-date', time());
107
+ delete_option( 'wp-short-pixel-bulk-last-status');
108
+ }
109
+
110
+ public static function onDeactivate() {
111
+ delete_option('wp-short-pixel-activation-notice');
112
+ }
113
+
114
+
115
+
116
+
117
+
118
+
119
+
120
+ public function __get($name)
121
+ {
122
+ if (array_key_exists($name, self::$_optionsMap)) {
123
+ return $this->getOpt(self::$_optionsMap[$name]);
124
+ }
125
+ $trace = debug_backtrace();
126
+ trigger_error(
127
+ 'Undefined property via __get(): ' . $name .
128
+ ' in ' . $trace[0]['file'] .
129
+ ' on line ' . $trace[0]['line'],
130
+ E_USER_NOTICE);
131
+ return null;
132
+ }
133
+
134
+ public function __set($name, $value) {
135
+ if (array_key_exists($name, self::$_optionsMap)) {
136
+ $this->setOpt(self::$_optionsMap[$name], $value);
137
+ }
138
+ }
139
+
140
+ public function getOpt($key, $default = null) {
141
+ if(get_option($key) === false) {
142
+ add_option( $key, $default, '', 'yes' );
143
+ }
144
+ return get_option($key);
145
+ }
146
+
147
+ public function setOpt($key, $val) {
148
+ update_option($key, $val);
149
+ }
150
+ }
wp-shortpixel.php CHANGED
@@ -3,11 +3,12 @@
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" target="_blank">Settings &gt; ShortPixel</a> page on how to start optimizing your image library and make your website load faster.
6
- * Version: 3.1.8
7
  * Author: ShortPixel
8
  * Author URI: https://shortpixel.com
9
  */
10
 
 
11
  require_once('shortpixel_api.php');
12
  require_once('shortpixel_queue.php');
13
  require_once('shortpixel_view.php');
@@ -21,7 +22,7 @@ define('SP_RESET_ON_ACTIVATE', false); //if true TODO set false
21
 
22
  define('SP_AFFILIATE_CODE', '');
23
 
24
- define('PLUGIN_VERSION', "3.1.8");
25
  define('SP_MAX_TIMEOUT', 10);
26
  define('SP_VALIDATE_MAX_TIMEOUT', 60);
27
  define('SP_BACKUP', 'ShortpixelBackups');
@@ -42,42 +43,27 @@ define("SP_MAX_RESULTS_QUERY", 6);
42
  class WPShortPixel {
43
 
44
  const BULK_EMPTY_QUEUE = 0;
45
-
46
- private $_apiKey = '';
47
- private $_affiliateSufix;
48
- private $_compressionType = 1;
49
- private $_processThumbnails = 1;
50
- private $_CMYKtoRGBconversion = 1;
51
- private $_backupImages = 1;
52
- private $_verifiedKey = false;
53
 
54
- private $_resizeImages = false;
55
- private $_resizeWidth = 0;
56
- private $_resizeHeight = 0;
57
 
58
  private $_apiInterface = null;
 
59
  private $prioQ = null;
60
  private $view = null;
61
 
62
- //handling older
63
- public function WPShortPixel() {
64
- $this->__construct();
65
- }
66
-
67
  public function __construct() {
68
  if (!session_id()) {
69
  session_start();
70
  }
71
- $this->populateOptions();
72
 
73
  $this->_affiliateSufix = (strlen(SP_AFFILIATE_CODE)) ? "/affiliate/" . SP_AFFILIATE_CODE : "";
74
- $this->_apiInterface = new ShortPixelAPI($this->_apiKey, $this->_compressionType, $this->_CMYKtoRGBconversion,
75
- $this->_resizeImages, $this->_resizeWidth, $this->_resizeHeight);
76
- $this->prioQ = new ShortPixelQueue($this);
77
  $this->view = new ShortPixelView($this);
78
 
79
  define('QUOTA_EXCEEDED', "Quota Exceeded. <a class='button button-smaller button-primary' href='https://shortpixel.com/login/"
80
- .$this->_apiKey."' target='_blank'>Extend Quota</a>"
81
  ."<a class='button button-smaller' href='admin.php?action=shortpixel_check_quota' target='_blank'>Check&nbsp;&nbsp;Quota</a>");
82
 
83
  $this->setDefaultViewModeList();//set default mode as list. only @ first run
@@ -104,7 +90,7 @@ class WPShortPixel {
104
  add_action( 'wp_ajax_shortpixel_dismiss_notice', array(&$this, 'dismissAdminNotice'));
105
  //backup restore
106
  add_action('admin_action_shortpixel_restore_backup', array(&$this, 'handleRestoreBackup'));
107
- //backup restore
108
  add_action('admin_action_shortpixel_check_quota', array(&$this, 'handleCheckQuota'));
109
 
110
  //This adds the constants used in PHP to be available also in JS
@@ -117,67 +103,18 @@ class WPShortPixel {
117
  $this->migrateBackupFolder();
118
  }
119
 
120
- public function populateOptions() {
121
-
122
- $this->_apiKey = self::getOpt('wp-short-pixel-apiKey', '');
123
- $this->_verifiedKey = self::getOpt('wp-short-pixel-verifiedKey', $this->_verifiedKey);
124
- $this->_compressionType = self::getOpt('wp-short-pixel-compression', $this->_compressionType);
125
- $this->_processThumbnails = self::getOpt('wp-short-process_thumbnails', $this->_processThumbnails);
126
- $this->_CMYKtoRGBconversion = self::getOpt('wp-short-pixel_cmyk2rgb', $this->_CMYKtoRGBconversion);
127
- $this->_backupImages = self::getOpt('wp-short-backup_images', $this->_backupImages);
128
- // the following practically set defaults for options if they're not set
129
- self::getOpt( 'wp-short-pixel-fileCount', 0);
130
- self::getOpt( 'wp-short-pixel-thumbnail-count', 0);//amount of optimized thumbnails
131
- self::getOpt( 'wp-short-pixel-files-under-5-percent', 0);//amount of optimized thumbnails
132
- self::getOpt( 'wp-short-pixel-savedSpace', 0);
133
- self::getOpt( 'wp-short-pixel-api-retries', 0);//sometimes we need to retry processing/downloading a file multiple times
134
- self::getOpt( 'wp-short-pixel-quota-exceeded', 0);
135
- self::getOpt( 'wp-short-pixel-total-original', 0);//amount of original data
136
- self::getOpt( 'wp-short-pixel-total-optimized', 0);//amount of optimized
137
- self::getOpt( 'wp-short-pixel-protocol', 'https');
138
-
139
- $this->_resizeImages = self::getOpt( 'wp-short-pixel-resize-images', 0);
140
- $this->_resizeWidth = self::getOpt( 'wp-short-pixel-resize-width', 0);
141
- $this->_resizeHeight = self::getOpt( 'wp-short-pixel-resize-height', 0);
142
  }
143
-
144
  public static function shortPixelActivatePlugin()//reset some params to avoid trouble for plugins that were activated/deactivated/activated
145
  {
146
  self::shortPixelDeactivatePlugin();
147
  if(SP_RESET_ON_ACTIVATE === true && WP_DEBUG === true) { //force reset plugin counters, only on specific occasions and on test environments
148
- delete_option('wp-short-pixel-apiKey');
149
- delete_option('wp-short-pixel-verifiedKey');
150
- delete_option('wp-short-pixel-compression');
151
- delete_option('wp-short-process_thumbnails');
152
- delete_option('wp-short-pixel_cmyk2rgb');
153
- delete_option('wp-short-backup_images');
154
- delete_option('wp-short-pixel-view-mode');
155
- update_option( 'wp-short-pixel-thumbnail-count', 0);
156
- update_option( 'wp-short-pixel-files-under-5-percent', 0);
157
- update_option( 'wp-short-pixel-savedSpace', 0);
158
- delete_option( 'wp-short-pixel-averageCompression');
159
- delete_option( 'wp-short-pixel-fileCount');
160
- delete_option( 'wp-short-pixel-total-original');
161
- delete_option( 'wp-short-pixel-total-optimized');
162
- update_option( 'wp-short-pixel-api-retries', 0);//sometimes we need to retry processing/downloading a file multiple times
163
- update_option( 'wp-short-pixel-quota-exceeded', 0);
164
- delete_option( 'wp-short-pixel-protocol');
165
- update_option( 'wp-short-pixel-bulk-ever-ran', 0);
166
- delete_option('wp-short-pixel-priorityQueue');
167
- delete_option( 'wp-short-pixel-resize-images');
168
- delete_option( 'wp-short-pixel-resize-width');
169
- delete_option( 'wp-short-pixel-resize-height');
170
- delete_option( 'wp-short-pixel-dismissed-notices');
171
- if(isset($_SESSION["wp-short-pixel-priorityQueue"])) {
172
- unset($_SESSION["wp-short-pixel-priorityQueue"]);
173
- }
174
- delete_option("wp-short-pixel-bulk-previous-percent");
175
- }
176
- if(!self::getOpt('wp-short-pixel-verifiedKey', false)) {
177
- update_option('wp-short-pixel-activation-notice', true);
178
  }
179
- update_option( 'wp-short-pixel-activation-date', time());
180
- delete_option( 'wp-short-pixel-bulk-last-status');
181
  }
182
 
183
  public static function shortPixelDeactivatePlugin()//reset some params to avoid trouble for plugins that were activated/deactivated/activated
@@ -185,15 +122,15 @@ class WPShortPixel {
185
  include_once dirname( __FILE__ ) . '/shortpixel_queue.php';
186
  ShortPixelQueue::resetBulk();
187
  ShortPixelQueue::resetPrio();
188
- delete_option('wp-short-pixel-activation-notice');
189
  }
190
 
191
  public function displayAdminNotices() {
192
- if(!$this->_verifiedKey) {
193
- $dismissed = self::getOpt( 'wp-short-pixel-dismissed-notices', array());
194
  $now = time();
195
- $act = self::getOpt( 'wp-short-pixel-activation-date', $now);
196
- if(self::getOpt( 'wp-short-pixel-activation-notice', false)) {
197
  ShortPixelView::displayActivationNotice();
198
  delete_option('wp-short-pixel-activation-notice');
199
  }
@@ -207,7 +144,7 @@ class WPShortPixel {
207
 
208
  public function dismissAdminNotice() {
209
  $noticeId = preg_replace('|[^a-z0-9]|i', '', $_GET['notice_id']);
210
- $dismissed = self::getOpt( 'wp-short-pixel-dismissed-notices', array());
211
  $dismissed[$noticeId] = true;
212
  update_option( 'wp-short-pixel-dismissed-notices', $dismissed);
213
  die(json_encode(array("Status" => 'success', "Message" => 'Notice ID: ' . $noticeId . ' dismissed')));
@@ -216,9 +153,9 @@ class WPShortPixel {
216
  //set default move as "list". only set once, it won't try to set the default mode again.
217
  public function setDefaultViewModeList()
218
  {
219
- if(get_option('wp-short-pixel-view-mode') === false)
220
  {
221
- add_option('wp-short-pixel-view-mode', 1, '', 'yes' );
222
  if ( function_exists('get_currentuserinfo') )
223
  {
224
  global $current_user;
@@ -254,7 +191,7 @@ class WPShortPixel {
254
  STATUS_NO_KEY: <?= ShortPixelAPI::STATUS_NO_KEY ?>,
255
  STATUS_RETRY: <?= ShortPixelAPI::STATUS_RETRY ?>,
256
  WP_PLUGIN_URL: '<?= plugins_url( '', __FILE__ ) ?>',
257
- API_KEY: "<?= $this->_apiKey ?>"
258
  });
259
  }
260
  });
@@ -273,16 +210,16 @@ class WPShortPixel {
273
  if($this->prioQ->processing()) {
274
  $extraClasses = " shortpixel-processing";
275
  }
276
- self::log("TOOLBAR: Quota exceeded: " . self::getOpt( 'wp-short-pixel-quota-exceeded', 0));
277
- if(self::getOpt( 'wp-short-pixel-quota-exceeded', 0)) {
278
  $extraClasses = " shortpixel-alert shortpixel-quota-exceeded";
279
  $tooltip = "ShortPixel quota exceeded. Click for details.";
280
- //$link = "http://shortpixel.com/login/" . $this->_apiKey;
281
  $link = "options-general.php?page=wp-shortpixel";
282
  //$blank = '_blank';
283
  //$icon = "shortpixel-alert.png";
284
  }
285
- $lastStatus = self::getOpt( 'wp-short-pixel-bulk-last-status', array('Status' => ShortPixelAPI::STATUS_SUCCESS));
286
  if($lastStatus['Status'] != ShortPixelAPI::STATUS_SUCCESS) {
287
  $extraClasses = " shortpixel-alert shortpixel-processing";
288
  $tooltip = $lastStatus['Message'];
@@ -300,13 +237,6 @@ class WPShortPixel {
300
  $wp_admin_bar->add_node( $args );
301
  }
302
 
303
- public static function getOpt($key, $default) {
304
- if(get_option($key) === false) {
305
- add_option( $key, $default, '', 'yes' );
306
- }
307
- return get_option($key);
308
- }
309
-
310
  public function handleCustomBulk() {
311
  // 1. get the action
312
  $wp_list_table = _get_list_table('WP_Media_List_Table');
@@ -337,7 +267,7 @@ class WPShortPixel {
337
 
338
  public function handleImageUpload($meta, $ID = null)
339
  {
340
- if( !$this->_verifiedKey) {// no API Key set/verified -> do nothing here, just return
341
  return $meta;
342
  }
343
  //else
@@ -351,7 +281,7 @@ class WPShortPixel {
351
  else
352
  {//the kind of file we can process. goody.
353
  $this->prioQ->push($ID);
354
- $URLsAndPATHs = $this->getURLsAndPATHs($ID, $meta);
355
  $this->_apiInterface->doRequests($URLsAndPATHs['URLs'], false, $ID);//send a processing request right after a file was uploaded, do NOT wait for response
356
  self::log("IMG: sent: " . json_encode($URLsAndPATHs));
357
  $meta['ShortPixel']['WaitingProcessing'] = true;
@@ -457,7 +387,7 @@ class WPShortPixel {
457
  public function handleImageProcessing($ID = null) {
458
  //die("stop");
459
  //0: check key
460
- if( $this->_verifiedKey == false) {
461
  if($ID == null){
462
  $ids = $this->getFromPrioAndCheck();
463
  $ID = (count($ids) > 0 ? $ids[0] : null);
@@ -523,7 +453,7 @@ class WPShortPixel {
523
  $prio = $this->prioQ->removeFromFailed($ID);
524
  $meta = wp_get_attachment_metadata($ID);
525
  $result["ThumbsCount"] = isset($meta['sizes']) && is_array($meta['sizes']) ? count($meta['sizes']): 0;
526
- $result["BackupEnabled"] = $this->_backupImages;
527
 
528
  if(!$prio && $ID <= $this->prioQ->getStartBulkId()) {
529
  $this->prioQ->setStartBulkId($ID - 1);
@@ -544,7 +474,7 @@ class WPShortPixel {
544
  $urlPath = implode("/", array_slice($filePath, 0, count($filePath) - 1));
545
  $urlBkPath = $this->_apiInterface->returnSubDir(get_attached_file($ID));
546
  $thumb = (isset($meta["sizes"]["medium"]) ? $meta["sizes"]["medium"]["file"] : (isset($meta["sizes"]["thumbnail"]) ? $meta["sizes"]["thumbnail"]["file"]: ""));
547
- if(strlen($thumb) && get_option('wp-short-backup_images') && $this->_processThumbnails) {
548
  $bkThumb = $uploadsUrl . SP_BACKUP . "/" . $urlBkPath . "/" . $thumb;
549
  }
550
  if(strlen($thumb)) {
@@ -724,13 +654,13 @@ class WPShortPixel {
724
  public function bulkProcess() {
725
  global $wpdb;
726
 
727
- if( $this->_verifiedKey == false ) {//invalid API Key
728
  ShortPixelView::displayActivationNotice();
729
  return;
730
  }
731
 
732
  $quotaData = $this->checkQuotaAndAlert();
733
- if(self::getOpt('wp-short-pixel-quota-exceeded', 0) != 0) return;
734
 
735
  if(isset($_POST['bulkProcessPause']))
736
  {//pause an ongoing bulk processing, it might be needed sometimes
@@ -783,8 +713,8 @@ class WPShortPixel {
783
  //$imageCount = $this->countAllProcessableFiles();
784
  //$imgProcessedCount = $this->countAllProcessedFiles();
785
  $imageOnlyThumbs = $quotaData['totalFiles'] - $quotaData['mainFiles'];
786
- $thumbsProcessedCount = self::getOpt( 'wp-short-pixel-thumbnail-count', 0);//amount of optimized thumbnails
787
- $under5PercentCount = self::getOpt( 'wp-short-pixel-files-under-5-percent', 0);//amount of under 5% optimized imgs.
788
 
789
  //average compression
790
  $averageCompression = self::getAverageCompression();
@@ -872,9 +802,7 @@ class WPShortPixel {
872
  {
873
  $validityData = $this->getQuotaInformation($_POST['key'], true, isset($_POST['validate']) && $_POST['validate'] == "validate");
874
 
875
- $this->_apiKey = $_POST['key'];
876
- $this->_apiInterface->setApiKey($this->_apiKey);
877
- update_option('wp-short-pixel-apiKey', $_POST['key']);
878
  if($validityData['APIKeyValid']) {
879
  if(isset($_POST['validate']) && $_POST['validate'] == "validate") {
880
  // delete last status if it was no valid key
@@ -889,13 +817,12 @@ class WPShortPixel {
889
  Please make sure that your server is accessible from the Internet before using the API or otherwise we won't be able to optimize them.");
890
  } else {
891
  if ( function_exists("is_multisite") && is_multisite() )
892
- $notice = array("status" => "success", "msg" => "API Key valid! <br>You seem to be running a multisite, please note that API Key can also be configured in wp-config.php like this:<BR> <b>define('SHORTPIXEL_API_KEY', '".$this->_apiKey."');</b>");
893
  else
894
  $notice = array("status" => "success", "msg" => 'API Key valid!');
895
  }
896
  }
897
- update_option('wp-short-pixel-verifiedKey', true);
898
- $this->_verifiedKey = true;
899
  //test that the "uploads" have the right rights and also we can create the backup dir for ShortPixel
900
  if ( !file_exists(SP_BACKUP_FOLDER) && !@mkdir(SP_BACKUP_FOLDER, 0777, true) )
901
  $notice = array("status" => "error", "msg" => "There is something preventing us to create a new folder for backing up your original files.<BR>
@@ -905,29 +832,22 @@ class WPShortPixel {
905
  //display notification
906
  $notice = array("status" => "error", "msg" => $validityData["Message"]);
907
  }
908
- update_option('wp-short-pixel-verifiedKey', false);
909
- $this->_verifiedKey = false;
910
  }
911
  }
912
 
913
 
914
  //if save button - we process the rest of the form elements
915
  if(isset($_POST['save'])) {
916
- update_option('wp-short-pixel-compression', $_POST['compressionType']);
917
- $this->_compressionType = $_POST['compressionType'];
918
- $this->_apiInterface->setCompressionType($this->_compressionType);
919
- if(isset($_POST['thumbnails'])) { $this->_processThumbnails = 1; } else { $this->_processThumbnails = 0; }
920
- if(isset($_POST['backupImages'])) { $this->_backupImages = 1; } else { $this->_backupImages = 0; }
921
- if(isset($_POST['cmyk2rgb'])) { $this->_CMYKtoRGBconversion = 1; } else { $this->_CMYKtoRGBconversion = 0; }
922
- update_option('wp-short-process_thumbnails', $this->_processThumbnails);
923
- update_option('wp-short-backup_images', $this->_backupImages);
924
- update_option('wp-short-pixel_cmyk2rgb', $this->_CMYKtoRGBconversion);
925
- $this->_resizeImages = (isset($_POST['resize']) ? 1: 0);
926
- $this->_resizeWidth = (isset($_POST['width']) ? $_POST['width']: $this->_resizeWidth);
927
- $this->_resizeHeight = (isset($_POST['height']) ? $_POST['height']: $this->_resizeHeight);
928
- update_option( 'wp-short-pixel-resize-images', $this->_resizeImages);
929
- update_option( 'wp-short-pixel-resize-width', 0 + $this->_resizeWidth);
930
- update_option( 'wp-short-pixel-resize-height', 0 + $this->_resizeHeight);
931
 
932
  if($_POST['save'] == "Save and Go to Bulk Process") {
933
  wp_redirect("upload.php?page=wp-short-pixel-bulk");
@@ -947,11 +867,11 @@ class WPShortPixel {
947
 
948
  $quotaData = $this->checkQuotaAndAlert();
949
 
950
- if($this->_verifiedKey) {
951
- $fileCount = number_format(get_option('wp-short-pixel-fileCount'));
952
- $savedSpace = self::formatBytes(get_option('wp-short-pixel-savedSpace'),2);
953
  $averageCompression = self::getAverageCompression();
954
- $savedBandwidth = self::formatBytes(get_option('wp-short-pixel-savedSpace') * 10000,2);
955
  if (is_numeric($quotaData['APICallsQuota'])) {
956
  $quotaData['APICallsQuota'] .= "/month";
957
  }
@@ -970,8 +890,8 @@ class WPShortPixel {
970
  }
971
 
972
  public function getAverageCompression(){
973
- return get_option('wp-short-pixel-total-optimized') > 0
974
- ? round(( 1 - ( get_option('wp-short-pixel-total-optimized') / get_option('wp-short-pixel-total-original') ) ) * 100, 2)
975
  : 0;
976
  }
977
 
@@ -984,7 +904,7 @@ class WPShortPixel {
984
  */
985
  public function getQuotaInformation($apiKey = null, $appendUserAgent = false, $validate = false) {
986
 
987
- if(is_null($apiKey)) { $apiKey = $this->_apiKey; }
988
 
989
  $requestURL = 'https://api.shortpixel.com/v2/api-status.php';
990
  $args = array('timeout'=> SP_VALIDATE_MAX_TIMEOUT,
@@ -1049,12 +969,12 @@ class WPShortPixel {
1049
  }
1050
 
1051
  if ( ( $data->APICallsMade + $data->APICallsMadeOneTime ) < ( $data->APICallsQuota + $data->APICallsQuotaOneTime ) ) //reset quota exceeded flag -> user is allowed to process more images.
1052
- update_option('wp-short-pixel-quota-exceeded',0);
1053
  else
1054
- update_option('wp-short-pixel-quota-exceeded',1);//activate quota limiting
1055
 
1056
  //if a not valid status exists, delete it
1057
- $lastStatus = self::getOpt( 'wp-short-pixel-bulk-last-status', array('Status' => ShortPixelAPI::STATUS_SUCCESS));
1058
  if($lastStatus['Status'] == ShortPixelAPI::STATUS_NO_KEY) {
1059
  delete_option('wp-short-pixel-bulk-last-status');
1060
  }
@@ -1086,14 +1006,14 @@ class WPShortPixel {
1086
  {
1087
  if ( $fileExtension <> "pdf" )
1088
  {
1089
- if(!$this->_verifiedKey)
1090
  print 'Invalid API Key. <a href="options-general.php?page=wp-shortpixel">Check your Settings</a>';
1091
  else
1092
  print 'Optimization N/A';
1093
  }
1094
  else
1095
  {
1096
- if ( get_option('wp-short-pixel-quota-exceeded') )
1097
  {
1098
  print QUOTA_EXCEEDED;
1099
  return;
@@ -1101,7 +1021,7 @@ class WPShortPixel {
1101
  else
1102
  {
1103
  print 'PDF not processed';
1104
- //if($this->_verifiedKey) {
1105
  print " <a class='button button-smaller button-primary' href=\"javascript:manualOptimization({$id})\">Optimize now</a>";
1106
  //}
1107
  return;
@@ -1112,7 +1032,7 @@ class WPShortPixel {
1112
  {
1113
  if(isset($meta['ShortPixel']['BulkProcessing']))
1114
  {
1115
- if ( get_option('wp-short-pixel-quota-exceeded') )
1116
  {
1117
  print QUOTA_EXCEEDED;
1118
  }
@@ -1130,12 +1050,14 @@ class WPShortPixel {
1130
  print "Bonus processing";
1131
  } else {
1132
  print 'Reduced by ';
1133
- print $data['ShortPixelImprovement'] . '%';
1134
  }
1135
  if ( get_option('wp-short-backup_images') && !isset($data['ShortPixel']['NoBackup'])) //display restore backup option only when backup is active
1136
  print " &nbsp; <a class='button button-smaller' href=\"admin.php?action=shortpixel_restore_backup&amp;attachment_ID={$id}\">Restore backup</a>";
1137
- if (isset($data['sizes']) && count($data['sizes'])) {
1138
- print "<br>+" . count($data['sizes']) . " thumbnails optimized";
 
 
1139
  }
1140
  }
1141
  elseif ( $data['ShortPixelImprovement'] <> "Optimization N/A" )
@@ -1143,7 +1065,7 @@ class WPShortPixel {
1143
  if ( trim(strip_tags($data['ShortPixelImprovement'])) == "Quota exceeded" )
1144
  {
1145
  print QUOTA_EXCEEDED;
1146
- if ( !get_option('wp-short-pixel-quota-exceeded') )
1147
  print " <a class='button button-smaller button-primary' href=\"javascript:manualOptimization({$id})\">Try again</a>";
1148
  }
1149
  elseif ( trim(strip_tags($data['ShortPixelImprovement'])) == "Cannot write optimized file" )
@@ -1162,7 +1084,7 @@ class WPShortPixel {
1162
  print "Optimization N/A";
1163
  }
1164
  } elseif(isset($data['ShortPixel']['WaitingProcessing'])) {
1165
- if ( get_option('wp-short-pixel-quota-exceeded') )
1166
  {
1167
  print QUOTA_EXCEEDED;
1168
  }
@@ -1180,7 +1102,7 @@ class WPShortPixel {
1180
 
1181
  if ( wp_attachment_is_image( $id ) )
1182
  {
1183
- if ( get_option('wp-short-pixel-quota-exceeded') )
1184
  {
1185
  print QUOTA_EXCEEDED;
1186
  }
@@ -1195,7 +1117,7 @@ class WPShortPixel {
1195
  }
1196
  elseif ( $fileExtension == "pdf" )
1197
  {
1198
- if ( get_option('wp-short-pixel-quota-exceeded') )
1199
  {
1200
  print QUOTA_EXCEEDED;
1201
  }
@@ -1279,7 +1201,7 @@ class WPShortPixel {
1279
 
1280
  //it is NOT a PDF file and thumbs are processable
1281
  if ( strtolower(substr($filePath[0],strrpos($filePath[0], ".")+1)) != "pdf"
1282
- && $this->_processThumbnails
1283
  && isset($meta['sizes']) && is_array($meta['sizes']))
1284
  {
1285
  foreach( $meta['sizes'] as $thumbnailInfo )
@@ -1359,6 +1281,20 @@ class WPShortPixel {
1359
  $limit = 500;
1360
  $pointer = 0;
1361
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1362
  //count all the files, main and thumbs
1363
  while ( 1 )
1364
  {
@@ -1369,28 +1305,31 @@ class WPShortPixel {
1369
  if ( empty($filesList) ) //we parsed all the results
1370
  break;
1371
 
 
1372
  foreach ( $filesList as $file )
1373
  {
1374
  if ( $file->meta_key == "_wp_attached_file" )
1375
  {//count pdf files only
1376
  $extension = substr($file->meta_value, strrpos($file->meta_value,".") + 1 );
1377
- if ( $extension == "pdf" )
1378
  {
1379
  $totalFiles++;
1380
  $mainFiles++;
 
1381
  }
1382
  }
1383
  else
1384
  {
1385
  $attachment = unserialize($file->meta_value);
1386
- if(isset($attachment['file']) && self::isProcessablePath($attachment['file'])){
1387
- if ( isset($attachment['sizes']) )
1388
  $totalFiles += count($attachment['sizes']);
1389
-
1390
  if ( isset($attachment['file']) )
1391
  {
1392
  $totalFiles++;
1393
  $mainFiles++;
 
1394
  }
1395
  }
1396
  }
@@ -1404,7 +1343,7 @@ class WPShortPixel {
1404
  }
1405
 
1406
 
1407
- //count all the processable files in media library (while limiting the results to max 10000)
1408
  public function countAllProcessedFiles($maxId = PHP_INT_MAX, $minId = 0){
1409
  global $wpdb;
1410
 
@@ -1413,6 +1352,7 @@ class WPShortPixel {
1413
  $pointer = 0;
1414
 
1415
  //count all the files, main and thumbs
 
1416
  while ( 1 )
1417
  {
1418
  $filesList= $wpdb->get_results("SELECT * FROM " . $wpdb->prefix . "postmeta
@@ -1425,12 +1365,20 @@ class WPShortPixel {
1425
  foreach ( $filesList as $file )
1426
  {
1427
  $attachment = unserialize($file->meta_value);
1428
- if ( isset($attachment['ShortPixelImprovement']) && ($attachment['ShortPixelImprovement'] > 0 || $attachment['ShortPixelImprovement'] === 0.0)) {
 
 
 
1429
  $processedMainFiles++;
1430
  $processedTotalFiles++;
1431
- if ( isset($attachment['sizes']) ) {
 
 
1432
  $processedTotalFiles += count($attachment['sizes']);
1433
  }
 
 
 
1434
  }
1435
  }
1436
  unset($filesList);
@@ -1486,7 +1434,7 @@ class WPShortPixel {
1486
  }
1487
 
1488
  public function getApiKey() {
1489
- return $this->_apiKey;
1490
  }
1491
 
1492
  public function getPrioQ() {
@@ -1494,35 +1442,41 @@ class WPShortPixel {
1494
  }
1495
 
1496
  public function backupImages() {
1497
- return $this->_backupImages;
1498
  }
1499
 
1500
  public function processThumbnails() {
1501
- return $this->_processThumbnails;
1502
  }
 
1503
  public function getCMYKtoRGBconversion() {
1504
- return $this->_CMYKtoRGBconversion;
 
 
 
 
1505
  }
1506
 
1507
- public function getResizeImages() {
1508
- return $this->_resizeImages;
 
1509
  }
1510
 
1511
  public function getResizeWidth() {
1512
- return $this->_resizeWidth;
1513
  }
1514
 
1515
  public function getResizeHeight() {
1516
- return $this->_resizeHeight;
1517
  }
1518
  public function getAffiliateSufix() {
1519
  return $this->_affiliateSufix;
1520
  }
1521
  public function getVerifiedKey() {
1522
- return $this->_verifiedKey;
1523
  }
1524
  public function getCompressionType() {
1525
- return $this->_compressionType;
1526
  }
1527
 
1528
  }
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" target="_blank">Settings &gt; ShortPixel</a> page on how to start optimizing your image library and make your website load faster.
6
+ * Version: 3.1.9
7
  * Author: ShortPixel
8
  * Author URI: https://shortpixel.com
9
  */
10
 
11
+ require_once('wp-shortpixel-settings.php');
12
  require_once('shortpixel_api.php');
13
  require_once('shortpixel_queue.php');
14
  require_once('shortpixel_view.php');
22
 
23
  define('SP_AFFILIATE_CODE', '');
24
 
25
+ define('PLUGIN_VERSION', "3.1.9");
26
  define('SP_MAX_TIMEOUT', 10);
27
  define('SP_VALIDATE_MAX_TIMEOUT', 60);
28
  define('SP_BACKUP', 'ShortpixelBackups');
43
  class WPShortPixel {
44
 
45
  const BULK_EMPTY_QUEUE = 0;
 
 
 
 
 
 
 
 
46
 
47
+ private $_affiliateSufix;
 
 
48
 
49
  private $_apiInterface = null;
50
+ private $_settings = null;
51
  private $prioQ = null;
52
  private $view = null;
53
 
 
 
 
 
 
54
  public function __construct() {
55
  if (!session_id()) {
56
  session_start();
57
  }
 
58
 
59
  $this->_affiliateSufix = (strlen(SP_AFFILIATE_CODE)) ? "/affiliate/" . SP_AFFILIATE_CODE : "";
60
+ $this->_settings = new WPShortPixelSettings();
61
+ $this->_apiInterface = new ShortPixelAPI($this->_settings);
62
+ $this->prioQ = new ShortPixelQueue($this, $this->_settings);
63
  $this->view = new ShortPixelView($this);
64
 
65
  define('QUOTA_EXCEEDED', "Quota Exceeded. <a class='button button-smaller button-primary' href='https://shortpixel.com/login/"
66
+ .$this->_settings->apiKey."' target='_blank'>Extend Quota</a>"
67
  ."<a class='button button-smaller' href='admin.php?action=shortpixel_check_quota' target='_blank'>Check&nbsp;&nbsp;Quota</a>");
68
 
69
  $this->setDefaultViewModeList();//set default mode as list. only @ first run
90
  add_action( 'wp_ajax_shortpixel_dismiss_notice', array(&$this, 'dismissAdminNotice'));
91
  //backup restore
92
  add_action('admin_action_shortpixel_restore_backup', array(&$this, 'handleRestoreBackup'));
93
+ //check quota
94
  add_action('admin_action_shortpixel_check_quota', array(&$this, 'handleCheckQuota'));
95
 
96
  //This adds the constants used in PHP to be available also in JS
103
  $this->migrateBackupFolder();
104
  }
105
 
106
+ //handling older
107
+ public function WPShortPixel() {
108
+ $this->__construct();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
109
  }
110
+
111
  public static function shortPixelActivatePlugin()//reset some params to avoid trouble for plugins that were activated/deactivated/activated
112
  {
113
  self::shortPixelDeactivatePlugin();
114
  if(SP_RESET_ON_ACTIVATE === true && WP_DEBUG === true) { //force reset plugin counters, only on specific occasions and on test environments
115
+ WPShortPixelSettings::debugResetOptions();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
116
  }
117
+ WPShortPixelSettings::onActivate();
 
118
  }
119
 
120
  public static function shortPixelDeactivatePlugin()//reset some params to avoid trouble for plugins that were activated/deactivated/activated
122
  include_once dirname( __FILE__ ) . '/shortpixel_queue.php';
123
  ShortPixelQueue::resetBulk();
124
  ShortPixelQueue::resetPrio();
125
+ WPShortPixelSettings::onDeactivate();
126
  }
127
 
128
  public function displayAdminNotices() {
129
+ if(!$this->_settings->verifiedKey) {
130
+ $dismissed = $this->_settings->getOpt( 'wp-short-pixel-dismissed-notices', array());
131
  $now = time();
132
+ $act = $this->_settings->getOpt( 'wp-short-pixel-activation-date', $now);
133
+ if($this->_settings->getOpt( 'wp-short-pixel-activation-notice', false)) {
134
  ShortPixelView::displayActivationNotice();
135
  delete_option('wp-short-pixel-activation-notice');
136
  }
144
 
145
  public function dismissAdminNotice() {
146
  $noticeId = preg_replace('|[^a-z0-9]|i', '', $_GET['notice_id']);
147
+ $dismissed = $this->_settings->getOpt( 'wp-short-pixel-dismissed-notices', array());
148
  $dismissed[$noticeId] = true;
149
  update_option( 'wp-short-pixel-dismissed-notices', $dismissed);
150
  die(json_encode(array("Status" => 'success', "Message" => 'Notice ID: ' . $noticeId . ' dismissed')));
153
  //set default move as "list". only set once, it won't try to set the default mode again.
154
  public function setDefaultViewModeList()
155
  {
156
+ if($this->_settings->getOpt('wp-short-pixel-view-mode') === false)
157
  {
158
+ $this->_settings->setOpt('wp-short-pixel-view-mode', 1);
159
  if ( function_exists('get_currentuserinfo') )
160
  {
161
  global $current_user;
191
  STATUS_NO_KEY: <?= ShortPixelAPI::STATUS_NO_KEY ?>,
192
  STATUS_RETRY: <?= ShortPixelAPI::STATUS_RETRY ?>,
193
  WP_PLUGIN_URL: '<?= plugins_url( '', __FILE__ ) ?>',
194
+ API_KEY: "<?= $this->_settings->apiKey ?>"
195
  });
196
  }
197
  });
210
  if($this->prioQ->processing()) {
211
  $extraClasses = " shortpixel-processing";
212
  }
213
+ self::log("TOOLBAR: Quota exceeded: " . $this->_settings->quotaExceeded);
214
+ if($this->_settings->quotaExceeded) {
215
  $extraClasses = " shortpixel-alert shortpixel-quota-exceeded";
216
  $tooltip = "ShortPixel quota exceeded. Click for details.";
217
+ //$link = "http://shortpixel.com/login/" . $this->_settings->apiKey;
218
  $link = "options-general.php?page=wp-shortpixel";
219
  //$blank = '_blank';
220
  //$icon = "shortpixel-alert.png";
221
  }
222
+ $lastStatus = $this->_settings->getOpt( 'wp-short-pixel-bulk-last-status', array('Status' => ShortPixelAPI::STATUS_SUCCESS));
223
  if($lastStatus['Status'] != ShortPixelAPI::STATUS_SUCCESS) {
224
  $extraClasses = " shortpixel-alert shortpixel-processing";
225
  $tooltip = $lastStatus['Message'];
237
  $wp_admin_bar->add_node( $args );
238
  }
239
 
 
 
 
 
 
 
 
240
  public function handleCustomBulk() {
241
  // 1. get the action
242
  $wp_list_table = _get_list_table('WP_Media_List_Table');
267
 
268
  public function handleImageUpload($meta, $ID = null)
269
  {
270
+ if( !$this->_settings->verifiedKey) {// no API Key set/verified -> do nothing here, just return
271
  return $meta;
272
  }
273
  //else
281
  else
282
  {//the kind of file we can process. goody.
283
  $this->prioQ->push($ID);
284
+ $URLsAndPATHs = $this->getURLsAndPATHs($ID, $meta);
285
  $this->_apiInterface->doRequests($URLsAndPATHs['URLs'], false, $ID);//send a processing request right after a file was uploaded, do NOT wait for response
286
  self::log("IMG: sent: " . json_encode($URLsAndPATHs));
287
  $meta['ShortPixel']['WaitingProcessing'] = true;
387
  public function handleImageProcessing($ID = null) {
388
  //die("stop");
389
  //0: check key
390
+ if( $this->_settings->verifiedKey == false) {
391
  if($ID == null){
392
  $ids = $this->getFromPrioAndCheck();
393
  $ID = (count($ids) > 0 ? $ids[0] : null);
453
  $prio = $this->prioQ->removeFromFailed($ID);
454
  $meta = wp_get_attachment_metadata($ID);
455
  $result["ThumbsCount"] = isset($meta['sizes']) && is_array($meta['sizes']) ? count($meta['sizes']): 0;
456
+ $result["BackupEnabled"] = $this->_settings->backupImages;
457
 
458
  if(!$prio && $ID <= $this->prioQ->getStartBulkId()) {
459
  $this->prioQ->setStartBulkId($ID - 1);
474
  $urlPath = implode("/", array_slice($filePath, 0, count($filePath) - 1));
475
  $urlBkPath = $this->_apiInterface->returnSubDir(get_attached_file($ID));
476
  $thumb = (isset($meta["sizes"]["medium"]) ? $meta["sizes"]["medium"]["file"] : (isset($meta["sizes"]["thumbnail"]) ? $meta["sizes"]["thumbnail"]["file"]: ""));
477
+ if(strlen($thumb) && get_option('wp-short-backup_images') && $this->_settings->processThumbnails) {
478
  $bkThumb = $uploadsUrl . SP_BACKUP . "/" . $urlBkPath . "/" . $thumb;
479
  }
480
  if(strlen($thumb)) {
654
  public function bulkProcess() {
655
  global $wpdb;
656
 
657
+ if( $this->_settings->verifiedKey == false ) {//invalid API Key
658
  ShortPixelView::displayActivationNotice();
659
  return;
660
  }
661
 
662
  $quotaData = $this->checkQuotaAndAlert();
663
+ if($this->_settings->getOpt('wp-short-pixel-quota-exceeded', 0) != 0) return;
664
 
665
  if(isset($_POST['bulkProcessPause']))
666
  {//pause an ongoing bulk processing, it might be needed sometimes
713
  //$imageCount = $this->countAllProcessableFiles();
714
  //$imgProcessedCount = $this->countAllProcessedFiles();
715
  $imageOnlyThumbs = $quotaData['totalFiles'] - $quotaData['mainFiles'];
716
+ $thumbsProcessedCount = $this->_settings->getOpt( 'wp-short-pixel-thumbnail-count', 0);//amount of optimized thumbnails
717
+ $under5PercentCount = $this->_settings->getOpt( 'wp-short-pixel-files-under-5-percent', 0);//amount of under 5% optimized imgs.
718
 
719
  //average compression
720
  $averageCompression = self::getAverageCompression();
802
  {
803
  $validityData = $this->getQuotaInformation($_POST['key'], true, isset($_POST['validate']) && $_POST['validate'] == "validate");
804
 
805
+ $this->_settings->apiKey = $_POST['key'];
 
 
806
  if($validityData['APIKeyValid']) {
807
  if(isset($_POST['validate']) && $_POST['validate'] == "validate") {
808
  // delete last status if it was no valid key
817
  Please make sure that your server is accessible from the Internet before using the API or otherwise we won't be able to optimize them.");
818
  } else {
819
  if ( function_exists("is_multisite") && is_multisite() )
820
+ $notice = array("status" => "success", "msg" => "API Key valid! <br>You seem to be running a multisite, please note that API Key can also be configured in wp-config.php like this:<BR> <b>define('SHORTPIXEL_API_KEY', '".$this->_settings->apiKey."');</b>");
821
  else
822
  $notice = array("status" => "success", "msg" => 'API Key valid!');
823
  }
824
  }
825
+ $this->_settings->verifiedKey = true;
 
826
  //test that the "uploads" have the right rights and also we can create the backup dir for ShortPixel
827
  if ( !file_exists(SP_BACKUP_FOLDER) && !@mkdir(SP_BACKUP_FOLDER, 0777, true) )
828
  $notice = array("status" => "error", "msg" => "There is something preventing us to create a new folder for backing up your original files.<BR>
832
  //display notification
833
  $notice = array("status" => "error", "msg" => $validityData["Message"]);
834
  }
835
+ $this->_settings->verifiedKey = false;
 
836
  }
837
  }
838
 
839
 
840
  //if save button - we process the rest of the form elements
841
  if(isset($_POST['save'])) {
842
+ $this->_settings->compressionType = $_POST['compressionType'];
843
+ if(isset($_POST['thumbnails'])) { $this->_settings->processThumbnails = 1; } else { $this->_settings->processThumbnails = 0; }
844
+ if(isset($_POST['backupImages'])) { $this->_settings->backupImages = 1; } else { $this->_settings->backupImages = 0; }
845
+ if(isset($_POST['cmyk2rgb'])) { $this->_settings->CMYKtoRGBconversion = 1; } else { $this->_settings->CMYKtoRGBconversion = 0; }
846
+ $this->_settings->keepExif = isset($_POST['removeExif']) ? 0 : 1;
847
+ //delete_option('wp-short-pixel-keep-exif');
848
+ $this->_settings->resizeImages = (isset($_POST['resize']) ? 1: 0);
849
+ $this->_settings->resizeWidth = (isset($_POST['width']) ? $_POST['width']: $this->_settings->resizeWidth);
850
+ $this->_settings->resizeHeight = (isset($_POST['height']) ? $_POST['height']: $this->_settings->resizeHeight);
 
 
 
 
 
 
851
 
852
  if($_POST['save'] == "Save and Go to Bulk Process") {
853
  wp_redirect("upload.php?page=wp-short-pixel-bulk");
867
 
868
  $quotaData = $this->checkQuotaAndAlert();
869
 
870
+ if($this->_settings->verifiedKey) {
871
+ $fileCount = number_format($this->_settings->fileCount);
872
+ $savedSpace = self::formatBytes($this->_settings->savedSpace,2);
873
  $averageCompression = self::getAverageCompression();
874
+ $savedBandwidth = self::formatBytes($this->_settings->savedSpace * 10000,2);
875
  if (is_numeric($quotaData['APICallsQuota'])) {
876
  $quotaData['APICallsQuota'] .= "/month";
877
  }
890
  }
891
 
892
  public function getAverageCompression(){
893
+ return $this->_settings->totalOptimized > 0
894
+ ? round(( 1 - ( $this->_settings->totalOptimized / $this->_settings->totalOriginal ) ) * 100, 2)
895
  : 0;
896
  }
897
 
904
  */
905
  public function getQuotaInformation($apiKey = null, $appendUserAgent = false, $validate = false) {
906
 
907
+ if(is_null($apiKey)) { $apiKey = $this->_settings->apiKey; }
908
 
909
  $requestURL = 'https://api.shortpixel.com/v2/api-status.php';
910
  $args = array('timeout'=> SP_VALIDATE_MAX_TIMEOUT,
969
  }
970
 
971
  if ( ( $data->APICallsMade + $data->APICallsMadeOneTime ) < ( $data->APICallsQuota + $data->APICallsQuotaOneTime ) ) //reset quota exceeded flag -> user is allowed to process more images.
972
+ $this->_settings->quotaExceeded = 0;
973
  else
974
+ $this->_settings->quotaExceeded = 1;//activate quota limiting
975
 
976
  //if a not valid status exists, delete it
977
+ $lastStatus = $this->_settings->getOpt( 'wp-short-pixel-bulk-last-status', array('Status' => ShortPixelAPI::STATUS_SUCCESS));
978
  if($lastStatus['Status'] == ShortPixelAPI::STATUS_NO_KEY) {
979
  delete_option('wp-short-pixel-bulk-last-status');
980
  }
1006
  {
1007
  if ( $fileExtension <> "pdf" )
1008
  {
1009
+ if(!$this->_settings->verifiedKey)
1010
  print 'Invalid API Key. <a href="options-general.php?page=wp-shortpixel">Check your Settings</a>';
1011
  else
1012
  print 'Optimization N/A';
1013
  }
1014
  else
1015
  {
1016
+ if ( $this->_settings->quotaExceeded )
1017
  {
1018
  print QUOTA_EXCEEDED;
1019
  return;
1021
  else
1022
  {
1023
  print 'PDF not processed';
1024
+ //if($this->_settings->verifiedKey) {
1025
  print " <a class='button button-smaller button-primary' href=\"javascript:manualOptimization({$id})\">Optimize now</a>";
1026
  //}
1027
  return;
1032
  {
1033
  if(isset($meta['ShortPixel']['BulkProcessing']))
1034
  {
1035
+ if ( $this->_settings->quotaExceeded )
1036
  {
1037
  print QUOTA_EXCEEDED;
1038
  }
1050
  print "Bonus processing";
1051
  } else {
1052
  print 'Reduced by ';
1053
+ print $data['ShortPixelImprovement'] . '%' . (isset($data['ShortPixel']['type']) ? ' (' . $data['ShortPixel']['type'] . ')' : '' );
1054
  }
1055
  if ( get_option('wp-short-backup_images') && !isset($data['ShortPixel']['NoBackup'])) //display restore backup option only when backup is active
1056
  print " &nbsp; <a class='button button-smaller' href=\"admin.php?action=shortpixel_restore_backup&amp;attachment_ID={$id}\">Restore backup</a>";
1057
+ if (isset($data['ShortPixel']['thumbs']) || (isset($data['sizes']) && count($data['sizes']))) {
1058
+ $sizes = count($data['sizes']);
1059
+ $cnt = isset($data['ShortPixel']['thumbsOpt']) ? $data['ShortPixel']['thumbsOpt'] : $sizes;
1060
+ print "<br>+" . $cnt . ($sizes > $cnt ? " of ".$sizes : '') . " thumbnails optimized";
1061
  }
1062
  }
1063
  elseif ( $data['ShortPixelImprovement'] <> "Optimization N/A" )
1065
  if ( trim(strip_tags($data['ShortPixelImprovement'])) == "Quota exceeded" )
1066
  {
1067
  print QUOTA_EXCEEDED;
1068
+ if ( !$this->_settings->quotaExceeded )
1069
  print " <a class='button button-smaller button-primary' href=\"javascript:manualOptimization({$id})\">Try again</a>";
1070
  }
1071
  elseif ( trim(strip_tags($data['ShortPixelImprovement'])) == "Cannot write optimized file" )
1084
  print "Optimization N/A";
1085
  }
1086
  } elseif(isset($data['ShortPixel']['WaitingProcessing'])) {
1087
+ if ( $this->_settings->quotaExceeded )
1088
  {
1089
  print QUOTA_EXCEEDED;
1090
  }
1102
 
1103
  if ( wp_attachment_is_image( $id ) )
1104
  {
1105
+ if ( $this->_settings->quotaExceeded )
1106
  {
1107
  print QUOTA_EXCEEDED;
1108
  }
1117
  }
1118
  elseif ( $fileExtension == "pdf" )
1119
  {
1120
+ if ( $this->_settings->quotaExceeded )
1121
  {
1122
  print QUOTA_EXCEEDED;
1123
  }
1201
 
1202
  //it is NOT a PDF file and thumbs are processable
1203
  if ( strtolower(substr($filePath[0],strrpos($filePath[0], ".")+1)) != "pdf"
1204
+ && $this->_settings->processThumbnails
1205
  && isset($meta['sizes']) && is_array($meta['sizes']))
1206
  {
1207
  foreach( $meta['sizes'] as $thumbnailInfo )
1281
  $limit = 500;
1282
  $pointer = 0;
1283
 
1284
+ //METODA DE A OBTINE LISTA DE IMAGINI CU API-UL WP
1285
+ $query_images_args = array(
1286
+ 'post_type' => 'attachment',
1287
+ 'post_mime_type' => array('image','application/pdf'),
1288
+ 'post_status' => 'inherit',
1289
+ 'posts_per_page' => - 1,
1290
+ );
1291
+
1292
+ $query_images = new WP_Query( $query_images_args );
1293
+
1294
+ //var_dump(count($query_images->posts));
1295
+
1296
+
1297
+
1298
  //count all the files, main and thumbs
1299
  while ( 1 )
1300
  {
1305
  if ( empty($filesList) ) //we parsed all the results
1306
  break;
1307
 
1308
+ $filesMap = array();
1309
  foreach ( $filesList as $file )
1310
  {
1311
  if ( $file->meta_key == "_wp_attached_file" )
1312
  {//count pdf files only
1313
  $extension = substr($file->meta_value, strrpos($file->meta_value,".") + 1 );
1314
+ if ( $extension == "pdf" && !isset($filesMap[$file->meta_value]))
1315
  {
1316
  $totalFiles++;
1317
  $mainFiles++;
1318
+ $filesMap[$file->meta_value] = 1;
1319
  }
1320
  }
1321
  else
1322
  {
1323
  $attachment = unserialize($file->meta_value);
1324
+ if(isset($attachment['file']) && !isset($filesMap[$attachment['file']]) && self::isProcessablePath($attachment['file'])){
1325
+ if ( isset($attachment['sizes']) ) {
1326
  $totalFiles += count($attachment['sizes']);
1327
+ }
1328
  if ( isset($attachment['file']) )
1329
  {
1330
  $totalFiles++;
1331
  $mainFiles++;
1332
+ $filesMap[$attachment['file']] = 1;
1333
  }
1334
  }
1335
  }
1343
  }
1344
 
1345
 
1346
+ //count all the already processed files in media library (while limiting the results to max 10000)
1347
  public function countAllProcessedFiles($maxId = PHP_INT_MAX, $minId = 0){
1348
  global $wpdb;
1349
 
1352
  $pointer = 0;
1353
 
1354
  //count all the files, main and thumbs
1355
+ $filesMap = array();
1356
  while ( 1 )
1357
  {
1358
  $filesList= $wpdb->get_results("SELECT * FROM " . $wpdb->prefix . "postmeta
1365
  foreach ( $filesList as $file )
1366
  {
1367
  $attachment = unserialize($file->meta_value);
1368
+ if ( isset($attachment['ShortPixelImprovement'])
1369
+ && ($attachment['ShortPixelImprovement'] > 0 || $attachment['ShortPixelImprovement'] === 0.0)
1370
+ //for PDFs there is no file field so just let it pass.
1371
+ && (!isset($attachment['file']) || !isset($filesMap[$attachment['file']])) ) {
1372
  $processedMainFiles++;
1373
  $processedTotalFiles++;
1374
+ if ( isset($attachment['ShortPixel']['thumbsOpt']) ) {
1375
+ $processedTotalFiles += $attachment['ShortPixel']['thumbsOpt'];
1376
+ } elseif ( isset($attachment['sizes']) ) {
1377
  $processedTotalFiles += count($attachment['sizes']);
1378
  }
1379
+ if ( isset($attachment['file']) ) {
1380
+ $filesMap[$attachment['file']] = 1;
1381
+ }
1382
  }
1383
  }
1384
  unset($filesList);
1434
  }
1435
 
1436
  public function getApiKey() {
1437
+ return $this->_settings->apiKey;
1438
  }
1439
 
1440
  public function getPrioQ() {
1442
  }
1443
 
1444
  public function backupImages() {
1445
+ return $this->_settings->backupImages;
1446
  }
1447
 
1448
  public function processThumbnails() {
1449
+ return $this->_settings->processThumbnails;
1450
  }
1451
+
1452
  public function getCMYKtoRGBconversion() {
1453
+ return $this->_settings->CMYKtoRGBconversion;
1454
+ }
1455
+
1456
+ public function getSettings() {
1457
+ return $this->_settings;
1458
  }
1459
 
1460
+
1461
+ public function getResizeImages() {
1462
+ return $this->_settings->resizeImages;
1463
  }
1464
 
1465
  public function getResizeWidth() {
1466
+ return $this->_settings->resizeWidth;
1467
  }
1468
 
1469
  public function getResizeHeight() {
1470
+ return $this->_settings->resizeHeight;
1471
  }
1472
  public function getAffiliateSufix() {
1473
  return $this->_affiliateSufix;
1474
  }
1475
  public function getVerifiedKey() {
1476
+ return $this->_settings->verifiedKey;
1477
  }
1478
  public function getCompressionType() {
1479
+ return $this->_settings->compressionType;
1480
  }
1481
 
1482
  }