ShortPixel Image Optimizer - Version 4.7.0

Version Description

  • convert PNG images to JPG option
  • action called upon optimizing an image: do_action('shortpixel_image_optimized', $post_id);
  • monitor Other Media folders for changes every hour
  • button to delete all ShortPixel metadata making ShortPixel forget it optimized the images in Media Library
  • plugin images at @2x
  • cleanup Other Media tables
  • fix wp-options that would not save in some circumstances
  • fix generate webp tags when post guids are absolute URLs and image URLs are changed, or when site has HTTP/HTTPS versions
  • fix problem with AMP pages when generating the tags - when using AMP for WP plugin AMP pages are not changed.
Download this release

Release Info

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

Code changes from version 4.6.0 to 4.7.0

class/db/shortpixel-custom-meta-dao.php CHANGED
@@ -286,7 +286,11 @@ class ShortPixelCustomMetaDao {
286
 
287
  public function batchInsertImages($pathsFile, $folderId) {
288
  $pathsFileHandle = fopen($pathsFile, 'r');
289
-
 
 
 
 
290
  $values = ''; $inserted = 0;
291
  $sql = "INSERT IGNORE INTO {$this->db->getPrefix()}shortpixel_meta(folder_id, path, name, path_md5, status) VALUES ";
292
  for ($i = 0; ($path = fgets($pathsFileHandle)) !== false; $i++) {
286
 
287
  public function batchInsertImages($pathsFile, $folderId) {
288
  $pathsFileHandle = fopen($pathsFile, 'r');
289
+
290
+ //facem un delete pe cele care nu au shortpixel_folder, pentru curatenie - am mai intalnit situatii in care stergerea s-a agatat (stop monitoring)
291
+ $sqlCleanup = "DELETE FROM {$this->db->getPrefix()}shortpixel_meta WHERE folder_id NOT IN (SELECT id FROM {$this->db->getPrefix()}shortpixel_folders)";
292
+ $this->db->query($sqlCleanup);
293
+
294
  $values = ''; $inserted = 0;
295
  $sql = "INSERT IGNORE INTO {$this->db->getPrefix()}shortpixel_meta(folder_id, path, name, path_md5, status) VALUES ";
296
  for ($i = 0; ($path = fgets($pathsFileHandle)) !== false; $i++) {
class/db/shortpixel-meta-facade.php CHANGED
@@ -187,6 +187,23 @@ class ShortPixelMetaFacade {
187
  }
188
  }
189
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
190
 
191
  function deleteMeta() {
192
  if($this->type == self::CUSTOM_TYPE) {
@@ -583,4 +600,11 @@ class ShortPixelMetaFacade {
583
  }
584
  return false;
585
  }
 
 
 
 
 
 
 
586
  }
187
  }
188
  }
189
  }
190
+
191
+ function cleanupMeta() {
192
+ if($this->type == ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE) {
193
+ if(!isset($this->rawMeta)) {
194
+ $rawMeta = $this->sanitizeMeta(wp_get_attachment_metadata($_ID));
195
+ } else {
196
+ $rawMeta = $this->rawMeta;
197
+ }
198
+ unset($rawMeta["ShortPixelImprovement"]);
199
+ unset($rawMeta['ShortPixel']);
200
+ unset($this->meta);
201
+ wp_update_attachment_metadata($this->ID, $rawMeta);
202
+ $this->rawMeta = $rawMeta;
203
+ } else {
204
+ throw new Exception("Not implemented 1");
205
+ }
206
+ }
207
 
208
  function deleteMeta() {
209
  if($this->type == self::CUSTOM_TYPE) {
600
  }
601
  return false;
602
  }
603
+
604
+ public function doActions() {
605
+ if($this->getType() == self::MEDIA_LIBRARY_TYPE) {
606
+ do_action( 'shortpixel_image_optimised', $this->getId() );
607
+ }
608
+
609
+ }
610
  }
