ShortPixel Image Optimizer - Version 2.1.0

Version Description

  • speedier file download from API resource
  • SQL changed to use less CPU intensive queries
  • improved BULK processing logic, faster results
  • different small fixes & improvements
  • skip processed images when running bulk processing
Download this release

Release Info

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

Code changes from version 2.0.9 to 2.1.0

Files changed (3) hide show
  1. readme.txt +8 -4
  2. shortpixel_api.php +81 -61
  3. wp-shortpixel.php +279 -182
readme.txt CHANGED
@@ -4,7 +4,7 @@ Contributors: AlexSP
4
  Tags: picture, optimization, image editor, pngout, upload speed, shortpixel, compression, jpegmini, webp, lossless, cwebp, media, tinypng, jpegtran,image, image optimisation, 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, optimise pdf, shrink pdf, jpg, jpeg, jpg optimisation, optimise jpg, shrink jpg, gif, animated gif, optimise gif
5
  Requires at least: 3.0.0 or higher
6
  Tested up to: 4.1.1
7
- Stable tag: 2.0.9
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
@@ -107,10 +107,14 @@ The ShortPixel team is here to help. <a href="https://shortpixel.com/contact">Co
107
 
108
  == Changelog ==
109
 
110
- = 2.0.9 =
 
 
 
 
 
 
111
 
112
- * fixed some missing quotes
113
- * fixed DB access in a function
114
 
115
  = 2.0.8 =
116
 
4
  Tags: picture, optimization, image editor, pngout, upload speed, shortpixel, compression, jpegmini, webp, lossless, cwebp, media, tinypng, jpegtran,image, image optimisation, 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, optimise pdf, shrink pdf, jpg, jpeg, jpg optimisation, optimise jpg, shrink jpg, gif, animated gif, optimise gif
5
  Requires at least: 3.0.0 or higher
6
  Tested up to: 4.1.1
7
+ Stable tag: 2.1.0
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
107
 
108
  == Changelog ==
109
 
110
+ = 2.1.0 =
111
+
112
+ * speedier file download from API resource
113
+ * SQL changed to use less CPU intensive queries
114
+ * improved BULK processing logic, faster results
115
+ * different small fixes & improvements
116
+ * skip processed images when running bulk processing
117
 
 
 
118
 
119
  = 2.0.8 =
120
 
shortpixel_api.php CHANGED
@@ -93,6 +93,9 @@ class shortpixel_api {
93
  $meta['ShortPixelImprovement'] = 'Timed out while processing.';
94
  unset($meta['ShortPixel']['WaitingProcessing']);
95
  wp_update_attachment_metadata($ID, $meta);
 
 
 
96
  }
97
  else
98
  {//we'll try again next time user visits a page on admin panel
@@ -100,8 +103,6 @@ class shortpixel_api {
100
  update_option('wp-short-pixel-api-retries', $apiRetries);
101
  exit('Timed out while processing. (pass '.$apiRetries.')');
102
  }
103
-
104
-
105
  }
106
 
107
  $response = $this->doRequests($url, $filePaths, $ID);//send requests to API
@@ -112,27 +113,21 @@ class shortpixel_api {
112
  return false;
113
  }
114
 
115
- $data = $this->parseResponse($response);//get the actual response from API
116
 
