ShortPixel Image Optimizer - Version 3.3.0

Version Description

  • reoptimize lossless/lossy
  • optimize thumbs for images already optimized
  • compatibility with WPML
Download this release

Release Info

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

Code changes from version 3.2.1 to 3.3.0

css/short-pixel.css CHANGED
@@ -1,3 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  li.shortpixel-toolbar-processing > a.ab-item > div,
2
  #wpadminbar li.shortpixel-toolbar-processing > a.ab-item > div{
3
  background-image: url("../img/loading-dark-big.gif");
@@ -107,9 +138,15 @@ li.shortpixel-hide {
107
  width: 290px;
108
  overflow: hidden;
109
  }
 
 
 
 
 
110
  .wp-core-ui .column-wp-shortPixel .button.button-smaller {
111
  font-size: 13px;
112
  padding:0px 5px;
 
113
  height:20px;
114
  line-height:16px;
115
  float:right;
1
+ div.shortpixel-rate-us {
2
+ display:inline-block;
3
+ margin-left: 20px;
4
+ vertical-align: top;
5
+ font-weight: bold;
6
+ padding-top: 5px;
7
+ }
8
+ div.shortpixel-rate-us > a {
9
+ vertical-align: middle;
10
+ padding: 16px 5px 0;
11
+ }
12
+ div.shortpixel-rate-us > a > div {
13
+ display: inline-block;
14
+ vertical-align: top;
15
+ margin-top: 14px;
16
+ }
17
+ div.shortpixel-rate-us > a > img {
18
+ padding-top: 7px;
19
+ }
20
+ div.shortpixel-rate-us > a:active,
21
+ div.shortpixel-rate-us > a:hover,
22
+ div.shortpixel-rate-us > a:focus {
23
+ outline:0;
24
+ border-style: none;
25
+ }
26
+ .sp-loading-small {
27
+ margin-top: 2px;
28
+ float: left;
29
+ margin-right: 5px;
30
+ }
31
+
32
  li.shortpixel-toolbar-processing > a.ab-item > div,
33
  #wpadminbar li.shortpixel-toolbar-processing > a.ab-item > div{
34
  background-image: url("../img/loading-dark-big.gif");
138
  width: 290px;
139
  overflow: hidden;
140
  }