class/db/wp-shortpixel-media-library-adapter.php CHANGED
@@ -6,7 +6,7 @@ class WpShortPixelMediaLbraryAdapter {
6
  public static function countAllProcessableFiles($includePdfs = true, $maxId = PHP_INT_MAX, $minId = 0){
7
  global $wpdb;
8
 
9
- $totalFiles = $mainFiles = $processedMainFiles = $processedTotalFiles =
10
  $procGlossyMainFiles = $procGlossyTotalFiles = $procLossyMainFiles = $procLossyTotalFiles = $procLosslessMainFiles = $procLosslessTotalFiles = $procUndefMainFiles = $procUndefTotalFiles = $mainUnprocessedThumbs = 0;
11
  $filesMap = $processedFilesMap = array();
12
  $limit = self::getOptimalChunkSize();
@@ -14,31 +14,38 @@ class WpShortPixelMediaLbraryAdapter {
14
  $filesWithErrors = array();
15
  $excludePatterns = WPShortPixelSettings::getOpt("excludePatterns");
16
 
 
 
 
 
17
  //count all the files, main and thumbs
18
  while ( 1 ) {
19
- $ids = self::getPostIdsChunk($minId, $maxId, $pointer, $limit);
20
- if($ids === null) {
21
  break; //we parsed all the results
22
  }
23
- elseif(count($ids) == 0) {
24
  $pointer += $limit;
25
  continue;
26
  }
27
 
28
  $filesList= $wpdb->get_results("SELECT * FROM " . $wpdb->prefix . "postmeta
29
- WHERE post_id IN (" . implode(',', $ids) . ")
30
  AND ( meta_key = '_wp_attached_file' OR meta_key = '_wp_attachment_metadata' )");
31
 
32
  foreach ( $filesList as $file )
33
- {
 
 
34
  if ( $file->meta_key == "_wp_attached_file" )
35
  {//count pdf files only
36
  $extension = substr($file->meta_value, strrpos($file->meta_value,".") + 1 );
37
  if ( $extension == "pdf" && !isset($filesMap[$file->meta_value]))
38
  {
39
  $totalFiles++;
 
40
  $mainFiles++;
41
- $filesMap[$file->meta_value] = 1;
42
  }
43
  }
44
  else //_wp_attachment_metadata
@@ -51,11 +58,13 @@ class WpShortPixelMediaLbraryAdapter {
51
  && WPShortPixel::_isProcessablePath($attachment['file'], array(), $excludePatterns)){
52
  $isProcessable = true;
53
  if ( isset($attachment['sizes']) ) {
54
- $totalFiles += $sizesCount;
 
55
  }
56
  if ( isset($attachment['file']) )
57
  {
58
  $totalFiles++;
 
59
  $mainFiles++;
60
  $filesMap[$attachment['file']] = 1;
61
  }
@@ -123,6 +132,18 @@ class WpShortPixelMediaLbraryAdapter {
123
  }
124
 
125
  }
 
 
 
 
 
 
 
 
 
 
 
 
126
  }
127
  unset($filesList);
128
  $pointer += $limit;
@@ -140,8 +161,8 @@ class WpShortPixelMediaLbraryAdapter {
140
  "totalProcGlossyMlFiles" => $procGlossyTotalFiles, "mainProcGlossyMlFiles" => $procGlossyMainFiles,
141
  "totalProcLosslessMlFiles" => $procLosslessTotalFiles, "mainProcLosslessMlFiles" => $procLosslessMainFiles,
142
  "totalProcUndefMlFiles" => $procUndefTotalFiles, "mainProcUndefMlFiles" => $procUndefMainFiles,
143
- "mainUnprocessedThumbs" => $mainUnprocessedThumbs,
144
- "filesWithErrors" => $filesWithErrors
145
  );
146
  }
147
 
@@ -211,8 +232,8 @@ class WpShortPixelMediaLbraryAdapter {
211
  protected static function getPostIdsChunk($minId, $maxId, $pointer, $limit) {
212
  global $wpdb;
213
 
214
- $ids = array();
215
- $idList = $wpdb->get_results("SELECT ID, post_mime_type FROM " . $wpdb->prefix . "posts
216
  WHERE ( ID <= $maxId AND ID > $minId )
217
  LIMIT $pointer,$limit");
218
  if ( empty($idList) ) {
@@ -221,9 +242,10 @@ class WpShortPixelMediaLbraryAdapter {
221
  foreach($idList as $item) {
222
  if($item->post_mime_type != '') {
223
  $ids[] = $item->ID;
 
224
  }
225
  }
226
- return $ids;
227
  }
228
 
229
  }
6
  public static function countAllProcessableFiles($includePdfs = true, $maxId = PHP_INT_MAX, $minId = 0){
7
  global $wpdb;
8
 
9
+ $totalFiles = $mainFiles = $processedMainFiles = $processedTotalFiles = $totalFilesM1 = $totalFilesM2 = $totalFilesM3 = $totalFilesM4 =
10
  $procGlossyMainFiles = $procGlossyTotalFiles = $procLossyMainFiles = $procLossyTotalFiles = $procLosslessMainFiles = $procLosslessTotalFiles = $procUndefMainFiles = $procUndefTotalFiles = $mainUnprocessedThumbs = 0;
11
  $filesMap = $processedFilesMap = array();
12
  $limit = self::getOptimalChunkSize();
14
  $filesWithErrors = array();
15
  $excludePatterns = WPShortPixelSettings::getOpt("excludePatterns");
16
 
17
+ $month1 = new DateTime(); $month2 = new DateTime(); $month3 = new DateTime(); $month4 = new DateTime();
18
+ $mi1 = new DateInterval('P1M'); $mi2 = new DateInterval('P2M'); $mi3 = new DateInterval('P3M'); $mi4 = new DateInterval('P4M');
19
+ $month1->sub($mi1); $month2->sub($mi2); $month3->sub($mi3); $month4->sub($mi4);
20
+
21
  //count all the files, main and thumbs
22
  while ( 1 ) {
23
+ $idInfo = self::getPostIdsChunk($minId, $maxId, $pointer, $limit);
24
+ if($idInfo === null) {
25
  break; //we parsed all the results
26
  }
27
+ elseif(count($idInfo->ids) == 0) {
28
  $pointer += $limit;
29
  continue;
30
  }
31
 
32
  $filesList= $wpdb->get_results("SELECT * FROM " . $wpdb->prefix . "postmeta
33
+ WHERE post_id IN (" . implode(',', $idInfo->ids) . ")
34
  AND ( meta_key = '_wp_attached_file' OR meta_key = '_wp_attachment_metadata' )");
35
 
36
  foreach ( $filesList as $file )
37
+ {
38
+ $totalFilesThis = 0;
39
+
40
  if ( $file->meta_key == "_wp_attached_file" )
41
  {//count pdf files only
42
  $extension = substr($file->meta_value, strrpos($file->meta_value,".") + 1 );
43
  if ( $extension == "pdf" && !isset($filesMap[$file->meta_value]))
44
  {
45
  $totalFiles++;
46
+ $totalFilesThis++;
47
  $mainFiles++;
48
+ $filesMap[$file->meta_value] = 1;
49
  }
50
  }
51
  else //_wp_attachment_metadata
58
  && WPShortPixel::_isProcessablePath($attachment['file'], array(), $excludePatterns)){
59
  $isProcessable = true;
60
  if ( isset($attachment['sizes']) ) {
61
+ $totalFiles += $sizesCount;
62
+ $totalFilesThis += $sizesCount;
63
  }
64
  if ( isset($attachment['file']) )
65
  {
66
  $totalFiles++;
67
+ $totalFilesThis++;
68
  $mainFiles++;
69
  $filesMap[$attachment['file']] = 1;
70
  }
132
  }
133
 
134
  }
135
+
136
+ $dt = new DateTime($idInfo->idDates[$file->post_id]);
137
+ if($dt > $month1) {
138
+ $totalFilesM1 += $totalFilesThis;
139
+ } else if($dt > $month2) {
140
+ $totalFilesM2 += $totalFilesThis;
141
+ } else if($dt > $month3) {
142
+ $totalFilesM3 += $totalFilesThis;
143
+ } else if($dt > $month4) {
144
+ $totalFilesM4 += $totalFilesThis;
145
+ }
146
+
147
  }
148
  unset($filesList);
149
  $pointer += $limit;
161
  "totalProcGlossyMlFiles" => $procGlossyTotalFiles, "mainProcGlossyMlFiles" => $procGlossyMainFiles,
162
  "totalProcLosslessMlFiles" => $procLosslessTotalFiles, "mainProcLosslessMlFiles" => $procLosslessMainFiles,
163
  "totalProcUndefMlFiles" => $procUndefTotalFiles, "mainProcUndefMlFiles" => $procUndefMainFiles,
164
+ "mainUnprocessedThumbs" => $mainUnprocessedThumbs, "totalM1" => $totalFilesM1, "totalM2" => $totalFilesM2, "totalM3" => $totalFilesM3, "totalM4" => $totalFilesM4,
165
+ "filesWithErrors" => $filesWithErrors,
166
  );
167
  }
168
 
232
  protected static function getPostIdsChunk($minId, $maxId, $pointer, $limit) {
233
  global $wpdb;
234
 
235
+ $ids = $idDates = array();
236
+ $idList = $wpdb->get_results("SELECT ID, post_mime_type, post_date FROM " . $wpdb->prefix . "posts
237
  WHERE ( ID <= $maxId AND ID > $minId )
238
  LIMIT $pointer,$limit");
239
  if ( empty($idList) ) {
242
  foreach($idList as $item) {
243
  if($item->post_mime_type != '') {
244
  $ids[] = $item->ID;
245
+ $idDates[$item->ID] = $item->post_date;
246
  }
247
  }
248
+ return (object)array('ids' => $ids, 'idDates' => $idDates);
249
  }
250
 
251
  }
class/front/img-to-picture-webp.php CHANGED
@@ -109,9 +109,23 @@ class ShortPixelImgToPictureWebp {
109
  $image_url = preg_replace('/^(.+?)(-\d+x\d+)?\.(jpg|jpeg|png|gif)((?:\?|#).+)?$/i', '$1.$3', $image_url);
110
  $prefix = $wpdb->prefix;
111
  $attachment_id = $wpdb->get_col($wpdb->prepare("SELECT ID FROM " . $prefix . "posts" . " WHERE guid='%s';", $image_url ));
112
- if ( !empty($attachment_id) ) {
113
- return $attachment_id[0];
114
- } else {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
115
  $attachment_id = $wpdb->get_col($wpdb->prepare("SELECT ID FROM " . $prefix . "posts" . " WHERE guid='%s';", $original_image_url ));
116
  }
117
  return !empty($attachment_id) ? $attachment_id[0] : false;
109
  $image_url = preg_replace('/^(.+?)(-\d+x\d+)?\.(jpg|jpeg|png|gif)((?:\?|#).+)?$/i', '$1.$3', $image_url);
110
  $prefix = $wpdb->prefix;
111
  $attachment_id = $wpdb->get_col($wpdb->prepare("SELECT ID FROM " . $prefix . "posts" . " WHERE guid='%s';", $image_url ));
112
+
113
+ //try the other proto (https - http) if full urls are used
114
+ if ( empty($attachment_id) && strpos($image_url, 'http://') === 0 ) {
115
+ $image_url_other_proto = strpos($image_url, 'https') === 0 ?
116
+ str_replace('https://', 'http://', $image_url) :
117
+ str_replace('http://', 'https://', $image_url);
118
+ $attachment_id = $wpdb->get_col($wpdb->prepare("SELECT ID FROM " . $prefix . "posts" . " WHERE guid='%s';", $image_url_other_proto ));
119
+ }
120
+
121
+ //try using only path
122
+ if (empty($attachment_id) ) {
123
+ $image_path = parse_url($image_url, PHP_URL_PATH); //some sites have different domains in posts guid (site changes, etc.)
124
+ $attachment_id = $wpdb->get_col($wpdb->prepare("SELECT ID FROM " . $prefix . "posts" . " WHERE guid like'%%%s';", $image_path ));
125
+ }
126
+
127
+ //try using the initial URL
128
+ if ( empty($attachment_id) ) {
129
  $attachment_id = $wpdb->get_col($wpdb->prepare("SELECT ID FROM " . $prefix . "posts" . " WHERE guid='%s';", $original_image_url ));
130
  }
131
  return !empty($attachment_id) ? $attachment_id[0] : false;
class/shortpixel_queue.php CHANGED
@@ -208,7 +208,7 @@ class ShortPixelQueue {
208
  }
209
 
210
  public function bulkPaused() {
211
- WPShortPixel::log("Bulk Paused: " . $this->settings->cancelPointer);
212
  return $this->settings->cancelPointer;
213
  }
214
 
@@ -217,7 +217,7 @@ class ShortPixelQueue {
217
  }
218
 
219
  public function processing() {
220
- WPShortPixel::log("QUEUE: processing(): get:" . json_encode($this->get()));
221
  return $this->bulkRunning() || count($this->get());
222
  }
223
 
@@ -391,15 +391,15 @@ class ShortPixelQueue {
391
 
392
  public function getBulkPercent() {
393
  $previousPercent = $this->settings->bulkPreviousPercent;
394
- WPShortPixel::log("QUEUE - BulkPrevPercent: " . $previousPercent . " BulkCurrentlyProcessing: "
395
- . $this->settings->bulkCurrentlyProcessed . " out of " . $this->getBulkToProcess());
396
 
397
  if($this->getBulkToProcess() <= 0) return ($this->processing () ? 99: 100);
398
  // return maximum 99%
399
  $percent = $previousPercent + round($this->settings->bulkCurrentlyProcessed / $this->getBulkToProcess()
400
  * (100 - $previousPercent));
401
 
402
- WPShortPixel::log("QUEUE - Calculated Percent: " . $percent);
403
 
404
  return min(99, $percent);
405
  }
208
  }
209
 
210
  public function bulkPaused() {
211
+ //WPShortPixel::log("Bulk Paused: " . $this->settings->cancelPointer);
212
  return $this->settings->cancelPointer;
213
  }
214
 
217
  }
218
 
219
  public function processing() {
220
+ //WPShortPixel::log("QUEUE: processing(): get:" . json_encode($this->get()));
221
  return $this->bulkRunning() || count($this->get());
222
  }
223
 
391
 
392
  public function getBulkPercent() {
393
  $previousPercent = $this->settings->bulkPreviousPercent;
394
+ //WPShortPixel::log("QUEUE - BulkPrevPercent: " . $previousPercent . " BulkCurrentlyProcessing: "
395
+ // . $this->settings->bulkCurrentlyProcessed . " out of " . $this->getBulkToProcess());
396
 
397
  if($this->getBulkToProcess() <= 0) return ($this->processing () ? 99: 100);
398
  // return maximum 99%
399
  $percent = $previousPercent + round($this->settings->bulkCurrentlyProcessed / $this->getBulkToProcess()
400
  * (100 - $previousPercent));
401
 
402
+ //WPShortPixel::log("QUEUE - Calculated Percent: " . $percent);
403
 
404
  return min(99, $percent);
405
  }
class/view/shortpixel_view.php CHANGED
@@ -98,6 +98,31 @@ class ShortPixelView {
98
  }
99
  echo("</ul>");
100
  break;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
101
  case 'generic' :
102
  echo("<p>$extra</p>");
103
  break;
@@ -166,7 +191,14 @@ class ShortPixelView {
166
  </div>
167
  </a>
168
  </div>
169
- <?php } else {?>
 
 
 
 
 
 
 
170
  <div class="bulk-play bulk-nothing-optimize">
171
  <?php _e('Nothing to optimize! The images that you add to Media Gallery will be automatically optimized after upload.','shortpixel-image-optimiser');?>
172
  </div>
@@ -212,7 +244,10 @@ class ShortPixelView {
212
  } else { ?>
213
  <div class="sp-container">
214
  <div class='sp-notice sp-notice-success sp-floating-block sp-single-width' style="height: 80px;overflow:hidden;">
215
- <div style='float:left;margin:5px 20px 5px 0'><img src="<?php echo(plugins_url( 'shortpixel-image-optimiser/res/img/slider.png' ));?>"></div>
 
 
 
216
  <div class="sp-bulk-summary">
217
  <input type="text" value="<?php echo("" . round($averageCompression))?>" id="sp-total-optimization-dial" class="dial">
218
  </div>
@@ -390,7 +425,8 @@ class ShortPixelView {
390
  <input type='checkbox' id='bulk-thumbnails' name='thumbnails' <?php echo($this->ctrl->processThumbnails() ? "checked":"");?>
391
  onchange="ShortPixel.onBulkThumbsCheck(this)"> <?php _e('Include thumbnails','shortpixel-image-optimiser');?><br><br>
392
  <input type='submit' name='bulkProcess' id='bulkProcess' class='button button-primary' value='<?php _e('Restart Optimizing','shortpixel-image-optimiser');?>'>
393
- <input type='submit' name='bulkRestore' id='bulkRestore' class='button' value='<?php _e('Bulk Restore Media Library','shortpixel-image-optimiser');?>' style="float: right;">
 
394
  </form>
395
  </div>
396
  <?php } ?>
@@ -495,7 +531,7 @@ class ShortPixelView {
495
  </div>
496
  </div>
497
  <?php if($running) {
498
- if($type) { ?>
499
  <div class="sp-h2"><?php
500
  echo($type & 1 ? __('Media Library','shortpixel-image-optimiser') . " " : "");
501
  echo($type & 3 == 3 ? __('and','shortpixel-image-optimiser') . " " : "");
@@ -503,11 +539,16 @@ class ShortPixelView {
503
  _e('optimization in progress ...','shortpixel-image-optimiser');?></div>
504
  <p style="margin: 0 0 18px;"><?php _e('Bulk optimization has started.','shortpixel-image-optimiser');?><br>
505
  <?php
506
- } else { // restore ?>
507
  <div class="sp-h2"><?php
508
  _e('Media Library restore in progress ...','shortpixel-image-optimiser');?></div>
509
  <p style="margin: 0 0 18px;"><?php _e('Bulk restore has started.','shortpixel-image-optimiser');?><br>
510
  <?php }
 
 
 
 
 
511
  printf(__('This process will take some time, depending on the number of images in your library. In the meantime, you can continue using
512
  the admin as usual, <a href="%s" target="_blank">in a different browser window or tab</a>.<br>
513
  However, <strong>if you close this window, the bulk processing will pause</strong> until you open the media gallery or the ShortPixel bulk page again.','shortpixel-image-optimiser'), get_admin_url());?>
@@ -518,7 +559,8 @@ class ShortPixelView {
518
  <?php }?>
519
  <div id="bulk-progress" class="progress" >
520
  <div class="progress-img" style="left: <?php echo($percent);?>%;">
521
- <img src="<?php echo(plugins_url( 'shortpixel-image-optimiser/res/img/slider.png' ));?>">
 
522
  <span><?php echo($percentAfter);?></span>
523
  </div>
524
  <div class="progress-left" style="width: <?php echo($percent);?>%"><?php echo($percentBefore);?></div>
@@ -835,6 +877,7 @@ class ShortPixelView {
835
  }
836
  $excludePatterns = substr($excludePatterns, 0, -2);
837
  }
 
838
  ?>
839
  <div class="wp-shortpixel-options">
840
  <?php if(!$this->ctrl->getVerifiedKey()) { ?>
@@ -912,7 +955,7 @@ class ShortPixelView {
912
  <p class="settings-info">
913
  <?php _e('Use the Select... button to select site folders. ShortPixel will optimize images and PDFs from the specified folders and their subfolders. The optimization status for each image or PDF in these folders can be seen in the <a href="upload.php?page=wp-short-pixel-custom">Other Media list</a>, under the Media menu.','shortpixel-image-optimiser');?>
914
  </p>
915
- <div class="sp-modal-shade">
916
  <div class="shortpixel-modal">
917
  <div class="sp-modal-title"><?php _e('Select the images folder','shortpixel-image-optimiser');?></div>
918
  <div class="sp-folder-picker"></div>
@@ -938,6 +981,15 @@ class ShortPixelView {
938
  </td>
939
  </tr>
940
  <?php } ?>
 
 
 
 
 
 
 
 
 
941
  <tr>
942
  <th scope="row"><label for="createWebp"><?php _e('WebP versions','shortpixel-image-optimiser');?></label></th>
943
  <td>
@@ -1262,7 +1314,7 @@ class ShortPixelView {
1262
  <div id="spUploadCompare" class="shortpixel-modal shortpixel-hide">
1263
  <div class="sp-modal-title">
1264
  <button type="button" class="sp-close-button">&times;</button>
1265
- Compare Images
1266
  </div>
1267
  <div class="sp-modal-body sptw-modal-spinner" style="height:400px;padding:0;">
1268
  <div class="shortpixel-slider" style="z-index:2000;">
98
  }
99
  echo("</ul>");
100
  break;
101
+ case 'upgmonth' :
102
+ case 'upgbulk' : ?>
103
+ <p> <?php
104
+ if($when == 'upgmonth') {
105
+ printf(__("You are adding an average of <strong>%d images and thumbnails every month</strong> to your Media Library and you have <strong>a plan of %d images/month</strong>."
106
+ . " You might need to upgrade you plan in order to have all your images optimized.", 'shortpixel_image_optimiser'), $extra['monthAvg'], $extra['monthlyQuota']);
107
+ } else {
108
+ printf(__("You currently have <strong>%d images and thumbnails to optimize</strong> in your Media Library but you only you have <strong>%d images</strong> available in your current plan."
109
+ . " You might need to upgrade you plan in order to have all your images optimized.", 'shortpixel_image_optimiser'), $extra['filesTodo'], $extra['quotaAvailable']);
110
+ }?>
111
+ <br><br>
112
+ <button class="button button-primary" id="shortpixel-upgrade-advice" onclick="ShortPixel.proposeUpgrade()"><strong>
113
+ <?php _e('Show me the best available options', 'shortpixel_image_optimiser'); ?></strong></button>
114
+ </p>
115
+ <div id="shortPixelProposeUpgradeShade" class="sp-modal-shade" style="display:none;">
116
+ <div id="shortPixelProposeUpgrade" class="shortpixel-modal shortpixel-hide">
117
+ <div class="sp-modal-title">
118
+ <button type="button" class="sp-close-upgrade-button" onclick="ShortPixel.closeProposeUpgrade()">&times;</button>
119
+ <?php _e('Upgrade your ShortPixel account', 'shortpixel-image-optimiser');?>
120
+ </div>
121
+ <div class="sp-modal-body sptw-modal-spinner" style="height:400px;padding:0;">
122
+ </div>
123
+ </div>
124
+ </div>
125
+ <?php break;
126
  case 'generic' :
127
  echo("<p>$extra</p>");
128
  break;
191
  </div>
192
  </a>
193
  </div>
194
+ <?php if($quotaData['mainProcessedMlFiles'] > 0) {?>
195
+ <div style="position: absolute;bottom: 10px;right: 10px;">
196
+ <input type='submit' name='bulkRestore' id='bulkRestore' class='button' value='<?php _e('Bulk Restore Media Library','shortpixel-image-optimiser');?>' onclick="ShortPixel.confirmBulkAction('Restore', event)" style="margin-bottom:10px;"><br>
197
+ <input type='submit' name='bulkCleanup' id='bulkRestore' class='button' value='<?php _e('Bulk Delete Metadata','shortpixel-image-optimiser');?>' onclick="ShortPixel.confirmBulkAction('Cleanup', event)" style="width:100%">
198
+ </div>
199
+
200
+ <?php }
201
+ } else {?>
202
  <div class="bulk-play bulk-nothing-optimize">
203
  <?php _e('Nothing to optimize! The images that you add to Media Gallery will be automatically optimized after upload.','shortpixel-image-optimiser');?>
204
  </div>
244
  } else { ?>
245
  <div class="sp-container">
246
  <div class='sp-notice sp-notice-success sp-floating-block sp-single-width' style="height: 80px;overflow:hidden;">
247
+ <div style='float:left;margin:5px 20px 5px 0'>
248
+ <img src="<?php echo(plugins_url( 'shortpixel-image-optimiser/res/img/slider.png' ));?>"
249
+ srcset='<?php echo(plugins_url( 'shortpixel-image-optimiser/res/img/slider.png' ));?> 1x, <?php echo(plugins_url( 'shortpixel-image-optimiser/res/img/slider@2x.png' ));?> 2x'>
250
+ </div>
251
  <div class="sp-bulk-summary">
252
  <input type="text" value="<?php echo("" . round($averageCompression))?>" id="sp-total-optimization-dial" class="dial">
253
  </div>
425
  <input type='checkbox' id='bulk-thumbnails' name='thumbnails' <?php echo($this->ctrl->processThumbnails() ? "checked":"");?>
426
  onchange="ShortPixel.onBulkThumbsCheck(this)"> <?php _e('Include thumbnails','shortpixel-image-optimiser');?><br><br>
427
  <input type='submit' name='bulkProcess' id='bulkProcess' class='button button-primary' value='<?php _e('Restart Optimizing','shortpixel-image-optimiser');?>'>
428
+ <input type='submit' name='bulkRestore' id='bulkRestore' class='button' value='<?php _e('Bulk Restore Media Library','shortpixel-image-optimiser');?>' onclick="ShortPixel.confirmBulkAction('Restore',event)" style="float: right;">
429
+ <input type='submit' name='bulkCleanup' id='bulkRestore' class='button' value='<?php _e('Bulk Delete Metadata','shortpixel-image-optimiser');?>' onclick="ShortPixel.confirmBulkAction('Cleanup',event)" style="float: right;margin-right:10px;">
430
  </form>
431
  </div>
432
  <?php } ?>
531
  </div>
532
  </div>
533
  <?php if($running) {
534
+ if($type > 0) { ?>
535
  <div class="sp-h2"><?php
536
  echo($type & 1 ? __('Media Library','shortpixel-image-optimiser') . " " : "");
537
  echo($type & 3 == 3 ? __('and','shortpixel-image-optimiser') . " " : "");
539
  _e('optimization in progress ...','shortpixel-image-optimiser');?></div>
540
  <p style="margin: 0 0 18px;"><?php _e('Bulk optimization has started.','shortpixel-image-optimiser');?><br>
541
  <?php
542
+ } elseif($type == 0) { // restore ?>
543
  <div class="sp-h2"><?php
544
  _e('Media Library restore in progress ...','shortpixel-image-optimiser');?></div>
545
  <p style="margin: 0 0 18px;"><?php _e('Bulk restore has started.','shortpixel-image-optimiser');?><br>
546
  <?php }
547
+ elseif($type == -1) { // cleanup ?>
548
+ <div class="sp-h2"><?php
549
+ _e('Media Library cleanup in progress ...','shortpixel-image-optimiser');?></div>
550
+ <p style="margin: 0 0 18px;"><?php _e('Bulk cleanup has started.','shortpixel-image-optimiser');?><br>
551
+ <?php }
552
  printf(__('This process will take some time, depending on the number of images in your library. In the meantime, you can continue using
553
  the admin as usual, <a href="%s" target="_blank">in a different browser window or tab</a>.<br>
554
  However, <strong>if you close this window, the bulk processing will pause</strong> until you open the media gallery or the ShortPixel bulk page again.','shortpixel-image-optimiser'), get_admin_url());?>
559
  <?php }?>
560
  <div id="bulk-progress" class="progress" >
561
  <div class="progress-img" style="left: <?php echo($percent);?>%;">
562
+ <img src="<?php echo(plugins_url( 'shortpixel-image-optimiser/res/img/slider.png' ));?>"
563
+ srcset='<?php echo(plugins_url( 'shortpixel-image-optimiser/res/img/slider.png' ));?> 1x, <?php echo(plugins_url( 'shortpixel-image-optimiser/res/img/slider@2x.png' ));?> 2x'>
564
  <span><?php echo($percentAfter);?></span>
565
  </div>
566
  <div class="progress-left" style="width: <?php echo($percent);?>%"><?php echo($percentBefore);?></div>
877
  }
878
  $excludePatterns = substr($excludePatterns, 0, -2);
879
  }
880
+ $convertPng2Jpg = ($settings->png2jpg ? 'checked' : '');
881
  ?>
882
  <div class="wp-shortpixel-options">
883
  <?php if(!$this->ctrl->getVerifiedKey()) { ?>
955
  <p class="settings-info">
956
  <?php _e('Use the Select... button to select site folders. ShortPixel will optimize images and PDFs from the specified folders and their subfolders. The optimization status for each image or PDF in these folders can be seen in the <a href="upload.php?page=wp-short-pixel-custom">Other Media list</a>, under the Media menu.','shortpixel-image-optimiser');?>
957
  </p>
958
+ <div class="sp-modal-shade sp-folder-picker-shade">
959
  <div class="shortpixel-modal">
960
  <div class="sp-modal-title"><?php _e('Select the images folder','shortpixel-image-optimiser');?></div>
961
  <div class="sp-folder-picker"></div>
981
  </td>
982
  </tr>
983
  <?php } ?>
984
+ <tr>
985
+ <th scope="row"><label for="png2jpg"><?php _e('Convert PNG images to JPEG','shortpixel-image-optimiser');?></label></th>
986
+ <td>
987
+ <input name="png2jpg" type="checkbox" id="resize" <?php echo( $convertPng2Jpg );?>> <?php _e('Automatically convert the PNG images to JPEG if possible.','shortpixel-image-optimiser');?>
988
+ <p class="settings-info">
989
+ <?php _e('Converts all PNGs that don\'t have transparent pixels to JPEG. This can dramatically reduce the file size, especially if you have pictures that are saved in PNG format.','shortpixel-image-optimiser');?>
990
+ </p>
991
+ </td>
992
+ </tr>
993
  <tr>
994
  <th scope="row"><label for="createWebp"><?php _e('WebP versions','shortpixel-image-optimiser');?></label></th>
995
  <td>
1314
  <div id="spUploadCompare" class="shortpixel-modal shortpixel-hide">
1315
  <div class="sp-modal-title">
1316
  <button type="button" class="sp-close-button">&times;</button>
1317
+ <?php _('Compare Images', 'shortpixel-image-optimiser');?>
1318
  </div>
1319
  <div class="sp-modal-body sptw-modal-spinner" style="height:400px;padding:0;">
1320
  <div class="shortpixel-slider" style="z-index:2000;">
class/wp-short-pixel.php CHANGED
@@ -75,7 +75,9 @@ class WPShortPixel {
75
  add_action('wp_ajax_shortpixel_browse_content', array(&$this, 'browseContent'));
76
  add_action('wp_ajax_shortpixel_get_backup_size', array(&$this, 'getBackupSize'));
77
  add_action('wp_ajax_shortpixel_get_comparer_data', array(&$this, 'getComparerData'));
78
-
 
 
79
  add_action( 'delete_attachment', array( &$this, 'handleDeleteAttachmentInBackup' ) );
80
  add_action( 'load-upload.php', array( &$this, 'handleCustomBulk'));
81
 
@@ -205,6 +207,26 @@ class WPShortPixel {
205
  ShortPixelView::displayActivationNotice('compat', $conflictPlugins);
206
  }
207
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
208
  }
209
 
210
  public function dismissAdminNotice() {
@@ -218,7 +240,25 @@ class WPShortPixel {
218
  public function dismissMediaAlert() {
219
  $this->_settings->mediaAlert = 1;
220
  die(json_encode(array("Status" => 'success', "Message" => __('Media alert dismissed','shortpixel-image-optimiser'))));
221
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
222
 
223
  //set default move as "list". only set once, it won't try to set the default mode again.
224
  public function setDefaultViewModeList()
@@ -239,12 +279,20 @@ class WPShortPixel {
239
  static function log($message) {
240
  if (SHORTPIXEL_DEBUG === true) {
241
  if (is_array($message) || is_object($message)) {
242
- error_log(print_r($message, true));
243
  } else {
244
- error_log($message);
245
  }
246
  }
247
  }
 
 
 
 
 
 
 
 
248
 
249
  function shortPixelJS() {
250
  require_once(ABSPATH . 'wp-admin/includes/screen.php');
@@ -300,7 +348,9 @@ class WPShortPixel {
300
  'thisContentNotProcessable' => __( 'This content is not processable.', 'shortpixel-image-optimiser' ),
301
  'imageWaitOptThumbs' => __( 'Image waiting to optimize thumbnails', 'shortpixel-image-optimiser' ),
302
  'pleaseDoNotSetLesserSize' => __( "Please do not set a {0} less than the {1} of the largest thumbnail which is {2}, to be able to still regenerate all your thumbnails in case you'll ever need this.", 'shortpixel-image-optimiser' ),
303
- 'pleaseDoNotSetLesser1024' => __( "Please do not set a {0} less than 1024, to be able to still regenerate all your thumbnails in case you'll ever need this.", 'shortpixel-image-optimiser' )
 
 
304
  );
305
  wp_localize_script( 'short-pixel.js', '_spTr', $jsTranslation );
306
  wp_enqueue_script('short-pixel.js');
@@ -401,46 +451,183 @@ class WPShortPixel {
401
  */
402
  public function handleMediaLibraryImageUpload($meta, $ID = null)
403
  {
404
- if( !$this->_settings->verifiedKey) {// no API Key set/verified -> do nothing here, just return
405
- return $meta;
406
- }
407
- //else
408
- //self::log("IMG: Auto-analyzing file ID #{$ID}");
409
-
410
- if(!$this->_settings->optimizePdfs && 'pdf' === pathinfo(get_attached_file($ID), PATHINFO_EXTENSION)) {
411
- //pdf is not optimized automatically as per the option, but can be optimized by button. Nothing to do.
412
- return $meta;
413
- }
414
- elseif( self::_isProcessable($ID, array(), $this->_settings->excludePatterns, $meta) == false )
415
- {//not a file that we can process
416
- $meta['ShortPixelImprovement'] = __('Optimization N/A','shortpixel-image-optimiser');
417
- return $meta;
418
- }
419
- else
420
- {//the kind of file we can process. goody.
421
-
422
- $this->prioQ->push($ID);
423
- //that's a hack for watermarking plugins, don't send the image right away to processing, only add it in the queue
424
- include_once( ABSPATH . 'wp-admin/includes/plugin.php' );
425
- if( !is_plugin_active('image-watermark/image-watermark.php')
426
- && !is_plugin_active('easy-watermark/index.php')) {
427
- $itemHandler = new ShortPixelMetaFacade($ID);
428
- $itemHandler->setRawMeta($meta);
429
- try {
430
- $URLsAndPATHs = $this->getURLsAndPATHs($itemHandler);
431
- //send a processing request right after a file was uploaded, do NOT wait for response
432
- $this->_apiInterface->doRequests($URLsAndPATHs['URLs'], false, $ID);
433
- } catch(Exception $e) {
434
- $meta['ShortPixelImprovement'] = $e->getMessage();
435
- return $meta;
436
- }
437
- //self::log("IMG: sent: " . json_encode($URLsAndPATHs));
438
  }
439
- $meta['ShortPixel']['WaitingProcessing'] = true;
440
- return $meta;
441
- }
 
 
442
  }//end handleMediaLibraryImageUpload
443
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
444
  /**
445
  * this is hooked onto the NextGen upload
446
  * @param type $image
@@ -523,6 +710,8 @@ class WPShortPixel {
523
  if ( $startQueryID <= $endQueryID ) {
524
  return false;
525
  }
 
 
526
 
527
  $startTime = time();
528
  $maxTime = (is_numeric(SHORTPIXEL_MAX_EXECUTION_TIME) && SHORTPIXEL_MAX_EXECUTION_TIME > 10 ? SHORTPIXEL_MAX_EXECUTION_TIME - 5 : 25);
@@ -546,8 +735,14 @@ class WPShortPixel {
546
  $item = new ShortPixelMetaFacade($crtStartQueryID);
547
  $meta = $item->getMeta();//wp_get_attachment_metadata($crtStartQueryID);
548
 
549
- if($meta->getStatus() == 2) {
550
- $res = $this->doRestore($crtStartQueryID);
 
 
 
 
 
 
551
  $restored[] = array('id' => $crtStartQueryID, 'status' => $res ? 'success' : 'fail');
552
  }
553
  }
@@ -586,7 +781,10 @@ class WPShortPixel {
586
  if ( empty($resultsPostMeta) ) {
587
  $crtStartQueryID -= SHORTPIXEL_MAX_RESULTS_QUERY;
588
  $startQueryID = $crtStartQueryID;
589
- $this->prioQ->setStartBulkId($startQueryID);
 
 
 
590
  continue;
591
  }
592
 
@@ -688,11 +886,13 @@ class WPShortPixel {
688
  $this->_settings->lastBackAction = time();
689
  }
690
 
691
- self::log("HIP: 0 Priority Queue: ".json_encode($this->prioQ->get()));
 
692
  //self::log("HIP: 0 Bulk running? " . $this->prioQ->bulkRunning() . " START " . $this->_settings->startBulkId . " STOP " . $this->_settings->stopBulkId);
693
 
694
  //handle the bulk restore and cleanup first - these are fast operations taking precedece over optimization
695
- if($this->prioQ->bulkRunning() && $this->prioQ->getBulkType() == ShortPixelQueue::BULK_TYPE_RESTORE) {
 
696
  $res = $this->bulkRestore();
697
  if($res === false) {
698
  $this->sendEmptyQueue();
@@ -726,12 +926,17 @@ class WPShortPixel {
726
  }
727
  }
728
 
729
- self::log("HIP: 0 Bulk ran: " . $this->prioQ->bulkRan());
730
  $customIds = false;
731
  if(count($ids) < 3 && $this->prioQ->bulkRan() && $this->_settings->hasCustomFolders
732
  && (!$this->_settings->cancelPointer || $this->_settings->skipToCustom)
733
  && !$this->_settings->customBulkPaused)
734
  { //take from custom images if any left to optimize - only if bulk was ever started
 
 
 
 
 
735
  $customIds = $this->spMetaDao->getPendingMetas( 3 - count($ids));
736
  if(is_array($customIds)) {
737
  $ids = array_merge($ids, array_map(array('ShortPixelMetaFacade', 'getNewFromRow'), $customIds));
@@ -740,8 +945,8 @@ class WPShortPixel {
740
  //var_dump($ids);
741
  //die("za stop 2");
742
 
743
- self::log("HIP: 1 Prio Queue: ".json_encode($this->prioQ->get()));
744
- self::log("HIP: 1 Selected IDs count: ".count($ids));
745
 
746
  //2: Send up to 3 files to the server for processing
747
  for($i = 0, $itemHandler = false; $ids !== false && $i < min(3, count($ids)); $i++) {
@@ -771,7 +976,7 @@ class WPShortPixel {
771
  "Message" => __('Searching images to optimize... ','shortpixel-image-optimiser') . $this->prioQ->getStartBulkId() . '->' . $this->prioQ->getStopBulkId() )));
772
  }
773
  //in this case the queue is really empty
774
- self::log("HIP: 1 STOP BULK");
775
  $bulkEverRan = $this->prioQ->stopBulk();
776
  $this->sendEmptyQueue();
777
  }
@@ -951,7 +1156,8 @@ class WPShortPixel {
951
  $percent = $this->prioQ->getBulkPercent();
952
  if(0 + $pendingMeta > 0) {
953
  $customMeta = $this->spMetaDao->getCustomMetaCount();
954
- $totalPercent = round(($percent * $this->_settings->currentTotalFiles + ($customMeta - $pendingMeta) * 100) / ($this->_settings->currentTotalFiles + $customMeta));
 
955
  $minutesRemaining = round($minutesRemaining * (100 - $totalPercent) / max(1, 100 - $percent));
956
  $percent = $totalPercent;
957
  }
@@ -960,6 +1166,15 @@ class WPShortPixel {
960
  }
961
 
962
  private function sendToProcessing($itemHandler, $compressionType = false, $onlyThumbs = false) {
 
 
 
 
 
 
 
 
 
963
  //WpShortPixelMediaLbraryAdapter::cleanupFoundThumbs($itemHandler);
964
  $URLsAndPATHs = $this->getURLsAndPATHs($itemHandler, NULL, $onlyThumbs);
965
 
@@ -1031,6 +1246,9 @@ class WPShortPixel {
1031
  public function handleManualOptimization() {
1032
  $imageId = $_GET['image_id'];
1033
  $cleanup = $_GET['cleanup'];
 
 
 
1034
  switch(substr($imageId, 0, 2)) {
1035
  case "N-":
1036
  return "Add the gallery to the custom folders list in ShortPixel settings.";
@@ -1102,8 +1320,14 @@ class WPShortPixel {
1102
 
1103
  public function getBackupFolder($file) {
1104
  if(realpath($file)) {
1105
- $file = realpath($file); //found cases when $file contains for example /wp/../wp-content - clean it up
 
1106
  }
 
 
 
 
 
1107
  $fileExtension = strtolower(substr($file,strrpos($file,".")+1));
1108
  $SubDir = ShortPixelMetaFacade::returnSubDir($file, ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE);
1109
  $SubDirOld = ShortPixelMetaFacade::returnSubDirOld($file, ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE);
@@ -1267,6 +1491,7 @@ class WPShortPixel {
1267
  public function handleRestoreBackup() {
1268
  $attachmentID = intval($_GET['attachment_ID']);
1269
 
 
1270
  $this->doRestore($attachmentID);
1271
 
1272
  // get the referring webpage location
@@ -1279,6 +1504,8 @@ class WPShortPixel {
1279
  }
1280
 
1281
  public function handleRedo() {
 
 
1282
  die(json_encode($this->redo($_GET['attachment_ID'], $_GET['type'])));
1283
  }
1284
 
@@ -1401,13 +1628,23 @@ class WPShortPixel {
1401
  $quotaData = $this->getQuotaInformation();
1402
  }
1403
  if ( !$quotaData['APIKeyValid']) {
1404
- $this->view->displayActivationNotice('generic', $quotaData['Message']);
1405
  return $quotaData;
1406
  }
1407
  //$tempus = microtime(true);
1408
- $imageCount = WpShortPixelMediaLbraryAdapter::countAllProcessableFiles($this->_settings->optimizePdfs);
1409
 
1410
- $this->_settings->currentTotalFiles = $imageCount['totalFiles'];
 
 
 
 
 
 
 
 
 
 
 
1411
 
1412
  //echo("Count took (seconds): " . (microtime(true) - $tempus));
1413
  foreach($imageCount as $key => $val) {
@@ -1483,7 +1720,7 @@ class WPShortPixel {
1483
  $customMediaListTable->display();
1484
  //push to the processing list the pending ones, just in case
1485
  //$count = $this->spMetaDao->getCustomMetaCount();
1486
- foreach ($items as $item) {
1487
  if($item->status == 1){
1488
  $this->prioQ->push(ShortPixelMetaFacade::queuedId(ShortPixelMetaFacade::CUSTOM_TYPE, $item->id));
1489
  }
@@ -1552,6 +1789,12 @@ class WPShortPixel {
1552
  $this->_settings->customBulkPaused = 0;
1553
  }//end bulk restore was clicked
1554
 
 
 
 
 
 
 
1555
  if(isset($_POST["bulkProcessResume"]))
1556
  {
1557
  $this->prioQ->resumeBulk();
@@ -1578,7 +1821,8 @@ class WPShortPixel {
1578
  $msg = $this->bulkProgressMessage($this->prioQ->getDeltaBulkPercent(), $this->prioQ->getTimeRemaining());
1579
 
1580
  $this->view->displayBulkProcessingRunning($this->getPercent($quotaData), $msg, $quotaData['APICallsRemaining'], $this->getAverageCompression(),
1581
- $this->prioQ->getBulkType() == ShortPixelQueue::BULK_TYPE_RESTORE ? 0 : ($pendingMeta !== null ? ($this->prioQ->bulkRunning() ? 3 : 2) : 1));
 
1582
 
1583
  } else
1584
  {
@@ -1723,6 +1967,47 @@ class WPShortPixel {
1723
  die(json_encode((object)$ret));
1724
  }
1725
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1726
  public static function getCustomFolderBase() {
1727
  if(is_main_site()) {
1728
  $base = get_home_path();
@@ -1907,13 +2192,14 @@ class WPShortPixel {
1907
  $notice = array("status" => "success", "msg" => __('Folder added successfully.','shortpixel-image-optimiser'));
1908
  }
1909
  $customFolders = $this->spMetaDao->getFolders();
1910
- $this->_settings->hasCustomFolders = true;
1911
  }
1912
 
1913
  $this->_settings->createWebp = (isset($_POST['createWebp']) ? 1: 0);
1914
  $this->_settings->createWebpMarkup = (isset($_POST['createWebpMarkup']) ? 1: 0);
1915
  $this->_settings->optimizeRetina = (isset($_POST['optimizeRetina']) ? 1: 0);
1916
  $this->_settings->optimizePdfs = (isset($_POST['optimizePdfs']) ? 1: 0);
 
1917
 
1918
  //die(var_dump($_POST['excludePatterns']));
1919
 
@@ -2012,7 +2298,7 @@ class WPShortPixel {
2012
  $ngGalleries = ShortPixelNextGenAdapter::getGalleries();
2013
  foreach($ngGalleries as $gallery) {
2014
  $folderMsg = $this->spMetaDao->newFolderFromPath($gallery, get_home_path(), self::getCustomFolderBase());
2015
- $this->_settings->hasCustomFolders = true;
2016
  }
2017
  $customFolders = $this->spMetaDao->getFolders();
2018
  }
@@ -2274,7 +2560,7 @@ class WPShortPixel {
2274
  elseif(isset($data['ShortPixel']['WaitingProcessing'])) {
2275
  $renderData['status'] = $quotaExceeded ? 'quotaExceeded' : 'retry';
2276
  $renderData['message'] = "<img src=\"" . plugins_url( 'res/img/loading.gif', SHORTPIXEL_PLUGIN_FILE ) . "\" class='sp-loading-small'>&nbsp;" . __("Image waiting to be processed.",'shortpixel-image-optimiser');
2277
- if(!$quotaExceeded && ($id > $this->prioQ->getFlagBulkId() || !$this->prioQ->bulkRunning())) {
2278
  $this->prioQ->push($id); //should be there but just to make sure
2279
  }
2280
  }
75
  add_action('wp_ajax_shortpixel_browse_content', array(&$this, 'browseContent'));
76
  add_action('wp_ajax_shortpixel_get_backup_size', array(&$this, 'getBackupSize'));
77
  add_action('wp_ajax_shortpixel_get_comparer_data', array(&$this, 'getComparerData'));
78
+
79
+ add_action('wp_ajax_shortpixel_propose_upgrade', array(&$this, 'proposeUpgrade'));
80
+
81
  add_action( 'delete_attachment', array( &$this, 'handleDeleteAttachmentInBackup' ) );
82
  add_action( 'load-upload.php', array( &$this, 'handleCustomBulk'));
83
 
207
  ShortPixelView::displayActivationNotice('compat', $conflictPlugins);
208
  }
209
  }
210
+ if(false)
211
+ if($this->_settings->verifiedKey
212
+ && (!isset($dismissed['upgmonth']) || !isset($dismissed['upgbulk'])) && is_array($this->_settings->currentStats)
213
+ && $this->_settings->currentStats['optimizePdfs'] == $this->_settings->optimizePdfs ) {
214
+ $screen = get_current_screen();
215
+ $stats = $this->_settings->currentStats;
216
+ $quotaData = $stats['quotaData'];
217
+
218
+ //this is for bulk page - alert on the total credits for total images
219
+ if( $screen && $screen->id == 'media_page_wp-short-pixel-bulk' && $this->bulkUpgradeNeeded($stats)) {
220
+ //looks like the user hasn't got enough credits to bulk process all media library
221
+ ShortPixelView::displayActivationNotice('upgbulk', array('filesTodo' => $stats['totalFiles'] - $stats['totalProcessedFiles'],
222
+ 'quotaAvailable' => $quotaData['APICallsQuotaNumeric'] + $quotaData['APICallsQuotaOneTimeNumeric'] - $quotaData['APICallsMadeNumeric'] - $quotaData['APICallsMadeOneTimeNumeric']));
223
+ }
224
+ //consider the monthly plus 1/6 of the available one-time credits.
225
+ elseif($this->monthlyUpgradeNeeded($stats)) {
226
+ //looks like the user hasn't got enough credits to process the monthly images, display a notice telling this
227
+ ShortPixelView::displayActivationNotice('upgmonth', array('monthAvg' => $this->getMonthAvg($stats), 'monthlyQuota' => $quotaData['APICallsQuotaNumeric']));
228
+ }
229
+ }
230
  }
231
 
232
  public function dismissAdminNotice() {
240
  public function dismissMediaAlert() {
241
  $this->_settings->mediaAlert = 1;
242
  die(json_encode(array("Status" => 'success', "Message" => __('Media alert dismissed','shortpixel-image-optimiser'))));
243
+ }
244
+
245
+ protected function getMonthAvg($stats) {
246
+ for($i = 4, $count = 0; $i>=1; $i--) {
247
+ if($count == 0 && $stats['totalM' . $i] == 0) continue;
248
+ $count++;
249
+ }
250
+ return ($stats['totalM1'] + $stats['totalM2'] + $stats['totalM3'] + $stats['totalM4']) / max(1,$count);
251
+ }
252
+
253
+ protected function monthlyUpgradeNeeded($stats) {
254
+ $quotaData = $stats['quotaData'];
255
+ return $this->getMonthAvg($stats) > $quotaData['APICallsQuotaNumeric'] + ($quotaData['APICallsQuotaOneTimeNumeric'] - $quotaData['APICallsMadeOneTimeNumeric'])/6 + 20;
256
+ }
257
+
258
+ protected function bulkUpgradeNeeded($stats) {
259
+ $quotaData = $stats['quotaData'];
260
+ return $stats['totalFiles'] - $stats['totalProcessedFiles'] > $quotaData['APICallsQuotaNumeric'] + $quotaData['APICallsQuotaOneTimeNumeric'] - $quotaData['APICallsMadeNumeric'] - $quotaData['APICallsMadeOneTimeNumeric'];
261
+ }
262
 
263
  //set default move as "list". only set once, it won't try to set the default mode again.
264
  public function setDefaultViewModeList()
279
  static function log($message) {
280
  if (SHORTPIXEL_DEBUG === true) {
281
  if (is_array($message) || is_object($message)) {
282
+ self::doLog(print_r($message, true));
283
  } else {
284
+ self::doLog($message);
285
  }
286
  }
287
  }
288
+
289
+ static protected function doLog($message) {
290
+ if(defined('SHORTPIXEL_DEBUG_TARGET')) {
291
+ file_put_contents(SHORTPIXEL_BACKUP_FOLDER . "/shortpixel_log", '[' . date('Y-m-d H:i:s') . "] $message\n", FILE_APPEND);
292
+ } else {
293
+ error_log($message);
294
+ }
295
+ }
296
 
297
  function shortPixelJS() {
298
  require_once(ABSPATH . 'wp-admin/includes/screen.php');
348
  'thisContentNotProcessable' => __( 'This content is not processable.', 'shortpixel-image-optimiser' ),
349
  'imageWaitOptThumbs' => __( 'Image waiting to optimize thumbnails', 'shortpixel-image-optimiser' ),
350
  'pleaseDoNotSetLesserSize' => __( "Please do not set a {0} less than the {1} of the largest thumbnail which is {2}, to be able to still regenerate all your thumbnails in case you'll ever need this.", 'shortpixel-image-optimiser' ),
351
+ 'pleaseDoNotSetLesser1024' => __( "Please do not set a {0} less than 1024, to be able to still regenerate all your thumbnails in case you'll ever need this.", 'shortpixel-image-optimiser' ),
352
+ 'confirmBulkRestore' => __( "Are you sure you want to restore from backup all the images in your Media Library optimized with ShortPixel?", 'shortpixel-image-optimiser' ),
353
+ 'confirmBulkCleanup' => __( "Are you sure you want to cleanup the ShortPixel metadata info for the images in your Media Library optimized with ShortPixel? This will make ShortPixel 'forget' that it optimized them and will optimize them again if you re-run the Bulk Optimization process.", 'shortpixel-image-optimiser' )
354
  );
355
  wp_localize_script( 'short-pixel.js', '_spTr', $jsTranslation );
356
  wp_enqueue_script('short-pixel.js');
451
  */
452
  public function handleMediaLibraryImageUpload($meta, $ID = null)
453
  {
454
+ if( !$this->_settings->verifiedKey) {// no API Key set/verified -> do nothing here, just return
455
+ return $meta;
456
+ }
457
+ //else
458
+ //self::log("IMG: Auto-analyzing file ID #{$ID}");
459
+
460
+ self::log("Handle Media Library Image Upload #{$ID}");
461
+
462
+ if(!$this->_settings->optimizePdfs && 'pdf' === pathinfo(get_attached_file($ID), PATHINFO_EXTENSION)) {
463
+ //pdf is not optimized automatically as per the option, but can be optimized by button. Nothing to do.
464
+ return $meta;
465
+ }
466
+ elseif( self::_isProcessable($ID, array(), $this->_settings->excludePatterns, $meta) == false )
467
+ {//not a file that we can process
468
+ $meta['ShortPixelImprovement'] = __('Optimization N/A','shortpixel-image-optimiser');
469
+ return $meta;
470
+ }
471
+ else
472
+ {//the kind of file we can process. goody.
473
+
474
+ $this->prioQ->push($ID);
475
+ //that's a hack for watermarking plugins, don't send the image right away to processing, only add it in the queue
476
+ include_once( ABSPATH . 'wp-admin/includes/plugin.php' );
477
+ if( !is_plugin_active('image-watermark/image-watermark.php')
478
+ && !is_plugin_active('easy-watermark/index.php')) {
479
+ $itemHandler = new ShortPixelMetaFacade($ID);
480
+ $itemHandler->setRawMeta($meta);
481
+ try {
482
+ $URLsAndPATHs = $this->getURLsAndPATHs($itemHandler);
483
+ //send a processing request right after a file was uploaded, do NOT wait for response
484
+ $this->_apiInterface->doRequests($URLsAndPATHs['URLs'], false, $ID);
485
+ } catch(Exception $e) {
486
+ $meta['ShortPixelImprovement'] = $e->getMessage();
487
+ return $meta;
488
  }
489
+ //self::log("IMG: sent: " . json_encode($URLsAndPATHs));
490
+ }
491
+ $meta['ShortPixel']['WaitingProcessing'] = true;
492
+ return $meta;
493
+ }
494
  }//end handleMediaLibraryImageUpload
495
 
496
+ protected function canConvertPng2Jpg($image) {
497
+ $transparent = 0;
498
+ $contents = file_get_contents($image);
499
+ if (ord(file_get_contents($image, false, null, 25, 1)) & 4) {
500
+ $transparent = 1;
501
+ }
502
+ if (stripos($contents, 'PLTE') !== false && stripos($contents, 'tRNS') !== false) {
503
+ $transparent = 1;
504
+ }
505
+ $transparent_pixel = $img = $bg = false;
506
+ if ($transparent) {
507
+ $img = imagecreatefrompng($image);
508
+ $w = imagesx($img); // Get the width of the image
509
+ $h = imagesy($img); // Get the height of the image
510
+ //run through pixels until transparent pixel is found:
511
+ for ($i = 0; $i < $w; $i++) {
512
+ for ($j = 0; $j < $h; $j++) {
513
+ $rgba = imagecolorat($img, $i, $j);
514
+ if (($rgba & 0x7F000000) >> 24) {
515
+ $transparent_pixel = true;
516
+ break;
517
+ }
518
+ }
519
+ }
520
+ }
521
+
522
+ return !$transparent || !$transparent_pixel;
523
+ }
524
+
525
+ /**
526
+ *
527
+ * @param type $params
528
+ * @param type $suffixRegex for example [0-9]+x[0-9]+ - a thumbnail suffix - to have the counter of file name collisions files before it.
529
+ * @param type $img
530
+ * @return string
531
+ */
532
+ protected function doConvertPng2Jpg($params, $suffixRegex = false, $img = false) {
533
+ if(!$img) {
534
+ $img = imagecreatefrompng($params['file']);
535
+ }
536
+
537
+ $bg = imagecreatetruecolor(imagesx($img), imagesy($img));
538
+ imagefill($bg, 0, 0, imagecolorallocate($bg, 255, 255, 255));
539
+ imagealphablending($bg, 1);
540
+ imagecopy($bg, $img, 0, 0, 0, 0, imagesx($img), imagesy($img));
541
+ $newPath = preg_replace("/\.png$/", ".jpg", $params['file']);
542
+ $newUrl = preg_replace("/\.png$/", ".jpg", $params['url']);
543
+ for ($i = 1; file_exists($newPath); $i++) {
544
+ if($suffixRegex) {
545
+ $newPath = preg_replace("/(" . $suffixRegex . ")\.png$/", $i . '-$1.jpg', $params['file']);
546
+ }else {
547
+ $newPath = preg_replace("/\.png$/", "-" . $i . ".jpg", $params['file']);
548
+ }
549
+ }
550
+ if (imagejpeg($bg, $newPath, 90)) {
551
+ $newSize = filesize($newPath);
552
+ $origSize = filesize($params['file']);
553
+ if($newSize > $origSize * 0.95) {
554
+ //if the image is not 5% smaller, don't bother.
555
+ unlink($newPath);
556
+ return $params;
557
+ }
558
+ unlink($params['file']);
559
+ $params['file'] = $newPath;
560
+ $params['url'] = $newUrl;
561
+ $params['type'] = 'image/jpeg';
562
+ }
563
+ return $params;
564
+ }
565
+
566
+ /**
567
+ * Convert an uploaded image from PNG to JPG
568
+ * @param type $params
569
+ * @return string
570
+ */
571
+ public function convertPng2Jpg($params) {
572
+
573
+ //echo("PARAMS : ");var_dump($params);
574
+ if(!$this->_settings->png2jpg || strtolower(substr($params['file'], -4)) !== '.png') {
575
+ return $params;
576
+ }
577
+
578
+ $image = $params['file'];
579
+ self::log("Convert Media PNG to JPG on upload: {$image}");
580
+
581
+ if ($this->canConvertPng2Jpg($image)) {
582
+ return $this->doConvertPng2Jpg($params);
583
+ }
584
+ return $params;
585
+ }
586
+
587
+ /**
588
+ * convert PNG to JPEG if possible
589
+ *
590
+ * @param type $meta
591
+ * @param type $ID
592
+ * @return string
593
+ */
594
+ public function checkConvertMediaPng2Jpg($meta, $ID) {
595
+
596
+ if(!$this->_settings->png2jpg || strtolower(substr($meta['file'], -4)) !== '.png') {
597
+ return $meta;
598
+ }
599
+
600
+ self::log("Send to processing: Convert Media PNG to JPG #{$ID}");
601
+
602
+ $image = $meta['file'];
603
+ $imagePath = get_attached_file($ID);
604
+ $basePath = trailingslashit(str_replace($image, "", $imagePath));
605
+
606
+ if(!$this->canConvertPng2Jpg($imagePath)) return $meta; //cannot convert it
607
+
608
+ $ret = $this->doConvertPng2Jpg(array('file' => $imagePath, 'url' => false, 'type' => 'image/png'));
609
+ //echo("CONVERT: " . $imagePath); var_dump($ret);
610
+
611
+ if ($ret['type'] == 'image/jpeg') {
612
+ //conversion succeeded for the main image, update meta and proceed to thumbs. (It could also not succeed if the converted file is not smaller)
613
+ $meta['file'] = str_replace($basePath, '', $ret['file']);
614
+
615
+ $baseRelPath = trailingslashit(dirname($image));
616
+ if(isset($meta['sizes'])) foreach($meta['sizes'] as $size => $info) {
617
+ $rett = $this->doConvertPng2Jpg(array('file' => $basePath . $baseRelPath . $info['file'], 'url' => false, 'type' => 'image/png'), "[0-9]+x[0-9]+");
618
+ //echo("CONVERT: " . $basePath . $baseRelPath . $info['file']); var_dump($rett);
619
+ if ($rett['type'] == 'image/jpeg') {
620
+ $meta['sizes'][$size]['file'] = wp_basename($rett['file']);
621
+ $meta['sizes'][$size]['mime-type'] = 'image/jpeg';
622
+ }
623
+ }
624
+ update_attached_file($ID, $meta['file']);
625
+ wp_update_attachment_metadata($ID, $meta);
626
+ }
627
+
628
+ return $meta;
629
+ }
630
+
631
  /**
632
  * this is hooked onto the NextGen upload
633
  * @param type $image
710
  if ( $startQueryID <= $endQueryID ) {
711
  return false;
712
  }
713
+
714
+ $this->prioQ->resetPrio();
715
 
716
  $startTime = time();
717
  $maxTime = (is_numeric(SHORTPIXEL_MAX_EXECUTION_TIME) && SHORTPIXEL_MAX_EXECUTION_TIME > 10 ? SHORTPIXEL_MAX_EXECUTION_TIME - 5 : 25);
735
  $item = new ShortPixelMetaFacade($crtStartQueryID);
736
  $meta = $item->getMeta();//wp_get_attachment_metadata($crtStartQueryID);
737
 
738
+ if($meta->getStatus() == 2 || $meta->getStatus() == 1) {
739
+ if($meta->getStatus() == 2 && $this->prioQ->getBulkType() == ShortPixelQueue::BULK_TYPE_RESTORE) {
740
+ $res = $this->doRestore($crtStartQueryID); //this is restore, the real
741
+ } else {
742
+ //this is only meta cleanup, no files are replaced (BACKUP REMAINS IN PLACE TOO)
743
+ $item->cleanupMeta();
744
+ $res = true;
745
+ }
746
  $restored[] = array('id' => $crtStartQueryID, 'status' => $res ? 'success' : 'fail');
747
  }
748
  }
781
  if ( empty($resultsPostMeta) ) {
782
  $crtStartQueryID -= SHORTPIXEL_MAX_RESULTS_QUERY;
783
  $startQueryID = $crtStartQueryID;
784
+ if(!count($idList)) { //none found so far, so decrease the start ID
785
+ //self::log("GETDB: empty slice. setStartBulkID to $startQueryID");
786
+ $this->prioQ->setStartBulkId($startQueryID);
787
+ }
788
  continue;
789
  }
790
 
886
  $this->_settings->lastBackAction = time();
887
  }
888
 
889
+ $rawPrioQ = $this->prioQ->get();
890
+ if(count($rawPrioQ)) { self::log("HIP: 0 Priority Queue: ".json_encode($rawPrioQ)); }
891
  //self::log("HIP: 0 Bulk running? " . $this->prioQ->bulkRunning() . " START " . $this->_settings->startBulkId . " STOP " . $this->_settings->stopBulkId);
892
 
893
  //handle the bulk restore and cleanup first - these are fast operations taking precedece over optimization
894
+ if( $this->prioQ->bulkRunning()
895
+ && ($this->prioQ->getBulkType() == ShortPixelQueue::BULK_TYPE_RESTORE || $this->prioQ->getBulkType() == ShortPixelQueue::BULK_TYPE_CLEANUP)) {
896
  $res = $this->bulkRestore();
897
  if($res === false) {
898
  $this->sendEmptyQueue();
926
  }
927
  }
928
 
929
+ //self::log("HIP: 0 Bulk ran: " . $this->prioQ->bulkRan());
930
  $customIds = false;
931
  if(count($ids) < 3 && $this->prioQ->bulkRan() && $this->_settings->hasCustomFolders
932
  && (!$this->_settings->cancelPointer || $this->_settings->skipToCustom)
933
  && !$this->_settings->customBulkPaused)
934
  { //take from custom images if any left to optimize - only if bulk was ever started
935
+ //but first refresh if it wasn't refreshed in the last hour
936
+ if(time() - $this->_settings->hasCustomFolders > 3600) {
937
+ $notice = null; $this->refreshCustomFolders($notice);
938
+ $this->_settings->hasCustomFolders = time();
939
+ }
940
  $customIds = $this->spMetaDao->getPendingMetas( 3 - count($ids));
941
  if(is_array($customIds)) {
942
  $ids = array_merge($ids, array_map(array('ShortPixelMetaFacade', 'getNewFromRow'), $customIds));
945
  //var_dump($ids);
946
  //die("za stop 2");
947
 
948
+ //self::log("HIP: 1 Prio Queue: ".json_encode($this->prioQ->get()));
949
+ if(count($ids)) { self::log("HIP: 1 Selected IDs: ".json_encode($ids));}
950
 
951
  //2: Send up to 3 files to the server for processing
952
  for($i = 0, $itemHandler = false; $ids !== false && $i < min(3, count($ids)); $i++) {
976
  "Message" => __('Searching images to optimize... ','shortpixel-image-optimiser') . $this->prioQ->getStartBulkId() . '->' . $this->prioQ->getStopBulkId() )));
977
  }
978
  //in this case the queue is really empty
979
+ //self::log("HIP: 1 STOP BULK");
980
  $bulkEverRan = $this->prioQ->stopBulk();
981
  $this->sendEmptyQueue();
982
  }
1156
  $percent = $this->prioQ->getBulkPercent();
1157
  if(0 + $pendingMeta > 0) {
1158
  $customMeta = $this->spMetaDao->getCustomMetaCount();
1159
+ $crtTotalFiles = is_array($this->_settings->currentStats) ? $this->_settings->currentStats['totalFiles'] : $this->_settings->currentStats;
1160
+ $totalPercent = round(($percent * $crtTotalFiles + ($customMeta - $pendingMeta) * 100) / ($crtTotalFiles + $customMeta));
1161
  $minutesRemaining = round($minutesRemaining * (100 - $totalPercent) / max(1, 100 - $percent));
1162
  $percent = $totalPercent;
1163
  }
1166
  }
1167
 
1168
  private function sendToProcessing($itemHandler, $compressionType = false, $onlyThumbs = false) {
1169
+
1170
+ if($itemHandler->getType() == ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE) { //currently only for ML
1171
+ $rawMeta = $this->checkConvertMediaPng2Jpg($itemHandler->getRawMeta(), $itemHandler->getId());
1172
+
1173
+ if(isset($rawMeta['type']) && $rawMeta['type'] == 'image/jpeg') {
1174
+ $itemHandler->setRawMeta($rawMeta);
1175
+ }
1176
+ }
1177
+
1178
  //WpShortPixelMediaLbraryAdapter::cleanupFoundThumbs($itemHandler);
1179
  $URLsAndPATHs = $this->getURLsAndPATHs($itemHandler, NULL, $onlyThumbs);
1180
 
1246
  public function handleManualOptimization() {
1247
  $imageId = $_GET['image_id'];
1248
  $cleanup = $_GET['cleanup'];
1249
+
1250
+ self::log("Handle Manual Optimization #{$imageId}");
1251
+
1252
  switch(substr($imageId, 0, 2)) {
1253
  case "N-":
1254
  return "Add the gallery to the custom folders list in ShortPixel settings.";
1320
 
1321
  public function getBackupFolder($file) {
1322
  if(realpath($file)) {
1323
+ $ret = $this->getBackupFolderInternal(realpath($file)); //found cases when $file contains for example /wp/../wp-content - clean it up
1324
+ if($ret) return $ret;
1325
  }
1326
+ //another chance at glory, maybe cleanup was too much? (we tried first the cleaned up version for historical reason, don't disturb the sleeping dragon, right? :))
1327
+ return $this->getBackupFolderInternal($file);
1328
+ }
1329
+
1330
+ private function getBackupFolderInternal($file) {
1331
  $fileExtension = strtolower(substr($file,strrpos($file,".")+1));
1332
  $SubDir = ShortPixelMetaFacade::returnSubDir($file, ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE);
1333
  $SubDirOld = ShortPixelMetaFacade::returnSubDirOld($file, ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE);
1491
  public function handleRestoreBackup() {
1492
  $attachmentID = intval($_GET['attachment_ID']);
1493
 
1494
+ self::log("Handle Restore Backup #{$attachmentID}");
1495
  $this->doRestore($attachmentID);
1496
 
1497
  // get the referring webpage location
1504
  }
1505
 
1506
  public function handleRedo() {
1507
+ self::log("Handle Redo #{$_GET['attachment_ID']} type {$_GET['type']}");
1508
+
1509
  die(json_encode($this->redo($_GET['attachment_ID'], $_GET['type'])));
1510
  }
1511
 
1628
  $quotaData = $this->getQuotaInformation();
1629
  }
1630
  if ( !$quotaData['APIKeyValid']) {
1631
+ if(strlen($this->_settings->apiKey)) $this->view->displayActivationNotice('generic', $quotaData['Message']);
1632
  return $quotaData;
1633
  }
1634
  //$tempus = microtime(true);
 
1635
 
1636
+ if( is_array($this->_settings->currentStats)
1637
+ && $this->_settings->currentStats['optimizePdfs'] == $this->_settings->optimizePdfs
1638
+ && (time() - $this->_settings->currentStats['time'] < 300))
1639
+ {
1640
+ $imageCount = $this->_settings->currentStats;
1641
+ } else {
1642
+ $imageCount = WpShortPixelMediaLbraryAdapter::countAllProcessableFiles($this->_settings->optimizePdfs);
1643
+ $imageCount['time'] = time();
1644
+ $imageCount['optimizePdfs'] = $this->_settings->optimizePdfs;
1645
+ $imageCount['quotaData'] = $quotaData;
1646
+ $this->_settings->currentStats = $imageCount;
1647
+ }
1648
 
1649
  //echo("Count took (seconds): " . (microtime(true) - $tempus));
1650
  foreach($imageCount as $key => $val) {
1720
  $customMediaListTable->display();
1721
  //push to the processing list the pending ones, just in case
1722
  //$count = $this->spMetaDao->getCustomMetaCount();
1723
+ if($this->_settings->autoMediaLibrary) foreach ($items as $item) {
1724
  if($item->status == 1){
1725
  $this->prioQ->push(ShortPixelMetaFacade::queuedId(ShortPixelMetaFacade::CUSTOM_TYPE, $item->id));
1726
  }
1789
  $this->_settings->customBulkPaused = 0;
1790
  }//end bulk restore was clicked
1791
 
1792
+ if(isset($_POST["bulkCleanup"]))
1793
+ {
1794
+ $this->prioQ->startBulk(ShortPixelQueue::BULK_TYPE_CLEANUP);
1795
+ $this->_settings->customBulkPaused = 0;
1796
+ }//end bulk restore was clicked
1797
+
1798
  if(isset($_POST["bulkProcessResume"]))
1799
  {
1800
  $this->prioQ->resumeBulk();
1821
  $msg = $this->bulkProgressMessage($this->prioQ->getDeltaBulkPercent(), $this->prioQ->getTimeRemaining());
1822
 
1823
  $this->view->displayBulkProcessingRunning($this->getPercent($quotaData), $msg, $quotaData['APICallsRemaining'], $this->getAverageCompression(),
1824
+ $this->prioQ->getBulkType() == ShortPixelQueue::BULK_TYPE_RESTORE ? 0 :
1825
+ ($this->prioQ->getBulkType() == ShortPixelQueue::BULK_TYPE_CLEANUP ? -1 : ($pendingMeta !== null ? ($this->prioQ->bulkRunning() ? 3 : 2) : 1)));
1826
 
1827
  } else
1828
  {
1967
  die(json_encode((object)$ret));
1968
  }
1969
 
1970
+ public function proposeUpgrade() {
1971
+ if ( !current_user_can( 'manage_options' ) ) {
1972
+ wp_die(__('You do not have sufficient permissions to access this page.','shortpixel-image-optimiser'));
1973
+ }
1974
+
1975
+ if( is_array($this->_settings->currentStats)
1976
+ && $this->_settings->currentStats['optimizePdfs'] == $this->_settings->optimizePdfs
1977
+ && (time() - $this->_settings->currentStats['time'] < 300))
1978
+ {
1979
+ $stats = $this->_settings->currentStats;
1980
+ } else {
1981
+ $stats = WpShortPixelMediaLbraryAdapter::countAllProcessableFiles($this->_settings->optimizePdfs);
1982
+ }
1983
+
1984
+ //$proposal = wp_remote_post($this->_settings->httpProto . "://shortpixel.com/propose-upgrade-frag", array(
1985
+ echo("<div style='color: #f50a0a; position: relative; top: -59px; right: -255px; height: 0px; font-weight: bold; font-size: 1.2em;'>atentie de trecut pe live propose-upgrade</div>");
1986
+ $proposal = wp_remote_post("http://dev.shortpixel.com/propose-upgrade-frag", array(
1987
+ 'method' => 'POST',
1988
+ 'timeout' => 10,
1989
+ 'redirection' => 5,
1990
+ 'httpversion' => '1.0',
1991
+ 'blocking' => true,
1992
+ 'headers' => array(),
1993
+ 'body' => json_encode(array(
1994
+ 'plugin_version' => SHORTPIXEL_IMAGE_OPTIMISER_VERSION,
1995
+ 'key' => $this->_settings->apiKey,
1996
+ 'm1' => $stats['totalM1'],
1997
+ 'm2' => $stats['totalM2'],
1998
+ 'm3' => $stats['totalM3'],
1999
+ 'm3' => $stats['totalM4'],
2000
+ 'filesTodo' => $stats['totalFiles'] - $stats['totalProcessedFiles']
2001
+ )),
2002
+ 'cookies' => array()
2003
+ ));
2004
+ if(is_wp_error( $proposal )) {
2005
+ $proposal = array('body' => '');
2006
+ }
2007
+ die($proposal['body']);
2008
+
2009
+ }
2010
+
2011
  public static function getCustomFolderBase() {
2012
  if(is_main_site()) {
2013
  $base = get_home_path();
2192
  $notice = array("status" => "success", "msg" => __('Folder added successfully.','shortpixel-image-optimiser'));
2193
  }
2194
  $customFolders = $this->spMetaDao->getFolders();
2195
+ $this->_settings->hasCustomFolders = time();
2196
  }
2197
 
2198
  $this->_settings->createWebp = (isset($_POST['createWebp']) ? 1: 0);
2199
  $this->_settings->createWebpMarkup = (isset($_POST['createWebpMarkup']) ? 1: 0);
2200
  $this->_settings->optimizeRetina = (isset($_POST['optimizeRetina']) ? 1: 0);
2201
  $this->_settings->optimizePdfs = (isset($_POST['optimizePdfs']) ? 1: 0);
2202
+ $this->_settings->png2jpg = (isset($_POST['png2jpg']) ? 1: 0);
2203
 
2204
  //die(var_dump($_POST['excludePatterns']));
2205
 
2298
  $ngGalleries = ShortPixelNextGenAdapter::getGalleries();
2299
  foreach($ngGalleries as $gallery) {
2300
  $folderMsg = $this->spMetaDao->newFolderFromPath($gallery, get_home_path(), self::getCustomFolderBase());
2301
+ $this->_settings->hasCustomFolders = time();
2302
  }
2303
  $customFolders = $this->spMetaDao->getFolders();
2304
  }
2560
  elseif(isset($data['ShortPixel']['WaitingProcessing'])) {
2561
  $renderData['status'] = $quotaExceeded ? 'quotaExceeded' : 'retry';
2562
  $renderData['message'] = "<img src=\"" . plugins_url( 'res/img/loading.gif', SHORTPIXEL_PLUGIN_FILE ) . "\" class='sp-loading-small'>&nbsp;" . __("Image waiting to be processed.",'shortpixel-image-optimiser');
2563
+ if($this->_settings->autoMediaLibrary && !$quotaExceeded && ($id > $this->prioQ->getFlagBulkId() || !$this->prioQ->bulkRunning())) {
2564
  $this->prioQ->push($id); //should be there but just to make sure
2565
  }
2566
  }
class/wp-shortpixel-settings.php CHANGED
@@ -38,6 +38,7 @@ class WPShortPixelSettings {
38
  'autoMediaLibrary' => array('key' => 'wp-short-pixel-auto-media-library', 'default' => 1),
39
  'optimizePdfs' => array('key' => 'wp-short-pixel-optimize-pdfs', 'default' => 1),
40
  'excludePatterns' => array('key' => 'wp-short-pixel-exclude-patterns', 'default' => array()),
 
41
 
42
  //optimize other images than the ones in Media Library
43
  'includeNextGen' => array('key' => 'wp-short-pixel-include-next-gen', 'default' => null),
@@ -45,7 +46,7 @@ class WPShortPixelSettings {
45
  'customBulkPaused' => array('key' => 'wp-short-pixel-custom-bulk-paused', 'default' => false),
46
 
47
  //stats, notices, etc.
48
- 'currentTotalFiles' => array('key' => 'wp-short-pixel-current-total-files', 'default' => null),
49
  'fileCount' => array('key' => 'wp-short-pixel-fileCount', 'default' => 0),
50
  'thumbsCount' => array('key' => 'wp-short-pixel-thumbnail-count', 'default' => 0),
51
  'under5Percent' => array('key' => 'wp-short-pixel-files-under-5-percent', 'default' => 0),
@@ -175,6 +176,11 @@ class WPShortPixelSettings {
175
  }
176
 
177
  public function setOpt($key, $val) {
178
- update_option($key, $val);
 
 
 
 
 
179
  }
180
  }
38
  'autoMediaLibrary' => array('key' => 'wp-short-pixel-auto-media-library', 'default' => 1),
39
  'optimizePdfs' => array('key' => 'wp-short-pixel-optimize-pdfs', 'default' => 1),
40
  'excludePatterns' => array('key' => 'wp-short-pixel-exclude-patterns', 'default' => array()),
41
+ 'png2jpg' => array('key' => 'wp-short-pixel-png2jpg', 'default' => 0),
42
 
43
  //optimize other images than the ones in Media Library
44
  'includeNextGen' => array('key' => 'wp-short-pixel-include-next-gen', 'default' => null),
46
  'customBulkPaused' => array('key' => 'wp-short-pixel-custom-bulk-paused', 'default' => false),
47
 
48
  //stats, notices, etc.
49
+ 'currentStats' => array('key' => 'wp-short-pixel-current-total-files', 'default' => null),
50
  'fileCount' => array('key' => 'wp-short-pixel-fileCount', 'default' => 0),
51
  'thumbsCount' => array('key' => 'wp-short-pixel-thumbnail-count', 'default' => 0),
52
  'under5Percent' => array('key' => 'wp-short-pixel-files-under-5-percent', 'default' => 0),
176
  }
177
 
178
  public function setOpt($key, $val) {
179
+ $ret = update_option($key, $val);
180
+ //hack for the situation when the option would just not update....
181
+ if($ret === false && $val != get_option($key)) {
182
+ delete_option($key);
183
+ update_option($key, $val);
184
+ }
185
  }
186
  }
readme.txt CHANGED
@@ -1,9 +1,9 @@
1
  === ShortPixel Image Optimizer ===
2
  Contributors: ShortPixel
3
- Tags: compress, image, compression, optimize, image optimizer, image compression, resize, compress pdf, compress jpg, compress png, image compression
4
  Requires at least: 3.2.0
5
  Tested up to: 4.8
6
- Stable tag: 4.6.0
7
  License: GPLv2 or later
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
 
@@ -28,8 +28,9 @@ Make an instant <a rel="friend" href="http://shortpixel.com/image-compression-te
28
 
29
  **Why is ShortPixel the best choice when it comes to image optimization or PDF compression?**
30
 
31
- * popular plugin with over 40,000 active installations according to WordPress
32
  * compress JPG, PNG, GIF (still or animated) images and also PDF documents
 
33
  * no file size limit
34
  * option to freely convert any JPEG, PNG or GIF (even animated ones!) to **WebP** for more Google love. <a rel="friend" href="http://blog.shortpixel.com/how-webp-images-can-speed-up-your-site/" target="_blank">How to enable WebP?</a>
35
  * option to include the generated WebP images into the front-end pages by using the &lt;picture&gt; tag instead of &lt;img&gt;
@@ -53,7 +54,7 @@ Make an instant <a rel="friend" href="http://shortpixel.com/image-compression-te
53
  * compatible with watermarking plugins
54
  * option to deactivate auto-optimizing images on upload
55
  * images that are optimized less that 5% are bonus
56
- * WooCommerce compatible
57
  * 40 days optimization report with all image details and overall statistics
58
  * **free optimization credits for non-profits**, <a href="https://shortpixel.com/contact" target="_blank">contact us</a> for details
59
 
@@ -96,6 +97,10 @@ Let's get ShortPixel plugin running on your WordPress website:
96
 
97
  == Frequently Asked Questions ==
98
 
 
 
 
 
99
  = Can I use the same API Key on multiple web sites? =
100
  Yes, you can.
101
  As long as you have available credits you can use a single API Key on as many websites as you wish!
@@ -222,6 +227,17 @@ The ShortPixel team is here to help. <a href="https://shortpixel.com/contact">Co
222
 
223
  == Changelog ==
224
 
 
 
 
 
 
 
 
 
 
 
 
225
  = 4.6.0 =
226
  * add a filter option to the Other Media table
227
  * fixes in order to comply with WP plugin guidelines
1
  === ShortPixel Image Optimizer ===
2
  Contributors: ShortPixel
3
+ Tags: compress, image, compression, optimize, image optimizer, image optimiser, image compression, resize, compress pdf, compress jpg, compress png, image compression
4
  Requires at least: 3.2.0
5
  Tested up to: 4.8
6
+ Stable tag: 4.7.0
7
  License: GPLv2 or later
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
 
28
 
29
  **Why is ShortPixel the best choice when it comes to image optimization or PDF compression?**
30
 
31
+ * popular plugin with over 50,000 active installations according to WordPress
32
  * compress JPG, PNG, GIF (still or animated) images and also PDF documents
33
+ * option to automatically convert PNG to JPG if that will result in smaller images. Ideal for large images in PNG format.
34
  * no file size limit
35
  * option to freely convert any JPEG, PNG or GIF (even animated ones!) to **WebP** for more Google love. <a rel="friend" href="http://blog.shortpixel.com/how-webp-images-can-speed-up-your-site/" target="_blank">How to enable WebP?</a>
36
  * option to include the generated WebP images into the front-end pages by using the &lt;picture&gt; tag instead of &lt;img&gt;
54
  * compatible with watermarking plugins
55
  * option to deactivate auto-optimizing images on upload
56
  * images that are optimized less that 5% are bonus
57
+ * WooCommerce, WP offload S3 compatible
58
  * 40 days optimization report with all image details and overall statistics
59
  * **free optimization credits for non-profits**, <a href="https://shortpixel.com/contact" target="_blank">contact us</a> for details
60
 
97
 
98
  == Frequently Asked Questions ==
99
 
100
+ = How does ShortPixel compare to other image optimisation plugins (e.g Smush, Imagify, TinyPNG, Kraken, EWWW)? =
101
+ ShortPixel has better compression rates, more features, supports backups and has very affordable one-time plans.
102
+ If you are serious about making an informed decision please take 10 minutes and read this <a rel="friend" href="https://blog.shortpixel.com/wp-image-optimization-wordpress-plugins/">article</a>.
103
+
104
  = Can I use the same API Key on multiple web sites? =
105
  Yes, you can.
106
  As long as you have available credits you can use a single API Key on as many websites as you wish!
227
 
228
  == Changelog ==
229
 
230
+ = 4.7.0 =
231
+ * convert PNG images to JPG option
232
+ * action called upon optimizing an image: do_action('shortpixel_image_optimized', $post_id);
233
+ * monitor Other Media folders for changes every hour
234
+ * button to delete all ShortPixel metadata making ShortPixel forget it optimized the images in Media Library
235
+ * plugin images at @2x
236
+ * cleanup Other Media tables
237
+ * fix wp-options that would not save in some circumstances
238
+ * fix generate webp <picture> tags when post guids are absolute URLs and image URLs are changed, or when site has HTTP/HTTPS versions
239
+ * fix problem with AMP pages when generating the <picture> tags - when using AMP for WP plugin AMP pages are not changed.
240
+
241
  = 4.6.0 =
242
  * add a filter option to the Other Media table
243
  * fixes in order to comply with WP plugin guidelines
res/css/short-pixel.css CHANGED
@@ -284,7 +284,7 @@ div.shortpixel-modal {
284
  width: 30%; /* Could be more or less, depending on screen size */
285
  min-width: 300px; /* Could be more or less, depending on screen size */
286
  }
287
- div.shortpixel-modal .sp-close-button {
288
  float: right;
289
  margin-top: 0px;
290
  background: transparent;
@@ -317,6 +317,7 @@ div.shortpixel-modal .sptw-modal-spinner {
317
  width:98%;
318
  background-color:white;
319
  padding:10px 10px 0;
 
320
  /*margin-top: 2em;*/
321
  }
322
 
284
  width: 30%; /* Could be more or less, depending on screen size */
285
  min-width: 300px; /* Could be more or less, depending on screen size */
286
  }
287
+ div.shortpixel-modal .sp-close-button, div.shortpixel-modal .sp-close-upgrade-button {
288
  float: right;
289
  margin-top: 0px;
290
  background: transparent;
317
  width:98%;
318
  background-color:white;
319
  padding:10px 10px 0;
320
+ position:relative;
321
  /*margin-top: 2em;*/
322
  }
323
 
res/img/slider.png CHANGED
Binary file
res/img/slider@2x.png ADDED
Binary file
res/js/short-pixel.js CHANGED
@@ -274,10 +274,34 @@ var ShortPixel = function() {
274
  });
275
  return browseResponse;
276
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
277
 
278
  function initFolderSelector() {
279
  jQuery(".select-folder-button").click(function(){
280
- jQuery(".sp-modal-shade").css("display", "block");
281
  jQuery(".sp-folder-picker").fileTree({
282
  script: ShortPixel.browseContent,
283
  //folderEvent: 'dblclick',
@@ -286,7 +310,7 @@ var ShortPixel = function() {
286
  });
287
  });
288
  jQuery(".shortpixel-modal input.select-folder-cancel").click(function(){
289
- jQuery(".sp-modal-shade").css("display", "none");
290
  });
291
  jQuery(".shortpixel-modal input.select-folder").click(function(){
292
  var subPath = jQuery("UL.jqueryFileTree LI.directory.selected A").attr("rel").trim();
@@ -295,7 +319,7 @@ var ShortPixel = function() {
295
  if(fullPath.slice(-1) == '/') fullPath = fullPath.slice(0, -1);
296
  jQuery("#addCustomFolder").val(fullPath);
297
  jQuery("#addCustomFolderView").val(fullPath);
298
- jQuery(".sp-modal-shade").css("display", "none");
299
  } else {
300
  alert("Please select a folder from the list.");
301
  }
@@ -353,6 +377,15 @@ var ShortPixel = function() {
353
  noticeTpl.after(notice);
354
  notice.css("display", "block");
355
  }
 
 
 
 
 
 
 
 
 
356
 
357
  function removeBulkMsg(me) {
358
  jQuery(me).parent().parent().remove();
@@ -485,11 +518,14 @@ var ShortPixel = function() {
485
  initFolderSelector : initFolderSelector,
486
  browseContent : browseContent,
487
  getBackupSize : getBackupSize,
 
 
488
  bulkShowLengthyMsg : bulkShowLengthyMsg,
489
  bulkHideLengthyMsg : bulkHideLengthyMsg,
490
  bulkShowMaintenanceMsg : bulkShowMaintenanceMsg,
491
  bulkHideMaintenanceMsg : bulkHideMaintenanceMsg,
492
  bulkShowError : bulkShowError,
 
493
  removeBulkMsg : removeBulkMsg,
494
  isCustomImageId : isCustomImageId,
495
  recheckQuota : recheckQuota,
274
  });
275
  return browseResponse;
276
  }
277
+
278
+ function proposeUpgrade() {
279
+ //first open the popup window with the spinner
280
+ jQuery("#shortPixelProposeUpgrade .sp-modal-body").addClass('sptw-modal-spinner');
281
+ jQuery("#shortPixelProposeUpgrade .sp-modal-body").html("");
282
+ jQuery("#shortPixelProposeUpgradeShade").css("display", "block");
283
+ jQuery("#shortPixelProposeUpgrade").removeClass('shortpixel-hide');
284
+ //get proposal from server
285
+ var browseData = { 'action': 'shortpixel_propose_upgrade'};
286
+ jQuery.ajax({
287
+ type: "POST",
288
+ url: ShortPixel.AJAX_URL,
289
+ data: browseData,
290
+ success: function(response) {
291
+ jQuery("#shortPixelProposeUpgrade .sp-modal-body").removeClass('sptw-modal-spinner');
292
+ jQuery("#shortPixelProposeUpgrade .sp-modal-body").html(response);
293
+ }
294
+ });
295
+ }
296
+
297
+ function closeProposeUpgrade() {
298
+ jQuery("#shortPixelProposeUpgradeShade").css("display", "none");
299
+ jQuery("#shortPixelProposeUpgrade").addClass('shortpixel-hide');
300
+ }
301
 
302
  function initFolderSelector() {
303
  jQuery(".select-folder-button").click(function(){
304
+ jQuery(".sp-folder-picker-shade").css("display", "block");
305
  jQuery(".sp-folder-picker").fileTree({
306
  script: ShortPixel.browseContent,
307
  //folderEvent: 'dblclick',
310
  });
311
  });
312
  jQuery(".shortpixel-modal input.select-folder-cancel").click(function(){
313
+ jQuery(".sp-folder-picker-shade").css("display", "none");
314
  });
315
  jQuery(".shortpixel-modal input.select-folder").click(function(){
316
  var subPath = jQuery("UL.jqueryFileTree LI.directory.selected A").attr("rel").trim();
319
  if(fullPath.slice(-1) == '/') fullPath = fullPath.slice(0, -1);
320
  jQuery("#addCustomFolder").val(fullPath);
321
  jQuery("#addCustomFolderView").val(fullPath);
322
+ jQuery(".sp-folder-picker-shade").css("display", "none");
323
  } else {
324
  alert("Please select a folder from the list.");
325
  }
377
  noticeTpl.after(notice);
378
  notice.css("display", "block");
379
  }
380
+
381
+ function confirmBulkAction(type, e) {
382
+ if(!confirm(_spTr['confirmBulk' + type])) {
383
+ e.stopPropagation();
384
+ e.preventDefault();
385
+ return false;
386
+ }
387
+ return true;
388
+ }
389
 
390
  function removeBulkMsg(me) {
391
  jQuery(me).parent().parent().remove();
518
  initFolderSelector : initFolderSelector,
519
  browseContent : browseContent,
520
  getBackupSize : getBackupSize,
521
+ proposeUpgrade : proposeUpgrade,
522
+ closeProposeUpgrade : closeProposeUpgrade,
523
  bulkShowLengthyMsg : bulkShowLengthyMsg,
524
  bulkHideLengthyMsg : bulkHideLengthyMsg,
525
  bulkShowMaintenanceMsg : bulkShowMaintenanceMsg,
526
  bulkHideMaintenanceMsg : bulkHideMaintenanceMsg,
527
  bulkShowError : bulkShowError,
528
+ confirmBulkAction : confirmBulkAction,
529
  removeBulkMsg : removeBulkMsg,
530
  isCustomImageId : isCustomImageId,
531
  recheckQuota : recheckQuota,
shortpixel_api.php CHANGED
@@ -580,6 +580,8 @@ class ShortPixelAPI {
580
  $meta->setStatus(2);
581
 
582
  $itemHandler->updateMeta($meta);
 
 
583
  if(!$originalSpace) { //das kann nicht sein, alles klar?!
584
  throw new Exception("OriginalSpace = 0. APIResponse" . json_encode($APIresponse));
585
  }
580
  $meta->setStatus(2);
581
 
582
  $itemHandler->updateMeta($meta);
583
+ $itemHandler->doActions();
584
+
585
  if(!$originalSpace) { //das kann nicht sein, alles klar?!
586
  throw new Exception("OriginalSpace = 0. APIResponse" . json_encode($APIresponse));
587
  }
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: 4.6.0
7
  * Author: ShortPixel
8
  * Author URI: https://shortpixel.com
9
  * Text Domain: shortpixel-image-optimiser
@@ -12,19 +12,22 @@
12
 
13
  define('SHORTPIXEL_RESET_ON_ACTIVATE', false); //if true TODO set false
14
  //define('SHORTPIXEL_DEBUG', true);
 
15
 
16
  define('SHORTPIXEL_PLUGIN_FILE', __FILE__);
17
 
18
  define('SHORTPIXEL_AFFILIATE_CODE', '');
19
 
20
- define('SHORTPIXEL_IMAGE_OPTIMISER_VERSION', "4.6.0");
21
  define('SHORTPIXEL_MAX_TIMEOUT', 10);
22
  define('SHORTPIXEL_VALIDATE_MAX_TIMEOUT', 15);
23
  define('SHORTPIXEL_BACKUP', 'ShortpixelBackups');
24
  define('SHORTPIXEL_MAX_API_RETRIES', 50);
25
  define('SHORTPIXEL_MAX_ERR_RETRIES', 5);
26
  define('SHORTPIXEL_MAX_FAIL_RETRIES', 3);
27
- define('SHORTPIXEL_MAX_THUMBS', 100);
 
 
28
 
29
  define('SHORTPIXEL_MAX_EXECUTION_TIME', ini_get('max_execution_time'));
30
 
@@ -75,6 +78,15 @@ function shortPixelHandleImageUploadHook($meta, $ID = null) {
75
  return $pluginInstance->handleMediaLibraryImageUpload($meta, $ID);
76
  }
77
 
 
 
 
 
 
 
 
 
 
78
  function shortPixelNggAdd($image) {
79
  global $pluginInstance;
80
  if(!isset($pluginInstance)) {
@@ -96,8 +108,12 @@ function shortPixelDeactivatePlugin () {
96
 
97
  //Picture generation, hooked on the_content filter
98
  function shortPixelConvertImgToPictureAddWebp($content) {
 
 
 
 
99
  require_once('class/front/img-to-picture-webp.php');
100
- return ShortPixelImgToPictureWebp::convert($content) . "<!-- PICTURE TAGS BY SHORTPIXEL -->";
101
  }
102
  function shortPixelAddPictureJs() {
103
  // Don't do anything with the RSS feed.
@@ -127,6 +143,10 @@ if ( !function_exists( 'vc_action' ) || vc_action() !== 'vc_inline' ) { //handle
127
  add_action( 'init', 'shortpixelInit');
128
  add_action('ngg_added_new_image', 'shortPixelNggAdd');
129
 
 
 
 
 
130
  $autoMediaLibrary = get_option('wp-short-pixel-auto-media-library');
131
  if($autoMediaLibrary) {
132
  add_filter( 'wp_generate_attachment_metadata', 'shortPixelHandleImageUploadHook', 10, 2 );
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: 4.7.0
7
  * Author: ShortPixel
8
  * Author URI: https://shortpixel.com
9
  * Text Domain: shortpixel-image-optimiser
12
 
13
  define('SHORTPIXEL_RESET_ON_ACTIVATE', false); //if true TODO set false
14
  //define('SHORTPIXEL_DEBUG', true);
15
+ //define('SHORTPIXEL_DEBUG_TARGET', true);
16
 
17
  define('SHORTPIXEL_PLUGIN_FILE', __FILE__);
18
 
19
  define('SHORTPIXEL_AFFILIATE_CODE', '');
20
 
21
+ define('SHORTPIXEL_IMAGE_OPTIMISER_VERSION', "4.7.0");
22
  define('SHORTPIXEL_MAX_TIMEOUT', 10);
23
  define('SHORTPIXEL_VALIDATE_MAX_TIMEOUT', 15);
24
  define('SHORTPIXEL_BACKUP', 'ShortpixelBackups');
25
  define('SHORTPIXEL_MAX_API_RETRIES', 50);
26
  define('SHORTPIXEL_MAX_ERR_RETRIES', 5);
27
  define('SHORTPIXEL_MAX_FAIL_RETRIES', 3);
28
+ if(!defined('SHORTPIXEL_MAX_THUMBS')) { //can be defined in wp-config.php
29
+ define('SHORTPIXEL_MAX_THUMBS', 100);
30
+ }
31
 
32
  define('SHORTPIXEL_MAX_EXECUTION_TIME', ini_get('max_execution_time'));
33
 
78
  return $pluginInstance->handleMediaLibraryImageUpload($meta, $ID);
79
  }
80
 
81
+ function shortPixelPng2JpgHook($params) {
82
+ global $pluginInstance;
83
+ if(!isset($pluginInstance)) {
84
+ require_once('wp-shortpixel-req.php');
85
+ $pluginInstance = new WPShortPixel;
86
+ }
87
+ return $pluginInstance->convertPng2Jpg($params);
88
+ }
89
+
90
  function shortPixelNggAdd($image) {
91
  global $pluginInstance;
92
  if(!isset($pluginInstance)) {
108
 
109
  //Picture generation, hooked on the_content filter
110
  function shortPixelConvertImgToPictureAddWebp($content) {
111
+ if(function_exists('is_amp_endpoint') && is_amp_endpoint()) {
112
+ //for AMP pages the <picture> tag is not allowed
113
+ return $content;
114
+ }
115
  require_once('class/front/img-to-picture-webp.php');
116
+ return ShortPixelImgToPictureWebp::convert($content);// . "<!-- PICTURE TAGS BY SHORTPIXEL -->";
117
  }
118
  function shortPixelAddPictureJs() {
119
  // Don't do anything with the RSS feed.
143
  add_action( 'init', 'shortpixelInit');
144
  add_action('ngg_added_new_image', 'shortPixelNggAdd');
145
 
146
+ $autoPng2Jpg = get_option('wp-short-pixel-png2jpg');
147
+ if($autoPng2Jpg) {
148
+ add_action( 'wp_handle_upload', 'shortPixelPng2JpgHook');
149
+ }
150
  $autoMediaLibrary = get_option('wp-short-pixel-auto-media-library');
151
  if($autoMediaLibrary) {
152
  add_filter( 'wp_generate_attachment_metadata', 'shortPixelHandleImageUploadHook', 10, 2 );