117
- if( !is_array($data) ) {// the answer from API isn't good
118
- printf('Web service returned an error. Please try again later.');
119
- return false;
120
- }
121
-
122
- $firstImage = $data[0];//extract as object first image
123
-
124
- //this part makes sure that all the sizes were processed and ready to be downloaded
125
- foreach ( $data as $imageObject )
126
  {
127
- if ( $imageObject->Status->Code <> 2 )
128
- {
129
- sleep(2);
130
- //echo "\n not ready($apiRetries):" . $imageObject->OriginalURL;//fai
131
- return $this->processImage($url, $filePaths, $ID, $startTime);
132
- }
133
- }
134
-
135
- switch($firstImage->Status->Code) {
 
 
136
  case 1:
137
  //handle image has been scheduled
138
  sleep(1);
@@ -142,6 +137,15 @@ class shortpixel_api {
142
  //handle image has been processed
143
  $this->handleSuccess($data, $url, $filePaths, $ID);
144
  break;
 
 
 
 
 
 
 
 
 
145
  case -403:
146
  return 'Quota exceeded</br>';
147
  break;
@@ -155,15 +159,16 @@ class shortpixel_api {
155
  //handle error
156
  if ( isset($data[0]->Status->Message) )
157
  return $data[0]->Status->Message;
158
-
 
159
  }
160
-
161
  return $data;
162
  }
163
 
164
 
165
  public function handleSuccess($callData, $url, $filePath, $ID) {
166
-
167
  $counter = 0;
168
  if($this->_compressionType)
169
  {
@@ -178,38 +183,43 @@ class shortpixel_api {
178
 
179
  foreach ( $callData as $fileData )//download each file from array and process it
180
  {
181
-
182
- if ( $counter == 0 )//save percent improvement for main file
183
- $percentImprovement = $fileData->PercentImprovement;
184
-
185
- $correctFileSize = $fileData->$fileSize;
186
- $tempFiles[$counter] = download_url(urldecode($fileData->$fileType));
187
-
188
- if(is_wp_error( $tempFiles[$counter] )) //also tries with http instead of https
189
  {
190
- sleep(2);
191
- $tempFiles[$counter] = download_url(str_replace('https://', 'http://', urldecode($fileData->$fileType)));
192
- }
193
 
194
- if ( is_wp_error( $tempFiles[$counter] ) ) {
195
- @unlink($tempFiles[$counter]);
196
- return sprintf("Error downloading file (%s)", $tempFiles[$counter]->get_error_message());
197
- die;
198
- }
199
-
200
- //check response so that download is OK
201
- if( filesize($tempFiles[$counter]) != $correctFileSize) {
202
- return sprintf("Error downloading file - incorrect file size");
203
- die;
204
- }
205
-
206
- if (!file_exists($tempFiles[$counter])) {
207
- return sprintf("Unable to locate downloaded file (%s)", $tempFiles[$counter]);
208
- die;
 
 
 
 
 
 
 
 
 
 
209
  }
 
 
210
  $counter++;
211
  }
212
 
 
213
  //if backup is enabled
214
  if(get_option('wp-short-backup_images'))
215
  {
@@ -220,9 +230,9 @@ class shortpixel_api {
220
  return sprintf("Backup folder does not exist and it could not be created");
221
  }
222
  $meta = wp_get_attachment_metadata($ID);
 
223
  $source = $filePath;
224
- $SubDir = trim(substr($meta['file'],0,strrpos($meta['file'],"/")+1));
225
-
226
  if ( empty($SubDir) ) //its a PDF?
227
  {
228
  $uploadFilePath = get_attached_file($ID);
@@ -286,16 +296,24 @@ class shortpixel_api {
286
  $sourceFile = $tempFile;
287
  $destinationFile = WP_CONTENT_DIR . DIRECTORY_SEPARATOR . 'uploads' . DIRECTORY_SEPARATOR . $SubDir . basename($url[$counter]);
288
 
289
- @unlink( $destinationFile );
290
- $success = @rename( $sourceFile, $destinationFile );
291
-
292
- if (!$success) {
293
- $copySuccess = copy($sourceFile, $destinationFile);
294
- unlink($sourceFile);
 
 
 
295
  }
296
-
 
 
 
 
 
297
  //save data to counters
298
- if($success || $copySuccess) {
299
  //update statistics
300
  $fileData = $callData[$counter];
301
  $savedSpace = $fileData->OriginalSize - $fileData->LossySize;
@@ -317,12 +335,14 @@ class shortpixel_api {
317
  //update metadata
318
  if(isset($ID)) {
319
  $meta = wp_get_attachment_metadata($ID);
320
- $meta['ShortPixelImprovement'] = $percentImprovement;
321
  wp_update_attachment_metadata($ID, $meta);
322
  }
323
 
324
  //we reset the retry counter in case of success
325
  update_option('wp-short-pixel-api-retries', 0);
 
 
326
 
327
  }//end handleSuccess
328
 
93
  $meta['ShortPixelImprovement'] = 'Timed out while processing.';
94
  unset($meta['ShortPixel']['WaitingProcessing']);
95
  wp_update_attachment_metadata($ID, $meta);
96
+ //also decrement last ID for queries so bulk won't hang in such cases
97
+ $startQueryID = get_option("wp-short-pixel-query-id-start");
98
+ update_option("wp-short-pixel-query-id-start", $startQueryID - 1);
99
  }
100
  else
101
  {//we'll try again next time user visits a page on admin panel
103
  update_option('wp-short-pixel-api-retries', $apiRetries);
104
  exit('Timed out while processing. (pass '.$apiRetries.')');
105
  }
 
 
106
  }
107
 
108
  $response = $this->doRequests($url, $filePaths, $ID);//send requests to API
113
  return false;
114
  }
115
 
116
+ $data = (array)$this->parseResponse($response);//get the actual response from API, convert it to an array if it is an object
117
 
118
+ if ( isset($data[0]) )//API returned image details
 
 
 
 
 
 
 
 
119
  {
120
+ $firstImage = $data[0];//extract as object first image
121
+ foreach ( $data as $imageObject )
122
+ { //this part makes sure that all the sizes were processed and ready to be downloaded
123
+ if ( $imageObject->Status->Code == 0 || $imageObject->Status->Code == 1 )
124
+ {
125
+ sleep(2);
126
+ return $this->processImage($url, $filePaths, $ID, $startTime);
127
+ }
128
+ }
129
+
130
+ switch($firstImage->Status->Code) {
131
  case 1:
132
  //handle image has been scheduled
133
  sleep(1);
137
  //handle image has been processed
138
  $this->handleSuccess($data, $url, $filePaths, $ID);
139
  break;
140
+ default:
141
+ //handle error
142
+ if ( isset($data[0]->Status->Message) )
143
+ return $data[0]->Status->Message;
144
+ }
145
+ }
146
+ else//API returned an error
147
+ {
148
+ switch($data['Status']->Code) {
149
  case -403:
150
  return 'Quota exceeded</br>';
151
  break;
159
  //handle error
160
  if ( isset($data[0]->Status->Message) )
161
  return $data[0]->Status->Message;
162
+ }
163
+
164
  }
165
+
166
  return $data;
167
  }
168
 
169
 
170
  public function handleSuccess($callData, $url, $filePath, $ID) {
171
+
172
  $counter = 0;
173
  if($this->_compressionType)
174
  {
183
 
184
  foreach ( $callData as $fileData )//download each file from array and process it
185
  {
186
+ if ( $fileData->Status->Code == 2 ) //file was processed OK
 
 
 
 
 
 
 
187
  {
188
+ if ( $counter == 0 )//save percent improvement for main file
189
+ $percentImprovement = $fileData->PercentImprovement;
 
190
 
191
+ $correctFileSize = $fileData->$fileSize;
192
+ $tempFiles[$counter] = download_url(urldecode($fileData->$fileType));
193
+
194
+ if(is_wp_error( $tempFiles[$counter] )) //also tries with http instead of https
195
+ {
196
+ sleep(1);
197
+ $tempFiles[$counter] = download_url(str_replace('https://', 'http://', urldecode($fileData->$fileType)));
198
+ }
199
+
200
+ if ( is_wp_error( $tempFiles[$counter] ) ) {
201
+ @unlink($tempFiles[$counter]);
202
+ return sprintf("Error downloading file (%s)", $tempFiles[$counter]->get_error_message());
203
+ die;
204
+ }
205
+
206
+ //check response so that download is OK
207
+ if( filesize($tempFiles[$counter]) != $correctFileSize) {
208
+ return sprintf("Error downloading file - incorrect file size");
209
+ die;
210
+ }
211
+
212
+ if (!file_exists($tempFiles[$counter])) {
213
+ return sprintf("Unable to locate downloaded file (%s)", $tempFiles[$counter]);
214
+ die;
215
+ }
216
  }
217
+ else //there was an error while trying to download a file
218
+ $tempFiles[$counter] = "";
219
  $counter++;
220
  }
221
 
222
+
223
  //if backup is enabled
224
  if(get_option('wp-short-backup_images'))
225
  {
230
  return sprintf("Backup folder does not exist and it could not be created");
231
  }
232
  $meta = wp_get_attachment_metadata($ID);
233
+ $SubDir = ( isset($meta['file']) ) ? trim(substr($meta['file'],0,strrpos($meta['file'],"/")+1)) : "";
234
  $source = $filePath;
235
+
 
236
  if ( empty($SubDir) ) //its a PDF?
237
  {
238
  $uploadFilePath = get_attached_file($ID);
296
  $sourceFile = $tempFile;
297
  $destinationFile = WP_CONTENT_DIR . DIRECTORY_SEPARATOR . 'uploads' . DIRECTORY_SEPARATOR . $SubDir . basename($url[$counter]);
298
 
299
+ if ( $sourceFile <> "" && file_exists($sourceFile) )//possibly there was an error and the file couldn't have been processed
300
+ {
301
+ @unlink( $destinationFile );
302
+ $success = @rename( $sourceFile, $destinationFile );
303
+
304
+ if (!$success) {
305
+ $copySuccess = copy($sourceFile, $destinationFile);
306
+ unlink($sourceFile);
307
+ }
308
  }
309
+ else
310
+ {
311
+ $success = 0;
312
+ $copySuccess = 0;
313
+ }
314
+
315
  //save data to counters
316
+ if( $success || $copySuccess) {
317
  //update statistics
318
  $fileData = $callData[$counter];
319
  $savedSpace = $fileData->OriginalSize - $fileData->LossySize;
335
  //update metadata
336
  if(isset($ID)) {
337
  $meta = wp_get_attachment_metadata($ID);
338
+ $meta['ShortPixelImprovement'] = round($percentImprovement,2);
339
  wp_update_attachment_metadata($ID, $meta);
340
  }
341
 
342
  //we reset the retry counter in case of success
343
  update_option('wp-short-pixel-api-retries', 0);
344
+ //set this file as processed -> we decrement the cursor
345
+ update_option("wp-short-pixel-query-id-start", $ID - 1);//update max ID
346
 
347
  }//end handleSuccess
348
 
wp-shortpixel.php CHANGED
@@ -3,7 +3,7 @@
3
  * Plugin Name: ShortPixel Image Optimiser
4
  * Plugin URI: https://shortpixel.com/
5
  * Description: ShortPixel is an image compression tool that helps improve your website performance. The plugin optimises images automatically using both lossy and lossless compression. Resulting, smaller, images are no different in quality from the original. To install: 1) Click the "Activate" link to the left of this description. 2) <a href="https://shortpixel.com/wp-apikey" target="_blank">Free Sign up</a> for your unique API Key . 3) Check your email for your API key. 4) Use your API key to activate ShortPixel plugin in the 'Plugins' menu in WordPress. 5) Done!
6
- * Version: 2.0.9
7
  * Author: ShortPixel
8
  * Author URI: https://shortpixel.com
9
  */
@@ -12,7 +12,7 @@ require_once('shortpixel_api.php');
12
  require_once( ABSPATH . 'wp-admin/includes/image.php' );
13
  require_once( ABSPATH . 'wp-includes/pluggable.php' );
14
 
15
- define('PLUGIN_VERSION', "2.0.9");
16
  define('SP_DEBUG', false);
17
  define('SP_LOG', false);
18
  define('SP_MAX_TIMEOUT', 10);
@@ -21,7 +21,8 @@ define('MUST_HAVE_KEY', true);
21
  define('MAX_API_RETRIES', 5);
22
  $MAX_EXECUTION_TIME = ini_get('max_execution_time');
23
  if ( is_numeric($MAX_EXECUTION_TIME) )
24
- define('MAX_EXECUTION_TIME', $MAX_EXECUTION_TIME - 1 ); //in seconds
 
25
 
26
  class WPShortPixel {
27
 
@@ -50,6 +51,10 @@ class WPShortPixel {
50
  add_action( 'admin_menu', array( &$this, 'registerSettingsPage' ) );//display SP in Settings menu
51
  add_action( 'admin_menu', array( &$this, 'registerAdminPage' ) );
52
  add_action( 'delete_attachment', array( &$this, 'handleDeleteAttachmentInBackup' ) );
 
 
 
 
53
 
54
  //automatic optimization
55
  add_action( 'admin_footer', array( &$this, 'my_action_javascript') );
@@ -109,9 +114,31 @@ class WPShortPixel {
109
  if(get_option('wp-short-pixel-api-retries') === false) {//sometimes we need to retry processing/downloading a file multiple times
110
  add_option( 'wp-short-pixel-api-retries', 0, '', 'yes' );
111
  }
 
 
 
 
 
 
 
 
 
 
112
 
 
 
 
 
 
113
  }
114
 
 
 
 
 
 
 
 
115
  //set default move as "list". only set once, it won't try to set the default mode again.
116
  public function setDefaultViewModeList()
117
  {
@@ -124,7 +151,6 @@ class WPShortPixel {
124
  get_currentuserinfo();
125
  $currentUserID = $current_user->ID;
126
  update_user_meta($currentUserID, "wp_media_library_mode", "list");
127
- echo "OK";
128
  }
129
  }
130
 
@@ -174,13 +200,30 @@ class WPShortPixel {
174
  }
175
 
176
  public function handleImageUpload($meta, $ID = null) {
 
177
  if(MUST_HAVE_KEY && $this->_verifiedKey)
178
  {
 
 
 
 
 
179
  self::log("Processing image id {$ID}");
180
  $url = wp_get_attachment_url($ID);
181
  $path = get_attached_file($ID);
182
  if(self::isProcesable($path) != false)
183
  {
 
 
 
 
 
 
 
 
 
 
 
184
  $urlList[] = $url;
185
  $filePath[] = $path;
186
  //send request for thumbs as well, if needed
@@ -202,16 +245,17 @@ class WPShortPixel {
202
  $this->_apiInterface->doRequests($urlList, $filePath);//send a processing request right after a file was uploaded
203
  }
204
  }
 
 
 
 
205
  }
206
  else
207
  {
208
- $meta['ShortPixelImprovement'] = 'File is not an image';
209
  return $meta;
210
  }
211
- }
212
-
213
- $meta['ShortPixel']['WaitingProcessing'] = true;
214
- return $meta;
215
  }
216
 
217
  public function handleImageProcessing($ID = null) {
@@ -219,30 +263,97 @@ class WPShortPixel {
219
  echo "Missing API Key";
220
  die();
221
  }
222
- //query database for first found entry that needs processing
223
  global $wpdb;
224
- $qry = "SELECT * FROM " . $wpdb->prefix . "postmeta
225
- WHERE (
226
- meta_value LIKE '%\"WaitingProcessing\";b:1;%'
227
- OR meta_value LIKE '%\"BulkProcessing\";b:1;%' )
228
- ORDER BY post_id DESC
229
- LIMIT 0,3";
230
- $idList = $wpdb->get_results($qry);
231
-
232
- if(empty($idList)) { echo 'Empty queue'; die; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
233
 
 
 
 
 
 
 
 
 
 
234
  //send a couple of pre-process requests (if available/needed)
235
  if ( isset($idList[1]) )
236
  {
237
  $itemDetails = $this->returnURLsAndPaths($idList[1]);
238
  $this->_apiInterface->doRequests($itemDetails['imageURLs'], $itemDetails['imagePaths']);
239
  }
 
240
  if ( isset($idList[2]) )
241
  {
242
  $itemDetails = $this->returnURLsAndPaths($idList[1]);
243
  $this->_apiInterface->doRequests($itemDetails['imageURLs'], $itemDetails['imagePaths']);
244
  }
245
 
 
246
  //send a request for the latest item
247
  $itemDetails = $this->returnURLsAndPaths($idList[0]);
248
  $meta = $itemDetails['meta'];
@@ -255,20 +366,29 @@ class WPShortPixel {
255
  $meta['ShortPixelImprovement'] = $result;
256
  wp_update_attachment_metadata($ID, $meta);
257
  echo "Error processing image: " . $result;
 
 
 
258
  die;
259
  }
260
 
261
  //$processThumbnails = get_option('wp-short-process_thumbnails');
 
 
262
 
263
- unset($meta['ShortPixel']['WaitingProcessing']);
264
-
265
- if(isset($meta['ShortPixel']['BulkProcessing'])) {
266
  unset($meta['ShortPixel']['BulkProcessing']);
267
- }
268
 
269
- $meta['ShortPixelImprovement'] = $result[0]->PercentImprovement;
270
  wp_update_attachment_metadata($ID, $meta);
271
  echo "\nProcessing done succesfully for image #{$ID}";
 
 
 
 
 
 
 
272
 
273
  die();
274
  }
@@ -278,13 +398,13 @@ class WPShortPixel {
278
  public function returnURLsAndPaths($itemDetails)
279
  {
280
  global $wpdb;
281
-
282
  $imageIndex=0;
283
  $ID = $itemDetails->post_id;
284
  $imageURL = wp_get_attachment_url($ID);
285
  $imagePath = get_attached_file($ID);
286
- $meta = wp_get_attachment_metadata($ID);
287
-
288
  if ( !isset($meta['file']) )//this could be a PDF file
289
  {
290
  $qry = "SELECT * FROM " . $wpdb->prefix . "postmeta
@@ -293,21 +413,24 @@ class WPShortPixel {
293
  meta_key = '_wp_attached_file'
294
  )";
295
  $idList = $wpdb->get_results($qry);
296
- $idList = $idList[0];
297
- $uploadDir = wp_upload_dir();
298
- $filePath = $uploadDir['path'] . DIRECTORY_SEPARATOR . basename($idList->meta_value);
299
-
300
- //check if the image file exists on disk, if not set the right params
301
- if(!file_exists($filePath)) {
302
- if(isset($meta['ShortPixel']['BulkProcessing'])) { unset($meta['ShortPixel']['BulkProcessing']); }
303
- if(isset($meta['ShortPixel']['WaitingProcessing'])) { unset($meta['ShortPixel']['WaitingProcessing']); }
304
- $meta['ShortPixel']['NoFileOnDisk'] = true;
305
- wp_update_attachment_metadata($ID, $meta);
306
- die;
 
 
 
 
 
 
307
  }
308
-
309
- $imageURLs[] = $uploadDir['url'] . DIRECTORY_SEPARATOR . basename($idList->meta_value);//URL to PDF file
310
- $imagePaths[] = $filePath;
311
  }
312
  else
313
  {//process images
@@ -342,8 +465,10 @@ class WPShortPixel {
342
  }
343
  }
344
 
345
-
346
- return array("imageURLs" => $imageURLs, "imagePaths" => $imagePaths, "meta" => $meta, "ID" => $ID);
 
 
347
  }
348
 
349
 
@@ -369,6 +494,9 @@ class WPShortPixel {
369
 
370
  $result = $this->_apiInterface->processImage($urlList, $filePath, $attachmentID);//request to process all the images
371
 
 
 
 
372
  // store the referring webpage location
373
  $sendback = wp_get_referer();
374
  // sanitize the referring webpage location
@@ -377,6 +505,14 @@ class WPShortPixel {
377
  wp_redirect($sendback);
378
  // we are done,
379
  }
 
 
 
 
 
 
 
 
380
 
381
  public function handleRestoreBackup() {
382
  $attachmentID = intval($_GET['attachment_ID']);
@@ -432,7 +568,11 @@ class WPShortPixel {
432
  if(self::isProcesable($uploadFilePath) != false) {
433
  try {
434
  $uploadDir = wp_upload_dir();
435
- $SubDir = substr($meta['file'],0,strrpos($meta['file'],"/")+1);
 
 
 
 
436
  if ( empty($SubDir) ) //its a PDF?
437
  {
438
  $uploadFilePath = get_attached_file($ID);
@@ -459,25 +599,6 @@ class WPShortPixel {
459
  }
460
  }
461
 
462
- public function bulkOptimizeActionHandler($hook) {
463
- if($hook == 'upload.php') {
464
- if($_GET['action'] == 2) {
465
- if(!empty($_GET['media'])) {
466
- $imageLog = array();
467
- //remove all ShortPixel data from metadata
468
- foreach($_GET['media'] as $attachmentID) {
469
- $meta = wp_get_attachment_metadata($attachmentID);
470
- $meta['ShortPixel']['BulkProcessing'] = true;
471
- unset($meta['ShortPixelImprovement']);
472
- wp_update_attachment_metadata($attachmentID, $meta);
473
- $imageLog[$attachmentID] = false;
474
- }
475
- update_option('bulkProcessingLog', $imageLog);
476
- }
477
- }
478
- }
479
- }
480
-
481
  public function registerSettingsPage() {
482
  add_options_page( 'ShortPixel Settings', 'ShortPixel', 'manage_options', 'wp-shortpixel', array($this, 'renderSettingsMenu'));
483
  }
@@ -487,6 +608,8 @@ class WPShortPixel {
487
  }
488
 
489
  public function bulkProcess() {
 
 
490
  echo '<h1>Bulk Image Optimisation by ShortPixel</h1>';
491
 
492
  if(MUST_HAVE_KEY && $this->_verifiedKey == false) {//invalid API Key
@@ -495,133 +618,94 @@ class WPShortPixel {
495
  return;
496
  }
497
 
498
- if($_GET['cancel']) {
499
- foreach($attachments as $attachment) {
500
- $meta = wp_get_attachment_metadata($attachment->ID);
501
- if(isset($meta['ShortPixel']['BulkProcessing'])) unset($meta['ShortPixel']['BulkProcessing']);
502
- wp_update_attachment_metadata($attachment->ID, $meta);
503
- }
504
  }
505
 
506
- $attachments = null;
507
- $attachments_images = get_posts( array(
508
- 'numberposts' => -1,
509
- 'post_type' => 'attachment',
510
- 'post_mime_type' => 'image'
511
- ));
512
- $attachments_pdf = get_posts( array(
513
- 'numberposts' => -1,
514
- 'post_type' => 'attachment',
515
- 'post_mime_type' => 'application/pdf'
516
- ));
517
- $attachments = array_merge($attachments_images, $attachments_pdf);
518
-
519
-
520
- if($_POST["bulkProcess"])
521
  {
522
- $uploadDir = wp_upload_dir();
523
- $uploadDir = $uploadDir['basedir'];
524
-
525
- //remove all ShortPixel data from metadata
526
- $imageList = array();
527
- $processThumbnails = get_option('wp-short-process_thumbnails');
528
-
529
- foreach($attachments as $attachment) {
530
- if(self::isProcesable(get_attached_file($attachment->ID)) == false) continue;//skip this record
531
- //apparently if the main image isn't on disk -> the result is false above
532
-
533
- //prepare bulk call for processing
534
- $imagePath = wp_get_attachment_url($attachment->ID);
535
- $filePathOnDisk = get_attached_file($attachment->ID);
536
- $imageDiskPath[] = $filePathOnDisk;
537
- $imageList[] = $imagePath;
538
-
539
- $meta = wp_get_attachment_metadata($attachment->ID);
540
- $SubDirs = substr($meta['file'],0,strrpos($meta['file'],"/")+1);
541
-
542
- if($processThumbnails && isset($meta['sizes'])) {
543
- foreach($meta['sizes'] as $thumbnailData) {
544
- $imageOnDisk = $uploadDir . DIRECTORY_SEPARATOR . $SubDirs . basename($thumbnailData["file"]);
545
-
546
- if ( file_exists($imageOnDisk) )//make sure each version of the main file is on disk
547
- {
548
- $thumbPath = substr($imagePath, 0, strrpos($imagePath, '/')) . '/' . $thumbnailData["file"];
549
- $imageList[] = $thumbPath;
550
- $imageDiskPath[] = $imageOnDisk;
551
- }
552
- }
553
- }
554
-
555
- $meta['ShortPixel']['BulkProcessing'] = true;
556
- wp_update_attachment_metadata($attachment->ID, $meta);
557
- }
558
-
559
-
560
- if(count($imageList) > 10) {
561
- echo "<BR>Counter going";
562
- $batchList = array();
563
- foreach($imageList as $image) {
564
- $batchList[] = $image;
565
 
566
- if(count($batchList) == 10) {
567
- // $this->_apiInterface->doBulkRequest($batchList);
568
- $batchList = array();
569
- }
570
- }
571
- //send the rest of the images in the list
572
- // if(count($batchList) > 0) { $this->_apiInterface->doBulkRequest($batchList); }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
573
 
574
- } else {
575
- // $this->_apiInterface->doBulkRequest($imageList);
576
- }
577
 
 
578
 
579
- update_option('bulkProcessingStatus', 'running');
580
- }//end bulk process was clicked
 
 
581
 
582
- global $wpdb;
583
- $qry = "SELECT * FROM " . $wpdb->prefix . "postmeta
584
- WHERE meta_value LIKE '%\"BulkProcessing\";b:1;%'";
585
- $idList = $wpdb->get_results($qry);
586
-
587
- if(!empty($idList)) {
588
- if(is_array($idList)) {
589
- echo "<p>
590
- Bulk optimisation has started. This process will take some time, depending on the number of images in your library. <BR>Do not worry about the slow speed, it is a necessary measure in order not to interfere with the normal functioning of your site.<BR><BR>
591
- This is a brief estimation of the bulk processing times:<BR>
592
- 1 to 100 images < 20 min <BR>
593
- 100 to 500 images < 2 hour<BR>
594
- 500 to 1000 images < 4 hours<BR>
595
- over 1000 images > 4 hours or more<BR><BR>
596
-
597
- The latest status of the processing will be displayed here every 30 seconds.<BR>
598
- In the meantime, you can continue using the admin as usual.<BR>
599
- However, <b>you musn’t close the WordPress admin</b>, or the bulk processing will stop.
600
- </p>";
601
- echo '
602
- <script type="text/javascript" >
603
- var bulkProcessingRunning = true;
604
- </script>
605
- ';
606
-
607
- $imagesLeft = count($idList);
608
- $totalImages = count($attachments);
609
-
610
- echo "<p>{$imagesLeft} out of {$totalImages} images left to process.</p>";
611
-
612
- echo '
613
- <a class="button button-secondary" href="' . get_admin_url() . 'upload.php">Media Library</a>
614
- <a class="button button-secondary" href="' . get_admin_url() . 'upload.php?page=wp-short-pixel-bulk&cancel=1">Cancel Processing</a>
615
- ';
616
- }
617
- } else {
618
  $bulkProcessingStatus = get_option('bulkProcessingStatus');
619
- if(isset($bulkProcessingStatus) && $bulkProcessingStatus == 'running') {
 
620
  echo "<p>Bulk optimisation was successful. ShortPixel has finished optimising all your images.</p>
621
  <p>Go to the ShortPixel <a href='" . get_admin_url() . "options-general.php?page=wp-shortpixel#facts'>Stats</a> and see your website's optimised stats (in Settings > ShortPixel). </p>";
622
- delete_option('bulkProcessingStatus');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
623
  }
624
- echo $this->getBulkProcessingForm(count($attachments));
 
625
  echo '
626
  <script type="text/javascript" >
627
  var bulkProcessingRunning = false;
@@ -661,6 +745,7 @@ class WPShortPixel {
661
  $noticeHTML = "<br/><div style=\"background-color: #fff; border-left: 4px solid %s; box-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.1); padding: 1px 12px;\"><p>%s</p></div>";
662
 
663
  if(isset($_POST['submit']) || isset($_POST['validate'])) {
 
664
  //handle API Key - common for submit and validate
665
  $_POST['key'] = trim($_POST['key']);
666
  $validityData = $this->getQuotaInformation($_POST['key'], true);
@@ -949,8 +1034,20 @@ HTML;
949
  $data = wp_get_attachment_metadata($id);
950
  $file = get_attached_file($id);
951
  $fileExtension = strtolower(substr($file,strrpos($file,".")+1));
952
-
953
- if ( isset( $data['ShortPixelImprovement'] ) ) {
 
 
 
 
 
 
 
 
 
 
 
 
954
  if(isset($meta['ShortPixel']['BulkProcessing'])) {
955
  print 'Waiting for bulk processing';
956
  return;
@@ -962,8 +1059,8 @@ HTML;
962
  print " | <a href=\"admin.php?action=shortpixel_restore_backup&amp;attachment_ID={$id}\">Restore backup</a>";
963
  return;
964
  }
965
- else
966
- print '';
967
  } elseif(isset($data['ShortPixel']['WaitingProcessing'])) {
968
  print 'Image waiting to be processed';
969
  return;
3
  * Plugin Name: ShortPixel Image Optimiser
4
  * Plugin URI: https://shortpixel.com/
5
  * Description: ShortPixel is an image compression tool that helps improve your website performance. The plugin optimises images automatically using both lossy and lossless compression. Resulting, smaller, images are no different in quality from the original. To install: 1) Click the "Activate" link to the left of this description. 2) <a href="https://shortpixel.com/wp-apikey" target="_blank">Free Sign up</a> for your unique API Key . 3) Check your email for your API key. 4) Use your API key to activate ShortPixel plugin in the 'Plugins' menu in WordPress. 5) Done!
6
+ * Version: 2.1.0
7
  * Author: ShortPixel
8
  * Author URI: https://shortpixel.com
9
  */
12
  require_once( ABSPATH . 'wp-admin/includes/image.php' );
13
  require_once( ABSPATH . 'wp-includes/pluggable.php' );
14
 
15
+ define('PLUGIN_VERSION', "2.1.0");
16
  define('SP_DEBUG', false);
17
  define('SP_LOG', false);
18
  define('SP_MAX_TIMEOUT', 10);
21
  define('MAX_API_RETRIES', 5);
22
  $MAX_EXECUTION_TIME = ini_get('max_execution_time');
23
  if ( is_numeric($MAX_EXECUTION_TIME) )
24
+ define('MAX_EXECUTION_TIME', $MAX_EXECUTION_TIME - 3 ); //in seconds
25
+ define("SP_MAX_RESULTS_QUERY", 6);
26
 
27
  class WPShortPixel {
28
 
51
  add_action( 'admin_menu', array( &$this, 'registerSettingsPage' ) );//display SP in Settings menu
52
  add_action( 'admin_menu', array( &$this, 'registerAdminPage' ) );
53
  add_action( 'delete_attachment', array( &$this, 'handleDeleteAttachmentInBackup' ) );
54
+
55
+ //when plugin is activated run this
56
+ register_activation_hook( __FILE__, array( &$this, 'shortPixelActivatePlugin' ) );
57
+ register_deactivation_hook( __FILE__, array( &$this, 'shortPixelDeactivatePlugin' ) );
58
 
59
  //automatic optimization
60
  add_action( 'admin_footer', array( &$this, 'my_action_javascript') );
114
  if(get_option('wp-short-pixel-api-retries') === false) {//sometimes we need to retry processing/downloading a file multiple times
115
  add_option( 'wp-short-pixel-api-retries', 0, '', 'yes' );
116
  }
117
+
118
+ if(get_option('wp-short-pixel-query-id-start') === false) {//current query ID used for postmeta
119
+ add_option( 'wp-short-pixel-query-id-start', 0, '', 'yes' );
120
+ }
121
+
122
+ if(get_option('wp-short-pixel-query-id-stop') === false) {//current query ID used for postmeta
123
+ add_option( 'wp-short-pixel-query-id-stop', 0, '', 'yes' );
124
+ }
125
+
126
+ }
127
 
128
+ public function shortPixelActivatePlugin()//reset some params to avoid troubles for plugins that were activated/deactivated/activated
129
+ {
130
+ delete_option('bulkProcessingStatus');
131
+ update_option( 'wp-short-pixel-query-id-stop', 0 );
132
+ update_option( 'wp-short-pixel-query-id-start', 0 );
133
  }
134
 
135
+ public function shortPixelDeactivatePlugin()//reset some params to avoid troubles for plugins that were activated/deactivated/activated
136
+ {
137
+ delete_option('bulkProcessingStatus');
138
+ update_option( 'wp-short-pixel-query-id-stop', 0 );
139
+ update_option( 'wp-short-pixel-query-id-start', 0 );
140
+ }
141
+
142
  //set default move as "list". only set once, it won't try to set the default mode again.
143
  public function setDefaultViewModeList()
144
  {
151
  get_currentuserinfo();
152
  $currentUserID = $current_user->ID;
153
  update_user_meta($currentUserID, "wp_media_library_mode", "list");
 
154
  }
155
  }
156
 
200
  }
201
 
202
  public function handleImageUpload($meta, $ID = null) {
203
+
204
  if(MUST_HAVE_KEY && $this->_verifiedKey)
205
  {
206
+ $bulkProcessingStatus = get_option('bulkProcessingStatus');
207
+ //update variable to keep track of this new attachment but only if bulk isn't running
208
+ if( $bulkProcessingStatus <> 'running' )
209
+ update_option("wp-short-pixel-query-id-start", $ID);
210
+
211
  self::log("Processing image id {$ID}");
212
  $url = wp_get_attachment_url($ID);
213
  $path = get_attached_file($ID);
214
  if(self::isProcesable($path) != false)
215
  {
216
+ if ( empty($meta) && $bulkProcessingStatus <> 'running' )//here's a PDF file most likely, while bulk not running
217
+ {
218
+ $meta['ShortPixel']['WaitingProcessing'] = true;
219
+ return $meta;
220
+ }
221
+ elseif ( empty($meta) && $bulkProcessingStatus == 'running' )//while bulk running
222
+ {
223
+ return $meta;
224
+ }
225
+
226
+
227
  $urlList[] = $url;
228
  $filePath[] = $path;
229
  //send request for thumbs as well, if needed
245
  $this->_apiInterface->doRequests($urlList, $filePath);//send a processing request right after a file was uploaded
246
  }
247
  }
248
+
249
+ if ( $bulkProcessingStatus <> 'running' )
250
+ $meta['ShortPixel']['WaitingProcessing'] = true;
251
+ return $meta;
252
  }
253
  else
254
  {
255
+ $meta['ShortPixelImprovement'] = 'Optimisation N/A';
256
  return $meta;
257
  }
258
+ }
 
 
 
259
  }
260
 
261
  public function handleImageProcessing($ID = null) {
263
  echo "Missing API Key";
264
  die();
265
  }
266
+ //query database for first found entry that needs processing //
267
  global $wpdb;
268
+
269
+ //////////////////
270
+
271
+ $startQueryID = get_option('wp-short-pixel-query-id-start');
272
+ $endQueryID = get_option('wp-short-pixel-query-id-stop');
273
+ sleep(1);
274
+ $queryPostMeta = "SELECT * FROM " . $wpdb->prefix . "postmeta
275
+ WHERE ( post_id <= $startQueryID AND post_id > $endQueryID ) AND (
276
+ meta_key = '_wp_attached_file'
277
+ OR meta_key = '_wp_attachment_metadata'
278
+ )
279
+ ORDER BY post_id DESC
280
+ LIMIT " . SP_MAX_RESULTS_QUERY;
281
+ $resultsPostMeta = $wpdb->get_results($queryPostMeta);
282
+ $idList = array();
283
+ foreach ( $resultsPostMeta as $itemMetaData )
284
+ {
285
+ $meta = wp_get_attachment_metadata($itemMetaData->post_id);
286
+ $meta['ShortPixelImprovement'] = ( isset($meta['ShortPixelImprovement']) ) ? $meta['ShortPixelImprovement'] : "";
287
+ $filePath = get_attached_file($itemMetaData->post_id);
288
+ $fileExtension = strtolower(substr($filePath,strrpos($filePath,".")+1));
289
+
290
+ if ( ( $itemMetaData->meta_key == "_wp_attachment_metadata" && $meta['ShortPixelImprovement'] <> "Optimisation N/A" && !is_numeric($meta['ShortPixelImprovement']) ) || $fileExtension == "pdf" )//Optimisation N/A = is an unsupported file format
291
+ {
292
+ $idList[] = $itemMetaData;
293
+ }
294
+ }
295
+
296
+ if ( isset($idList[0]) )
297
+ {
298
+ $meta = wp_get_attachment_metadata($idList[0]->post_id);
299
+ $filePath = get_attached_file($idList[0]->post_id);
300
+ $fileExtension = strtolower(substr($filePath,strrpos($filePath,".")+1));
301
+
302
+ if( !empty($meta) && !isset($meta['ShortPixel']['WaitingProcessing']) ) //possibly the file wasn't processed in the first pass so we'll wait for it to be completed
303
+ {
304
+ $startQueryID = ( $idList[0]->post_id );
305
+ update_option("wp-short-pixel-query-id-start", $startQueryID);//update max ID
306
+ }
307
+ elseif ( empty($meta) && $fileExtension <> "pdf" )//file is not an image or PDF so we just skip to the next batch
308
+ {
309
+ $startQueryID = $startQueryID - SP_MAX_RESULTS_QUERY;
310
+ update_option("wp-short-pixel-query-id-start", $startQueryID);//update max ID
311
+ die();
312
+ }
313
+ elseif ( !self::isProcesable($filePath) )//file has a non-supported extension, we skip it
314
+ {
315
+ $startQueryID = $idList[0]->post_id - 1;
316
+ update_option("wp-short-pixel-query-id-start", $startQueryID);//update max ID
317
+ die();
318
+ }
319
+ else //file was processed in the first pass
320
+ {
321
+ $startQueryID = $idList[0]->post_id;
322
+ update_option("wp-short-pixel-query-id-start", $startQueryID);//update max ID
323
+ }
324
+ }
325
+ elseif ( $startQueryID > $endQueryID )
326
+ {
327
+ $startQueryID = $startQueryID - 1;
328
+ update_option("wp-short-pixel-query-id-start", $startQueryID);//update max ID
329
+ die();
330
+ }
331
+
332
+ //////////////////////
333
 
334
+ if( empty($idList) && $startQueryID <= $endQueryID ) { //die but before set the $endQueryID so only new files will be processed
335
+ $queryMax = "SELECT max(post_id) as startQueryID FROM " . $wpdb->prefix . "postmeta";
336
+ $resultQuery = $wpdb->get_results($queryMax);
337
+ $endQueryID = $resultQuery[0]->startQueryID;
338
+ update_option('wp-short-pixel-query-id-stop', $endQueryID);
339
+ delete_option('bulkProcessingStatus');
340
+ echo 'Empty queue - '.$endQueryID; die;
341
+ }
342
+
343
  //send a couple of pre-process requests (if available/needed)
344
  if ( isset($idList[1]) )
345
  {
346
  $itemDetails = $this->returnURLsAndPaths($idList[1]);
347
  $this->_apiInterface->doRequests($itemDetails['imageURLs'], $itemDetails['imagePaths']);
348
  }
349
+
350
  if ( isset($idList[2]) )
351
  {
352
  $itemDetails = $this->returnURLsAndPaths($idList[1]);
353
  $this->_apiInterface->doRequests($itemDetails['imageURLs'], $itemDetails['imagePaths']);
354
  }
355
 
356
+
357
  //send a request for the latest item
358
  $itemDetails = $this->returnURLsAndPaths($idList[0]);
359
  $meta = $itemDetails['meta'];
366
  $meta['ShortPixelImprovement'] = $result;
367
  wp_update_attachment_metadata($ID, $meta);
368
  echo "Error processing image: " . $result;
369
+ //also decrement last ID for queries so bulk won't hang in such cases
370
+ $startQueryID = get_option("wp-short-pixel-query-id-start");
371
+ update_option("wp-short-pixel-query-id-start", $startQueryID - 1);
372
  die;
373
  }
374
 
375
  //$processThumbnails = get_option('wp-short-process_thumbnails');
376
+ if ( isset($meta['ShortPixel']['WaitingProcessing']) )
377
+ unset($meta['ShortPixel']['WaitingProcessing']);
378
 
379
+ if( isset($meta['ShortPixel']['BulkProcessing']) )
 
 
380
  unset($meta['ShortPixel']['BulkProcessing']);
 
381
 
382
+ $meta['ShortPixelImprovement'] = round($result[0]->PercentImprovement,2);
383
  wp_update_attachment_metadata($ID, $meta);
384
  echo "\nProcessing done succesfully for image #{$ID}";
385
+
386
+ //set the next ID to be processed (skip to the next valid value)
387
+ if ( isset($isList[1]) )
388
+ {
389
+ $startQueryID = $idList[1]->post_id;
390
+ update_option("wp-short-pixel-query-id-start", $startQueryID);//update max ID
391
+ }
392
 
393
  die();
394
  }
398
  public function returnURLsAndPaths($itemDetails)
399
  {
400
  global $wpdb;
401
+
402
  $imageIndex=0;
403
  $ID = $itemDetails->post_id;
404
  $imageURL = wp_get_attachment_url($ID);
405
  $imagePath = get_attached_file($ID);
406
+ $meta = wp_get_attachment_metadata($ID);
407
+
408
  if ( !isset($meta['file']) )//this could be a PDF file
409
  {
410
  $qry = "SELECT * FROM " . $wpdb->prefix . "postmeta
413
  meta_key = '_wp_attached_file'
414
  )";
415
  $idList = $wpdb->get_results($qry);
416
+ if ( isset($idList[0]) )
417
+ {
418
+ $idList = $idList[0];
419
+ $uploadDir = wp_upload_dir();
420
+ $filePath = $uploadDir['path'] . DIRECTORY_SEPARATOR . basename($idList->meta_value);
421
+
422
+ //check if the image file exists on disk, if not set the right params
423
+ if(!file_exists($filePath)) {
424
+ if(isset($meta['ShortPixel']['BulkProcessing'])) { unset($meta['ShortPixel']['BulkProcessing']); }
425
+ if(isset($meta['ShortPixel']['WaitingProcessing'])) { unset($meta['ShortPixel']['WaitingProcessing']); }
426
+ $meta['ShortPixel']['NoFileOnDisk'] = true;
427
+ wp_update_attachment_metadata($ID, $meta);
428
+ die;
429
+ }
430
+
431
+ $imageURLs[] = $uploadDir['url'] . DIRECTORY_SEPARATOR . basename($idList->meta_value);//URL to PDF file
432
+ $imagePaths[] = $filePath;
433
  }
 
 
 
434
  }
435
  else
436
  {//process images
465
  }
466
  }
467
 
468
+ if ( isset($imageURLs) )
469
+ return array("imageURLs" => $imageURLs, "imagePaths" => $imagePaths, "meta" => $meta, "ID" => $ID);
470
+ else
471
+ return false;
472
  }
473
 
474
 
494
 
495
  $result = $this->_apiInterface->processImage($urlList, $filePath, $attachmentID);//request to process all the images
496
 
497
+ if ( !is_array($result) )//there was an error, we save it in ShortPixelImprovement data
498
+ $this->handleError($attachmentID, $result);
499
+
500
  // store the referring webpage location
501
  $sendback = wp_get_referer();
502
  // sanitize the referring webpage location
505
  wp_redirect($sendback);
506
  // we are done,
507
  }
508
+
509
+ //save error in file's meta data
510
+ public function handleError($ID, $result)
511
+ {
512
+ $meta = wp_get_attachment_metadata($ID);
513
+ $meta['ShortPixelImprovement'] = $result;
514
+ wp_update_attachment_metadata($ID, $meta);
515
+ }
516
 
517
  public function handleRestoreBackup() {
518
  $attachmentID = intval($_GET['attachment_ID']);
568
  if(self::isProcesable($uploadFilePath) != false) {
569
  try {
570
  $uploadDir = wp_upload_dir();
571
+ if ( isset($meta['file']) )
572
+ $SubDir = substr($meta['file'],0,strrpos($meta['file'],"/")+1);
573
+ else
574
+ $SubDir = "";
575
+
576
  if ( empty($SubDir) ) //its a PDF?
577
  {
578
  $uploadFilePath = get_attached_file($ID);
599
  }
600
  }
601
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
602
  public function registerSettingsPage() {
603
  add_options_page( 'ShortPixel Settings', 'ShortPixel', 'manage_options', 'wp-shortpixel', array($this, 'renderSettingsMenu'));
604
  }
608
  }
609
 
610
  public function bulkProcess() {
611
+ global $wpdb;
612
+
613
  echo '<h1>Bulk Image Optimisation by ShortPixel</h1>';
614
 
615
  if(MUST_HAVE_KEY && $this->_verifiedKey == false) {//invalid API Key
618
  return;
619
  }
620
 
621
+ if(isset($_GET['cancel']))
622
+ {//cancel an ongoing bulk processing, it might be needed sometimes
623
+ update_option("wp-short-pixel-query-id-start", 0);
624
+ update_option("wp-short-pixel-query-id-stop", 0);
625
+ delete_option('bulkProcessingStatus');
 
626
  }
627
 
628
+ if(isset($_POST["bulkProcess"]))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
629
  {
630
+ $queryMax = "SELECT max(post_id) as startQueryID FROM " . $wpdb->prefix . "postmeta";
631
+ $resultQuery = $wpdb->get_results($queryMax);
632
+ $startQueryID = $resultQuery[0]->startQueryID;
633
+ update_option("wp-short-pixel-query-id-start", $startQueryID);//start downwards from the biggest item ID
634
+ update_option("wp-short-pixel-query-id-stop", 0);
635
+ update_option("wp-short-pixel-flag-id", $startQueryID);//we use to detect new added files while bulk is running
636
+ add_option('bulkProcessingStatus', 'running');//set bulk flag
637
+ }//end bulk process was clicked
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
638
 
639
+ $bulkProcessingStatus = get_option('bulkProcessingStatus');
640
+ $startQueryID = get_option('wp-short-pixel-query-id-start');
641
+
642
+ //figure out all the files that could be processed
643
+ $qry = "SELECT count(*) FilesToBeProcessed FROM " . $wpdb->prefix . "postmeta
644
+ WHERE meta_key = '_wp_attached_file' ";
645
+ $allFiles = $wpdb->get_results($qry);
646
+ //figure out the files that are left to be processed
647
+ $qry_left = "SELECT count(*) FilesLeftToBeProcessed FROM " . $wpdb->prefix . "postmeta
648
+ WHERE meta_key = '_wp_attached_file' AND post_id <= $startQueryID";
649
+ $filesLeft = $wpdb->get_results($qry_left);
650
+
651
+ if( $filesLeft[0]->FilesLeftToBeProcessed > 0 && $bulkProcessingStatus == "running" )//bulk processing was started and wasn't yet ended
652
+ {
653
+ echo "<p>
654
+ Bulk optimisation has started. This process will take some time, depending on the number of images in your library. <BR>Do not worry about the slow speed, it is a necessary measure in order not to interfere with the normal functioning of your site.<BR><BR>
655
+ This is a brief estimation of the bulk processing times:<BR>
656
+ 1 to 100 images < 20 min <BR>
657
+ 100 to 500 images < 2 hour<BR>
658
+ 500 to 1000 images < 4 hours<BR>
659
+ over 1000 images > 4 hours or more<BR><BR>
660
+
661
+ The latest status of the processing will be displayed here every 30 seconds.<BR>
662
+ In the meantime, you can continue using the admin as usual.<BR>
663
+ However, <b>you musn’t close the WordPress admin</b>, or the bulk processing will stop.
664
+ </p>";
665
+ echo '
666
+ <script type="text/javascript" >
667
+ var bulkProcessingRunning = true;
668
+ </script>
669
+ ';
670
 
671
+ $imagesLeft = $filesLeft[0]->FilesLeftToBeProcessed;
672
+ $totalImages = $allFiles[0]->FilesToBeProcessed;
 
673
 
674
+ echo "<p>{$imagesLeft} out of {$totalImages} images left to process.</p>";
675
 
676
+ echo '
677
+ <a class="button button-secondary" href="' . get_admin_url() . 'upload.php">Media Library</a>
678
+ <a class="button button-secondary" href="' . get_admin_url() . 'upload.php?page=wp-short-pixel-bulk&cancel=1">Cancel Processing</a>
679
+ ';
680
 
681
+ } else
682
+ {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
683
  $bulkProcessingStatus = get_option('bulkProcessingStatus');
684
+ if(isset($bulkProcessingStatus) && $bulkProcessingStatus == 'running')
685
+ {
686
  echo "<p>Bulk optimisation was successful. ShortPixel has finished optimising all your images.</p>
687
  <p>Go to the ShortPixel <a href='" . get_admin_url() . "options-general.php?page=wp-shortpixel#facts'>Stats</a> and see your website's optimised stats (in Settings > ShortPixel). </p>";
688
+
689
+ $queryMax = "SELECT max(post_id) as startQueryID FROM " . $wpdb->prefix . "postmeta";
690
+ $resultQuery = $wpdb->get_results($queryMax);
691
+ $startQueryID = $resultQuery[0]->startQueryID;
692
+ $maxIDbeforeBulk = get_option("wp-short-pixel-flag-id");//what was the max id before bulk was started?
693
+
694
+ if ( $startQueryID > $maxIDbeforeBulk )//basically we resume the processing for the files uploaded while bulk was running
695
+ {
696
+ update_option("wp-short-pixel-query-id-start", $startQueryID);
697
+ update_option("wp-short-pixel-query-id-stop", $maxIDbeforeBulk);
698
+ delete_option('bulkProcessingStatus');
699
+ }
700
+ else
701
+ {
702
+ update_option("wp-short-pixel-query-id-start", 0);
703
+ update_option("wp-short-pixel-query-id-stop", 0);
704
+ delete_option('bulkProcessingStatus');
705
+ }
706
  }
707
+
708
+ echo $this->getBulkProcessingForm($allFiles[0]->FilesToBeProcessed);
709
  echo '
710
  <script type="text/javascript" >
711
  var bulkProcessingRunning = false;
745
  $noticeHTML = "<br/><div style=\"background-color: #fff; border-left: 4px solid %s; box-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.1); padding: 1px 12px;\"><p>%s</p></div>";
746
 
747
  if(isset($_POST['submit']) || isset($_POST['validate'])) {
748
+
749
  //handle API Key - common for submit and validate
750
  $_POST['key'] = trim($_POST['key']);
751
  $validityData = $this->getQuotaInformation($_POST['key'], true);
1034
  $data = wp_get_attachment_metadata($id);
1035
  $file = get_attached_file($id);
1036
  $fileExtension = strtolower(substr($file,strrpos($file,".")+1));
1037
+
1038
+ if ( empty($data) )
1039
+ {
1040
+ if ( $fileExtension <> "pdf" )
1041
+ print 'Optimisation N/A';
1042
+ else
1043
+ {
1044
+ print 'PDF not processed';
1045
+ print " | <a href=\"admin.php?action=shortpixel_manual_optimize&amp;attachment_ID={$id}\">Optimize now</a>";
1046
+ }
1047
+ return;
1048
+ }
1049
+ elseif ( isset( $data['ShortPixelImprovement'] ) )
1050
+ {
1051
  if(isset($meta['ShortPixel']['BulkProcessing'])) {
1052
  print 'Waiting for bulk processing';
1053
  return;
1059
  print " | <a href=\"admin.php?action=shortpixel_restore_backup&amp;attachment_ID={$id}\">Restore backup</a>";
1060
  return;
1061
  }
1062
+ elseif ( $data['ShortPixelImprovement'] <> "Optimisation N/A" || is_numeric($data['ShortPixelImprovement']) )
1063
+ print '%';
1064
  } elseif(isset($data['ShortPixel']['WaitingProcessing'])) {
1065
  print 'Image waiting to be processed';
1066
  return;