141
+ .wp-core-ui .column-wp-shortPixel .sp-column-actions {
142
+ max-width: 120px;
143
+ float:right;
144
+ text-align: right;
145
+ }
146
  .wp-core-ui .column-wp-shortPixel .button.button-smaller {
147
  font-size: 13px;
148
  padding:0px 5px;
149
+ margin-bottom: 4px;
150
  height:20px;
151
  line-height:16px;
152
  float:right;
img/stars.png ADDED
Binary file
js/short-pixel.js CHANGED
@@ -8,6 +8,10 @@ jQuery(document).ready(function($){
8
  //register a bulk action
9
  jQuery('select[name^="action"] option:last-child').before('<option value="short-pixel-bulk">Optimize with ShortPixel</option>');
10
  }
 
 
 
 
11
  //
12
  jQuery(window).unload(function(){
13
  if(ShortPixel.bulkProcessor == true) {
@@ -41,11 +45,34 @@ var ShortPixel = function() {
41
  jQuery("section#" +target).addClass("sel-tab");
42
  }
43
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
 
45
  return {
46
- setOptions : setOptions,
47
- checkThumbsUpdTotal: checkThumbsUpdTotal,
48
- switchSettingsTab : switchSettingsTab
 
 
49
  }
50
  }();
51
 
@@ -66,6 +93,10 @@ function showToolBarAlert($status, $message) {
66
  //jQuery("a div", robo).attr("title", "ShortPixel quota exceeded. Click to top-up");
67
  jQuery("a div", robo).attr("title", "ShortPixel quota exceeded. Click for details.");
68
  break;
 
 
 
 
69
  case ShortPixel.STATUS_FAIL:
70
  robo.addClass("shortpixel-alert shortpixel-processing");
71
  jQuery("a div", robo).attr("title", $message);
@@ -200,11 +231,23 @@ function checkBulkProcessingCallApi(){
200
  break;
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
- }
 
 
 
 
 
 
 
 
 
 
 
 
208
  showToolBarAlert(ShortPixel.STATUS_SUCCESS, "");
209
  setCellMessage(id, cellMsg);
210
  var animator = new PercentageAnimator("#sp-msg-" + id + " span.percent", percent);
@@ -215,10 +258,20 @@ function checkBulkProcessingCallApi(){
215
  sliderUpdate(id, data["Thumb"], data["BkThumb"], data["PercentImprovement"]);
216
  }
217
  }
218
- //fall through
219
- case ShortPixel.STATUS_RETRY:
 
 
 
 
 
220
  case ShortPixel.STATUS_ERROR: //for error and skip also we retry
221
  case ShortPixel.STATUS_SKIP:
 
 
 
 
 
222
  console.log('Server response: ' + response);
223
  if(isBulkPage && typeof data["BulkPercent"] !== 'undefined') {
224
  progressUpdate(data["BulkPercent"], data["BulkMsg"]);
@@ -246,7 +299,7 @@ function setCellMessage(id, message){
246
  }
247
 
248
  function manualOptimization(id) {
249
- setCellMessage(id, "<img src='" + ShortPixel.WP_PLUGIN_URL + "/img/loading.gif'>Image waiting to be processed");
250
  jQuery("li.shortpixel-toolbar-processing").removeClass("shortpixel-hide");
251
  jQuery("li.shortpixel-toolbar-processing").addClass("shortpixel-processing");
252
  var data = { action : 'shortpixel_manual_optimization',
@@ -256,12 +309,47 @@ function manualOptimization(id) {
256
  if(data["Status"] == ShortPixel.STATUS_SUCCESS) {
257
  setTimeout(checkBulkProgress, 2000);
258
  } else {
259
- setCellMessage(id, "This content is not processable.");
260
  }
261
  //aici e aici
262
  });
263
  }
264
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
265
  function dismissShortPixelNotice(id) {
266
  jQuery("#short-pixel-notice-" + id).hide();
267
  var data = { action : 'shortpixel_dismiss_notice',
8
  //register a bulk action
9
  jQuery('select[name^="action"] option:last-child').before('<option value="short-pixel-bulk">Optimize with ShortPixel</option>');
10
  }
11
+ if( ShortPixel.MEDIA_ALERT == 'todo' && jQuery('div.media-frame.mode-grid').length > 0) {
12
+ //the media table is not in the list mode, alert the user
13
+ jQuery('div.media-frame.mode-grid').before('<div id="short-pixel-media-alert" class="notice notice-warning"><p>In order to access the ShortPixel Optimization actions and info, please change to <a href="/wp-admin/upload.php?mode=list" class="view-list"><span class="screen-reader-text">List View</span>List View</a><a class="alignright" href="javascript:ShortPixel.dismissMediaAlert();">Dismiss</a></p></div>');
14
+ }
15
  //
16
  jQuery(window).unload(function(){
17
  if(ShortPixel.bulkProcessor == true) {
45
  jQuery("section#" +target).addClass("sel-tab");
46
  }
47
  }
48
+
49
+ function dismissMediaAlert() {
50
+ var data = { action : 'shortpixel_dismiss_media_alert'};
51
+ jQuery.get(ajaxurl, data, function(response) {
52
+ data = JSON.parse(response);
53
+ if(data["Status"] == 'success') {
54
+ jQuery("#short-pixel-media-alert").hide();
55
+ console.log("dismissed");
56
+ }
57
+ });
58
+ }
59
+
60
+ function onBulkThumbsCheck(check) {
61
+ if(check.checked) {
62
+ jQuery("#with-thumbs").css('display', 'inherit');
63
+ jQuery("#without-thumbs").css('display', 'none');
64
+ } else {
65
+ jQuery("#without-thumbs").css('display', 'inherit');
66
+ jQuery("#with-thumbs").css('display', 'none');
67
+ }
68
+ }
69
 
70
  return {
71
+ setOptions : setOptions,
72
+ checkThumbsUpdTotal : checkThumbsUpdTotal,
73
+ switchSettingsTab : switchSettingsTab,
74
+ onBulkThumbsCheck : onBulkThumbsCheck,
75
+ dismissMediaAlert : dismissMediaAlert
76
  }
77
  }();
78
 
93
  //jQuery("a div", robo).attr("title", "ShortPixel quota exceeded. Click to top-up");
94
  jQuery("a div", robo).attr("title", "ShortPixel quota exceeded. Click for details.");
95
  break;
96
+ case ShortPixel.STATUS_SKIP:
97
+ robo.addClass("shortpixel-alert shortpixel-processing");
98
+ jQuery("a div", robo).attr("title", $message);
99
+ break;
100
  case ShortPixel.STATUS_FAIL:
101
  robo.addClass("shortpixel-alert shortpixel-processing");
102
  jQuery("a div", robo).attr("title", $message);
231
  break;
232
  case ShortPixel.STATUS_SUCCESS:
233
  var percent = data["PercentImprovement"];
234
+ var otherType = data["Type"].length > 0 ? (data["Type"] == "lossy" ? "lossless" : "lossy") : null;
235
+
236
+ var cellMsg = (percent > 0 ? "<div class='sp-column-info'>Reduced by <span class='percent'>" + percent + "%</span> " : "")
237
+ + (percent > 0 && percent < 5 ? "<br>" : '')
238
+ + (percent < 5 ? "Bonus processing" : '')
239
+ + (data["Type"].length > 0 ? " ("+data["Type"]+")" : "")
240
+ + (0 + data['ThumbsCount'] > 0 ? "<br>+" + data['ThumbsCount'] + " thumbnails optimized" :"")
241
+ + "</div>";
242
+
243
+ if(data["BackupEnabled"] == 1) {
244
+ cellMsg = '<div class="sp-column-actions">'
245
+ + (data["ThumbsTotal"] > data["ThumbsCount"] ? "<a class='button button-smaller button-primary' href=\"javascript:optimizeThumbs(" + id + ");\">Optimize " + (data["ThumbsTotal"] - data["ThumbsCount"]) + " thumbnails</a>" : "")
246
+ + (otherType.length ? "<a class='button button-smaller' href=\"javascript:reoptimize(" + id + ", '" + otherType + "');\">Re-optimize " + otherType + "</a>" : "")
247
+ + "<a class='button button-smaller' href=\"admin.php?action=shortpixel_restore_backup&attachment_ID=" + id + ")\">Restore backup</a>"
248
+ + "</div>" + cellMsg;
249
+ }
250
+
251
  showToolBarAlert(ShortPixel.STATUS_SUCCESS, "");
252
  setCellMessage(id, cellMsg);
253
  var animator = new PercentageAnimator("#sp-msg-" + id + " span.percent", percent);
258
  sliderUpdate(id, data["Thumb"], data["BkThumb"], data["PercentImprovement"]);
259
  }
260
  }
261
+ console.log('Server response: ' + response);
262
+ if(isBulkPage && typeof data["BulkPercent"] !== 'undefined') {
263
+ progressUpdate(data["BulkPercent"], data["BulkMsg"]);
264
+ }
265
+ setTimeout(checkBulkProgress, 5000);
266
+ break;
267
+
268
  case ShortPixel.STATUS_ERROR: //for error and skip also we retry
269
  case ShortPixel.STATUS_SKIP:
270
+ if(typeof data["Message"] !== 'undefined') {
271
+ showToolBarAlert(ShortPixel.STATUS_SKIP, data["Message"] + ' Image ID: ' + id);
272
+ setCellMessage(id, data["Message"]);
273
+ }
274
+ case ShortPixel.STATUS_RETRY:
275
  console.log('Server response: ' + response);
276
  if(isBulkPage && typeof data["BulkPercent"] !== 'undefined') {
277
  progressUpdate(data["BulkPercent"], data["BulkMsg"]);
299
  }
300
 
301
  function manualOptimization(id) {
302
+ setCellMessage(id, "<img src='" + ShortPixel.WP_PLUGIN_URL + "/img/loading.gif' class='sp-loading-small'>Image waiting to be processed");
303
  jQuery("li.shortpixel-toolbar-processing").removeClass("shortpixel-hide");
304
  jQuery("li.shortpixel-toolbar-processing").addClass("shortpixel-processing");
305
  var data = { action : 'shortpixel_manual_optimization',
309
  if(data["Status"] == ShortPixel.STATUS_SUCCESS) {
310
  setTimeout(checkBulkProgress, 2000);
311
  } else {
312
+ setCellMessage(id, typeof data["Message"] !== "undefined" ? data["Message"] : "This content is not processable.");
313
  }
314
  //aici e aici
315
  });
316
  }
317
 
318
+ function reoptimize(id, type) {
319
+ setCellMessage(id, "<img src='" + ShortPixel.WP_PLUGIN_URL + "/img/loading.gif' class='sp-loading-small'>Image waiting to be reprocessed");
320
+ jQuery("li.shortpixel-toolbar-processing").removeClass("shortpixel-hide");
321
+ jQuery("li.shortpixel-toolbar-processing").addClass("shortpixel-processing");
322
+ var data = { action : 'shortpixel_redo',
323
+ attachment_ID: id,
324
+ type: type};
325
+ jQuery.get(ajaxurl, data, function(response) {
326
+ data = JSON.parse(response);
327
+ if(data["Status"] == ShortPixel.STATUS_SUCCESS) {
328
+ setTimeout(checkBulkProgress, 2000);
329
+ } else {
330
+ $msg = typeof data["Message"] !== "undefined" ? data["Message"] : "This content is not processable.";
331
+ setCellMessage(id, $msg);
332
+ showToolBarAlert(ShortPixel.STATUS_FAIL, $msg);
333
+ }
334
+ });
335
+ }
336
+
337
+ function optimizeThumbs(id) {
338
+ setCellMessage(id, "<img src='" + ShortPixel.WP_PLUGIN_URL + "/img/loading.gif' class='sp-loading-small'>Image waiting to optimize thumbnails");
339
+ jQuery("li.shortpixel-toolbar-processing").removeClass("shortpixel-hide");
340
+ jQuery("li.shortpixel-toolbar-processing").addClass("shortpixel-processing");
341
+ var data = { action : 'shortpixel_optimize_thumbs',
342
+ attachment_ID: id};
343
+ jQuery.get(ajaxurl, data, function(response) {
344
+ data = JSON.parse(response);
345
+ if(data["Status"] == ShortPixel.STATUS_SUCCESS) {
346
+ setTimeout(checkBulkProgress, 2000);
347
+ } else {
348
+ setCellMessage(id, typeof data["Message"] !== "undefined" ? data["Message"] : "This content is not processable.");
349
+ }
350
+ });
351
+ }
352
+
353
  function dismissShortPixelNotice(id) {
354
  jQuery("#short-pixel-notice-" + id).hide();
355
  var data = { action : 'shortpixel_dismiss_notice',
readme.txt CHANGED
@@ -5,7 +5,7 @@ Tags: picture, optimization, image editor, pngout, upload speed, shortpixel, co
5
 
6
  Requires at least: 3.2.0
7
  Tested up to: 4.4
8
- Stable tag: 3.2.1
9
  License: GPLv2 or later
10
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
11
 
@@ -38,14 +38,14 @@ Both new and old images can be optimized with ShortPixel. Once activated, the pl
38
 
39
  ShortPixel free and paid plans offer the same features and deliver the same optimization quality. The difference is made by the available image quota. 100 images/month are for free, additional image quota requires a small fee ($4,99 for 5,000 image credits).
40
 
41
- Both monthly subscriptions and one-time plans are available. The same plan can be used for multiple websites. Check our <a rel="friend" href="http://shortpixel.com/free-demo">free demo</a> and see the <a href="http://shortpixel.com/pricing">optimization plans</a> on our site.
42
 
43
  We believe in a better society, so we support educational non-profits. <a href="http://shortpixel.com/contact">Contact us</a> and we’ll see how we can help!
44
 
45
  Help us spread a the word by recommending ShortPixel to your friends and collect 100 additional image credits for each referred sign up.
46
  Make money by promoting a great plugin with our <a href="https://shortpixel.com/free-sign-up-affiliate">50/50 affiliate program</a>.
47
 
48
- **Why use ShortPixel to optimize you images?**
49
 
50
  Image size is crucial to your website’s speed, and website speed affects search ranking. With ShortPixel plugin you will downsize your images and improve your web performance on the spot.
51
 
@@ -170,6 +170,12 @@ The ShortPixel team is here to help. <a href="https://shortpixel.com/contact">Co
170
 
171
  == Changelog ==
172
 
 
 
 
 
 
 
173
  = 3.2.1 =
174
 
175
  * old PHP compatibility fix
5
 
6
  Requires at least: 3.2.0
7
  Tested up to: 4.4
8
+ Stable tag: 3.3.0
9
  License: GPLv2 or later
10
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
11
 
38
 
39
  ShortPixel free and paid plans offer the same features and deliver the same optimization quality. The difference is made by the available image quota. 100 images/month are for free, additional image quota requires a small fee ($4,99 for 5,000 image credits).
40
 
41
+ Both monthly subscriptions and one-time plans are available. The same plan can be used for multiple websites. Make an instant <a rel="friend" href="http://shortpixel.com/image-compression-test">image compression test</a> on your site or <a rel="friend" href="http://shortpixel.com/online-image-compression">compress some images</a> to make sure they are to your liking.
42
 
43
  We believe in a better society, so we support educational non-profits. <a href="http://shortpixel.com/contact">Contact us</a> and we’ll see how we can help!
44
 
45
  Help us spread a the word by recommending ShortPixel to your friends and collect 100 additional image credits for each referred sign up.
46
  Make money by promoting a great plugin with our <a href="https://shortpixel.com/free-sign-up-affiliate">50/50 affiliate program</a>.
47
 
48
+ **Why use ShortPixel to optimize your images?**
49
 
50
  Image size is crucial to your website’s speed, and website speed affects search ranking. With ShortPixel plugin you will downsize your images and improve your web performance on the spot.
51
 
170
 
171
  == Changelog ==
172
 
173
+ = 3.3.0 =
174
+
175
+ * reoptimize lossless/lossy
176
+ * optimize thumbs for images already optimized
177
+ * compatibility with WPML
178
+
179
  = 3.2.1 =
180
 
181
  * old PHP compatibility fix
shortpixel_api.php CHANGED
@@ -22,7 +22,7 @@ class ShortPixelAPI {
22
 
23
  public function __construct($settings) {
24
  $this->_settings = $settings;
25
- $this->_apiEndPoint = $this->_settings->httpProto . '://api.shortpixel.com/v2/reducer_dev.php';
26
  add_action('processImageAction', array(&$this, 'processImageAction'), 10, 4);
27
  }
28
 
@@ -30,12 +30,12 @@ class ShortPixelAPI {
30
  $this->processImage($URLs, $PATHs, $ID, $time);
31
  }
32
 
33
- public function doRequests($URLs, $Blocking, $ID) {
34
 
35
  $requestParameters = array(
36
  'plugin_version' => PLUGIN_VERSION,
37
  'key' => $this->_settings->apiKey,
38
- 'lossy' => $this->_settings->compressionType,
39
  'cmyk2rgb' => $this->_settings->CMYKtoRGBconversion,
40
  'keep_exif' => ($this->_settings->keepExif ? "1" : "0"),
41
  'resize' => $this->_settings->resizeImages,
@@ -45,7 +45,7 @@ class ShortPixelAPI {
45
  );
46
  $arguments = array(
47
  'method' => 'POST',
48
- 'timeout' => 45,
49
  'redirection' => 3,
50
  'sslverify' => false,
51
  'httpversion' => '1.0',
@@ -54,13 +54,16 @@ class ShortPixelAPI {
54
  'body' => json_encode($requestParameters),
55
  'cookies' => array()
56
  );
57
- //echo("URL:".$this->_apiEndPoint."ARGUMENTS:");var_dump($arguments);
 
 
 
58
  $response = wp_remote_post($this->_apiEndPoint, $arguments );
59
- //echo("RESPONSE:"); var_dump($response);
60
 
61
  //only if $Blocking is true analyze the response
62
  if ( $Blocking )
63
  {
 
64
  //there was an error, save this error inside file's SP optimization field
65
  if ( is_object($response) && get_class($response) == 'WP_Error' )
66
  {
@@ -81,7 +84,7 @@ class ShortPixelAPI {
81
  wp_update_attachment_metadata($ID, $meta);
82
  return array("response" => array("code" => $errorCode, "message" => $errorMessage ));
83
  }
84
-
85
  return $response;//this can be an error or a good response
86
  }
87
 
@@ -98,25 +101,31 @@ class ShortPixelAPI {
98
  public function processImage($URLs, $PATHs, $ID = null, $startTime = 0)
99
  {
100
 
 
 
101
  $PATHs = self::CheckAndFixImagePaths($PATHs);//check for images to make sure they exist on disk
102
- if ( $PATHs === false )
103
- return array("Status" => self::STATUS_SKIP, "Message" => 'The file(s) do not exist on disk, Image ID: ' .$ID);
 
 
 
 
104
 
105
  //tries multiple times (till timeout almost reached) to fetch images.
106
  if($startTime == 0) {
107
  $startTime = time();
108
  }
109
  $apiRetries = get_option('wp-short-pixel-api-retries');
 
110
  if( time() - $startTime > MAX_EXECUTION_TIME)
111
  {//keeps track of time
112
  if ( $apiRetries > MAX_API_RETRIES )//we tried to process this time too many times, giving up...
113
  {
114
- $meta = wp_get_attachment_metadata($ID);
115
  $meta['ShortPixelImprovement'] = 'Timed out while processing.';
116
  unset($meta['ShortPixel']['WaitingProcessing']);
117
  update_option('wp-short-pixel-api-retries', 0);//fai added to solve a bug?
118
  wp_update_attachment_metadata($ID, $meta);
119
- return array("Status" => self::STATUS_SKIP, "Message" => 'Skip this image, tries the next one.');
120
  }
121
  else
122
  {//we'll try again next time user visits a page on admin panel
@@ -125,7 +134,9 @@ class ShortPixelAPI {
125
  return array("Status" => self::STATUS_RETRY, "Message" => 'Timed out while processing. (pass '.$apiRetries.')');
126
  }
127
  }
128
- $response = $this->doRequests($URLs, true, $ID);//send requests to API
 
 
129
 
130
  if($response['response']['code'] != 200)//response <> 200 -> there was an error apparently?
131
  return array("Status" => self::STATUS_FAIL, "Message" => "There was an error and your request was not processed.");
@@ -149,7 +160,7 @@ class ShortPixelAPI {
149
  case 2:
150
  //handle image has been processed
151
  update_option( 'wp-short-pixel-quota-exceeded', 0);//reset the quota exceeded flag
152
- return $this->handleSuccess($APIresponse, $URLs, $PATHs, $ID);
153
  break;
154
  default:
155
  //handle error
@@ -183,9 +194,24 @@ class ShortPixelAPI {
183
 
184
  }
185
 
186
- public function handleDownload($fileData,$counter){
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
187
  //var_dump($fileData);
188
- if($this->_settings->compressionType)
189
  {
190
  $fileType = "LossyURL";
191
  $fileSize = "LossySize";
@@ -201,12 +227,16 @@ class ShortPixelAPI {
201
  return array("Status" => self::STATUS_UNCHANGED, "Message" => "File wasn't optimized so we do not download it.");
202
 
203
  $correctFileSize = $fileData->$fileSize;
204
- $tempFiles[$counter] = download_url(urldecode($fileData->$fileType));
 
 
 
205
  //var_dump($tempFiles);
206
 
207
- if(is_wp_error( $tempFiles[$counter] )) //also tries with http instead of https
208
- {
209
- $tempFiles[$counter] = download_url(str_replace('http://', 'https://', urldecode($fileData->$fileType)));
 
210
  }
211
  //on success we return this
212
  $returnMessage = array("Status" => self::STATUS_SUCCESS, "Message" => $tempFiles[$counter]);
@@ -231,8 +261,9 @@ class ShortPixelAPI {
231
  return $returnMessage;
232
  }
233
 
234
- public function handleSuccess($APIresponse, $URLs, $PATHs, $ID) {
235
  $counter = $savedSpace = $originalSpace = $optimizedSpace = $averageCompression = 0;
 
236
 
237
  //download each file from array and process it
238
  foreach ( $APIresponse as $fileData )
@@ -243,7 +274,7 @@ class ShortPixelAPI {
243
  $percentImprovement = $fileData->PercentImprovement;
244
  else //count thumbnails only
245
  update_option( 'wp-short-pixel-thumbnail-count', get_option('wp-short-pixel-thumbnail-count') + 1 );
246
- $downloadResult = $this->handleDownload($fileData,$counter);
247
  //when the status is STATUS_UNCHANGED we just skip the array line for that one
248
  if ( $downloadResult['Status'] == self::STATUS_SUCCESS ) {
249
  $tempFiles[$counter] = $downloadResult['Message'];
@@ -261,10 +292,10 @@ class ShortPixelAPI {
261
  $SubDir = $this->returnSubDir(get_attached_file($ID));
262
 
263
  //if backup is enabled - we try to save the images
264
- if( get_option('wp-short-backup_images') )
265
  {
266
  $uploadDir = wp_upload_dir();
267
- $source = $PATHs;//array with final paths for this files
268
 
269
  if( !file_exists(SP_BACKUP_FOLDER) && !@mkdir(SP_BACKUP_FOLDER, 0777, true) ) {//creates backup folder if it doesn't exist
270
  return array("Status" => self::STATUS_FAIL, "Message" => "Backup folder does not exist and it cannot be created");
@@ -285,12 +316,13 @@ class ShortPixelAPI {
285
  if ( !file_exists($filePATH) )
286
  {
287
  if ( !@copy($source[$fileID], $destination[$fileID]) )
288
- {//file couldn't have been saved in backup folder
289
  ShortPixelAPI::SaveMessageinMetadata($ID, 'Cannot save file <i>' . self::MB_basename($source[$fileID]) . '</i> in backup directory');
290
  return array("Status" => self::STATUS_FAIL, "Message" => 'Cannot save file <i>' . self::MB_basename($source[$fileID]) . '</i> in backup directory');
291
  }
292
  }
293
  }
 
294
  } else {//cannot write to the backup dir, return with an error
295
  ShortPixelAPI::SaveMessageinMetadata($ID, 'Cannot save file in backup directory');
296
  return array("Status" => self::STATUS_FAIL, "Message" => 'Cannot save file in backup directory');
@@ -298,7 +330,6 @@ class ShortPixelAPI {
298
 
299
  }//end backup section
300
 
301
-
302
  $writeFailed = 0;
303
 
304
  if ( !empty($tempFiles) )
@@ -312,27 +343,29 @@ class ShortPixelAPI {
312
  $writeFailed++;
313
  }
314
  @unlink($tempFilePATH);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
315
 
316
- if ( $writeFailed > 0 )//there was an error
317
- {
318
- ShortPixelAPI::SaveMessageinMetadata($ID, 'Error: optimized version of ' . $writeFailed . ' file(s) couldn\'t be updated.');
319
- update_option('bulkProcessingStatus', "error");
320
- return array("Status" => self::STATUS_FAIL, "Code" =>"write-fail", "Message" => 'Error: optimized version of ' . $writeFailed . ' file(s) couldn\'t be updated.');
321
- }
322
- else
323
- {//all files were copied, optimization data regarding the savings locally in DB
324
- $fileType = ( $this->_settings->compressionType ) ? "LossySize" : "LoselessSize";
325
- $savedSpace += $APIresponse[$tempFileID]->OriginalSize - $APIresponse[$tempFileID]->$fileType;
326
- $originalSpace += $APIresponse[$tempFileID]->OriginalSize;
327
- $optimizedSpace += $APIresponse[$tempFileID]->$fileType;
328
- $averageCompression += $fileData->PercentImprovement;
329
-
330
- //add the number of files with < 5% optimization
331
- if ( ( ( 1 - $APIresponse[$tempFileID]->$fileType/$APIresponse[$tempFileID]->OriginalSize ) * 100 ) < 5 )
332
- $this->_settings->under5Percent++;
333
-
334
  }
335
- }
 
 
336
  }
337
  //old average counting
338
  $this->_settings->savedSpace += $savedSpace;
@@ -343,18 +376,52 @@ class ShortPixelAPI {
343
  //new average counting
344
  $this->_settings->totalOriginal += $originalSpace;
345
  $this->_settings->totalOptimized += $optimizedSpace;
 
346
  //update metadata for this file
347
- $meta = wp_get_attachment_metadata($ID);
348
- $meta['ShortPixelImprovement'] = round($percentImprovement,2);
349
- $meta['ShortPixel']['type'] = $this->_settings->compressionType == 1 ? 'lossy' : 'lossless';
350
- $meta['ShortPixel']['thumbsOpt'] = $this->_settings->processThumbnails && isset($meta['sizes']) ? count($meta['sizes']) : 0;
351
- wp_update_attachment_metadata($ID, $meta);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
352
  //we reset the retry counter in case of success
353
  update_option('wp-short-pixel-api-retries', 0);
354
 
355
  return array("Status" => self::STATUS_SUCCESS, "Message" => 'Success: No pixels remained unsqueezed :-)', "PercentImprovement" => $percentImprovement);
356
  }//end handleSuccess
357
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
358
  static public function returnSubDir($file)//return subdir for that particular attached file
359
  {
360
  $Atoms = explode("/", $file);
@@ -401,7 +468,10 @@ class ShortPixelAPI {
401
  return $PATHs;
402
 
403
  }
404
-
 
 
 
405
 
406
  static private function SaveMessageinMetadata($ID, $Message)
407
  {
22
 
23
  public function __construct($settings) {
24
  $this->_settings = $settings;
25
+ $this->_apiEndPoint = $this->_settings->httpProto . '://api.shortpixel.com/v2/reducer.php';
26
  add_action('processImageAction', array(&$this, 'processImageAction'), 10, 4);
27
  }
28
 
30
  $this->processImage($URLs, $PATHs, $ID, $time);
31
  }
32
 
33
+ public function doRequests($URLs, $Blocking, $ID, $compressionType = false) {
34
 
35
  $requestParameters = array(
36
  'plugin_version' => PLUGIN_VERSION,
37
  'key' => $this->_settings->apiKey,
38
+ 'lossy' => $compressionType === false ? $this->_settings->compressionType : $compressionType,
39
  'cmyk2rgb' => $this->_settings->CMYKtoRGBconversion,
40
  'keep_exif' => ($this->_settings->keepExif ? "1" : "0"),
41
  'resize' => $this->_settings->resizeImages,
45
  );
46
  $arguments = array(
47
  'method' => 'POST',
48
+ 'timeout' => 15,
49
  'redirection' => 3,
50
  'sslverify' => false,
51
  'httpversion' => '1.0',
54
  'body' => json_encode($requestParameters),
55
  'cookies' => array()
56
  );
57
+ //add this explicitely only for https, otherwise (for http) it slows the request
58
+ if($this->_settings->httpProto !== 'https') {
59
+ unset($arguments['sslverify']);
60
+ }
61
  $response = wp_remote_post($this->_apiEndPoint, $arguments );
 
62
 
63
  //only if $Blocking is true analyze the response
64
  if ( $Blocking )
65
  {
66
+ //die(var_dump(array('URL: ' => $this->_apiEndPoint, '<br><br>REQUEST:' => $arguments, '<br><br>RESPONSE: ' => $response )));
67
  //there was an error, save this error inside file's SP optimization field
68
  if ( is_object($response) && get_class($response) == 'WP_Error' )
69
  {
84
  wp_update_attachment_metadata($ID, $meta);
85
  return array("response" => array("code" => $errorCode, "message" => $errorMessage ));
86
  }
87
+
88
  return $response;//this can be an error or a good response
89
  }
90
 
101
  public function processImage($URLs, $PATHs, $ID = null, $startTime = 0)
102
  {
103
 
104
+ $meta = wp_get_attachment_metadata($ID);
105
+
106
  $PATHs = self::CheckAndFixImagePaths($PATHs);//check for images to make sure they exist on disk
107
+ if ( $PATHs === false ) {
108
+ $msg = 'The file(s) do not exist on disk.';
109
+ $meta['ShortPixelImprovement'] = $msg;
110
+ wp_update_attachment_metadata($ID, $meta);
111
+ return array("Status" => self::STATUS_SKIP, "Message" => $msg);
112
+ }
113
 
114
  //tries multiple times (till timeout almost reached) to fetch images.
115
  if($startTime == 0) {
116
  $startTime = time();
117
  }
118
  $apiRetries = get_option('wp-short-pixel-api-retries');
119
+
120
  if( time() - $startTime > MAX_EXECUTION_TIME)
121
  {//keeps track of time
122
  if ( $apiRetries > MAX_API_RETRIES )//we tried to process this time too many times, giving up...
123
  {
 
124
  $meta['ShortPixelImprovement'] = 'Timed out while processing.';
125
  unset($meta['ShortPixel']['WaitingProcessing']);
126
  update_option('wp-short-pixel-api-retries', 0);//fai added to solve a bug?
127
  wp_update_attachment_metadata($ID, $meta);
128
+ return array("Status" => self::STATUS_SKIP, "Message" => 'Image ID: ' . $ID .' Skip this image, try the next one.');
129
  }
130
  else
131
  {//we'll try again next time user visits a page on admin panel
134
  return array("Status" => self::STATUS_RETRY, "Message" => 'Timed out while processing. (pass '.$apiRetries.')');
135
  }
136
  }
137
+
138
+ $compressionType = isset($meta['ShortPixel']['type']) ? ($meta['ShortPixel']['type'] == 'lossy' ? 1 : 0) : $this->_settings->compressionType;
139
+ $response = $this->doRequests($URLs, true, $ID, $compressionType);//send requests to API
140
 
141
  if($response['response']['code'] != 200)//response <> 200 -> there was an error apparently?
142
  return array("Status" => self::STATUS_FAIL, "Message" => "There was an error and your request was not processed.");
160
  case 2:
161
  //handle image has been processed
162
  update_option( 'wp-short-pixel-quota-exceeded', 0);//reset the quota exceeded flag
163
+ return $this->handleSuccess($APIresponse, $URLs, $PATHs, $ID, $compressionType);
164
  break;
165
  default:
166
  //handle error
194
 
195
  }
196
 
197
+ public function setPreferredProtocol($url, $reset = false) {
198
+ //switch protocol based on the formerly detected working protocol
199
+ if($this->_settings->downloadProto == '' || $reset) {
200
+ //make a test to see if the http is working
201
+ $testURL = 'http://api.shortpixel.com/img/connection-test-image.png';
202
+ $result = download_url($testURL, 10);
203
+ $this->_settings->downloadProto = is_wp_error( $result ) ? 'https' : 'http';
204
+ }
205
+ return $this->_settings->downloadProto == 'http' ?
206
+ str_replace('https://', 'http://', $url) :
207
+ str_replace('http://', 'https://', $url);
208
+
209
+
210
+ }
211
+
212
+ public function handleDownload($fileData,$counter, $compressionType){
213
  //var_dump($fileData);
214
+ if($compressionType)
215
  {
216
  $fileType = "LossyURL";
217
  $fileSize = "LossySize";
227
  return array("Status" => self::STATUS_UNCHANGED, "Message" => "File wasn't optimized so we do not download it.");
228
 
229
  $correctFileSize = $fileData->$fileSize;
230
+ $fileURL = $this->setPreferredProtocol(urldecode($fileData->$fileType));
231
+
232
+ $downloadTimeout = ini_get('max_execution_time') - 10;
233
+ $tempFiles[$counter] = download_url($fileURL, $downloadTimeout);
234
  //var_dump($tempFiles);
235
 
236
+ if(is_wp_error( $tempFiles[$counter] ))
237
+ { //try to switch the default protocol
238
+ $fileURL = $this->setPreferredProtocol(urldecode($fileData->$fileType), true); //force recheck of the protocol
239
+ $tempFiles[$counter] = download_url($fileURL, $downloadTimeout);
240
  }
241
  //on success we return this
242
  $returnMessage = array("Status" => self::STATUS_SUCCESS, "Message" => $tempFiles[$counter]);
261
  return $returnMessage;
262
  }
263
 
264
+ public function handleSuccess($APIresponse, $URLs, $PATHs, $ID, $compressionType) {
265
  $counter = $savedSpace = $originalSpace = $optimizedSpace = $averageCompression = 0;
266
+ $NoBackup = true;
267
 
268
  //download each file from array and process it
269
  foreach ( $APIresponse as $fileData )
274
  $percentImprovement = $fileData->PercentImprovement;
275
  else //count thumbnails only
276
  update_option( 'wp-short-pixel-thumbnail-count', get_option('wp-short-pixel-thumbnail-count') + 1 );
277
+ $downloadResult = $this->handleDownload($fileData,$counter,$compressionType);
278
  //when the status is STATUS_UNCHANGED we just skip the array line for that one
279
  if ( $downloadResult['Status'] == self::STATUS_SUCCESS ) {
280
  $tempFiles[$counter] = $downloadResult['Message'];
292
  $SubDir = $this->returnSubDir(get_attached_file($ID));
293
 
294
  //if backup is enabled - we try to save the images
295
+ if( $this->_settings->backupImages )
296
  {
297
  $uploadDir = wp_upload_dir();
298
+ $source = $PATHs; //array with final paths for these files
299
 
300
  if( !file_exists(SP_BACKUP_FOLDER) && !@mkdir(SP_BACKUP_FOLDER, 0777, true) ) {//creates backup folder if it doesn't exist
301
  return array("Status" => self::STATUS_FAIL, "Message" => "Backup folder does not exist and it cannot be created");
316
  if ( !file_exists($filePATH) )
317
  {
318
  if ( !@copy($source[$fileID], $destination[$fileID]) )
319
+ {//file couldn't be saved in backup folder
320
  ShortPixelAPI::SaveMessageinMetadata($ID, 'Cannot save file <i>' . self::MB_basename($source[$fileID]) . '</i> in backup directory');
321
  return array("Status" => self::STATUS_FAIL, "Message" => 'Cannot save file <i>' . self::MB_basename($source[$fileID]) . '</i> in backup directory');
322
  }
323
  }
324
  }
325
+ $NoBackup = true;
326
  } else {//cannot write to the backup dir, return with an error
327
  ShortPixelAPI::SaveMessageinMetadata($ID, 'Cannot save file in backup directory');
328
  return array("Status" => self::STATUS_FAIL, "Message" => 'Cannot save file in backup directory');
330
 
331
  }//end backup section
332
 
 
333
  $writeFailed = 0;
334
 
335
  if ( !empty($tempFiles) )
343
  $writeFailed++;
344
  }
345
  @unlink($tempFilePATH);
346
+ }
347
+
348
+ if ( $writeFailed > 0 )//there was an error
349
+ {
350
+ ShortPixelAPI::SaveMessageinMetadata($ID, 'Error: optimized version of ' . $writeFailed . ' file(s) couldn\'t be updated.');
351
+ update_option('bulkProcessingStatus', "error");
352
+ return array("Status" => self::STATUS_FAIL, "Code" =>"write-fail", "Message" => 'Error: optimized version of ' . $writeFailed . ' file(s) couldn\'t be updated.');
353
+ }
354
+ else
355
+ {//all files were copied, optimization data regarding the savings locally in DB
356
+ $fileType = ( $this->_settings->compressionType ) ? "LossySize" : "LoselessSize";
357
+ $savedSpace += $APIresponse[$tempFileID]->OriginalSize - $APIresponse[$tempFileID]->$fileType;
358
+ $originalSpace += $APIresponse[$tempFileID]->OriginalSize;
359
+ $optimizedSpace += $APIresponse[$tempFileID]->$fileType;
360
+ $averageCompression += $fileData->PercentImprovement;
361
 
362
+ //add the number of files with < 5% optimization
363
+ if ( ( ( 1 - $APIresponse[$tempFileID]->$fileType/$APIresponse[$tempFileID]->OriginalSize ) * 100 ) < 5 ) {
364
+ $this->_settings->under5Percent++;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
365
  }
366
+ }
367
+ } elseif( 0 + $fileData->PercentImprovement < 5) {
368
+ $this->_settings->under5Percent++;
369
  }
370
  //old average counting
371
  $this->_settings->savedSpace += $savedSpace;
376
  //new average counting
377
  $this->_settings->totalOriginal += $originalSpace;
378
  $this->_settings->totalOptimized += $optimizedSpace;
379
+
380
  //update metadata for this file
381
+ $duplicates = self::getWPMLDuplicates($ID);
382
+ foreach($duplicates as $_ID) {
383
+ $meta = wp_get_attachment_metadata($_ID);
384
+ $meta['ShortPixel']['type'] = self::getCompressionTypeName($compressionType);
385
+ $meta['ShortPixel']['exifKept'] = $this->_settings->keepExif;
386
+ $meta['ShortPixel']['date'] = date("Y-m-d");
387
+ //thumbs were processed if settings or if they were explicitely requested
388
+ $meta['ShortPixel']['thumbsOpt'] = (isset($meta['ShortPixel']['thumbsTodo']) || $this->_settings->processThumbnails) && isset($meta['sizes']) ? count($meta['sizes']) : 0;
389
+ //if thumbsTodo - this means there was an explicit request to process thumbs for an image that was previously processed without
390
+ // don't update the ShortPixelImprovement ratio as this is only calculated based on main image
391
+ if(isset($meta['ShortPixel']['thumbsTodo'])) {
392
+ unset($meta['ShortPixel']['thumbsTodo']);
393
+ $percentImprovement = $meta['ShortPixelImprovement'];
394
+ } else {
395
+ $meta['ShortPixelImprovement'] = "".round($percentImprovement,2);
396
+ }
397
+ if($NoBackup) {
398
+ $meta['ShortPixel']['NoBackup'] = true;
399
+ }
400
+ wp_update_attachment_metadata($_ID, $meta);
401
+ }
402
  //we reset the retry counter in case of success
403
  update_option('wp-short-pixel-api-retries', 0);
404
 
405
  return array("Status" => self::STATUS_SUCCESS, "Message" => 'Success: No pixels remained unsqueezed :-)', "PercentImprovement" => $percentImprovement);
406
  }//end handleSuccess
407
 
408
+ static public function getWPMLDuplicates( $id ) {
409
+ global $wpdb;
410
+
411
+ $parentId = get_post_meta ($id, '_icl_lang_duplicate_of', true );
412
+ if($parentId) $id = $parentId;
413
+
414
+ $duplicates = $wpdb->get_col( $wpdb->prepare( "
415
+ SELECT pm.post_id FROM {$wpdb->postmeta} pm
416
+ WHERE pm.meta_value = %s AND pm.meta_key = '_icl_lang_duplicate_of'
417
+ ", $id ) );
418
+
419
+ if(!in_array($id, $duplicates)) $duplicates[] = $id;
420
+
421
+ return $duplicates;
422
+ }
423
+
424
+
425
  static public function returnSubDir($file)//return subdir for that particular attached file
426
  {
427
  $Atoms = explode("/", $file);
468
  return $PATHs;
469
 
470
  }
471
+
472
+ static public function getCompressionTypeName($compressionType) {
473
+ return $compressionType == 1 ? 'lossy' : 'lossless';
474
+ }
475
 
476
  static private function SaveMessageinMetadata($ID, $Message)
477
  {
shortpixel_queue.php CHANGED
@@ -117,8 +117,19 @@ class ShortPixelQueue {
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
  }
123
 
124
  public function bulkRunning() {
@@ -167,13 +178,20 @@ class ShortPixelQueue {
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 ? $this->bulkCount : 1) * 100);
117
 
118
  public function getFailed() {
119
  $failed = $this->settings->getOpt('wp-short-pixel-failed-imgs','');
120
+ $failed = "83";
121
  if(!strlen($failed)) return array();
122
+ $ret = explode(",", $failed);
123
+ $fails = array();
124
+ foreach($ret as $fail) {
125
+ $meta = wp_get_attachment_metadata($fail);
126
+ if(!$meta || (isset($meta["ShortPixelImprovement"]) && is_numeric($meta["ShortPixelImprovement"]))){
127
+ $this->removeFromFailed($fail);
128
+ } else {
129
+ $fails[] = $fail;
130
+ }
131
+ }
132
+ return $fails;
133
  }
134
 
135
  public function bulkRunning() {
178
  }
179
 
180
  public function setBulkPreviousPercent() {
181
+ //processable and already processed
182
  $res = $this->ctrl->countAllProcessableFiles($this->getFlagBulkId(), $this->stopBulkId);
183
  $this->bulkCount = $res["mainFiles"];
184
  $this->settings->setOpt("wp-short-pixel-bulk-count", $this->bulkCount);
185
+
186
+ //if compression type changed, add also the images with the other compression type
187
+ $this->bulkAlreadyDoneCount = $res["mainProcessedFiles"] - $res["mainProc".((0 + $this->ctrl->getCompressionType() == 1) ? "Lossless" : "Lossy")."Files"];
188
+ // if the thumbnails are to be processed, add also the images that have thumbs not processed
189
+ if($this->settings->processThumbnails) {
190
+ $this->bulkAlreadyDoneCount -= $res["mainUnprocessedThumbs"];
191
+ }
192
+
193
+ //die(var_dump($res));
194
+
195
  $this->settings->setOpt("wp-short-pixel-bulk-done-count", $this->bulkAlreadyDoneCount);
196
  //percent already done
197
  $this->bulkPreviousPercent = round($this->bulkAlreadyDoneCount / ($this->bulkCount ? $this->bulkCount : 1) * 100);
shortpixel_view.php CHANGED
@@ -145,7 +145,8 @@ class ShortPixelView {
145
  <?php $this->displayBulkStats($quotaData['totalProcessedFiles'], $quotaData['mainProcessedFiles'], $under5PercentCount, $averageCompression, $savedSpace);?>
146
  <?php if($quotaData['totalProcessedFiles'] < $quotaData['totalFiles']) { ?>
147
  <p><?php echo(number_format($quotaData['mainFiles'] - $quotaData['mainProcessedFiles']));?> images and
148
- <?php echo(number_format(($quotaData['totalFiles'] - $quotaData['mainFiles']) - ($quotaData['totalProcessedFiles'] - $quotaData['mainProcessedFiles'])));?> thumbnails are not yet optimized by ShortPixel.</p>
 
149
  <?php } ?>
150
  <p>You can continue optimizing your Media Gallery from where you left, by clicking the Resume processing button. Already optimized images will not be reprocessed.</p>
151
  <?php
@@ -166,23 +167,90 @@ class ShortPixelView {
166
  fjs.parentNode.insertBefore(js,fjs);}}(document, 'script', 'twitter-wjs');
167
  </script>
168
  </div>
 
 
 
 
 
 
 
 
 
169
  </div>
170
  <?php $this->displayBulkStats($quotaData['totalProcessedFiles'], $quotaData['mainProcessedFiles'], $under5PercentCount, $averageCompression, $savedSpace);?>
171
- <p>Go to the ShortPixel <a href='<?php echo(get_admin_url());?>options-general.php?page=wp-shortpixel#stats'>Stats</a> and see all your websites' optimized stats. Download your detailed <a href="https://api.shortpixel.com/v2/report.php?key=<?php echo($this->ctrl->getApiKey());?>">Optimization Report</a> to check your image optimization statistics for the last 40 days</p>
172
- <?php if($quotaData['totalProcessedFiles'] < $quotaData['totalFiles']) { ?>
173
- <p><?php echo(number_format($quotaData['mainFiles'] - $quotaData['mainProcessedFiles']));?> images and
174
- <?php echo(number_format(($quotaData['totalFiles'] - $quotaData['mainFiles']) - ($quotaData['totalProcessedFiles'] - $quotaData['mainProcessedFiles'])));?> thumbnails are not yet optimized by ShortPixel.</p>
175
- <?php }
176
  $failed = $this->ctrl->getPrioQ()->getFailed();
177
  if(count($failed)) { ?>
178
- <p>The following images could not be processed because of their limited write rights. This usually happens if you have changed your hosting provider. Please restart the optimization process after you granted write rights to all the files below.</p>
179
- <?php $this->displayFailed($failed);?>
 
 
 
 
180
  <?php } ?>
181
- <p>Restart the optimization process for new images added to your library by clicking the button below. Already optimized images will not be reprocessed.
182
- <form action='' method='POST' >
183
- <input type='checkbox' name='thumbnails' <?php echo($this->ctrl->processThumbnails() ? "checked":"");?>> Include thumbnails<br><br>
184
- <input type='submit' name='bulkProcess' id='bulkProcess' class='button button-primary' value='Restart Optimizing'>
185
- </form>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
186
  <?php } ?>
187
  </div>
188
  <?php
@@ -266,12 +334,8 @@ class ShortPixelView {
266
  <div class="bulk-progress bulk-stats">
267
  <?php foreach($failed as $fail) {
268
  $meta = wp_get_attachment_metadata($fail);
269
- if(isset($meta["ShortPixelImprovement"]) && is_numeric($meta["ShortPixelImprovement"])){
270
- $this->ctrl->getPrioQ()->removeFromFailed($fail);
271
- } else {
272
- ?> <div class="label"><a href="/wp-admin/post.php?post=<?php echo($fail);?>&action=edit"><?php echo(substr($meta["file"], 0, 80));?> - ID: <?php echo($fail);?></a></div><br/>
273
- <?php }
274
- }?>
275
  </div>
276
  <?php
277
  }
@@ -285,7 +349,7 @@ class ShortPixelView {
285
  <a href="https://shortpixel.com/<?php echo($this->ctrl->getVerifiedKey() ? "login/".$this->ctrl->getApiKey() : "pricing");?>" target="_blank" style="font-size:18px">
286
  Upgrade now
287
  </a> |
288
- <a href="https://shortpixel.com/contact" target="_blank" style="font-size:18px">Support </a>
289
  </p>
290
  <?php if($notice !== null) { ?>
291
  <br/>
@@ -393,7 +457,7 @@ class ShortPixelView {
393
  <tr>
394
  <th scope="row"><label for="thumbnails">Also include thumbnails:</label></th>
395
  <td><input name="thumbnails" type="checkbox" id="thumbnails" <?php echo( $checked );?>> Apply compression also to
396
- <strong><?php echo($thumbnailsToProcess ? number_format($thumbnailsToProcess) : "");?> image thumbnails.</strong>
397
  <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>
398
  </td>
399
  </tr>
@@ -446,7 +510,7 @@ class ShortPixelView {
446
  if(this !== prev) {
447
  prev = this;
448
  }
449
- alert('This type of optimization will apply to new uploaded images.\nImages that were already processed will not be re-optimized.');
450
  };
451
  }
452
  function enableResize(elm) {
@@ -554,4 +618,72 @@ class ShortPixelView {
554
  </div>
555
  <?php
556
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
557
  }
145
  <?php $this->displayBulkStats($quotaData['totalProcessedFiles'], $quotaData['mainProcessedFiles'], $under5PercentCount, $averageCompression, $savedSpace);?>
146
  <?php if($quotaData['totalProcessedFiles'] < $quotaData['totalFiles']) { ?>
147
  <p><?php echo(number_format($quotaData['mainFiles'] - $quotaData['mainProcessedFiles']));?> images and
148
+ <?php echo(number_format(($quotaData['totalFiles'] - $quotaData['mainFiles']) - ($quotaData['totalProcessedFiles'] - $quotaData['mainProcessedFiles'])));
149
+ ?> thumbnails are not yet optimized by ShortPixel.</p>
150
  <?php } ?>
151
  <p>You can continue optimizing your Media Gallery from where you left, by clicking the Resume processing button. Already optimized images will not be reprocessed.</p>
152
  <?php
167
  fjs.parentNode.insertBefore(js,fjs);}}(document, 'script', 'twitter-wjs');
168
  </script>
169
  </div>
170
+ <?php if(0+$averageCompression>30) {?>
171
+ <div class='shortpixel-rate-us'>
172
+ <a href="https://wordpress.org/support/view/plugin-reviews/shortpixel-image-optimiser?rate=5#postform" target="_blank">
173
+ <div>
174
+ Please rate us!&nbsp;
175
+ </div><img src="<?php echo(plugins_url( 'img/stars.png', __FILE__ ));?>">
176
+ </a>
177
+ </div>
178
+ <?php } ?>
179
  </div>
180
  <?php $this->displayBulkStats($quotaData['totalProcessedFiles'], $quotaData['mainProcessedFiles'], $under5PercentCount, $averageCompression, $savedSpace);?>
181
+ <p>Go to the ShortPixel <a href='<?php echo(get_admin_url());?>options-general.php?page=wp-shortpixel#stats'>Stats</a> and see all your websites' optimized stats. Download your detailed <a href="https://api.shortpixel.com/v2/report.php?key=<?php echo($this->ctrl->getApiKey());?>">Optimization Report</a> to check your image optimization statistics for the last 40 days.</p>
182
+ <?php
 
 
 
183
  $failed = $this->ctrl->getPrioQ()->getFailed();
184
  if(count($failed)) { ?>
185
+ <div class="bulk-progress" style="margin-bottom: 15px">
186
+ <p>
187
+ The following images could not be processed because of their limited write rights. This usually happens if you have changed your hosting provider. Please restart the optimization process after you granted write rights to all the files below.
188
+ </p>
189
+ <?php $this->displayFailed($failed); ?>
190
+ </div>
191
  <?php } ?>
192
+ <div class="bulk-progress">
193
+ <?php
194
+ $todo = false;
195
+ if($quotaData['totalProcessedFiles'] < $quotaData['totalFiles']) {
196
+ $todo = true;
197
+ $mainNotProcessed = $quotaData['mainFiles'] - $quotaData['mainProcessedFiles'];
198
+ $thumbsNotProcessed = ($quotaData['totalFiles'] - $quotaData['mainFiles']) - ($quotaData['totalProcessedFiles'] - $quotaData['mainProcessedFiles']);
199
+ ?>
200
+ <p>
201
+ <?php echo($mainNotProcessed ? number_format($mainNotProcessed) . " images" : "");?>
202
+ <?php echo($mainNotProcessed && $thumbsNotProcessed ? " and" : "");?>
203
+ <?php echo($thumbsNotProcessed ? number_format($thumbsNotProcessed) . " thumbnails" : "");?> are not yet optimized by ShortPixel.
204
+ <?php if (count($quotaData['filesWithErrors'])) { ?>
205
+ Some have errors:
206
+ <?php foreach($quotaData['filesWithErrors'] as $id => $data) {
207
+ echo('<a href="post.php?post='.$id.'&action=edit" title="'.$data['Message'].'">'.$data['Name'].'</a>,&nbsp;');
208
+ } ?>
209
+ <?php } ?>
210
+ </p>
211
+ <?php }
212
+ $settings = $this->ctrl->getSettings();
213
+ $optType = $settings->compressionType == '1' ? 'lossy' : 'lossless';
214
+ $otherType = $settings->compressionType == '1' ? 'lossless' : 'lossy';
215
+ if( !$this->ctrl->backupFolderIsEmpty()
216
+ && ( ($quotaData['totalProcLossyFiles'] > 0 && $settings->compressionType == 0)
217
+ || ($quotaData['totalProcLosslessFiles'] > 0 && $settings->compressionType == 1)))
218
+ {
219
+ $todo = true;
220
+ $statType = $settings->compressionType == '1' ? 'Lossless' : 'Lossy';
221
+ $thumbsCount = $quotaData['totalProc'.$statType.'Files'] - $quotaData['mainProc'.$statType.'Files'];
222
+ ?>
223
+ <p id="with-thumbs" <?php echo(!$settings->processThumbnails ? 'style="display:none;"' : "");?>>
224
+ <?php echo(number_format($quotaData['mainProc'.$statType.'Files']));?> images and
225
+ <?php echo(number_format($quotaData['totalProc'.$statType.'Files'] - $quotaData['mainProc'.$statType.'Files']));?> thumbnails were optimized
226
+ <strong>
227
+ <?php echo($otherType);?>
228
+ </strong>. You can re-optimize
229
+ <strong>
230
+ <?php echo($optType);?>
231
+ </strong> the ones that have backup.
232
+ </p>
233
+ <p id="without-thumbs" <?php echo($settings->processThumbnails ? 'style="display:none;"' : "");?>>
234
+ <?php echo(number_format($quotaData['mainProc'.$statType.'Files']));?> images are optimized
235
+ <strong>
236
+ <?php echo($otherType);?>
237
+ </strong>. You can re-optimize
238
+ <strong>
239
+ <?php echo($optType);?>
240
+ </strong> the ones that have backup.
241
+ <?php echo($thumbsCount ? number_format($thumbsCount) . ' thumbnails will be restored to originals.' : '');?>
242
+ </p>
243
+ <?php
244
+ } ?>
245
+ <p>Restart the optimization process for <?php echo($todo ? 'these images' : 'new images added to your library');?> by clicking the button below.
246
+ Already <strong><?php echo($todo ? ($optType) : '');?></strong> optimized images will not be reprocessed.
247
+ <br>Please note that reoptimizing images as <strong>lossy/lossless</strong> may use additional credits. <a href="http://blog.shortpixel.com/the-all-new-re-optimization-functions-in-shortpixel/" target="_blank">More info</a>
248
+ </p>
249
+ <form action='' method='POST' >
250
+ <input type='checkbox' id='bulk-thumbnails' name='thumbnails' <?php echo($this->ctrl->processThumbnails() ? "checked":"");?> onchange="ShortPixel.onBulkThumbsCheck(this)"> Include thumbnails<br><br>
251
+ <input type='submit' name='bulkProcess' id='bulkProcess' class='button button-primary' value='Restart Optimizing'>
252
+ </form>
253
+ </div>
254
  <?php } ?>
255
  </div>
256
  <?php
334
  <div class="bulk-progress bulk-stats">
335
  <?php foreach($failed as $fail) {
336
  $meta = wp_get_attachment_metadata($fail);
337
+ ?> <div class="label"><a href="/wp-admin/post.php?post=<?php echo($fail);?>&action=edit"><?php echo(substr($meta["file"], 0, 80));?> - ID: <?php echo($fail);?></a></div><br/>
338
+ <?php }?>
 
 
 
 
339
  </div>
340
  <?php
341
  }
349
  <a href="https://shortpixel.com/<?php echo($this->ctrl->getVerifiedKey() ? "login/".$this->ctrl->getApiKey() : "pricing");?>" target="_blank" style="font-size:18px">
350
  Upgrade now
351
  </a> |
352
+ <a href="https://shortpixel.com/contact/<?php echo($this->ctrl->getEncryptedData());?>" target="_blank" style="font-size:18px">Support </a>
353
  </p>
354
  <?php if($notice !== null) { ?>
355
  <br/>
457
  <tr>
458
  <th scope="row"><label for="thumbnails">Also include thumbnails:</label></th>
459
  <td><input name="thumbnails" type="checkbox" id="thumbnails" <?php echo( $checked );?>> Apply compression also to
460
+ <strong>image thumbnails.</strong> (<?php echo($thumbnailsToProcess ? number_format($thumbnailsToProcess) : "");?> thumbnails to optimize)
461
  <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>
462
  </td>
463
  </tr>
510
  if(this !== prev) {
511
  prev = this;
512
  }
513
+ alert('This type of optimization will apply to new uploaded images.\nImages that were already processed will not be re-optimized unless you restart the bulk process.');
514
  };
515
  }
516
  function enableResize(elm) {
618
  </div>
619
  <?php
620
  }
621
+
622
+ public function renderCustomColumn($id, $data){ ?>
623
+ <div id='sp-msg-<?php echo($id);?>'>
624
+ <?php switch($data['status']) {
625
+ case 'n/a': ?>
626
+ Optimization N/A <?php
627
+ break;
628
+ case 'notFound': ?>
629
+ Image does not exist. <?php
630
+ break;
631
+ case 'invalidKey': ?>
632
+ Invalid API Key. <a href="options-general.php?page=wp-shortpixel">Check your Settings</a> <?php
633
+ break;
634
+ case 'quotaExceeded':
635
+ echo($this->getQuotaExceededHTML(isset($data['message']) ? $data['message'] : ''));
636
+ break;
637
+ case 'optimizeNow':
638
+ echo($data['message']) ?> <a class='button button-smaller button-primary' href="javascript:manualOptimization(<?php echo($id)?>)">Optimize now</a> <?php
639
+ if(isset($data['thumbsTotal']) && $data['thumbsTotal'] > 0) {
640
+ echo("<br>+" . $data['thumbsTotal'] . " thumbnails");
641
+ }
642
+ break;
643
+ case 'retry': ?>
644
+ <?php echo($data['message'])?> <a class='button button-smaller button-primary' href="javascript:manualOptimization(<?php echo($id)?>)">Retry</a> <?php
645
+ break;
646
+ case 'pdfOptimized':
647
+ case 'imgOptimized': ?>
648
+ <?php if($data['showActions']) { ?>
649
+ <div class='sp-column-actions'>
650
+ <?php if(!$data['thumbsOpt'] && $data['thumbsTotal']) { ?>
651
+ <a class='button button-smaller button-primary' href="javascript:optimizeThumbs(<?php echo($id)?>);">
652
+ Optimize <?php echo($data['thumbsTotal']);?> thumbnails
653
+ </a>
654
+ <?php }
655
+ if($data['backup']) {
656
+ if($data['type']) {
657
+ $type = $data['type'] == 'lossy' ? 'lossless' : 'lossy'; ?>
658
+ <a class='button button-smaller' href="javascript:reoptimize(<?php echo($id)?>, '<?php echo($type)?>');" title="Using the backed-up image">
659
+ Re-optimize <?php echo($type)?>
660
+ </a><?php
661
+ } ?>
662
+ <a class='button button-smaller' href="admin.php?action=shortpixel_restore_backup&attachment_ID=<?php echo($id)?>">
663
+ Restore backup
664
+ </a>
665
+ <?php } ?>
666
+ </div>
667
+ <?php } ?>
668
+ <div class='sp-column-info'>
669
+ <?php echo(($data['percent'] ? 'Reduced by ' . $data['percent'] . '% ' : '')
670
+ .($data['bonus'] && $data['percent'] ? '<br>' : '')
671
+ .($data['bonus'] ? 'Bonus processing' : '')
672
+ .($data['type'] ? ' ('.$data['type'].')':'') . '<br>');?>
673
+ <?php echo($data['thumbsOpt']
674
+ ? "+" . $data['thumbsOpt'] . ($data['thumbsTotal'] > $data['thumbsOpt'] ? " of ".$data['thumbsTotal'] : '') . " thumbnails optimized" : '');?>
675
+ </div> <?php
676
+ break;
677
+ }
678
+ //die(var_dump($data));
679
+ ?>
680
+ </div>
681
+ <?php
682
+ }
683
+
684
+ public function getQuotaExceededHTML($message = '') {
685
+ return $message . " Quota Exceeded.
686
+ <a class='button button-smaller button-primary' href='https://shortpixel.com/login/". $this->ctrl->getApiKey() . "' target='_blank'>Extend Quota</a>
687
+ <a class='button button-smaller' href='admin.php?action=shortpixel_check_quota' target='_blank'>Check&nbsp;&nbsp;Quota</a>";
688
+ }
689
  }
wp-shortpixel-settings.php CHANGED
@@ -34,6 +34,8 @@ class WPShortPixelSettings {
34
  'totalOriginal' => 'wp-short-pixel-total-original',
35
  'quotaExceeded' => 'wp-short-pixel-quota-exceeded',
36
  'httpProto' => 'wp-short-pixel-protocol',
 
 
37
  '' => '',
38
  );
39
 
34
  'totalOriginal' => 'wp-short-pixel-total-original',
35
  'quotaExceeded' => 'wp-short-pixel-quota-exceeded',
36
  'httpProto' => 'wp-short-pixel-protocol',
37
+ 'downloadProto' => 'wp-short-pixel-download-protocol',
38
+ 'mediaAlert' => 'wp-short-pixel-media-alert',
39
  '' => '',
40
  );
41
 
wp-shortpixel.php CHANGED
@@ -3,7 +3,7 @@
3
  * Plugin Name: ShortPixel Image Optimizer
4
  * Plugin URI: https://shortpixel.com/
5
  * Description: ShortPixel optimizes images automatically, while guarding the quality of your images. Check your <a href="options-general.php?page=wp-shortpixel" target="_blank">Settings &gt; ShortPixel</a> page on how to start optimizing your image library and make your website load faster.
6
- * Version: 3.2.1
7
  * Author: ShortPixel
8
  * Author URI: https://shortpixel.com
9
  */
@@ -22,12 +22,13 @@ define('SP_RESET_ON_ACTIVATE', false); //if true TODO set false
22
 
23
  define('SP_AFFILIATE_CODE', '');
24
 
25
- define('PLUGIN_VERSION', "3.2.1");
26
  define('SP_MAX_TIMEOUT', 10);
27
  define('SP_VALIDATE_MAX_TIMEOUT', 15);
28
  define('SP_BACKUP', 'ShortpixelBackups');
29
  define('SP_BACKUP_FOLDER', WP_CONTENT_DIR . DIRECTORY_SEPARATOR . 'uploads' . DIRECTORY_SEPARATOR . SP_BACKUP);
30
  define('MAX_API_RETRIES', 50);
 
31
  $MAX_EXECUTION_TIME = ini_get('max_execution_time');
32
 
33
  /*
@@ -56,40 +57,54 @@ class WPShortPixel {
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
70
 
71
  //add hook for image upload processing
72
  add_filter( 'wp_generate_attachment_metadata', array( &$this, 'handleImageUpload' ), 10, 2 );
73
- add_filter( 'manage_media_columns', array( &$this, 'columns' ) );//add media library column header
74
  add_filter( 'plugin_action_links_' . plugin_basename(__FILE__), array(&$this, 'generatePluginLinks'));//for plugin settings page
75
 
76
  //add_action( 'admin_footer', array(&$this, 'handleImageProcessing'));
 
 
 
77
  add_action( 'manage_media_custom_column', array( &$this, 'generateCustomColumn' ), 10, 2 );//generate the media library column
78
 
79
- //add settings page
80
- add_action( 'admin_menu', array( &$this, 'registerSettingsPage' ) );//display SP in Settings menu
81
- add_action( 'admin_menu', array( &$this, 'registerAdminPage' ) );
82
- add_action( 'delete_attachment', array( &$this, 'handleDeleteAttachmentInBackup' ) );
83
- add_action( 'load-upload.php', array( &$this, 'handleCustomBulk'));
 
 
 
 
 
 
 
 
 
 
 
 
 
84
 
85
  //automatic optimization
86
  add_action( 'wp_ajax_shortpixel_image_processing', array( &$this, 'handleImageProcessing') );
87
  //manual optimization
88
  add_action( 'wp_ajax_shortpixel_manual_optimization', array(&$this, 'handleManualOptimization'));
89
- //manual optimization
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
 
@@ -97,8 +112,6 @@ class WPShortPixel {
97
  add_action( 'admin_footer', array( &$this, 'shortPixelJS') );
98
  //register a method to display admin notices if necessary
99
  add_action('admin_notices', array( &$this, 'displayAdminNotices'));
100
- //toolbar notifications
101
- add_action( 'admin_bar_menu', array( &$this, 'toolbar_shortpixel_processing'), 999 );
102
 
103
  $this->migrateBackupFolder();
104
  }
@@ -108,6 +121,14 @@ class 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();
@@ -150,6 +171,11 @@ class WPShortPixel {
150
  die(json_encode(array("Status" => 'success', "Message" => 'Notice ID: ' . $noticeId . ' dismissed')));
151
  }
152
 
 
 
 
 
 
153
  //set default move as "list". only set once, it won't try to set the default mode again.
154
  public function setDefaultViewModeList()
155
  {
@@ -192,16 +218,17 @@ class WPShortPixel {
192
  STATUS_RETRY: <?php echo ShortPixelAPI::STATUS_RETRY; ?>,
193
  WP_PLUGIN_URL: '<?php echo plugins_url( '', __FILE__ ); ?>',
194
  WP_ADMIN_URL: '<?php echo admin_url(); ?>',
195
- API_KEY: "<?php echo $this->_settings->apiKey; ?>"
 
196
  });
197
  }
198
  });
199
  </script> <?php
200
  wp_enqueue_style('short-pixel.css', plugins_url('/css/short-pixel.css',__FILE__) );
 
201
  }
202
 
203
  function toolbar_shortpixel_processing( $wp_admin_bar ) {
204
- wp_enqueue_script('short-pixel.js', plugins_url('/js/short-pixel.js',__FILE__) );
205
 
206
  $extraClasses = " shortpixel-hide";
207
  $tooltip = "ShortPixel optimizing...";
@@ -283,7 +310,8 @@ class WPShortPixel {
283
  {//the kind of file we can process. goody.
284
  $this->prioQ->push($ID);
285
  $URLsAndPATHs = $this->getURLsAndPATHs($ID, $meta);
286
- $this->_apiInterface->doRequests($URLsAndPATHs['URLs'], false, $ID);//send a processing request right after a file was uploaded, do NOT wait for response
 
287
  self::log("IMG: sent: " . json_encode($URLsAndPATHs));
288
  $meta['ShortPixel']['WaitingProcessing'] = true;
289
  return $meta;
@@ -340,9 +368,26 @@ class WPShortPixel {
340
  $crtStartQueryID = $itemMetaData->post_id;
341
  if(!in_array($crtStartQueryID, $idList) && self::isProcessable($crtStartQueryID)) {
342
  $meta = wp_get_attachment_metadata($crtStartQueryID);
343
- if(!isset($meta["ShortPixelImprovement"]) || !is_numeric($meta["ShortPixelImprovement"])) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
344
  $idList[] = $crtStartQueryID;
345
- } elseif($itemMetaData->meta_key == '_wp_attachment_metadata') { //count skipped
 
346
  $skippedAlreadyProcessed++;
347
  }
348
  }
@@ -351,8 +396,8 @@ class WPShortPixel {
351
  //daca n-am adaugat niciuna pana acum, n-are sens sa mai selectez zona asta de id-uri in bulk-ul asta.
352
  $leapStart = $this->prioQ->getStartBulkId();
353
  $crtStartQueryID = $startQueryID = $itemMetaData->post_id - 1; //decrement it so we don't select it again
354
- $res = self::countAllProcessedFiles($leapStart, $crtStartQueryID);
355
- $skippedAlreadyProcessed += $res["mainFiles"];
356
  $this->prioQ->setStartBulkId($startQueryID);
357
  } else {
358
  $crtStartQueryID--;
@@ -431,14 +476,15 @@ class WPShortPixel {
431
  //2: Send up to 3 files to the server for processing
432
  for($i = 0; $i < min(3, count($ids)); $i++) {
433
  $ID = $ids[$i];
434
- $URLsAndPATHs = $this->sendToProcessing($ID);
 
 
435
  if($i == 0) { //save for later use
436
  $firstUrlAndPaths = $URLsAndPATHs;
437
  }
438
  }
439
 
440
  self::log("HIP: 2 Prio Queue: ".json_encode($this->prioQ->get()));
441
-
442
  //3: Retrieve the file for the first element of the list
443
  $ID = $ids[0];
444
  $result = $this->_apiInterface->processImage($firstUrlAndPaths['URLs'], $firstUrlAndPaths['PATHs'], $ID);
@@ -453,17 +499,17 @@ class WPShortPixel {
453
  //remove also from the failed list if it failed in the past
454
  $prio = $this->prioQ->removeFromFailed($ID);
455
  $meta = wp_get_attachment_metadata($ID);
456
- $result["ThumbsCount"] = isset($meta['sizes']) && is_array($meta['sizes']) ? count($meta['sizes']): 0;
457
- $result["BackupEnabled"] = $this->_settings->backupImages;
 
 
 
 
 
458
 
459
  if(!$prio && $ID <= $this->prioQ->getStartBulkId()) {
460
- $this->prioQ->setStartBulkId($ID - 1);
461
- $this->prioQ->logBulkProgress();
462
 
463
- $deltaBulkPercent = $this->prioQ->getDeltaBulkPercent();
464
- $msg = $this->bulkProgressMessage($deltaBulkPercent, $this->prioQ->getTimeRemaining());
465
- $result["BulkPercent"] = $this->prioQ->getBulkPercent();;
466
- $result["BulkMsg"] = $msg;
467
 
468
  $thumb = $bkThumb = "";
469
  $percent = 0;
@@ -480,10 +526,10 @@ class WPShortPixel {
480
  $thumb = count($sizes) ? $sizes[0]['file'] : '';
481
  }
482
  } else { //fallback to the image itself
483
- $thumb = $meta["file"];
484
  }
485
 
486
- if(strlen($thumb) && get_option('wp-short-backup_images') && $this->_settings->processThumbnails) {
487
  $backupUrl = content_url() . "/uploads/" . SP_BACKUP . "/";
488
  $urlBkPath = $this->_apiInterface->returnSubDir(get_attached_file($ID));
489
  $bkThumb = $backupUrl . $urlBkPath . "/" . $thumb;
@@ -499,6 +545,23 @@ class WPShortPixel {
499
  }
500
  }
501
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
502
  elseif ($result["Status"] == ShortPixelAPI::STATUS_SKIP
503
  || $result["Status"] == ShortPixelAPI::STATUS_FAIL) {
504
  $prio = $this->prioQ->remove($ID);
@@ -506,14 +569,7 @@ class WPShortPixel {
506
  //put this one in the failed images list - to show the user at the end
507
  $prio = $this->prioQ->addToFailed($ID);
508
  }
509
- if($ID <= $this->prioQ->getStartBulkId()) {
510
- $this->prioQ->setStartBulkId($ID - 1);
511
- $this->prioQ->logBulkProgress();
512
- $deltaBulkPercent = $this->prioQ->getDeltaBulkPercent();
513
- $msg = $this->bulkProgressMessage($deltaBulkPercent, $this->prioQ->getTimeRemaining());
514
- $result["BulkPercent"] = $this->prioQ->getBulkPercent();
515
- $result["BulkMsg"] = $msg;
516
- }
517
  }
518
  if($result["Status"] !== ShortPixelAPI::STATUS_RETRY) {
519
  update_option( 'wp-short-pixel-bulk-last-status', $result);
@@ -521,9 +577,20 @@ class WPShortPixel {
521
  die(json_encode($result));
522
  }
523
 
524
- private function sendToProcessing($ID) {
525
- $URLsAndPATHs = $this->getURLsAndPATHs($ID);
526
- $this->_apiInterface->doRequests($URLsAndPATHs['URLs'], false, $ID);//send a request, do NOT wait for response
 
 
 
 
 
 
 
 
 
 
 
527
  $meta = wp_get_attachment_metadata($ID);
528
  $meta['ShortPixel']['WaitingProcessing'] = true;
529
  wp_update_attachment_metadata($ID, $meta);
@@ -531,6 +598,7 @@ class WPShortPixel {
531
  }
532
 
533
  public function handleManualOptimization() {
 
534
  $imageId = intval($_GET['image_id']);
535
 
536
  if(self::isProcessable($imageId)) {
@@ -551,41 +619,91 @@ class WPShortPixel {
551
  wp_update_attachment_metadata($ID, $meta);
552
  }
553
 
554
- public function handleRestoreBackup() {
555
- $attachmentID = intval($_GET['attachment_ID']);
556
-
557
- $file = get_attached_file($attachmentID);
558
- $meta = wp_get_attachment_metadata($attachmentID);
559
- $pathInfo = pathinfo($file);
560
-
561
  $fileExtension = strtolower(substr($file,strrpos($file,".")+1));
562
  $SubDir = $this->_apiInterface->returnSubDir($file);
563
 
564
  //sometimes the month of original file and backup can differ
565
- if ( !file_exists(SP_BACKUP_FOLDER . DIRECTORY_SEPARATOR . $SubDir . ShortPixelAPI::MB_basename($file)) )
566
  $SubDir = date("Y") . "/" . date("m") . "/";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
567
 
568
- try {
569
- //main file
570
- @rename(SP_BACKUP_FOLDER . DIRECTORY_SEPARATOR . $SubDir . ShortPixelAPI::MB_basename($file), $file);
 
571
 
572
- //overwriting thumbnails
573
- if( !empty($meta['file']) ) {
574
- foreach($meta["sizes"] as $size => $imageData) {
575
- $source = SP_BACKUP_FOLDER . DIRECTORY_SEPARATOR . $SubDir . $imageData['file'];
576
- $destination = $pathInfo['dirname'] . DIRECTORY_SEPARATOR . $imageData['file'];
577
  @rename($source, $destination);
578
  }
579
- }
580
- unset($meta["ShortPixelImprovement"]);
581
- //unset($meta['ShortPixel']['WaitingProcessing']);
582
- unset($meta['ShortPixel']);
583
- wp_update_attachment_metadata($attachmentID, $meta);
 
 
 
 
 
 
584
 
585
- } catch(Exception $e) {
586
- //what to do, what to do?
 
 
 
 
587
  }
588
- // store the referring webpage location
 
 
 
 
 
 
 
 
 
589
  $sendback = wp_get_referer();
590
  // sanitize the referring webpage location
591
  $sendback = preg_replace('|[^a-z0-9-~+_.?#=&;,/:]|i', '', $sendback);
@@ -594,6 +712,42 @@ class WPShortPixel {
594
  // we are done
595
  }
596
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
597
  public function handleCheckQuota() {
598
  $this->getQuotaInformation();
599
  // store the referring webpage location
@@ -634,25 +788,23 @@ class WPShortPixel {
634
  }
635
  }
636
 
637
- public function registerSettingsPage() {
638
- add_options_page( 'ShortPixel Settings', 'ShortPixel', 'manage_options', 'wp-shortpixel', array($this, 'renderSettingsMenu'));
639
- }
640
-
641
- function registerAdminPage( ) {
642
- add_media_page( 'ShortPixel Bulk Process', 'Bulk ShortPixel', 'edit_others_posts', 'wp-short-pixel-bulk', array( &$this, 'bulkProcess' ) );
643
- }
644
-
645
- public function checkQuotaAndAlert() {
646
- $quotaData = $this->getQuotaInformation();
647
  if ( !$quotaData['APIKeyValid']) {
648
  return $quotaData;
649
  }
 
650
  $imageCount = $this->countAllProcessableFiles();
651
- $imageProcessedCount = $this->countAllProcessedFiles();
652
- $quotaData['totalFiles'] = $imageCount['totalFiles'];
653
- $quotaData['totalProcessedFiles'] = $imageProcessedCount['totalFiles'];
654
- $quotaData['mainFiles'] = $imageCount['mainFiles'];
655
- $quotaData['mainProcessedFiles'] = $imageProcessedCount['mainFiles'];
 
 
 
656
 
657
  if($quotaData['APICallsQuotaNumeric'] + $quotaData['APICallsQuotaOneTimeNumeric'] > $quotaData['APICallsMadeNumeric'] + $quotaData['APICallsMadeOneTimeNumeric']) {
658
  update_option('wp-short-pixel-quota-exceeded','0');
@@ -725,7 +877,6 @@ class WPShortPixel {
725
 
726
  //image count
727
  //$imageCount = $this->countAllProcessableFiles();
728
- //$imgProcessedCount = $this->countAllProcessedFiles();
729
  $imageOnlyThumbs = $quotaData['totalFiles'] - $quotaData['mainFiles'];
730
  $thumbsProcessedCount = $this->_settings->getOpt( 'wp-short-pixel-thumbnail-count', 0);//amount of optimized thumbnails
731
  $under5PercentCount = $this->_settings->getOpt( 'wp-short-pixel-files-under-5-percent', 0);//amount of under 5% optimized imgs.
@@ -785,6 +936,10 @@ class WPShortPixel {
785
  }
786
  }
787
 
 
 
 
 
788
  public function renderSettingsMenu() {
789
  if ( !current_user_can( 'manage_options' ) ) {
790
  wp_die('You do not have sufficient permissions to access this page.');
@@ -795,9 +950,11 @@ class WPShortPixel {
795
  $notice = null;
796
 
797
  //by default we try to fetch the API Key from wp-config.php (if defined)
798
- if ( !isset($_POST['save']) && defined("SHORTPIXEL_API_KEY") && strlen(SHORTPIXEL_API_KEY) == 20 )
799
  {
800
- $_POST['validate'] = "validate";
 
 
801
  $_POST['key'] = SHORTPIXEL_API_KEY;
802
  }
803
 
@@ -830,7 +987,7 @@ class WPShortPixel {
830
  $notice = array("status" => "warn", "msg" => "API Key is valid but your site is not accessible from our servers.
831
  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.");
832
  } else {
833
- if ( function_exists("is_multisite") && is_multisite() )
834
  $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>");
835
  else
836
  $notice = array("status" => "success", "msg" => 'API Key valid!');
@@ -879,7 +1036,7 @@ class WPShortPixel {
879
  $this->emptyBackup();
880
  }
881
 
882
- $quotaData = $this->checkQuotaAndAlert();
883
 
884
  if($this->_settings->verifiedKey) {
885
  $fileCount = number_format($this->_settings->fileCount);
@@ -893,8 +1050,11 @@ class WPShortPixel {
893
  $remainingImages = $quotaData['APICallsQuotaNumeric'] + $quotaData['APICallsQuotaOneTimeNumeric'] - $quotaData['APICallsMadeNumeric'] - $quotaData['APICallsMadeOneTimeNumeric'];
894
  $remainingImages = ( $remainingImages < 0 ) ? 0 : number_format($remainingImages);
895
  $totalCallsMade = number_format($quotaData['APICallsMadeNumeric'] + $quotaData['APICallsMadeOneTimeNumeric']);
896
-
897
  $resources = wp_remote_get($this->_settings->httpProto . "://shortpixel.com/resources-frag");
 
 
 
898
  $this->view->displaySettings(is_main_site() || (is_multisite() && !defined("SHORTPIXEL_API_KEY")),
899
  $quotaData, $notice, $resources, $averageCompression, $savedSpace, $savedBandwidth,
900
  $remainingImages, $totalCallsMade, $fileCount, $backupFolderSize);
@@ -922,12 +1082,13 @@ class WPShortPixel {
922
 
923
  if(is_null($apiKey)) { $apiKey = $this->_settings->apiKey; }
924
 
925
- //$this->_settings->httpProto = 'https';
 
 
926
 
927
  $requestURL = $this->_settings->httpProto . '://api.shortpixel.com/v2/api-status.php';
928
  $args = array(
929
  'timeout'=> SP_VALIDATE_MAX_TIMEOUT,
930
- 'sslverify' => false,
931
  'body' => array('key' => $apiKey)
932
  );
933
  $argsStr = "?key=".$apiKey;
@@ -944,28 +1105,47 @@ class WPShortPixel {
944
  $argsStr .= "&DomainCheck={$args['body']['DomainCheck']}&ImagesCount={$imageCount['mainFiles']}&ThumbsCount={$args['body']['ThumbsCount']}";
945
  }
946
 
947
- //Try first HTTPS post
 
 
 
 
 
948
  $response = wp_remote_post($requestURL, $args);
 
 
949
  //some hosting providers won't allow https:// POST connections so we try http:// as well
950
  if(is_wp_error( $response )) {
951
  //echo("protocol " . $this->_settings->httpProto . " failed. switching...");
952
  $requestURL = $this->_settings->httpProto == 'https' ?
953
  str_replace('https://', 'http://', $requestURL) :
954
  str_replace('http://', 'https://', $requestURL);
955
- $response = wp_remote_post($requestURL, $args);
956
- if(!is_wp_error( $response )){
957
- $this->_settings->httpProto = ($this->_settings->httpProto == 'https' ? 'http' : 'https');
958
- //echo("protocol " . $this->_settings->httpProto . " succeeded");
959
- } else {
960
- //echo("protocol " . $this->_settings->httpProto . " failed too");
961
- }
 
 
 
 
 
 
 
 
962
  }
963
  //Second fallback to HTTP get
964
  if(is_wp_error( $response )){
965
  $args['body'] = null;
966
  $requestURL .= $argsStr;
967
  $response = wp_remote_get($requestURL, $args);
 
968
  }
 
 
 
969
  $defaultData = array(
970
  "APIKeyValid" => false,
971
  "Message" => 'API Key could not be validated due to a connectivity error.<BR>Your firewall may be blocking us. Please contact your hosting provider and ask them to allow connections from your site to IP 176.9.106.46.<BR> If you still cannot validate your API Key after this, please <a href="https://shortpixel.com/contact" target="_blank">contact us</a> and we will try to help. ',
@@ -977,9 +1157,9 @@ class WPShortPixel {
977
 
978
  $urlElements = parse_url($requestURL);
979
  $portConnect = @fsockopen($urlElements['host'],8,$errno,$errstr,15);
980
- if(!$portConnect)
981
  $defaultData['Message'] .= "<BR>Debug info: <i>$errstr</i>";
982
-
983
  return $defaultData;
984
  }
985
 
@@ -1029,141 +1209,87 @@ class WPShortPixel {
1029
  $data = wp_get_attachment_metadata($id);
1030
  $file = get_attached_file($id);
1031
  $fileExtension = strtolower(substr($file,strrpos($file,".")+1));
 
 
 
1032
 
1033
- print "<div id='sp-msg-{$id}'>";
1034
 
1035
- if ( empty($data) )
1036
- {
1037
- if ( $fileExtension <> "pdf" )
1038
- {
1039
- if(!$this->_settings->verifiedKey)
1040
- print 'Invalid API Key. <a href="options-general.php?page=wp-shortpixel">Check your Settings</a>';
1041
- else
1042
- print 'Optimization N/A';
1043
- }
1044
- else
1045
- {
1046
- if ( $this->_settings->quotaExceeded )
1047
- {
1048
- print QUOTA_EXCEEDED;
1049
- return;
1050
- }
1051
- else
1052
- {
1053
- print 'PDF not processed';
1054
- //if($this->_settings->verifiedKey) {
1055
- print " <a class='button button-smaller button-primary' href=\"javascript:manualOptimization({$id})\">Optimize now</a>";
1056
- //}
1057
- return;
1058
- }
1059
- }
1060
  }
1061
- elseif ( isset( $data['ShortPixelImprovement'] ) )
1062
- {
1063
- if(isset($meta['ShortPixel']['BulkProcessing']))
1064
- {
1065
- if ( $this->_settings->quotaExceeded )
1066
- {
1067
- print QUOTA_EXCEEDED;
1068
- }
1069
- else
1070
- {
1071
- print 'Waiting for bulk processing';
1072
- print " <a class='button button-smaller button-primary' href=\"javascript:manualOptimization({$id})\">Optimize now</a>";
1073
- }
1074
- }
1075
- elseif( is_numeric($data['ShortPixelImprovement']) ) {
1076
- if ( $data['ShortPixelImprovement'] < 5 ) {
1077
- if($data['ShortPixelImprovement'] > 0 ) {
1078
- print $data['ShortPixelImprovement'] . '% optimized<br>';
1079
- }
1080
- print "Bonus processing";
1081
- } else {
1082
- print 'Reduced by ';
1083
- print $data['ShortPixelImprovement'] . '%' . (isset($data['ShortPixel']['type']) ? ' (' . $data['ShortPixel']['type'] . ')' : '' );
1084
- }
1085
- if ( get_option('wp-short-backup_images') && !isset($data['ShortPixel']['NoBackup'])) //display restore backup option only when backup is active
1086
- print " &nbsp; <a class='button button-smaller' href=\"admin.php?action=shortpixel_restore_backup&amp;attachment_ID={$id}\">Restore backup</a>";
1087
- if (isset($data['ShortPixel']['thumbs']) || (isset($data['sizes']) && count($data['sizes']))) {
1088
- $sizes = count($data['sizes']);
1089
- $cnt = isset($data['ShortPixel']['thumbsOpt']) ? $data['ShortPixel']['thumbsOpt'] : $sizes;
1090
- print "<br>+" . $cnt . ($sizes > $cnt ? " of ".$sizes : '') . " thumbnails optimized";
1091
- }
1092
- }
1093
- elseif ( $data['ShortPixelImprovement'] <> "Optimization N/A" )
1094
- {
1095
- if ( trim(strip_tags($data['ShortPixelImprovement'])) == "Quota exceeded" )
1096
- {
1097
- print QUOTA_EXCEEDED;
1098
- if ( !$this->_settings->quotaExceeded )
1099
- print " <a class='button button-smaller button-primary' href=\"javascript:manualOptimization({$id})\">Try again</a>";
1100
- }
1101
- elseif ( trim(strip_tags($data['ShortPixelImprovement'])) == "Cannot write optimized file" )
1102
- {
1103
- print $data['ShortPixelImprovement'];
1104
- print " - <a href='https://shortpixel.com/faq#cannot-write-optimized-file' target='_blank'>Why?</a>";
1105
- }
1106
- else
1107
- {
1108
- print $data['ShortPixelImprovement'];
1109
- print " | <a href=\"javascript:manualOptimization({$id})\">Try again</a>";
1110
- }
1111
- }
1112
- else
1113
- {
1114
- print "Optimization N/A";
1115
- }
1116
- } elseif(isset($data['ShortPixel']['WaitingProcessing'])) {
1117
- if ( $this->_settings->quotaExceeded )
1118
- {
1119
- print QUOTA_EXCEEDED;
1120
  }
1121
- else
1122
- {
1123
- print "<img src=\"" . plugins_url( 'img/loading.gif', __FILE__ ) . "\">&nbsp;Image waiting to be processed
1124
- | <a href=\"javascript:manualOptimization({$id})\">Retry</a></div>";
1125
- if($id > $this->prioQ->getFlagBulkId()) $this->prioQ->push($id); //should be there but just to make sure
1126
- }
1127
-
1128
- } elseif(isset($data['ShortPixel']['NoFileOnDisk'])) {
1129
- print 'Image does not exist';
1130
-
1131
- } else {
1132
 
1133
- if ( wp_attachment_is_image( $id ) )
1134
- {
1135
- if ( $this->_settings->quotaExceeded )
1136
- {
1137
- print QUOTA_EXCEEDED;
1138
- }
1139
- else
1140
- {
1141
- print 'Image not processed';
1142
- print " <a class='button button-smaller button-primary' href=\"javascript:manualOptimization({$id})\">Optimize now</a>";
1143
- }
1144
- if (count($data['sizes'])) {
1145
- print "<br>+" . count($data['sizes']) . " thumbnails";
1146
- }
1147
- }
1148
- elseif ( $fileExtension == "pdf" )
1149
- {
1150
- if ( $this->_settings->quotaExceeded )
1151
- {
1152
- print QUOTA_EXCEEDED;
1153
- }
1154
- else
1155
- {
1156
- print 'PDF not processed';
1157
- print " <a class='button button-smaller button-primary' href=\"javascript:manualOptimization({$id})\">Optimize now</a>";
1158
- }
1159
- }
 
 
1160
  }
1161
- print "</div>";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1162
  }
1163
  }
1164
 
1165
  public function columns( $defaults ) {
1166
- $defaults['wp-shortPixel'] = 'ShortPixel Compression&nbsp;<a href="options-general.php?page=wp-shortpixel#stats" title="ShortPixel Statistics"><span class="dashicons dashicons-dashboard"></span></a>';
 
 
 
1167
  return $defaults;
1168
  }
1169
 
@@ -1213,25 +1339,25 @@ class WPShortPixel {
1213
 
1214
 
1215
  //return an array with URL(s) and PATH(s) for this file
1216
- public function getURLsAndPATHs($ID, $meta = NULL) {
1217
 
1218
- if ( !parse_url(WP_CONTENT_URL, PHP_URL_SCHEME) )
1219
- {//no absolute URLs used -> we implement a hack
1220
  $url = get_site_url() . wp_get_attachment_url($ID);//get the file URL
1221
  }
1222
- else
1223
  $url = wp_get_attachment_url($ID);//get the file URL
1224
-
1225
  $urlList[] = $url;
1226
  $path = get_attached_file($ID);//get the full file PATH
1227
  $filePath[] = $path;
 
1228
  if ( $meta == NULL ) {
1229
  $meta = wp_get_attachment_metadata($ID);
1230
  }
1231
 
1232
  //it is NOT a PDF file and thumbs are processable
1233
  if ( strtolower(substr($filePath[0],strrpos($filePath[0], ".")+1)) != "pdf"
1234
- && $this->_settings->processThumbnails
1235
  && isset($meta['sizes']) && is_array($meta['sizes']))
1236
  {
1237
  foreach( $meta['sizes'] as $thumbnailInfo )
@@ -1243,6 +1369,11 @@ class WPShortPixel {
1243
  if(!isset($meta['sizes']) || !is_array($meta['sizes'])) {
1244
  self::log("getURLsAndPATHs: no meta sizes for ID $ID : " . json_encode($meta));
1245
  }
 
 
 
 
 
1246
  return array("URLs" => $urlList, "PATHs" => $filePath);
1247
  }
1248
 
@@ -1302,40 +1433,74 @@ class WPShortPixel {
1302
  return $resultQuery[0]->QueryID;
1303
  }
1304
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1305
  //count all the processable files in media library (while limiting the results to max 10000)
1306
  public function countAllProcessableFiles($maxId = PHP_INT_MAX, $minId = 0){
1307
  global $wpdb;
1308
 
1309
- $totalFiles = 0;
1310
- $mainFiles = 0;
1311
- $limit = 500;
 
1312
  $pointer = 0;
1313
-
1314
- //METODA DE A OBTINE LISTA DE IMAGINI CU API-UL WP
1315
- $query_images_args = array(
1316
- 'post_type' => 'attachment',
1317
- 'post_mime_type' => array('image','application/pdf'),
1318
- 'post_status' => 'inherit',
1319
- 'posts_per_page' => - 1,
1320
- );
1321
-
1322
- $query_images = new WP_Query( $query_images_args );
1323
-
1324
- //var_dump(count($query_images->posts));
1325
-
1326
-
1327
-
1328
  //count all the files, main and thumbs
1329
- while ( 1 )
1330
- {
1331
- $filesList= $wpdb->get_results("SELECT * FROM " . $wpdb->prefix . "postmeta
1332
- WHERE ( post_id <= $maxId AND post_id > $minId )
1333
- AND ( meta_key = '_wp_attached_file' OR meta_key = '_wp_attachment_metadata' )
 
1334
  LIMIT $pointer,$limit");
1335
  if ( empty($filesList) ) //we parsed all the results
1336
  break;
 
 
 
 
 
 
 
 
 
 
 
 
 
1337
 
1338
- $filesMap = array();
1339
  foreach ( $filesList as $file )
1340
  {
1341
  if ( $file->meta_key == "_wp_attached_file" )
@@ -1348,10 +1513,13 @@ class WPShortPixel {
1348
  $filesMap[$file->meta_value] = 1;
1349
  }
1350
  }
1351
- else
1352
  {
1353
  $attachment = unserialize($file->meta_value);
 
 
1354
  if(isset($attachment['file']) && !isset($filesMap[$attachment['file']]) && self::isProcessablePath($attachment['file'])){
 
1355
  if ( isset($attachment['sizes']) ) {
1356
  $totalFiles += count($attachment['sizes']);
1357
  }
@@ -1362,53 +1530,54 @@ class WPShortPixel {
1362
  $filesMap[$attachment['file']] = 1;
1363
  }
1364
  }
1365
- }
1366
- }
1367
- unset($filesList);
1368
- $pointer += $limit;
1369
-
1370
- }//end while
1371
-
1372
- return array("totalFiles" => $totalFiles, "mainFiles" => $mainFiles);
1373
- }
1374
-
1375
-
1376
- //count all the already processed files in media library (while limiting the results to max 10000)
1377
- public function countAllProcessedFiles($maxId = PHP_INT_MAX, $minId = 0){
1378
- global $wpdb;
1379
-
1380
- $processedMainFiles = $processedTotalFiles = 0;
1381
- $limit = 500;
1382
- $pointer = 0;
1383
-
1384
- //count all the files, main and thumbs
1385
- $filesMap = array();
1386
- while ( 1 )
1387
- {
1388
- $filesList= $wpdb->get_results("SELECT * FROM " . $wpdb->prefix . "postmeta
1389
- WHERE ( post_id <= $maxId AND post_id > $minId )
1390
- AND ( meta_key = '_wp_attachment_metadata' )
1391
- LIMIT $pointer,$limit");
1392
- if ( empty($filesList) ) {//we parsed all the results
1393
- break;
1394
- }
1395
- foreach ( $filesList as $file )
1396
- {
1397
- $attachment = unserialize($file->meta_value);
1398
- if ( isset($attachment['ShortPixelImprovement'])
1399
- && ($attachment['ShortPixelImprovement'] > 0 || $attachment['ShortPixelImprovement'] === 0.0)
1400
- //for PDFs there is no file field so just let it pass.
1401
- && (!isset($attachment['file']) || !isset($filesMap[$attachment['file']])) ) {
1402
- $processedMainFiles++;
1403
- $processedTotalFiles++;
1404
- if ( isset($attachment['ShortPixel']['thumbsOpt']) ) {
1405
- $processedTotalFiles += $attachment['ShortPixel']['thumbsOpt'];
1406
- } elseif ( isset($attachment['sizes']) ) {
1407
- $processedTotalFiles += count($attachment['sizes']);
1408
  }
1409
- if ( isset($attachment['file']) ) {
1410
- $filesMap[$attachment['file']] = 1;
 
 
1411
  }
 
1412
  }
1413
  }
1414
  unset($filesList);
@@ -1416,7 +1585,13 @@ class WPShortPixel {
1416
 
1417
  }//end while
1418
 
1419
- return array("totalFiles" => $processedTotalFiles, "mainFiles" => $processedMainFiles);
 
 
 
 
 
 
1420
  }
1421
 
1422
  public function migrateBackupFolder() {
@@ -1462,6 +1637,21 @@ class WPShortPixel {
1462
  }
1463
  return array('width' => $width, 'height' => $height);
1464
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1465
 
1466
  public function getApiKey() {
1467
  return $this->_settings->apiKey;
@@ -1512,7 +1702,7 @@ class WPShortPixel {
1512
  }
1513
 
1514
  function onInit() {
1515
- if ( ! is_admin() || !is_user_logged_in() || ! current_user_can( 'manage_options' ) ) {
1516
  return;
1517
  }
1518
  $pluginInstance = new WPShortPixel;
@@ -1526,8 +1716,4 @@ if ( !function_exists( 'vc_action' ) || vc_action() !== 'vc_inline' ) { //handle
1526
  register_deactivation_hook( __FILE__, array( 'WPShortPixel', 'shortPixelDeactivatePlugin' ) );
1527
 
1528
  }
1529
-
1530
- //$pluginInstance = new WPShortPixel();
1531
- //global $pluginInstance;
1532
-
1533
  ?>
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.3.0
7
  * Author: ShortPixel
8
  * Author URI: https://shortpixel.com
9
  */
22
 
23
  define('SP_AFFILIATE_CODE', '');
24
 
25
+ define('PLUGIN_VERSION', "3.3.0");
26
  define('SP_MAX_TIMEOUT', 10);
27
  define('SP_VALIDATE_MAX_TIMEOUT', 15);
28
  define('SP_BACKUP', 'ShortpixelBackups');
29
  define('SP_BACKUP_FOLDER', WP_CONTENT_DIR . DIRECTORY_SEPARATOR . 'uploads' . DIRECTORY_SEPARATOR . SP_BACKUP);
30
  define('MAX_API_RETRIES', 50);
31
+ define('MAX_ERR_RETRIES', 5);
32
  $MAX_EXECUTION_TIME = ini_get('max_execution_time');
33
 
34
  /*
57
  session_start();
58
  }
59
 
60
+ $isAdminUser = current_user_can( 'manage_options' );
61
+
62
  $this->_affiliateSufix = (strlen(SP_AFFILIATE_CODE)) ? "/affiliate/" . SP_AFFILIATE_CODE : "";
63
  $this->_settings = new WPShortPixelSettings();
64
  $this->_apiInterface = new ShortPixelAPI($this->_settings);
65
  $this->prioQ = new ShortPixelQueue($this, $this->_settings);
66
  $this->view = new ShortPixelView($this);
67
 
68
+ define('QUOTA_EXCEEDED', $this->view->getQuotaExceededHTML());
 
 
69
 
70
  $this->setDefaultViewModeList();//set default mode as list. only @ first run
71
 
72
  //add hook for image upload processing
73
  add_filter( 'wp_generate_attachment_metadata', array( &$this, 'handleImageUpload' ), 10, 2 );
 
74
  add_filter( 'plugin_action_links_' . plugin_basename(__FILE__), array(&$this, 'generatePluginLinks'));//for plugin settings page
75
 
76
  //add_action( 'admin_footer', array(&$this, 'handleImageProcessing'));
77
+
78
+ //Media custom column
79
+ add_filter( 'manage_media_columns', array( &$this, 'columns' ) );//add media library column header
80
  add_action( 'manage_media_custom_column', array( &$this, 'generateCustomColumn' ), 10, 2 );//generate the media library column
81
 
82
+ if($isAdminUser) {
83
+ //add settings page
84
+ add_action( 'admin_menu', array( &$this, 'registerSettingsPage' ) );//display SP in Settings menu
85
+ add_action( 'admin_menu', array( &$this, 'registerAdminPage' ) );
86
+
87
+ add_action( 'delete_attachment', array( &$this, 'handleDeleteAttachmentInBackup' ) );
88
+ add_action( 'load-upload.php', array( &$this, 'handleCustomBulk'));
89
+
90
+ //backup restore
91
+ add_action('admin_action_shortpixel_restore_backup', array(&$this, 'handleRestoreBackup'));
92
+ //reoptimize with a different algorithm (losless/lossy)
93
+ add_action('wp_ajax_shortpixel_redo', array(&$this, 'handleRedo'));
94
+ //optimize thumbnails
95
+ add_action('wp_ajax_shortpixel_optimize_thumbs', array(&$this, 'handleOptimizeThumbs'));
96
+
97
+ //toolbar notifications
98
+ add_action( 'admin_bar_menu', array( &$this, 'toolbar_shortpixel_processing'), 999 );
99
+ }
100
 
101
  //automatic optimization
102
  add_action( 'wp_ajax_shortpixel_image_processing', array( &$this, 'handleImageProcessing') );
103
  //manual optimization
104
  add_action( 'wp_ajax_shortpixel_manual_optimization', array(&$this, 'handleManualOptimization'));
105
+ //dismiss notices
106
  add_action( 'wp_ajax_shortpixel_dismiss_notice', array(&$this, 'dismissAdminNotice'));
107
+ add_action( 'wp_ajax_shortpixel_dismiss_media_alert', array(&$this, 'dismissMediaAlert'));
 
108
  //check quota
109
  add_action('admin_action_shortpixel_check_quota', array(&$this, 'handleCheckQuota'));
110
 
112
  add_action( 'admin_footer', array( &$this, 'shortPixelJS') );
113
  //register a method to display admin notices if necessary
114
  add_action('admin_notices', array( &$this, 'displayAdminNotices'));
 
 
115
 
116
  $this->migrateBackupFolder();
117
  }
121
  $this->__construct();
122
  }
123
 
124
+ public function registerSettingsPage() {
125
+ add_options_page( 'ShortPixel Settings', 'ShortPixel', 'manage_options', 'wp-shortpixel', array($this, 'renderSettingsMenu'));
126
+ }
127
+
128
+ function registerAdminPage( ) {
129
+ add_media_page( 'ShortPixel Bulk Process', 'Bulk ShortPixel', 'edit_others_posts', 'wp-short-pixel-bulk', array( &$this, 'bulkProcess' ) );
130
+ }
131
+
132
  public static function shortPixelActivatePlugin()//reset some params to avoid trouble for plugins that were activated/deactivated/activated
133
  {
134
  self::shortPixelDeactivatePlugin();
171
  die(json_encode(array("Status" => 'success', "Message" => 'Notice ID: ' . $noticeId . ' dismissed')));
172
  }
173
 
174
+ public function dismissMediaAlert() {
175
+ $this->_settings->mediaAlert = 1;
176
+ die(json_encode(array("Status" => 'success', "Message" => 'Media alert dismissed')));
177
+ }
178
+
179
  //set default move as "list". only set once, it won't try to set the default mode again.
180
  public function setDefaultViewModeList()
181
  {
218
  STATUS_RETRY: <?php echo ShortPixelAPI::STATUS_RETRY; ?>,
219
  WP_PLUGIN_URL: '<?php echo plugins_url( '', __FILE__ ); ?>',
220
  WP_ADMIN_URL: '<?php echo admin_url(); ?>',
221
+ API_KEY: "<?php echo $this->_settings->apiKey; ?>",
222
+ MEDIA_ALERT: '<?php echo $this->_settings->mediaAlert ? "done" : "todo"; ?>'
223
  });
224
  }
225
  });
226
  </script> <?php
227
  wp_enqueue_style('short-pixel.css', plugins_url('/css/short-pixel.css',__FILE__) );
228
+ wp_enqueue_script('short-pixel.js', plugins_url('/js/short-pixel.js',__FILE__) );
229
  }
230
 
231
  function toolbar_shortpixel_processing( $wp_admin_bar ) {
 
232
 
233
  $extraClasses = " shortpixel-hide";
234
  $tooltip = "ShortPixel optimizing...";
310
  {//the kind of file we can process. goody.
311
  $this->prioQ->push($ID);
312
  $URLsAndPATHs = $this->getURLsAndPATHs($ID, $meta);
313
+ //send a processing request right after a file was uploaded, do NOT wait for response
314
+ $this->_apiInterface->doRequests($URLsAndPATHs['URLs'], false, $ID);
315
  self::log("IMG: sent: " . json_encode($URLsAndPATHs));
316
  $meta['ShortPixel']['WaitingProcessing'] = true;
317
  return $meta;
368
  $crtStartQueryID = $itemMetaData->post_id;
369
  if(!in_array($crtStartQueryID, $idList) && self::isProcessable($crtStartQueryID)) {
370
  $meta = wp_get_attachment_metadata($crtStartQueryID);
371
+ $compression = ShortPixelAPI::getCompressionTypeName($this->_settings->compressionType);
372
+
373
+ if(! isset($meta["ShortPixelImprovement"]) || !is_numeric($meta["ShortPixelImprovement"])) {
374
+ $idList[] = $crtStartQueryID;
375
+ }
376
+ elseif(isset($meta["ShortPixel"]["type"]) && $meta["ShortPixel"]["type"] != $compression) {//a different type of compression was chosen in settings
377
+ if($this->doRestore($crtStartQueryID, $meta)) {
378
+ $idList[] = $crtStartQueryID;
379
+ } else {
380
+ $skippedAlreadyProcessed++;
381
+ }
382
+ }
383
+ elseif( $this->_settings->processThumbnails && isset($meta["ShortPixel"]["thumbsOpt"]) && $meta["ShortPixel"]["thumbsOpt"] == 0
384
+ && isset($meta["sizes"]) && count($meta["sizes"]) > 0) { //thumbs were chosen in settings
385
+ //if($crtStartQueryID == 44 || $crtStartQueryID == 49) {echo("No THuMBS?");die(var_dump($meta));}
386
+ $meta["ShortPixel"]["thumbsTodo"] = true;
387
+ wp_update_attachment_metadata($crtStartQueryID, $meta);
388
  $idList[] = $crtStartQueryID;
389
+ }
390
+ elseif($itemMetaData->meta_key == '_wp_attachment_metadata') { //count skipped
391
  $skippedAlreadyProcessed++;
392
  }
393
  }
396
  //daca n-am adaugat niciuna pana acum, n-are sens sa mai selectez zona asta de id-uri in bulk-ul asta.
397
  $leapStart = $this->prioQ->getStartBulkId();
398
  $crtStartQueryID = $startQueryID = $itemMetaData->post_id - 1; //decrement it so we don't select it again
399
+ $res = self::countAllProcessableFiles($leapStart, $crtStartQueryID);
400
+ $skippedAlreadyProcessed += $res["mainProcessedFiles"] - $res["mainProc".($this->getCompressionType() == 1 ? "Lossy" : "Lossless")."Files"];
401
  $this->prioQ->setStartBulkId($startQueryID);
402
  } else {
403
  $crtStartQueryID--;
476
  //2: Send up to 3 files to the server for processing
477
  for($i = 0; $i < min(3, count($ids)); $i++) {
478
  $ID = $ids[$i];
479
+ $tmpMeta = wp_get_attachment_metadata($ID);
480
+ $compType = (isset($tmpMeta['ShortPixel']['type']) ? ($tmpMeta['ShortPixel']['type'] == 'lossy' ? 1 : 0) : $this->_settings->compressionType);
481
+ $URLsAndPATHs = $this->sendToProcessing($ID, $compType, isset($tmpMeta['ShortPixel']['thumbsTodo']));
482
  if($i == 0) { //save for later use
483
  $firstUrlAndPaths = $URLsAndPATHs;
484
  }
485
  }
486
 
487
  self::log("HIP: 2 Prio Queue: ".json_encode($this->prioQ->get()));
 
488
  //3: Retrieve the file for the first element of the list
489
  $ID = $ids[0];
490
  $result = $this->_apiInterface->processImage($firstUrlAndPaths['URLs'], $firstUrlAndPaths['PATHs'], $ID);
499
  //remove also from the failed list if it failed in the past
500
  $prio = $this->prioQ->removeFromFailed($ID);
501
  $meta = wp_get_attachment_metadata($ID);
502
+ $result["Type"] = isset($meta['ShortPixel']['type']) ? $meta['ShortPixel']['type'] : '';
503
+ $result["ThumbsTotal"] = isset($meta['sizes']) && is_array($meta['sizes']) ? count($meta['sizes']): 0;
504
+ $result["ThumbsCount"] = isset($meta['ShortPixel']['thumbsOpt'])
505
+ ? $meta['ShortPixel']['thumbsOpt'] //below is the fallback for old optimized images that don't have thumbsOpt
506
+ : ($this->_settings->processThumbnails ? $result["ThumbsTotal"] : 0);
507
+
508
+ $result["BackupEnabled"] = ($this->getBackupFolder(get_attached_file($ID)) ? true : false);//$this->_settings->backupImages;
509
 
510
  if(!$prio && $ID <= $this->prioQ->getStartBulkId()) {
 
 
511
 
512
+ $this->advanceBulk($ID, $result);
 
 
 
513
 
514
  $thumb = $bkThumb = "";
515
  $percent = 0;
526
  $thumb = count($sizes) ? $sizes[0]['file'] : '';
527
  }
528
  } else { //fallback to the image itself
529
+ $thumb = is_array($filePath) ? $filePath[count($filePath) - 1] : $filePath;
530
  }
531
 
532
+ if(strlen($thumb) && $this->_settings->backupImages && $this->_settings->processThumbnails) {
533
  $backupUrl = content_url() . "/uploads/" . SP_BACKUP . "/";
534
  $urlBkPath = $this->_apiInterface->returnSubDir(get_attached_file($ID));
535
  $bkThumb = $backupUrl . $urlBkPath . "/" . $thumb;
545
  }
546
  }
547
  }
548
+ elseif ($result["Status"] == ShortPixelAPI::STATUS_ERROR) {
549
+ $meta = wp_get_attachment_metadata($ID);
550
+ if(isset($meta['ShortPixel']['Retries']) && $meta['ShortPixel']['Retries'] > MAX_ERR_RETRIES) {
551
+ if(! $this->prioQ->remove($ID) ){
552
+ $this->advanceBulk($ID, $result);
553
+ }
554
+ unset($meta['ShortPixel']);
555
+ wp_update_attachment_metadata($ID, $meta);
556
+ $result["Status"] = ShortPixelAPI::STATUS_SKIP;
557
+ $result["Message"] .= " Retry limit reached. Skipping file ID " . $ID . ".";
558
+ }
559
+ else {
560
+ if(!isset($meta['ShortPixel'])) { $meta['ShortPixel'] = array(); }
561
+ $meta['ShortPixel']['Retries'] = isset($meta['ShortPixel']['Retries']) ? $meta['ShortPixel']['Retries'] + 1 : 1;
562
+ wp_update_attachment_metadata($ID, $meta);
563
+ }
564
+ }
565
  elseif ($result["Status"] == ShortPixelAPI::STATUS_SKIP
566
  || $result["Status"] == ShortPixelAPI::STATUS_FAIL) {
567
  $prio = $this->prioQ->remove($ID);
569
  //put this one in the failed images list - to show the user at the end
570
  $prio = $this->prioQ->addToFailed($ID);
571
  }
572
+ $this->advanceBulk($ID, $result);
 
 
 
 
 
 
 
573
  }
574
  if($result["Status"] !== ShortPixelAPI::STATUS_RETRY) {
575
  update_option( 'wp-short-pixel-bulk-last-status', $result);
577
  die(json_encode($result));
578
  }
579
 
580
+ private function advanceBulk($processedID, &$result) {
581
+ if($processedID <= $this->prioQ->getStartBulkId()) {
582
+ $this->prioQ->setStartBulkId($processedID - 1);
583
+ $this->prioQ->logBulkProgress();
584
+ $deltaBulkPercent = $this->prioQ->getDeltaBulkPercent();
585
+ $msg = $this->bulkProgressMessage($deltaBulkPercent, $this->prioQ->getTimeRemaining());
586
+ $result["BulkPercent"] = $this->prioQ->getBulkPercent();
587
+ $result["BulkMsg"] = $msg;
588
+ }
589
+ }
590
+
591
+ private function sendToProcessing($ID, $compressionType = false, $onlyThumbs = false) {
592
+ $URLsAndPATHs = $this->getURLsAndPATHs($ID, NULL, $onlyThumbs);
593
+ $this->_apiInterface->doRequests($URLsAndPATHs['URLs'], false, $ID, $compressionType === false ? $this->_settings->compressionType : $compressionType);//send a request, do NOT wait for response
594
  $meta = wp_get_attachment_metadata($ID);
595
  $meta['ShortPixel']['WaitingProcessing'] = true;
596
  wp_update_attachment_metadata($ID, $meta);
598
  }
599
 
600
  public function handleManualOptimization() {
601
+
602
  $imageId = intval($_GET['image_id']);
603
 
604
  if(self::isProcessable($imageId)) {
619
  wp_update_attachment_metadata($ID, $meta);
620
  }
621
 
622
+ public function getBackupFolder($file) {
 
 
 
 
 
 
623
  $fileExtension = strtolower(substr($file,strrpos($file,".")+1));
624
  $SubDir = $this->_apiInterface->returnSubDir($file);
625
 
626
  //sometimes the month of original file and backup can differ
627
+ if ( !file_exists(SP_BACKUP_FOLDER . DIRECTORY_SEPARATOR . $SubDir . ShortPixelAPI::MB_basename($file)) ) {
628
  $SubDir = date("Y") . "/" . date("m") . "/";
629
+ if( !file_exists(SP_BACKUP_FOLDER . DIRECTORY_SEPARATOR . $SubDir . ShortPixelAPI::MB_basename($file)) ) {
630
+ return false;
631
+ }
632
+ }
633
+ return SP_BACKUP_FOLDER . DIRECTORY_SEPARATOR . $SubDir;
634
+ }
635
+
636
+ protected function setFilePerms($file) {
637
+ //die(getenv('USERNAME') ? getenv('USERNAME') : getenv('USER'));
638
+ $perms = @fileperms($file);
639
+ if(!($perms & 0x0100) || !($perms & 0x0080)) {
640
+ if(!@chmod($file, $perms | 0x0100 | 0x0080)) {
641
+ return false;
642
+ }
643
+ }
644
+ return true;
645
+ }
646
+
647
+ protected function doRestore($attachmentID, $meta = null) {
648
+ $file = get_attached_file($attachmentID);
649
+ if(!$meta) {
650
+ $meta = wp_get_attachment_metadata($attachmentID);
651
+ }
652
+ $pathInfo = pathinfo($file);
653
+
654
+ $bkFolder = $this->getBackupFolder($file);
655
+ $bkFile = $bkFolder . ShortPixelAPI::MB_basename($file);
656
+
657
+ //first check if the file is readable by the current user - otherwise it will be unaccessible for the web browser
658
+ // - collect the thumbs paths in the process
659
+ if(! $this->setFilePerms($bkFile) ) return false;
660
+ $thumbsPaths = array();
661
+ if( !empty($meta['file']) ) {
662
+ foreach($meta["sizes"] as $size => $imageData) {
663
+ $source = $bkFolder . $imageData['file'];
664
+ $thumbsPaths[$source] = $pathInfo['dirname'] . DIRECTORY_SEPARATOR . $imageData['file'];
665
+ if(! $this->setFilePerms($source)) return false;
666
+ }
667
+ }
668
 
669
+ if($bkFolder) {
670
+ try {
671
+ //main file
672
+ @rename($bkFile, $file);
673
 
674
+ //overwriting thumbnails
675
+ foreach($thumbsPaths as $source => $destination) {
 
 
 
676
  @rename($source, $destination);
677
  }
678
+
679
+ $duplicates = ShortPixelAPI::getWPMLDuplicates($attachmentID);
680
+ foreach($duplicates as $ID) {
681
+ $crtMeta = $attachmentID == $ID ? $meta : wp_get_attachment_metadata($ID);
682
+ if(is_numeric($crtMeta["ShortPixelImprovement"]) && 0 + $crtMeta["ShortPixelImprovement"] < 5 && $this->_settings->under5Percent > 0) {
683
+ $this->_settings->under5Percent = $this->_settings->under5Percent - 1; // - (isset($crtMeta["ShortPixel"]["thumbsOpt"]) ? $crtMeta["ShortPixel"]["thumbsOpt"] : 0);
684
+ }
685
+ unset($crtMeta["ShortPixelImprovement"]);
686
+ unset($crtMeta['ShortPixel']);
687
+ wp_update_attachment_metadata($ID, $crtMeta);
688
+ }
689
 
690
+ } catch(Exception $e) {
691
+ //what to do, what to do?
692
+ return false;
693
+ }
694
+ } else {
695
+ return false;
696
  }
697
+
698
+ return $meta;
699
+ }
700
+
701
+ public function handleRestoreBackup() {
702
+ $attachmentID = intval($_GET['attachment_ID']);
703
+
704
+ $this->doRestore($attachmentID);
705
+
706
+ // get the referring webpage location
707
  $sendback = wp_get_referer();
708
  // sanitize the referring webpage location
709
  $sendback = preg_replace('|[^a-z0-9-~+_.?#=&;,/:]|i', '', $sendback);
712
  // we are done
713
  }
714
 
715
+ public function handleRedo() {
716
+ $ID = intval($_GET['attachment_ID']);
717
+ $type = ($_GET['type'] == 'lossless' ? 'lossless' : 'lossy'); //sanity check
718
+
719
+ $meta = $this->doRestore($ID);
720
+ //die(var_dump($meta));
721
+ if($meta) { //restore succeeded
722
+ $meta['ShortPixel'] = array("type" => $type);
723
+ wp_update_attachment_metadata($ID, $meta);
724
+ $this->prioQ->push($ID);
725
+ $this->sendToProcessing($ID, $type == 'lossy' ? 1 : 0);
726
+ $ret = array("Status" => ShortPixelAPI::STATUS_SUCCESS, "Message" => "");
727
+ } else {
728
+ $ret = array("Status" => ShortPixelAPI::STATUS_SKIP, "Message" => "Could not restore from backup: " . $ID);
729
+ }
730
+ die(json_encode($ret));
731
+ }
732
+
733
+ public function handleOptimizeThumbs() {
734
+ $ID = intval($_GET['attachment_ID']);
735
+ $meta = wp_get_attachment_metadata($ID);
736
+ //die(var_dump($meta));
737
+ if( isset($meta['ShortPixelImprovement'])
738
+ && isset($meta['sizes']) && count($meta['sizes'])
739
+ && ( !isset($meta['ShortPixel']['thumbsOpt']) || $meta['ShortPixel']['thumbsOpt'] == 0)) { //optimized without thumbs, thumbs exist
740
+ $meta['ShortPixel']['thumbsTodo'] = true;
741
+ wp_update_attachment_metadata($ID, $meta);
742
+ $this->prioQ->push($ID);
743
+ $this->sendToProcessing($ID);
744
+ $ret = array("Status" => ShortPixelAPI::STATUS_SUCCESS, "message" => "");
745
+ } else {
746
+ $ret = array("Status" => ShortPixelAPI::STATUS_SKIP, "message" => (isset($meta['ShortPixelImprovement']) ? "No thumbnails to optimize for ID: " : "Please optimize image for ID:") . $ID);
747
+ }
748
+ die(json_encode($ret));
749
+ }
750
+
751
  public function handleCheckQuota() {
752
  $this->getQuotaInformation();
753
  // store the referring webpage location
788
  }
789
  }
790
 
791
+ public function checkQuotaAndAlert($quotaData = null) {
792
+ if(!$quotaData) {
793
+ $quotaData = $this->getQuotaInformation();
794
+ }
 
 
 
 
 
 
795
  if ( !$quotaData['APIKeyValid']) {
796
  return $quotaData;
797
  }
798
+ //$tempus = microtime(true);
799
  $imageCount = $this->countAllProcessableFiles();
800
+ //echo("Count took (seconds): " . (microtime(true) - $tempus));
801
+ foreach($imageCount as $key => $val) {
802
+ $quotaData[$key] = $val;
803
+ }
804
+ //$quotaData['totalFiles'] = $imageCount['totalFiles'];
805
+ //$quotaData['totalProcessedFiles'] = $imageCount['totalProcessedFiles'];
806
+ //$quotaData['mainFiles'] = $imageCount['mainFiles'];
807
+ //$quotaData['mainProcessedFiles'] = $imageCount['mainProcessedFiles'];
808
 
809
  if($quotaData['APICallsQuotaNumeric'] + $quotaData['APICallsQuotaOneTimeNumeric'] > $quotaData['APICallsMadeNumeric'] + $quotaData['APICallsMadeOneTimeNumeric']) {
810
  update_option('wp-short-pixel-quota-exceeded','0');
877
 
878
  //image count
879
  //$imageCount = $this->countAllProcessableFiles();
 
880
  $imageOnlyThumbs = $quotaData['totalFiles'] - $quotaData['mainFiles'];
881
  $thumbsProcessedCount = $this->_settings->getOpt( 'wp-short-pixel-thumbnail-count', 0);//amount of optimized thumbnails
882
  $under5PercentCount = $this->_settings->getOpt( 'wp-short-pixel-files-under-5-percent', 0);//amount of under 5% optimized imgs.
936
  }
937
  }
938
 
939
+ public function backupFolderIsEmpty() {
940
+ return count(scandir(SP_BACKUP_FOLDER)) > 2 ? false : true;
941
+ }
942
+
943
  public function renderSettingsMenu() {
944
  if ( !current_user_can( 'manage_options' ) ) {
945
  wp_die('You do not have sufficient permissions to access this page.');
950
  $notice = null;
951
 
952
  //by default we try to fetch the API Key from wp-config.php (if defined)
953
+ if ( defined("SHORTPIXEL_API_KEY") && strlen(SHORTPIXEL_API_KEY) == 20)
954
  {
955
+ if(!isset($_POST['save']) && strlen($this->getApiKey()) == 0) {
956
+ $_POST['validate'] = "validate";
957
+ }
958
  $_POST['key'] = SHORTPIXEL_API_KEY;
959
  }
960
 
987
  $notice = array("status" => "warn", "msg" => "API Key is valid but your site is not accessible from our servers.
988
  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.");
989
  } else {
990
+ if ( function_exists("is_multisite") && is_multisite() && !defined("SHORTPIXEL_API_KEY"))
991
  $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>");
992
  else
993
  $notice = array("status" => "success", "msg" => 'API Key valid!');
1036
  $this->emptyBackup();
1037
  }
1038
 
1039
+ $quotaData = $this->checkQuotaAndAlert(isset($validityData) ? $validityData : null);
1040
 
1041
  if($this->_settings->verifiedKey) {
1042
  $fileCount = number_format($this->_settings->fileCount);
1050
  $remainingImages = $quotaData['APICallsQuotaNumeric'] + $quotaData['APICallsQuotaOneTimeNumeric'] - $quotaData['APICallsMadeNumeric'] - $quotaData['APICallsMadeOneTimeNumeric'];
1051
  $remainingImages = ( $remainingImages < 0 ) ? 0 : number_format($remainingImages);
1052
  $totalCallsMade = number_format($quotaData['APICallsMadeNumeric'] + $quotaData['APICallsMadeOneTimeNumeric']);
1053
+
1054
  $resources = wp_remote_get($this->_settings->httpProto . "://shortpixel.com/resources-frag");
1055
+ if(is_wp_error( $resources )) {
1056
+ $resources = array();
1057
+ }
1058
  $this->view->displaySettings(is_main_site() || (is_multisite() && !defined("SHORTPIXEL_API_KEY")),
1059
  $quotaData, $notice, $resources, $averageCompression, $savedSpace, $savedBandwidth,
1060
  $remainingImages, $totalCallsMade, $fileCount, $backupFolderSize);
1082
 
1083
  if(is_null($apiKey)) { $apiKey = $this->_settings->apiKey; }
1084
 
1085
+ if($this->_settings->httpProto != 'https' && $this->_settings->httpProto != 'http') {
1086
+ $this->_settings->httpProto = 'https';
1087
+ }
1088
 
1089
  $requestURL = $this->_settings->httpProto . '://api.shortpixel.com/v2/api-status.php';
1090
  $args = array(
1091
  'timeout'=> SP_VALIDATE_MAX_TIMEOUT,
 
1092
  'body' => array('key' => $apiKey)
1093
  );
1094
  $argsStr = "?key=".$apiKey;
1105
  $argsStr .= "&DomainCheck={$args['body']['DomainCheck']}&ImagesCount={$imageCount['mainFiles']}&ThumbsCount={$args['body']['ThumbsCount']}";
1106
  }
1107
 
1108
+ $comm = array();
1109
+
1110
+ //Try first HTTPS post. add the sslverify = false if https
1111
+ if($this->_settings->httpProto === 'https') {
1112
+ $args['sslverify'] = false;
1113
+ }
1114
  $response = wp_remote_post($requestURL, $args);
1115
+ $comm[] = array("sent" => "POST: " . $requestURL, "args" => $args, "received" => $response);
1116
+
1117
  //some hosting providers won't allow https:// POST connections so we try http:// as well
1118
  if(is_wp_error( $response )) {
1119
  //echo("protocol " . $this->_settings->httpProto . " failed. switching...");
1120
  $requestURL = $this->_settings->httpProto == 'https' ?
1121
  str_replace('https://', 'http://', $requestURL) :
1122
  str_replace('http://', 'https://', $requestURL);
1123
+ // add or remove the sslverify
1124
+ if($this->_settings->httpProto === 'http') {
1125
+ $args['sslverify'] = false;
1126
+ } else {
1127
+ unset($args['sslverify']);
1128
+ }
1129
+ $response = wp_remote_post($requestURL, $args);
1130
+ $comm[] = array("sent" => "POST: " . $requestURL, "args" => $args, "received" => $response);
1131
+
1132
+ if(!is_wp_error( $response )){
1133
+ $this->_settings->httpProto = ($this->_settings->httpProto == 'https' ? 'http' : 'https');
1134
+ //echo("protocol " . $this->_settings->httpProto . " succeeded");
1135
+ } else {
1136
+ //echo("protocol " . $this->_settings->httpProto . " failed too");
1137
+ }
1138
  }
1139
  //Second fallback to HTTP get
1140
  if(is_wp_error( $response )){
1141
  $args['body'] = null;
1142
  $requestURL .= $argsStr;
1143
  $response = wp_remote_get($requestURL, $args);
1144
+ $comm[] = array("sent" => "POST: " . $requestURL, "args" => $args, "received" => $response);
1145
  }
1146
+
1147
+ //die(var_dump($comm));
1148
+
1149
  $defaultData = array(
1150
  "APIKeyValid" => false,
1151
  "Message" => 'API Key could not be validated due to a connectivity error.<BR>Your firewall may be blocking us. Please contact your hosting provider and ask them to allow connections from your site to IP 176.9.106.46.<BR> If you still cannot validate your API Key after this, please <a href="https://shortpixel.com/contact" target="_blank">contact us</a> and we will try to help. ',
1157
 
1158
  $urlElements = parse_url($requestURL);
1159
  $portConnect = @fsockopen($urlElements['host'],8,$errno,$errstr,15);
1160
+ if(!$portConnect) {
1161
  $defaultData['Message'] .= "<BR>Debug info: <i>$errstr</i>";
1162
+ }
1163
  return $defaultData;
1164
  }
1165
 
1209
  $data = wp_get_attachment_metadata($id);
1210
  $file = get_attached_file($id);
1211
  $fileExtension = strtolower(substr($file,strrpos($file,".")+1));
1212
+ $invalidKey = !$this->_settings->verifiedKey;
1213
+ $quotaExceeded = $this->_settings->quotaExceeded;
1214
+ $renderData = array("id" => $id, "showActions" => current_user_can( 'manage_options' ));
1215
 
1216
+ $data2 = $data;
1217
 
1218
+
1219
+ if($invalidKey) { //invalid key - let the user first register and only then
1220
+ $renderData['status'] = 'invalidKey';
1221
+ $this->view->renderCustomColumn($id, $renderData);
1222
+ return;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1223
  }
1224
+
1225
+ //empty data means document, we handle only PDF
1226
+ elseif (empty($data)) { //TODO asta devine if si decomentam returnurile
1227
+ if($fileExtension == "pdf") {
1228
+ $renderData['status'] = $quotaExceeded ? 'quotaExceeded' : 'optimizeNow';
1229
+ $renderData['message'] = 'PDF not processed';
1230
+ }
1231
+ else { //Optimization N/A
1232
+ $renderData['status'] = 'n/a';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1233
  }
1234
+ $this->view->renderCustomColumn($id, $renderData);
1235
+ return;
1236
+ }
 
 
 
 
 
 
 
 
1237
 
1238
+ if(!isset($data['ShortPixelImprovement'])) { //new image
1239
+ $data['ShortPixelImprovement'] = '';
1240
+ }
1241
+
1242
+ if(is_numeric($data['ShortPixelImprovement'])) { //already optimized
1243
+ $renderData['status'] = $fileExtension == "pdf" ? 'pdfOptimized' : 'imgOptimized';
1244
+ $renderData['percent'] = $data['ShortPixelImprovement'];
1245
+ $renderData['bonus'] = ($data['ShortPixelImprovement'] < 5);
1246
+ $renderData['backup'] = $this->getBackupFolder(get_attached_file($id)) ;
1247
+ $renderData['type'] = isset($data['ShortPixel']['type']) ? $data['ShortPixel']['type'] : '';
1248
+ $sizes = isset($data['sizes']) ? count($data['sizes']) : 0;
1249
+ $renderData['thumbsTotal'] = $sizes;
1250
+ $renderData['thumbsOpt'] = isset($data['ShortPixel']['thumbsOpt']) ? $data['ShortPixel']['thumbsOpt'] : $sizes;
1251
+ $renderData['quotaExceeded'] = $quotaExceeded;
1252
+ }
1253
+ elseif($data['ShortPixelImprovement'] == "Optimization N/A") { //We don't optimize this
1254
+ $renderData['status'] = 'n/a';
1255
+ }
1256
+ elseif(isset($meta['ShortPixel']['BulkProcessing'])) { //Scheduled to bulk.
1257
+ $renderData['status'] = $quotaExceeded ? 'quotaExceeded' : 'optimizeNow';
1258
+ $renderData['message'] = 'Waiting for bulk processing.';
1259
+ }
1260
+ elseif( trim(strip_tags($data['ShortPixelImprovement'])) == "Cannot write optimized file" ) {
1261
+ $renderData['status'] = $quotaExceeded ? 'quotaExceeded' : 'retry';
1262
+ $renderData['message'] = "Cannot write optimized file - <a href='https://shortpixel.com/faq#cannot-write-optimized-file' target='_blank'>Why?</a>";
1263
+ }
1264
+ elseif( strlen(trim(strip_tags($data['ShortPixelImprovement']))) > 0 ) {
1265
+ $renderData['status'] = $quotaExceeded ? 'quotaExceeded' : 'retry';
1266
+ $renderData['message'] = $data['ShortPixelImprovement'];
1267
  }
1268
+ elseif(isset($data['ShortPixel']['NoFileOnDisk'])) {
1269
+ $renderData['status'] = 'notFound';
1270
+ $renderData['message'] = 'Image does not exist';
1271
+ }
1272
+ elseif(isset($data['ShortPixel']['WaitingProcessing'])) {
1273
+ $renderData['status'] = $quotaExceeded ? 'quotaExceeded' : 'retry';
1274
+ $renderData['message'] = "<img src=\"" . plugins_url( 'img/loading.gif', __FILE__ ) . "\" class='sp-loading-small'>&nbsp;Image waiting to be processed";
1275
+ if($id > $this->prioQ->getFlagBulkId()) $this->prioQ->push($id); //should be there but just to make sure
1276
+ }
1277
+ else { //finally
1278
+ $renderData['status'] = $quotaExceeded ? 'quotaExceeded' : 'optimizeNow';
1279
+ $sizes = isset($data['sizes']) ? count($data['sizes']) : 0;
1280
+ $renderData['thumbsTotal'] = $sizes;
1281
+ $renderData['message'] = ($fileExtension == "pdf" ? 'PDF' : 'Image') . ' not processed';
1282
+ }
1283
+
1284
+ $this->view->renderCustomColumn($id, $renderData);
1285
  }
1286
  }
1287
 
1288
  public function columns( $defaults ) {
1289
+ $defaults['wp-shortPixel'] = 'ShortPixel Compression';
1290
+ if(current_user_can( 'manage_options' )) {
1291
+ $defaults['wp-shortPixel'] .= '&nbsp;<a href="options-general.php?page=wp-shortpixel#stats" title="ShortPixel Statistics"><span class="dashicons dashicons-dashboard"></span></a>';
1292
+ }
1293
  return $defaults;
1294
  }
1295
 
1339
 
1340
 
1341
  //return an array with URL(s) and PATH(s) for this file
1342
+ public function getURLsAndPATHs($ID, $meta = NULL, $onlyThumbs = false) {
1343
 
1344
+ if ( !parse_url(WP_CONTENT_URL, PHP_URL_SCHEME) ) {//no absolute URLs used -> we implement a hack
 
1345
  $url = get_site_url() . wp_get_attachment_url($ID);//get the file URL
1346
  }
1347
+ else {
1348
  $url = wp_get_attachment_url($ID);//get the file URL
1349
+ }
1350
  $urlList[] = $url;
1351
  $path = get_attached_file($ID);//get the full file PATH
1352
  $filePath[] = $path;
1353
+
1354
  if ( $meta == NULL ) {
1355
  $meta = wp_get_attachment_metadata($ID);
1356
  }
1357
 
1358
  //it is NOT a PDF file and thumbs are processable
1359
  if ( strtolower(substr($filePath[0],strrpos($filePath[0], ".")+1)) != "pdf"
1360
+ && ($this->_settings->processThumbnails || $onlyThumbs)
1361
  && isset($meta['sizes']) && is_array($meta['sizes']))
1362
  {
1363
  foreach( $meta['sizes'] as $thumbnailInfo )
1369
  if(!isset($meta['sizes']) || !is_array($meta['sizes'])) {
1370
  self::log("getURLsAndPATHs: no meta sizes for ID $ID : " . json_encode($meta));
1371
  }
1372
+
1373
+ if($onlyThumbs) { //remove the main image
1374
+ array_shift($urlList);
1375
+ array_shift($filePath);
1376
+ }
1377
  return array("URLs" => $urlList, "PATHs" => $filePath);
1378
  }
1379
 
1433
  return $resultQuery[0]->QueryID;
1434
  }
1435
 
1436
+ protected function getOptimalChunkSize() {
1437
+ global $wpdb;
1438
+ $cnt = $wpdb->get_results("SELECT count(*) posts FROM " . $wpdb->prefix . "posts");
1439
+ $posts = isset($cnt) && count($cnt) > 0 ? $cnt[0]->posts : 0;
1440
+ if($posts > 100000) {
1441
+ return 20000;
1442
+ } elseif ($posts > 50000) {
1443
+ return 5000;
1444
+ } elseif($posts > 10000) {
1445
+ return 2000;
1446
+ } else {
1447
+ return 500;
1448
+ }
1449
+ }
1450
+
1451
+ protected function getPostIdsChunk($minId, $maxId, $pointer, $limit) {
1452
+ global $wpdb;
1453
+
1454
+ $ids = array();
1455
+ $idList = $wpdb->get_results("SELECT ID, post_mime_type FROM " . $wpdb->prefix . "posts
1456
+ WHERE ( ID <= $maxId AND ID > $minId )
1457
+ LIMIT $pointer,$limit");
1458
+ if ( empty($idList) ) {
1459
+ return null;
1460
+ }
1461
+ foreach($idList as $item) {
1462
+ if($item->post_mime_type != '') {
1463
+ $ids[] = $item->ID;
1464
+ }
1465
+ }
1466
+ return $ids;
1467
+ }
1468
+
1469
  //count all the processable files in media library (while limiting the results to max 10000)
1470
  public function countAllProcessableFiles($maxId = PHP_INT_MAX, $minId = 0){
1471
  global $wpdb;
1472
 
1473
+ $totalFiles = $mainFiles = $processedMainFiles = $processedTotalFiles =
1474
+ $procLossyMainFiles = $procLossyTotalFiles = $procLosslessMainFiles = $procLosslessTotalFiles = $mainUnprocessedThumbs = 0;
1475
+ $filesMap = $processedFilesMap = array();
1476
+ $limit = $this->getOptimalChunkSize();
1477
  $pointer = 0;
1478
+ $filesWithErrors = array();
1479
+
 
 
 
 
 
 
 
 
 
 
 
 
 
1480
  //count all the files, main and thumbs
1481
+ while ( 1 ) {
1482
+ /* ALTERNATE CODE WITH JOIN - seems less efficient than select ids / select in
1483
+ $filesList= $wpdb->get_results("SELECT pm.* FROM " . $wpdb->prefix . "postmeta pm
1484
+ INNER JOIN " . $wpdb->prefix . "posts p on p.ID = pm.post_id
1485
+ WHERE ( p.ID <= $maxId AND p.ID > $minId ) and p.post_mime_type <> ''
1486
+ AND ( pm.meta_key = '_wp_attached_file' OR pm.meta_key = '_wp_attachment_metadata' )
1487
  LIMIT $pointer,$limit");
1488
  if ( empty($filesList) ) //we parsed all the results
1489
  break;
1490
+ */
1491
+ $ids = $this->getPostIdsChunk($minId, $maxId, $pointer, $limit);
1492
+ if($ids === null) {
1493
+ break; //we parsed all the results
1494
+ }
1495
+ elseif(count($ids) == 0) {
1496
+ $pointer += $limit;
1497
+ continue;
1498
+ }
1499
+
1500
+ $filesList= $wpdb->get_results("SELECT * FROM " . $wpdb->prefix . "postmeta
1501
+ WHERE post_id IN (" . implode(',', $ids) . ")
1502
+ AND ( meta_key = '_wp_attached_file' OR meta_key = '_wp_attachment_metadata' )");
1503
 
 
1504
  foreach ( $filesList as $file )
1505
  {
1506
  if ( $file->meta_key == "_wp_attached_file" )
1513
  $filesMap[$file->meta_value] = 1;
1514
  }
1515
  }
1516
+ else //_wp_attachment_metadata
1517
  {
1518
  $attachment = unserialize($file->meta_value);
1519
+ //processable
1520
+ $isProcessable = false;
1521
  if(isset($attachment['file']) && !isset($filesMap[$attachment['file']]) && self::isProcessablePath($attachment['file'])){
1522
+ $isProcessable = true;
1523
  if ( isset($attachment['sizes']) ) {
1524
  $totalFiles += count($attachment['sizes']);
1525
  }
1530
  $filesMap[$attachment['file']] = 1;
1531
  }
1532
  }
1533
+ //processed
1534
+ if (isset($attachment['ShortPixelImprovement'])
1535
+ && ($attachment['ShortPixelImprovement'] > 0 || $attachment['ShortPixelImprovement'] === 0.0 || $attachment['ShortPixelImprovement'] === "0")
1536
+ //for PDFs there is no file field so just let it pass.
1537
+ && (!isset($attachment['file']) || !isset($processedFilesMap[$attachment['file']])) ) {
1538
+
1539
+ //add main file to counts
1540
+ $processedMainFiles++;
1541
+ $processedTotalFiles++;
1542
+ $type = isset($attachment['ShortPixel']['type']) ? $attachment['ShortPixel']['type'] : null;
1543
+ if($type == 'lossy') {
1544
+ $procLossyMainFiles++;
1545
+ $procLossyTotalFiles++;
1546
+ } else {
1547
+ $procLosslessMainFiles++;
1548
+ $procLosslessTotalFiles++;
1549
+ }
1550
+
1551
+ //get the thumbs processed for that attachment
1552
+ $thumbs = $allThumbs = 0;
1553
+ if ( isset($attachment['ShortPixel']['thumbsOpt']) ) {
1554
+ $thumbs = $attachment['ShortPixel']['thumbsOpt'];
1555
+ }
1556
+ elseif ( isset($attachment['sizes']) ) {
1557
+ $thumbs = count($attachment['sizes']);
1558
+ }
1559
+ if ( isset($attachment['sizes']) & count($attachment['sizes']) > $thumbs) {
1560
+ $mainUnprocessedThumbs++;
1561
+ }
1562
+
1563
+ //increment with thumbs processed
1564
+ $processedTotalFiles += $thumbs;
1565
+ if($type == 'lossy') {
1566
+ $procLossyTotalFiles += $thumbs;
1567
+ } else {
1568
+ $procLosslessTotalFiles += $thumbs;
1569
+ }
1570
+
1571
+ if ( isset($attachment['file']) ) {
1572
+ $processedFilesMap[$attachment['file']] = 1;
1573
+ }
 
 
1574
  }
1575
+ elseif($isProcessable && isset($attachment['ShortPixelImprovement']) && count($filesWithErrors) < 50) {
1576
+ $filePath = explode("/", $attachment["file"]);
1577
+ $name = is_array($filePath)? $filePath[count($filePath) - 1] : $file->post_id;
1578
+ $filesWithErrors[$file->post_id] = array('Name' => $name, 'Message' => $attachment['ShortPixelImprovement']);
1579
  }
1580
+
1581
  }
1582
  }
1583
  unset($filesList);
1585
 
1586
  }//end while
1587
 
1588
+ return array("totalFiles" => $totalFiles, "mainFiles" => $mainFiles,
1589
+ "totalProcessedFiles" => $processedTotalFiles, "mainProcessedFiles" => $processedMainFiles,
1590
+ "totalProcLossyFiles" => $procLossyTotalFiles, "mainProcLossyFiles" => $procLossyMainFiles,
1591
+ "totalProcLosslessFiles" => $procLosslessTotalFiles, "mainProcLosslessFiles" => $procLosslessMainFiles,
1592
+ "mainUnprocessedThumbs" => $mainUnprocessedThumbs,
1593
+ "filesWithErrors" => $filesWithErrors
1594
+ );
1595
  }
1596
 
1597
  public function migrateBackupFolder() {
1637
  }
1638
  return array('width' => $width, 'height' => $height);
1639
  }
1640
+
1641
+ public function getEncryptedData() {
1642
+ return base64_encode(self::encrypt($this->getApiKey() . "|" . get_site_url(), "sh0r+Pix3l8im1N3r"));
1643
+ }
1644
+ /**
1645
+ * Returns an encrypted & utf8-encoded
1646
+ */
1647
+ public static function encrypt($pure_string, $encryption_key)
1648
+ {
1649
+ $iv_size = \mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB);
1650
+ $iv = \mcrypt_create_iv($iv_size, MCRYPT_RAND);
1651
+ $encrypted_string = \mcrypt_encrypt(MCRYPT_BLOWFISH, $encryption_key, utf8_encode($pure_string), MCRYPT_MODE_ECB, $iv);
1652
+ return $encrypted_string;
1653
+ }
1654
+
1655
 
1656
  public function getApiKey() {
1657
  return $this->_settings->apiKey;
1702
  }
1703
 
1704
  function onInit() {
1705
+ if ( ! is_admin() || !is_user_logged_in() || ! (current_user_can( 'manage_options' ) || current_user_can( 'upload_files' )) ) {
1706
  return;
1707
  }
1708
  $pluginInstance = new WPShortPixel;
1716
  register_deactivation_hook( __FILE__, array( 'WPShortPixel', 'shortPixelDeactivatePlugin' ) );
1717
 
1718
  }
 
 
 
 
1719
  ?>