ShortPixel Image Optimizer - Version 4.8.0

Version Description

  • propose best plans options for optimizing all images
  • option to optimize or not the found unlisted thumbs, alert the user about them.
  • convert png to jpeg also when doing bulk if option set. Also search for usages of the image and replace the URLs in the content.
  • fix compatbility problem with S3 Offload which caused sending two different sets of URLs for an image.
  • trim site_url output - found a client case where it ended with a tab...
  • all wp_options with autoload=no
  • minify all js and css files
  • performance improvements for the picture tag generation
  • retina versions of the icons
  • fix "Optimize 0 thumbnails" in column menu generated from Javascript.
Download this release

Release Info

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

Code changes from version 4.7.2 to 4.8.0

class/db/shortpixel-meta-facade.php CHANGED
@@ -54,6 +54,7 @@ class ShortPixelMetaFacade {
54
  "webPath" => (isset($rawMeta["file"]) ? $rawMeta["file"] : null),
55
  "thumbs" => (isset($rawMeta["sizes"]) ? $rawMeta["sizes"] : array()),
56
  "message" =>(isset($rawMeta["ShortPixelImprovement"]) ? $rawMeta["ShortPixelImprovement"] : null),
 
57
  "compressionType" =>(isset($rawMeta["ShortPixel"]["type"])
58
  ? ($rawMeta["ShortPixel"]["type"] == 'glossy' ? 2 : ($rawMeta["ShortPixel"]["type"] == "lossy" ? 1 : 0) )
59
  : null),
@@ -197,6 +198,7 @@ class ShortPixelMetaFacade {
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;
@@ -272,7 +274,8 @@ class ShortPixelMetaFacade {
272
  }
273
 
274
  public static function getHomeUrl() {
275
- return trailingslashit((function_exists("is_multisite") && is_multisite()) ? network_site_url("/") : home_url());
 
276
  }
277
 
278
  //this is in test
@@ -369,7 +372,7 @@ class ShortPixelMetaFacade {
369
  WPShortPixel::log("getURLsAndPATHs: no meta sizes for ID " . $this->ID . " : " . json_encode($this->rawMeta));
370
  }
371
 
372
- if($onlyThumbs && $mainExists) { //remove the main image
373
  array_shift($urlList);
374
  array_shift($filePaths);
375
  }
@@ -541,7 +544,7 @@ class ShortPixelMetaFacade {
541
  * @param type $file
542
  * @return string
543
  */
544
- static public function returnSubDirOld($file, $type)
545
  {
546
  if(strstr($file, get_home_path())) {
547
  $path = str_replace( get_home_path(), "", $file);
@@ -559,7 +562,7 @@ class ShortPixelMetaFacade {
559
  * @param type $file
560
  * @return string
561
  */
562
- static public function returnSubDir($file, $type)
563
  {
564
  $hp = wp_normalize_path(get_home_path());
565
  $file = wp_normalize_path($file);
54
  "webPath" => (isset($rawMeta["file"]) ? $rawMeta["file"] : null),
55
  "thumbs" => (isset($rawMeta["sizes"]) ? $rawMeta["sizes"] : array()),
56
  "message" =>(isset($rawMeta["ShortPixelImprovement"]) ? $rawMeta["ShortPixelImprovement"] : null),
57
+ "png2jpg" => (isset($rawMeta["ShortPixelPng2Jpg"]) ? $rawMeta["ShortPixelPng2Jpg"] : false),
58
  "compressionType" =>(isset($rawMeta["ShortPixel"]["type"])
59
  ? ($rawMeta["ShortPixel"]["type"] == 'glossy' ? 2 : ($rawMeta["ShortPixel"]["type"] == "lossy" ? 1 : 0) )
60
  : null),
198
  }
199
  unset($rawMeta["ShortPixelImprovement"]);
200
  unset($rawMeta['ShortPixel']);
201
+ unset($rawMeta['ShortPixelPng2Jpg']);
202
  unset($this->meta);
203
  wp_update_attachment_metadata($this->ID, $rawMeta);
204
  $this->rawMeta = $rawMeta;
274
  }
275
 
276
  public static function getHomeUrl() {
277
+ //trim is because we found a site set up with a tab, like this: https://modernpeasantcooking.com\t
278
+ return trailingslashit((function_exists("is_multisite") && is_multisite()) ? trim(network_site_url("/")) : trim(home_url()));
279
  }
280
 
281
  //this is in test
372
  WPShortPixel::log("getURLsAndPATHs: no meta sizes for ID " . $this->ID . " : " . json_encode($this->rawMeta));
373
  }
374
 
375
+ if($onlyThumbs && $mainExists && count($urlList) > 1) { //remove the main image
376
  array_shift($urlList);
377
  array_shift($filePaths);
378
  }
544
  * @param type $file
545
  * @return string
546
  */
547
+ static public function returnSubDirOld($file)
548
  {
549
  if(strstr($file, get_home_path())) {
550
  $path = str_replace( get_home_path(), "", $file);
562
  * @param type $file
563
  * @return string
564
  */
565
+ static public function returnSubDir($file)
566
  {
567
  $hp = wp_normalize_path(get_home_path());
568
  $file = wp_normalize_path($file);
class/db/wp-shortpixel-media-library-adapter.php CHANGED
@@ -5,7 +5,7 @@ class WpShortPixelMediaLbraryAdapter {
5
  //count all the processable files in media library (while limiting the results to max 10000)
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();
@@ -18,6 +18,8 @@ class WpShortPixelMediaLbraryAdapter {
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);
@@ -35,7 +37,8 @@ class WpShortPixelMediaLbraryAdapter {
35
 
36
  foreach ( $filesList as $file )
37
  {
38
- $totalFilesThis = 0;
 
39
 
40
  if ( $file->meta_key == "_wp_attached_file" )
41
  {//count pdf files only
@@ -52,15 +55,50 @@ class WpShortPixelMediaLbraryAdapter {
52
  {
53
  $attachment = unserialize($file->meta_value);
54
  $sizesCount = isset($attachment['sizes']) ? WpShortPixelMediaLbraryAdapter::countNonWebpSizes($attachment['sizes']) : 0;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
  //processable
56
  $isProcessable = false;
57
- if( isset($attachment['file']) && !isset($filesMap[$attachment['file']])
 
 
 
 
 
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++;
@@ -70,14 +108,11 @@ class WpShortPixelMediaLbraryAdapter {
70
  }
71
  }
72
  //processed
73
- if (isset($attachment['ShortPixelImprovement'])
74
- && ($attachment['ShortPixelImprovement'] > 0 || $attachment['ShortPixelImprovement'] === 0.0 || $attachment['ShortPixelImprovement'] === "0")
75
- //for PDFs there is no file field so just let it pass.
76
- && (!isset($attachment['file']) || !isset($processedFilesMap[$attachment['file']])) ) {
77
-
78
  //add main file to counts
79
- $processedMainFiles++;
80
- $processedTotalFiles++;
 
81
  $type = isset($attachment['ShortPixel']['type']) ? $attachment['ShortPixel']['type'] : null;
82
  switch($type) {
83
  case 'lossy' :
@@ -101,10 +136,14 @@ class WpShortPixelMediaLbraryAdapter {
101
  $thumbs = $allThumbs = 0;
102
  if ( isset($attachment['ShortPixel']['thumbsOpt']) ) {
103
  $thumbs = $attachment['ShortPixel']['thumbsOpt'];
104
- }
105
  elseif ( isset($attachment['sizes']) ) {
106
  $thumbs = $sizesCount;
107
- }
 
 
 
 
108
  $thumbsMissing = isset($attachment['ShortPixel']['thumbsMissing']) ? $attachment['ShortPixel']['thumbsMissing'] : array();
109
 
110
  if ( isset($attachment['sizes']) && $sizesCount > $thumbs + count($thumbsMissing)) {
@@ -113,6 +152,7 @@ class WpShortPixelMediaLbraryAdapter {
113
 
114
  //increment with thumbs processed
115
  $processedTotalFiles += $thumbs;
 
116
  if($type == 'glossy') {
117
  $procGlossyTotalFiles += $thumbs;
118
  } elseif ($type == 'lossy') {
@@ -132,7 +172,12 @@ class WpShortPixelMediaLbraryAdapter {
132
  }
133
 
134
  }
135
-
 
 
 
 
 
136
  $dt = new DateTime($idInfo->idDates[$file->post_id]);
137
  if($dt > $month1) {
138
  $totalFilesM1 += $totalFilesThis;
@@ -147,7 +192,6 @@ class WpShortPixelMediaLbraryAdapter {
147
  }
148
  unset($filesList);
149
  $pointer += $limit;
150
-
151
  }//end while
152
 
153
  return array("totalFiles" => $totalFiles, "mainFiles" => $mainFiles,
@@ -163,6 +207,7 @@ class WpShortPixelMediaLbraryAdapter {
163
  "totalProcUndefMlFiles" => $procUndefTotalFiles, "mainProcUndefMlFiles" => $procUndefMainFiles,
164
  "mainUnprocessedThumbs" => $mainUnprocessedThumbs, "totalM1" => $totalFilesM1, "totalM2" => $totalFilesM2, "totalM3" => $totalFilesM3, "totalM4" => $totalFilesM4,
165
  "filesWithErrors" => $filesWithErrors,
 
166
  );
167
  }
168
 
5
  //count all the processable files in media library (while limiting the results to max 10000)
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();
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
+ $counter = 0; $foundUnlistedThumbs = false;
22
+
23
  //count all the files, main and thumbs
24
  while ( 1 ) {
25
  $idInfo = self::getPostIdsChunk($minId, $maxId, $pointer, $limit);
37
 
38
  foreach ( $filesList as $file )
39
  {
40
+ $totalFilesThis = $processedFilesThis = 0;
41
+ //if($file->post_id == 945) {var_dump($file);}
42
 
43
  if ( $file->meta_key == "_wp_attached_file" )
44
  {//count pdf files only
55
  {
56
  $attachment = unserialize($file->meta_value);
57
  $sizesCount = isset($attachment['sizes']) ? WpShortPixelMediaLbraryAdapter::countNonWebpSizes($attachment['sizes']) : 0;
58
+
59
+ // LA FIECARE 100 de imagini facem un test si daca findThumbs da diferit, sa dam o avertizare si eventual optiune
60
+ if( $foundUnlistedThumbs === false && $maxId == PHP_INT_MAX && (in_array($counter, array(2,4,6,8)) || floor($counter/100) == 0 && $counter%10 == 0
61
+ || floor($counter/1000) == 0 && $counter%100 == 0 || floor($counter/10000) == 0 && $counter%1000 == 0))
62
+ {
63
+ $filePath = isset($attachment['file']) ? trailingslashit(SHORTPIXEL_UPLOADS_BASE).$attachment['file'] : false;
64
+ if ($filePath && file_exists($filePath) && isset($attachment['sizes']) &&
65
+ ( !isset($attachment['ShortPixelImprovement']) || $attachment['ShortPixelImprovement'] === 0
66
+ || $attachment['ShortPixelImprovement'] === 0.0 || $attachment['ShortPixelImprovement'] === "0"))
67
+ {
68
+ $foundThumbs = WpShortPixelMediaLbraryAdapter::findThumbs($filePath);
69
+ $foundCount = count($foundThumbs);
70
+ //echo(" <br>&gt; $counter CHECKING FILE THUMBS: FOUND $foundCount "
71
+ // . ($foundCount > $sizesCount ? " DIFFERENT ($sizesCount)!" : ""));
72
+ if(count($foundThumbs) > $sizesCount) {
73
+ $unlisted = array();
74
+ foreach($foundThumbs as $found) {
75
+ $match = ShortPixelTools::findItem(wp_basename($found), $attachment['sizes'], 'file');
76
+ if(!$match) {
77
+ $unlisted[] = wp_basename($found);
78
+ }
79
+ }
80
+ //echo( " UNLISTED for {$file->post_id} : " . json_encode($unlisted));
81
+ $foundUnlistedThumbs = (object)array("id" => $file->post_id, "name" => wp_basename($attachment['file']), "unlisted" => $unlisted);
82
+ }
83
+ } else {
84
+ $counter--; // will take the next one
85
+ $realSizesCount = $sizesCount;
86
+ }
87
+ }
88
+ $counter++;
89
+
90
  //processable
91
  $isProcessable = false;
92
+ $isProcessed = isset($attachment['ShortPixelImprovement'])
93
+ && ($attachment['ShortPixelImprovement'] > 0 || $attachment['ShortPixelImprovement'] === 0.0 || $attachment['ShortPixelImprovement'] === "0")
94
+ //for PDFs there is no file field so just let it pass.
95
+ && (!isset($attachment['file']) || !isset($processedFilesMap[$attachment['file']]));
96
+
97
+ if( isset($attachment['file']) && !isset($filesMap[$attachment['file']])
98
  && WPShortPixel::_isProcessablePath($attachment['file'], array(), $excludePatterns)){
99
  $isProcessable = true;
100
+ $totalFiles += $sizesCount;
101
+ $totalFilesThis += $sizesCount;
 
 
102
  if ( isset($attachment['file']) )
103
  {
104
  $totalFiles++;
108
  }
109
  }
110
  //processed
111
+ if ($isProcessed) {
 
 
 
 
112
  //add main file to counts
113
+ $processedMainFiles++;
114
+ $processedTotalFiles++;
115
+ $processedFilesThis++;
116
  $type = isset($attachment['ShortPixel']['type']) ? $attachment['ShortPixel']['type'] : null;
117
  switch($type) {
118
  case 'lossy' :
136
  $thumbs = $allThumbs = 0;
137
  if ( isset($attachment['ShortPixel']['thumbsOpt']) ) {
138
  $thumbs = $attachment['ShortPixel']['thumbsOpt'];
139
+ }
140
  elseif ( isset($attachment['sizes']) ) {
141
  $thumbs = $sizesCount;
142
+ }
143
+ if(!isset($attachment['file'])) { //for the pdfs that have thumbs, have to add the thumbs too (not added above )
144
+ $totalFiles += $thumbs;
145
+ $totalFilesThis += $thumbs;
146
+ }
147
  $thumbsMissing = isset($attachment['ShortPixel']['thumbsMissing']) ? $attachment['ShortPixel']['thumbsMissing'] : array();
148
 
149
  if ( isset($attachment['sizes']) && $sizesCount > $thumbs + count($thumbsMissing)) {
152
 
153
  //increment with thumbs processed
154
  $processedTotalFiles += $thumbs;
155
+ $processedFilesThis += $thumbs;
156
  if($type == 'glossy') {
157
  $procGlossyTotalFiles += $thumbs;
158
  } elseif ($type == 'lossy') {
172
  }
173
 
174
  }
175
+
176
+ if( false && $totalFilesThis < $processedFilesThis) {
177
+ echo(" <br>ID: {$file->post_id} {$file->meta_key} SIZESCOUNT: $sizesCount ". ($isProcessed ? "isProcessed" : "")
178
+ ." TOTAL: $totalFiles PROCESSED: $processedTotalFiles TOTAL FILES THIS: $totalFilesThis PROCESSED THIS $processedFilesThis ");
179
+ }
180
+
181
  $dt = new DateTime($idInfo->idDates[$file->post_id]);
182
  if($dt > $month1) {
183
  $totalFilesM1 += $totalFilesThis;
192
  }
193
  unset($filesList);
194
  $pointer += $limit;
 
195
  }//end while
196
 
197
  return array("totalFiles" => $totalFiles, "mainFiles" => $mainFiles,
207
  "totalProcUndefMlFiles" => $procUndefTotalFiles, "mainProcUndefMlFiles" => $procUndefMainFiles,
208
  "mainUnprocessedThumbs" => $mainUnprocessedThumbs, "totalM1" => $totalFilesM1, "totalM2" => $totalFilesM2, "totalM3" => $totalFilesM3, "totalM4" => $totalFilesM4,
209
  "filesWithErrors" => $filesWithErrors,
210
+ "foundUnlistedThumbs" => $foundUnlistedThumbs
211
  );
212
  }
213
 
class/front/img-to-picture-webp.php CHANGED
@@ -10,24 +10,31 @@ class ShortPixelImgToPictureWebp {
10
  // Don't do anything with the RSS feed.
11
  if ( is_feed() || is_admin() ) { return $content; }
12
 
13
- return preg_replace_callback('/<img[^>]*>/', function ($match) {
 
14
  // Do nothing with images that has the 'rwp-not-responsive' class.
15
  if ( strpos($match[0], 'sp-no-webp') ) { return $match[0]; }
16
 
17
- $img = self::get_attributes($match[0]);
18
 
19
  $src = (isset($img['src'])) ? $img['src'] : false;
20
  $srcset = (isset($img['srcset'])) ? $img['srcset'] : false;
21
  $sizes = (isset($img['sizes'])) ? $img['sizes'] : false;
22
 
23
  //check if there are webps
24
- $id = self::url_to_attachment_id( $src );
25
  if(!$id) {
26
  return $match[0];
27
  }
28
-
29
  $imageBase = dirname(get_attached_file($id)) . '/';
30
-
 
 
 
 
 
 
 
31
  // We don't wanna have an src attribute on the <img>
32
  unset($img['src']);
33
  //unset($img['srcset']);
@@ -64,7 +71,7 @@ class ShortPixelImgToPictureWebp {
64
  return '<picture>'
65
  .'<source srcset="' . $srcsetWebP . '"' . ($sizes ? ' sizes="' . $sizes . '"' : '') . ' type="image/webp">'
66
  .'<source srcset="' . $srcset . '"' . ($sizes ? ' sizes="' . $sizes . '"' : '') . '>'
67
- .'<img src="' . $src . '" ' . self::create_attributes($img) . '>'
68
  .'</picture>';
69
  }, $content);
70
  }
10
  // Don't do anything with the RSS feed.
11
  if ( is_feed() || is_admin() ) { return $content; }
12
 
13
+ $thisClass = __CLASS__; // hack for PHP 5.3 which doesn't accept self:: in closures
14
+ return preg_replace_callback('/<img[^>]*>/', function ($match) use ($thisClass) {
15
  // Do nothing with images that has the 'rwp-not-responsive' class.
16
  if ( strpos($match[0], 'sp-no-webp') ) { return $match[0]; }
17
 
18
+ $img = $thisClass::get_attributes($match[0]);
19
 
20
  $src = (isset($img['src'])) ? $img['src'] : false;
21
  $srcset = (isset($img['srcset'])) ? $img['srcset'] : false;
22
  $sizes = (isset($img['sizes'])) ? $img['sizes'] : false;
23
 
24
  //check if there are webps
25
+ /*$id = $thisClass::url_to_attachment_id( $src );
26
  if(!$id) {
27
  return $match[0];
28
  }
 
29
  $imageBase = dirname(get_attached_file($id)) . '/';
30
+ */
31
+ $updir = wp_upload_dir();
32
+ $imageBase = str_replace($updir['baseurl'], $updir['basedir'], $src);
33
+ if($imageBase == $src) {
34
+ return $match[0];
35
+ }
36
+ $imageBase = dirname($imageBase) . '/';
37
+
38
  // We don't wanna have an src attribute on the <img>
39
  unset($img['src']);
40
  //unset($img['srcset']);
71
  return '<picture>'
72
  .'<source srcset="' . $srcsetWebP . '"' . ($sizes ? ' sizes="' . $sizes . '"' : '') . ' type="image/webp">'
73
  .'<source srcset="' . $srcset . '"' . ($sizes ? ' sizes="' . $sizes . '"' : '') . '>'
74
+ .'<img src="' . $src . '" ' . $thisClass::create_attributes($img) . '>'
75
  .'</picture>';
76
  }, $content);
77
  }
class/model/shortpixel-meta.php CHANGED
@@ -11,6 +11,7 @@ class ShortPixelMeta extends ShortPixelEntity{
11
  protected $webPath;
12
  protected $compressionType;
13
  protected $compressedSize;
 
14
  protected $thumbsOpt;
15
  protected $thumbsOptList;
16
  protected $thumbsMissing;
@@ -121,6 +122,14 @@ class ShortPixelMeta extends ShortPixelEntity{
121
  return $this->compressedSize;
122
  }
123
 
 
 
 
 
 
 
 
 
124
  function setName($name) {
125
  $this->name = $name;
126
  }
11
  protected $webPath;
12
  protected $compressionType;
13
  protected $compressedSize;
14
+ protected $png2Jpg;
15
  protected $thumbsOpt;
16
  protected $thumbsOptList;
17
  protected $thumbsMissing;
122
  return $this->compressedSize;
123
  }
124
 
125
+ function getPng2Jpg() {
126
+ return $this->png2Jpg;
127
+ }
128
+
129
+ function setPng2Jpg($png2jpg) {
130
+ $this->png2Jpg = $png2jpg;
131
+ }
132
+
133
  function setName($name) {
134
  $this->name = $name;
135
  }
class/shortpixel-tools.php CHANGED
@@ -54,4 +54,20 @@ class ShortPixelTools {
54
  @header( 'Content-Type: application/json; charset=' . get_option( 'blog_charset' ) );
55
  die(json_encode($response));
56
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
57
  }
54
  @header( 'Content-Type: application/json; charset=' . get_option( 'blog_charset' ) );
55
  die(json_encode($response));
56
  }
57
+
58
+ /**
59
+ * finds if an array contains an item, comparing the property given as key
60
+ * @param $item
61
+ * @param $arr
62
+ * @param $key
63
+ * @return the position that was removed, false if not found
64
+ */
65
+ public static function findItem($item, $arr, $key) {
66
+ foreach($arr as $elm) {
67
+ if($elm[$key] == $item) {
68
+ return $elm;
69
+ }
70
+ }
71
+ return false;
72
+ }
73
  }
class/shortpixel_queue.php CHANGED
@@ -357,8 +357,8 @@ class ShortPixelQueue {
357
  delete_option( 'wp-short-pixel-cancel-pointer');
358
  delete_option( "wp-short-pixel-flag-id");
359
  $startBulkId = $stopBulkId = ShortPixelMetaFacade::getMaxMediaId();
360
- update_option( 'wp-short-pixel-query-id-stop', $startBulkId );
361
- update_option( 'wp-short-pixel-query-id-start', $startBulkId );
362
  delete_option( "wp-short-pixel-bulk-previous-percent");
363
  delete_option( "wp-short-pixel-bulk-processed-items");
364
  delete_option('wp-short-pixel-bulk-running-time');
357
  delete_option( 'wp-short-pixel-cancel-pointer');
358
  delete_option( "wp-short-pixel-flag-id");
359
  $startBulkId = $stopBulkId = ShortPixelMetaFacade::getMaxMediaId();
360
+ update_option( 'wp-short-pixel-query-id-stop', $startBulkId, 'no');
361
+ update_option( 'wp-short-pixel-query-id-start', $startBulkId, 'no');
362
  delete_option( "wp-short-pixel-bulk-previous-percent");
363
  delete_option( "wp-short-pixel-bulk-processed-items");
364
  delete_option('wp-short-pixel-bulk-running-time');
class/view/shortpixel_view.php CHANGED
@@ -30,6 +30,9 @@ class ShortPixelView {
30
  </div>
31
  </div>
32
  <?php } ?>
 
 
 
33
  <h3><?php /* translators: header of the alert box */ _e('Quota Exceeded','shortpixel-image-optimiser');?></h3>
34
  <p><?php /* translators: body of the alert box */
35
  if($recheck) {
@@ -44,7 +47,12 @@ class ShortPixelView {
44
  number_format(max(0, ($quotaData['totalFiles'] - $quotaData['mainFiles']) - ($quotaData['totalProcessedFiles'] - $quotaData['mainProcessedFiles'])))); ?>
45
  <?php } ?></p>
46
  <div> <!-- style='float:right;margin-top:20px;'> -->
47
- <a class='button button-primary' href='https://shortpixel.com/login/<?php echo($this->ctrl->getApiKey());?>' target='_blank'><?php _e('Upgrade','shortpixel-image-optimiser');?></a>
 
 
 
 
 
48
  <input type='button' name='checkQuota' class='button' value='<?php _e('Confirm New Quota','shortpixel-image-optimiser');?>'
49
  onclick="ShortPixel.recheckQuota()">
50
  </div>
@@ -54,7 +62,7 @@ class ShortPixelView {
54
  </a> <?php _e('for your unique referral link. For each user that joins, you will receive +100 additional image credits/month.','shortpixel-image-optimiser');?>
55
  </p>
56
 
57
- </div> <?php
58
  }
59
 
60
  public static function displayApiKeyAlert()
@@ -69,15 +77,39 @@ class ShortPixelView {
69
  }
70
 
71
  public static function displayActivationNotice($when = 'activate', $extra = '') {
72
- $extraStyle = $when == 'compat' ? "style='border-left: 4px solid#ff0000;'" : '';
 
 
 
 
 
 
 
73
  ?>
74
  <div class='notice notice-warning' id='short-pixel-notice-<?php echo($when);?>' <?php echo($extraStyle);?>>
75
  <?php if($when != 'activate') { ?>
76
- <div style="float:right;"><a href="javascript:dismissShortPixelNotice('<?php echo($when);?>')" class="button" style="margin-top:10px;"><?php _e('Dismiss','shortpixel-image-optimiser');?></a></div>
77
- <?php } ?>
78
- <h3><?php
79
- if($when == 'compat') {_e('Warning','shortpixel-image-optimiser'); echo(' - ');}
80
- _e('ShortPixel Image Optimizer','shortpixel-image-optimiser');?></h3> <?php
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
81
  switch($when) {
82
  case '2h' :
83
  _e("Action needed. Please <a href='https://shortpixel.com/wp-apikey' target='_blank'>get your API key</a> to activate your ShortPixel plugin.",'shortpixel-image-optimiser') . "<BR><BR>";
@@ -105,24 +137,21 @@ class ShortPixelView {
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;
@@ -132,6 +161,19 @@ class ShortPixelView {
132
  <?php
133
  }
134
 
 
 
 
 
 
 
 
 
 
 
 
 
 
135
  public function displayBulkProcessingForm($quotaData, $thumbsProcessedCount, $under5PercentCount, $bulkRan,
136
  $averageCompression, $filesOptimized, $savedSpace, $percent, $customCount) {
137
  ?>
@@ -177,7 +219,8 @@ class ShortPixelView {
177
  <a href='javascript:void(0);' onclick="document.getElementById('startBulk').submit();" class='button'>
178
  <div style="width: 320px">
179
  <div class="bulk-btn-img" class="bulk-btn-img">
180
- <img src='<?php echo(plugins_url( 'shortpixel-image-optimiser/res/img/robo-slider.png' ));?>'/>
 
181
  </div>
182
  <div class="bulk-btn-txt">
183
  <?php printf(__('<span class="label">Start Optimizing</span><br> <span class="total">%s</span> images','shortpixel-image-optimiser'),
@@ -418,7 +461,9 @@ class ShortPixelView {
418
  printf(__('Already <strong>%s</strong> optimized images will not be reprocessed.','shortpixel-image-optimiser'), $todo ? ($optType) : '');
419
  if($reopt) { ?>
420
  <br><?php _e('Please note that reoptimizing images as <strong>lossy/lossless</strong> may use additional credits.','shortpixel-image-optimiser')?>
421
- <a href="http://blog.shortpixel.com/the-all-new-re-optimization-functions-in-shortpixel/" target="_blank"><?php _e('More info','shortpixel-image-optimiser');?></a>
 
 
422
  <?php } ?>
423
  </p>
424
  <form action='' method='POST' >
@@ -606,10 +651,10 @@ class ShortPixelView {
606
  <?php foreach($failed as $fail) {
607
  if($fail->type == ShortPixelMetaFacade::CUSTOM_TYPE) {
608
  $meta = $fail->meta;
609
- ?> <div class="label"><a href="<?php echo(ShortPixelMetaFacade::getHomeUrl() . $fail->meta->getWebPath());?>"><?php echo(substr($fail->meta->getName(), 0, 80));?> - ID: C-<?php echo($fail->id);?></a></div><br/>
610
  <?php } else {
611
- $meta = wp_get_attachment_metadata($fail);
612
- ?> <div class="label"><a href="/wp-admin/post.php?post=<?php echo($fail->id);?>&action=edit"><?php echo(substr($fail->meta["file"], 0, 80));?> - ID: <?php echo($fail->id);?></a></div><br/>
613
  <?php }
614
  }?>
615
  </div>
@@ -646,8 +691,10 @@ class ShortPixelView {
646
  <article id="shortpixel-settings-tabs" class="sp-tabs">
647
  <form name='wp_shortpixel_options' action='options-general.php?page=wp-shortpixel&noheader=true' method='post' id='wp_shortpixel_options'>
648
  <section <?php echo($showAdvanced ? "" : "class='sel-tab'");?> id="tab-settings">
 
649
  <h2><a class='tab-link' href='javascript:void(0);' data-id="tab-settings"><?php _e('General','shortpixel-image-optimiser');?></a></h2>
650
- <?php $this->displaySettingsForm($showApiKey, $editApiKey, $quotaData);?>
 
651
  </section>
652
  <?php if($this->ctrl->getVerifiedKey()) {?>
653
  <section <?php echo($showAdvanced ? "class='sel-tab'" : "");?> id="tab-adv-settings">
@@ -691,12 +738,13 @@ class ShortPixelView {
691
  $settings = $this->ctrl->getSettings();
692
  $checked = ($this->ctrl->processThumbnails() ? 'checked' : '');
693
  $checkedBackupImages = ($this->ctrl->backupImages() ? 'checked' : '');
694
- $cmyk2rgb = ($this->ctrl->getCMYKtoRGBconversion() ? 'checked' : '');
695
  $removeExif = ($settings->keepExif ? '' : 'checked');
696
  $resize = ($this->ctrl->getResizeImages() ? 'checked' : '');
697
  $resizeDisabled = ($this->ctrl->getResizeImages() ? '' : 'disabled');
698
  $minSizes = $this->ctrl->getMaxIntermediateImageSize();
699
  $thumbnailsToProcess = isset($quotaData['totalFiles']) ? ($quotaData['totalFiles'] - $quotaData['mainFiles']) - ($quotaData['totalProcessedFiles'] - $quotaData['mainProcessedFiles']) : 0;
 
 
700
  ?>
701
  <div class="wp-shortpixel-options">
702
  <?php if($this->ctrl->getVerifiedKey()) { ?>
@@ -710,22 +758,35 @@ class ShortPixelView {
710
  <tr>
711
  <th scope="row"><label for="key"><?php _e('E-mail address:','shortpixel-image-optimiser');?></label></th>
712
  <td>
713
- <input name="pluginemail" type="text" id="pluginemail" value="<?php echo( get_bloginfo('admin_email') );?>"
714
  onchange="ShortPixel.updateSignupEmail();" class="regular-text">
 
715
  <a type="button" id="request_key" class="button button-primary" title="<?php _e('Request a new API key','shortpixel-image-optimiser');?>"
716
- href="https://shortpixel.com/free-sign-up?pluginemail=<?php echo( get_bloginfo('admin_email') );?>"
717
- onmouseenter="ShortPixel.updateSignupEmail();" target="_blank">
 
718
  <?php _e('Request Key','shortpixel-image-optimiser');?>
719
  </a>
720
- <p class="settings-info">
721
- <?php printf(__('<b>%s</b> is the e-mail address in your WordPress Settings. You can use it, or change it to any valid e-mail address that you own.','shortpixel-image-optimiser'), get_bloginfo('admin_email'));?>
 
 
 
 
 
 
 
722
  </p>
723
  </td>
724
  </tr>
725
  </tbody>
726
  </table>
727
- <h3><?php _e('Step 2:','shortpixel-image-optimiser');?></h3>
728
- <p style='font-size: 14px'><?php _e('Please enter here the API Key you received by email and press Validate.','shortpixel-image-optimiser');?></p>
 
 
 
 
729
  <?php }
730
  }?>
731
  <table class="form-table">
@@ -750,6 +811,7 @@ class ShortPixelView {
750
  ?>" class="regular-text">
751
  <?php } ?>
752
  <input type="hidden" name="validate" id="valid" value=""/>
 
753
  <button type="button" id="validate" class="button button-primary" title="<?php _e('Validate the provided API key','shortpixel-image-optimiser');?>"
754
  onclick="ShortPixel.validateKey()" <?php echo $canValidate ? "" : "disabled"?>><?php _e('Validate','shortpixel-image-optimiser');?></button>
755
  <?php if($showApiKey && !$editApiKey) { ?>
@@ -774,7 +836,10 @@ class ShortPixelView {
774
  <input type="radio" name="compressionType" value="2" <?php echo( $this->ctrl->getCompressionType() == 2 ? "checked" : "" );?>><?php
775
  _e('Glossy','shortpixel-image-optimiser');?></br>
776
  <p class="settings-info"><?php _e('<b>Glossy compression: </b>creates images that are almost pixel-perfect identical to the originals.</br> Best option for photographers and other professionals that use very high quality images on their sites and want best compression while keeping the quality untouched.','shortpixel-image-optimiser');?>
777
- </p></br>
 
 
 
778
  <input type="radio" name="compressionType" value="0" <?php echo( $this->ctrl->getCompressionType() == 0 ? "checked" : "" );?>><?php
779
  _e('Lossless','shortpixel-image-optimiser');?>
780
  <p class="settings-info">
@@ -804,13 +869,6 @@ class ShortPixelView {
804
  <p class="settings-info"><?php _e('You <strong>need to have backup active</strong> in order to be able to restore images to originals or to convert from Lossy to Lossless and back.','shortpixel-image-optimiser');?></p>
805
  </td>
806
  </tr>
807
- <tr>
808
- <th scope="row"><label for="cmyk2rgb"><?php _e('CMYK to RGB conversion','shortpixel-image-optimiser');?></label></th>
809
- <td>
810
- <input name="cmyk2rgb" type="checkbox" id="cmyk2rgb" <?php echo( $cmyk2rgb );?>><?php _e('Adjust your images for computer and mobile screen display.','shortpixel-image-optimiser');?>
811
- <p class="settings-info"><?php _e('Images for the web only need RGB format and converting them from CMYK to RGB makes them smaller.','shortpixel-image-optimiser');?></p>
812
- </td>
813
- </tr>
814
  <tr>
815
  <th scope="row"><label for="removeExif"><?php _e('Remove EXIF','shortpixel-image-optimiser');?></label></th>
816
  <td>
@@ -824,21 +882,28 @@ class ShortPixelView {
824
  <td>
825
  <input name="resize" type="checkbox" id="resize" <?php echo( $resize );?>> <?php
826
  _e('to maximum','shortpixel-image-optimiser');?> <input type="text" name="width" id="width" style="width:70px" class="resize-sizes"
827
- value="<?php echo( $this->ctrl->getResizeWidth() > 0 ? $this->ctrl->getResizeWidth() : min(1024, $minSizes['width']) );?>" <?php echo( $resizeDisabled );?>/> <?php
828
  _e('pixels wide &times;','shortpixel-image-optimiser');?>
829
  <input type="text" name="height" id="height" class="resize-sizes" style="width:70px"
830
- value="<?php echo( $this->ctrl->getResizeHeight() > 0 ? $this->ctrl->getResizeHeight() : min(1024, $minSizes['height']) );?>" <?php echo( $resizeDisabled );?>/> <?php
831
  _e('pixels high (original aspect ratio is preserved and image is not cropped)','shortpixel-image-optimiser');?>
832
  <input type="hidden" id="min-width" value="<?php echo($minSizes['width']);?>"/>
833
  <input type="hidden" id="min-height" value="<?php echo($minSizes['height']);?>"/>
834
  <p class="settings-info">
835
- <?php _e('Recommended for large photos, like the ones taken with your phone. Saved space can go up to 80% or more after resizing.','shortpixel-image-optimiser');?><br/>
 
 
 
836
  </p>
837
  <div style="margin-top: 10px;">
838
  <input type="radio" name="resize_type" id="resize_type_outer" value="outer" <?php echo($settings->resizeType == 'inner' ? '' : 'checked') ?> style="margin: -50px 10px 60px 0;">
839
- <img src="<?php echo(plugins_url( 'shortpixel-image-optimiser/res/img/resize-outer.png' ));?>" title="<?php _e('Sizes will be greater or equal to the corresponding value. For example, if you set the resize dimensions at 1000x1200, an image of 2000x3000px will be resized to 1000x1500px while an image of 3000x2000px will be resized to 1800x1200px','shortpixel-image-optimiser');?>">
 
 
840
  <input type="radio" name="resize_type" id="resize_type_inner" value="inner" <?php echo($settings->resizeType == 'inner' ? 'checked' : '') ?> style="margin: -50px 10px 60px 35px;">
841
- <img src="<?php echo(plugins_url( 'shortpixel-image-optimiser/res/img/resize-inner.png' ));?>" title="<?php _e('Sizes will be smaller or equal to the corresponding value. For example, if you set the resize dimensions at 1000x1200, an image of 2000x3000px will be resized to 800x1200px while an image of 3000x2000px will be resized to 1000x667px','shortpixel-image-optimiser');?>">
 
 
842
  </div>
843
  </td>
844
  </tr>
@@ -852,8 +917,8 @@ class ShortPixelView {
852
  <script>
853
  jQuery(document).ready(function () {
854
  ShortPixel.setupGeneralTab(document.wp_shortpixel_options.compressionType,
855
- Math.min(1024, <?php echo($minSizes['width']);?>),
856
- Math.min(1024, <?php echo($minSizes['height']);?>));
857
  });
858
  </script>
859
  <?php }
@@ -865,10 +930,12 @@ class ShortPixelView {
865
  $hasNextGen = $this->ctrl->hasNextGen();
866
  $frontBootstrap = ($settings->frontBootstrap ? 'checked' : '');
867
  $includeNextGen = ($settings->includeNextGen ? 'checked' : '');
 
868
  $createWebp = ($settings->createWebp ? 'checked' : '');
869
  $createWebpMarkup = ($settings->createWebpMarkup ? 'checked' : '');
870
  $autoMediaLibrary = ($settings->autoMediaLibrary ? 'checked' : '');
871
  $optimizeRetina = ($settings->optimizeRetina ? 'checked' : '');
 
872
  $optimizePdfs = ($settings->optimizePdfs ? 'checked' : '');
873
  $excludePatterns = "";
874
  if($settings->excludePatterns) {
@@ -954,6 +1021,9 @@ class ShortPixelView {
954
  <input type="submit" name="saveAdv" id="saveAdvAddFolder" class="button button-primary" title="<?php _e('Add Folder','shortpixel-image-optimiser');?>" value="<?php _e('Add Folder','shortpixel-image-optimiser');?>">
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">
@@ -986,16 +1056,26 @@ class ShortPixelView {
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. <strong>It currently works only on new media uploaded and provides no backup.</strong>','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>
996
  <input name="createWebp" type="checkbox" id="createWebp" <?php echo( $createWebp );?>> <?php _e('Create also <a href="http://blog.shortpixel.com/how-webp-images-can-speed-up-your-site/" target="_blank">WebP versions</a> of the images <strong>for free</strong>.','shortpixel-image-optimiser');?>
997
  <p class="settings-info">
998
  <?php _e('WebP images can be up to three times smaller than PNGs and 25% smaller than JPGs. Choosing this option <strong>does not use up additional credits</strong>.','shortpixel-image-optimiser');?>
 
 
 
999
  </p>
1000
  </td>
1001
  </tr>
@@ -1013,7 +1093,19 @@ class ShortPixelView {
1013
  <td>
1014
  <input name="optimizeRetina" type="checkbox" id="optimizeRetina" <?php echo( $optimizeRetina );?>> <?php _e('Optimize also the Retina images (@2x) if they exist.','shortpixel-image-optimiser');?>
1015
  <p class="settings-info">
1016
- <?php _e('If you have a Retina plugin that generates Retina-specific images (@2x), ShortPixel can optimize them too, alongside the regular Media Library images and thumbnails. <a href="http://blog.shortpixel.com/how-to-use-optimized-retina-images-on-your-wordpress-site-for-best-user-experience-on-apple-devices/" target="_blank">More info.</a>','shortpixel-image-optimiser');?>
 
 
 
 
 
 
 
 
 
 
 
 
1017
  </p>
1018
  </td>
1019
  </tr>
@@ -1231,6 +1323,7 @@ class ShortPixelView {
1231
  }
1232
  $successText .= ($data['webpCount'] ? "<br>+" . $data['webpCount'] . __(" WebP images", 'shortpixel-image-optimiser') : "")
1233
  . "<br>EXIF: " . ($data['exifKept'] ? __('kept','shortpixel-image-optimiser') : __('removed','shortpixel-image-optimiser'))
 
1234
  . "<br>" . __("Optimized on", 'shortpixel-image-optimiser') . ": " . $data['date']
1235
  . $missingThumbs;
1236
  }
@@ -1241,14 +1334,16 @@ class ShortPixelView {
1241
 
1242
  break;
1243
  }
1244
- //die(var_dump($data));
 
 
1245
  ?>
1246
  </div>
1247
  <?php
1248
  }
1249
 
1250
  public function getSuccessText($percent, $bonus, $type, $thumbsOpt = 0, $thumbsTotal = 0, $retinasOpt = 0) {
1251
- return ($percent ? __('Reduced by','shortpixel-image-optimiser') . ' <strong>' . $percent . '%</strong> ' : '')
1252
  .(!$bonus ? ' ('.$type.')':'')
1253
  .($bonus && $percent ? '<br>' : '')
1254
  .($bonus ? __('Bonus processing','shortpixel-image-optimiser') : '')
@@ -1306,7 +1401,7 @@ class ShortPixelView {
1306
  <a class='button button-smaller' href='admin.php?action=shortpixel_check_quota'>"
1307
  . __('Check&nbsp;&nbsp;Quota','shortpixel-image-optimiser') .
1308
  "</a></div>
1309
- <div class='sp-column-info'>" . $message . " Quota Exceeded.</div>";
1310
  }
1311
 
1312
  public function outputComparerHTML() {?>
@@ -1314,7 +1409,7 @@ class ShortPixelView {
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;">
30
  </div>
31
  </div>
32
  <?php } ?>
33
+ <img src="<?php echo(plugins_url('/shortpixel-image-optimiser/res/img/robo-scared.png'));?>"
34
+ srcset='<?php echo(plugins_url( 'shortpixel-image-optimiser/res/img/robo-scared.png' ));?> 1x, <?php echo(plugins_url( 'shortpixel-image-optimiser/res/img/robo-scared@2x.png' ));?> 2x'
35
+ class='short-pixel-notice-icon'>
36
  <h3><?php /* translators: header of the alert box */ _e('Quota Exceeded','shortpixel-image-optimiser');?></h3>
37
  <p><?php /* translators: body of the alert box */
38
  if($recheck) {
47
  number_format(max(0, ($quotaData['totalFiles'] - $quotaData['mainFiles']) - ($quotaData['totalProcessedFiles'] - $quotaData['mainProcessedFiles'])))); ?>
48
  <?php } ?></p>
49
  <div> <!-- style='float:right;margin-top:20px;'> -->
50
+ <button class="button button-primary" id="shortpixel-upgrade-advice" onclick="ShortPixel.proposeUpgrade()" style="margin-right:10px;"><strong>
51
+ <?php _e('Show me the best available options', 'shortpixel_image_optimiser'); ?></strong></button>
52
+ <a class='button button-primary' href='https://shortpixel.com/login/<?php echo($this->ctrl->getApiKey());?>'
53
+ title='<?php _e('Go to my account and select a plan','shortpixel-image-optimiser');?>' target='_blank' style="margin-right:10px;">
54
+ <strong><?php _e('Upgrade','shortpixel-image-optimiser');?></strong>
55
+ </a>
56
  <input type='button' name='checkQuota' class='button' value='<?php _e('Confirm New Quota','shortpixel-image-optimiser');?>'
57
  onclick="ShortPixel.recheckQuota()">
58
  </div>
62
  </a> <?php _e('for your unique referral link. For each user that joins, you will receive +100 additional image credits/month.','shortpixel-image-optimiser');?>
63
  </p>
64
 
65
+ </div> <?php self::includeProposeUpgradePopup();
66
  }
67
 
68
  public static function displayApiKeyAlert()
77
  }
78
 
79
  public static function displayActivationNotice($when = 'activate', $extra = '') {
80
+ $extraStyle = $when == 'compat' ? "style='border-left: 4px solid #ff0000;'" :
81
+ ($when == 'upgmonth' || $when == 'upgbulk' ? "style='border-left: 4px solid #46b450;'" : '');
82
+ $icon = false;
83
+ switch($when) {
84
+ case 'unlisted': $icon = 'magnifier'; break;
85
+ case 'upgmonth':
86
+ case 'upgbulk': $icon = 'notes'; break;
87
+ }
88
  ?>
89
  <div class='notice notice-warning' id='short-pixel-notice-<?php echo($when);?>' <?php echo($extraStyle);?>>
90
  <?php if($when != 'activate') { ?>
91
+ <div style="float:right;">
92
+ <?php if($when == 'upgmonth' || $when == 'upgbulk'){ ?>
93
+ <button class="button button-primary" id="shortpixel-upgrade-advice" onclick="ShortPixel.proposeUpgrade()" style="margin-top:10px;margin-left:10px;"><strong>
94
+ <?php _e('Show me the best available options', 'shortpixel_image_optimiser'); ?></strong></button>
95
+ <?php } ?>
96
+ <?php if($when == 'unlisted'){ ?>
97
+ <a href="javascript:ShortPixel.includeUnlisted()" class="button button-primary" style="margin-top:10px;margin-left:10px;">
98
+ <strong><?php _e('Yes, include these thumbnails','shortpixel-image-optimiser');?></strong></a>
99
+ <?php } ?>
100
+ <a href="javascript:dismissShortPixelNotice('<?php echo($when);?>')" class="button" style="margin-top:10px;"><?php _e('Dismiss','shortpixel-image-optimiser');?></a>
101
+ </div>
102
+ <?php if($icon){ ?>
103
+ <img src="<?php echo(plugins_url('/shortpixel-image-optimiser/res/img/robo-' . $icon . '.png'));?>"
104
+ srcset='<?php echo(plugins_url( 'shortpixel-image-optimiser/res/img/robo-' . $icon . '.png' ));?> 1x, <?php echo(plugins_url( 'shortpixel-image-optimiser/res/img/robo-' . $icon . '@2x.png' ));?> 2x'
105
+ class='short-pixel-notice-icon'>
106
+ <?php }
107
+ } ?>
108
+ <h3><?php _e('ShortPixel Image Optimizer','shortpixel-image-optimiser');
109
+ if($when == 'compat') { echo(' '); _e('Warning','shortpixel-image-optimiser');}
110
+ if($when == 'unlisted') { echo(' '); _e(' alert','shortpixel-image-optimiser');}
111
+ if($when == 'upgmonth' || $when == 'upgbulk') { echo(' '); _e('advice','shortpixel-image-optimiser');}
112
+ ?></h3> <?php
113
  switch($when) {
114
  case '2h' :
115
  _e("Action needed. Please <a href='https://shortpixel.com/wp-apikey' target='_blank'>get your API key</a> to activate your ShortPixel plugin.",'shortpixel-image-optimiser') . "<BR><BR>";
137
  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>."
138
  . " You might need to upgrade you plan in order to have all your images optimized.", 'shortpixel_image_optimiser'), $extra['monthAvg'], $extra['monthlyQuota']);
139
  } else {
140
+ printf(__("You currently have <strong>%d images and thumbnails to optimize</strong> but you only you have <strong>%d images</strong> available in your current plan."
141
  . " You might need to upgrade you plan in order to have all your images optimized.", 'shortpixel_image_optimiser'), $extra['filesTodo'], $extra['quotaAvailable']);
142
+ }?></p><?php
143
+ self::includeProposeUpgradePopup();
144
+ break;
145
+ case 'unlisted' :
146
+ _e("<p>ShortPixel found thumbnails which are not registered in the metadata but present alongside the other thumbnails. These thumbnails could be created and needed by some plugin or by the theme. Let ShortPixel optimize them as well?</p>", 'shortpixel-image-optimiser');?>
147
+ <p>
148
+ <?php _e("For example, the image", 'shortpixel-image-optimiser');?>
149
+ <a href='post.php?post=<?php echo($extra->id);?>&action=edit' target='_blank'>
150
+ <?php echo($extra->name); ?>
151
+ </a> has also these thumbs not listed in metadata:
152
+ <?php echo(implode(', ', $extra->unlisted)); ?>
153
+ </p><?php
154
+ break;
 
 
 
155
  case 'generic' :
156
  echo("<p>$extra</p>");
157
  break;
161
  <?php
162
  }
163
 
164
+ protected static function includeProposeUpgradePopup() { ?>
165
+ <div id="shortPixelProposeUpgradeShade" class="sp-modal-shade" style="display:none;">
166
+ <div id="shortPixelProposeUpgrade" class="shortpixel-modal shortpixel-hide" style="min-width: 610px;">
167
+ <div class="sp-modal-title">
168
+ <button type="button" class="sp-close-upgrade-button" onclick="ShortPixel.closeProposeUpgrade()">&times;</button>
169
+ <?php _e('Upgrade your ShortPixel account', 'shortpixel-image-optimiser');?>
170
+ </div>
171
+ <div class="sp-modal-body sptw-modal-spinner" style="height:auto;min-height:400px;padding:0;">
172
+ </div>
173
+ </div>
174
+ </div>
175
+ <?php }
176
+
177
  public function displayBulkProcessingForm($quotaData, $thumbsProcessedCount, $under5PercentCount, $bulkRan,
178
  $averageCompression, $filesOptimized, $savedSpace, $percent, $customCount) {
179
  ?>
219
  <a href='javascript:void(0);' onclick="document.getElementById('startBulk').submit();" class='button'>
220
  <div style="width: 320px">
221
  <div class="bulk-btn-img" class="bulk-btn-img">
222
+ <img src='<?php echo(plugins_url( 'shortpixel-image-optimiser/res/img/robo-slider.png' ));?>'
223
+ srcset='<?php echo(plugins_url( 'shortpixel-image-optimiser/res/img/robo-slider.png' ));?> 1x, <?php echo(plugins_url( 'shortpixel-image-optimiser/res/img/robo-slider@2x.png' ));?> 2x'/>
224
  </div>
225
  <div class="bulk-btn-txt">
226
  <?php printf(__('<span class="label">Start Optimizing</span><br> <span class="total">%s</span> images','shortpixel-image-optimiser'),
461
  printf(__('Already <strong>%s</strong> optimized images will not be reprocessed.','shortpixel-image-optimiser'), $todo ? ($optType) : '');
462
  if($reopt) { ?>
463
  <br><?php _e('Please note that reoptimizing images as <strong>lossy/lossless</strong> may use additional credits.','shortpixel-image-optimiser')?>
464
+ <a href="http://blog.shortpixel.com/the-all-new-re-optimization-functions-in-shortpixel/" target="_blank" class="shortpixel-help-link">
465
+ <span class="dashicons dashicons-editor-help"></span><?php _e('More info','shortpixel-image-optimiser');?>
466
+ </a>
467
  <?php } ?>
468
  </p>
469
  <form action='' method='POST' >
651
  <?php foreach($failed as $fail) {
652
  if($fail->type == ShortPixelMetaFacade::CUSTOM_TYPE) {
653
  $meta = $fail->meta;
654
+ ?> <div><a href="<?php echo(ShortPixelMetaFacade::getHomeUrl() . $meta->getWebPath());?>"><?php echo(substr($meta->getName(), 0, 80));?> - ID: C-<?php echo($fail->id);?></a></div><br/>
655
  <?php } else {
656
+ $meta = isset($fail->meta) ? $fail->meta : wp_get_attachment_metadata($fail->id);
657
+ ?> <div><a href="/wp-admin/post.php?post=<?php echo($fail->id);?>&action=edit"><?php echo(substr($meta["file"], 0, 80));?> - ID: <?php echo($fail->id);?></a></div><br/>
658
  <?php }
659
  }?>
660
  </div>
691
  <article id="shortpixel-settings-tabs" class="sp-tabs">
692
  <form name='wp_shortpixel_options' action='options-general.php?page=wp-shortpixel&noheader=true' method='post' id='wp_shortpixel_options'>
693
  <section <?php echo($showAdvanced ? "" : "class='sel-tab'");?> id="tab-settings">
694
+ <?php if($this->ctrl->getVerifiedKey()) { ?>
695
  <h2><a class='tab-link' href='javascript:void(0);' data-id="tab-settings"><?php _e('General','shortpixel-image-optimiser');?></a></h2>
696
+ <?php }
697
+ $this->displaySettingsForm($showApiKey, $editApiKey, $quotaData);?>
698
  </section>
699
  <?php if($this->ctrl->getVerifiedKey()) {?>
700
  <section <?php echo($showAdvanced ? "class='sel-tab'" : "");?> id="tab-adv-settings">
738
  $settings = $this->ctrl->getSettings();
739
  $checked = ($this->ctrl->processThumbnails() ? 'checked' : '');
740
  $checkedBackupImages = ($this->ctrl->backupImages() ? 'checked' : '');
 
741
  $removeExif = ($settings->keepExif ? '' : 'checked');
742
  $resize = ($this->ctrl->getResizeImages() ? 'checked' : '');
743
  $resizeDisabled = ($this->ctrl->getResizeImages() ? '' : 'disabled');
744
  $minSizes = $this->ctrl->getMaxIntermediateImageSize();
745
  $thumbnailsToProcess = isset($quotaData['totalFiles']) ? ($quotaData['totalFiles'] - $quotaData['mainFiles']) - ($quotaData['totalProcessedFiles'] - $quotaData['mainProcessedFiles']) : 0;
746
+ $adminEmail = get_bloginfo('admin_email');
747
+ if($adminEmail == 'noreply@addendio.com') $adminEmail = false; //hack for the addendio sandbox e-mail
748
  ?>
749
  <div class="wp-shortpixel-options">
750
  <?php if($this->ctrl->getVerifiedKey()) { ?>
758
  <tr>
759
  <th scope="row"><label for="key"><?php _e('E-mail address:','shortpixel-image-optimiser');?></label></th>
760
  <td>
761
+ <input name="pluginemail" type="text" id="pluginemail" value="<?php echo( $adminEmail );?>"
762
  onchange="ShortPixel.updateSignupEmail();" class="regular-text">
763
+ <span class="spinner" id="pluginemail_spinner" style="float:none;"></span>
764
  <a type="button" id="request_key" class="button button-primary" title="<?php _e('Request a new API key','shortpixel-image-optimiser');?>"
765
+ href="https://shortpixel.com/free-sign-up?pluginemail=<?php echo( $adminEmail );?>"
766
+ onclick="ShortPixel.newApiKey(event);"
767
+ onmouseenter="ShortPixel.updateSignupEmail();">
768
  <?php _e('Request Key','shortpixel-image-optimiser');?>
769
  </a>
770
+ <p class="settings-info shortpixel-settings-error" style='display:none;' id='pluginemail-error'>
771
+ <b><?php _e('Please provide a valid e-mail address.', 'shortpixel-image-optimiser');?></b>
772
+ </p>
773
+ <p class="settings-info" id='pluginemail-info'>
774
+ <?php if($adminEmail) {
775
+ printf(__('<b>%s</b> is the e-mail address in your WordPress Settings. You can use it, or change it to any valid e-mail address that you own.','shortpixel-image-optimiser'), $adminEmail);
776
+ } else {
777
+ _e('Please input your e-mail address and press the Request Key button.','shortpixel-image-optimiser');
778
+ }?>
779
  </p>
780
  </td>
781
  </tr>
782
  </tbody>
783
  </table>
784
+ <h3>
785
+ <?php _e('Step 2:','shortpixel-image-optimiser');?>
786
+ </h3>
787
+ <p style='font-size: 14px'>
788
+ <?php _e('Please enter here the API Key and press Validate.','shortpixel-image-optimiser');?>
789
+ </p>
790
  <?php }
791
  }?>
792
  <table class="form-table">
811
  ?>" class="regular-text">
812
  <?php } ?>
813
  <input type="hidden" name="validate" id="valid" value=""/>
814
+ <span class="spinner" id="pluginemail_spinner" style="float:none;"></span>
815
  <button type="button" id="validate" class="button button-primary" title="<?php _e('Validate the provided API key','shortpixel-image-optimiser');?>"
816
  onclick="ShortPixel.validateKey()" <?php echo $canValidate ? "" : "disabled"?>><?php _e('Validate','shortpixel-image-optimiser');?></button>
817
  <?php if($showApiKey && !$editApiKey) { ?>
836
  <input type="radio" name="compressionType" value="2" <?php echo( $this->ctrl->getCompressionType() == 2 ? "checked" : "" );?>><?php
837
  _e('Glossy','shortpixel-image-optimiser');?></br>
838
  <p class="settings-info"><?php _e('<b>Glossy compression: </b>creates images that are almost pixel-perfect identical to the originals.</br> Best option for photographers and other professionals that use very high quality images on their sites and want best compression while keeping the quality untouched.','shortpixel-image-optimiser');?>
839
+ <a href="http://blog.shortpixel.com/glossy-image-optimization-for-photographers/" target="_blank" class="shortpixel-help-link">
840
+ <span class="dashicons dashicons-editor-help"></span><?php _e('More info about glossy','shortpixel-image-optimiser');?>
841
+ </a></p>
842
+ </br>
843
  <input type="radio" name="compressionType" value="0" <?php echo( $this->ctrl->getCompressionType() == 0 ? "checked" : "" );?>><?php
844
  _e('Lossless','shortpixel-image-optimiser');?>
845
  <p class="settings-info">
869
  <p class="settings-info"><?php _e('You <strong>need to have backup active</strong> in order to be able to restore images to originals or to convert from Lossy to Lossless and back.','shortpixel-image-optimiser');?></p>
870
  </td>
871
  </tr>
 
 
 
 
 
 
 
872
  <tr>
873
  <th scope="row"><label for="removeExif"><?php _e('Remove EXIF','shortpixel-image-optimiser');?></label></th>
874
  <td>
882
  <td>
883
  <input name="resize" type="checkbox" id="resize" <?php echo( $resize );?>> <?php
884
  _e('to maximum','shortpixel-image-optimiser');?> <input type="text" name="width" id="width" style="width:70px" class="resize-sizes"
885
+ value="<?php echo( $this->ctrl->getResizeWidth() > 0 ? $this->ctrl->getResizeWidth() : min(924, $minSizes['width']) );?>" <?php echo( $resizeDisabled );?>/> <?php
886
  _e('pixels wide &times;','shortpixel-image-optimiser');?>
887
  <input type="text" name="height" id="height" class="resize-sizes" style="width:70px"
888
+ value="<?php echo( $this->ctrl->getResizeHeight() > 0 ? $this->ctrl->getResizeHeight() : min(924, $minSizes['height']) );?>" <?php echo( $resizeDisabled );?>/> <?php
889
  _e('pixels high (original aspect ratio is preserved and image is not cropped)','shortpixel-image-optimiser');?>
890
  <input type="hidden" id="min-width" value="<?php echo($minSizes['width']);?>"/>
891
  <input type="hidden" id="min-height" value="<?php echo($minSizes['height']);?>"/>
892
  <p class="settings-info">
893
+ <?php _e('Recommended for large photos, like the ones taken with your phone. Saved space can go up to 80% or more after resizing.','shortpixel-image-optimiser');?>
894
+ <a href="https://blog.shortpixel.com/resize-images/" class="shortpixel-help-link" target="_blank">
895
+ <span class="dashicons dashicons-editor-help"></span><?php _e('Read more','shortpixel-image-optimiser');?>
896
+ </a><br/>
897
  </p>
898
  <div style="margin-top: 10px;">
899
  <input type="radio" name="resize_type" id="resize_type_outer" value="outer" <?php echo($settings->resizeType == 'inner' ? '' : 'checked') ?> style="margin: -50px 10px 60px 0;">
900
+ <img src="<?php echo(plugins_url( 'shortpixel-image-optimiser/res/img/resize-outer.png' ));?>"
901
+ srcset='<?php echo(plugins_url( 'shortpixel-image-optimiser/res/img/resize-outer.png' ));?> 1x, <?php echo(plugins_url( 'shortpixel-image-optimiser/res/img/resize-outer@2x.png' ));?> 2x'
902
+ title="<?php _e('Sizes will be greater or equal to the corresponding value. For example, if you set the resize dimensions at 1000x1200, an image of 2000x3000px will be resized to 1000x1500px while an image of 3000x2000px will be resized to 1800x1200px','shortpixel-image-optimiser');?>">
903
  <input type="radio" name="resize_type" id="resize_type_inner" value="inner" <?php echo($settings->resizeType == 'inner' ? 'checked' : '') ?> style="margin: -50px 10px 60px 35px;">
904
+ <img src="<?php echo(plugins_url( 'shortpixel-image-optimiser/res/img/resize-inner.png' ));?>"
905
+ srcset='<?php echo(plugins_url( 'shortpixel-image-optimiser/res/img/resize-inner.png' ));?> 1x, <?php echo(plugins_url( 'shortpixel-image-optimiser/res/img/resize-inner@2x.png' ));?> 2x'
906
+ title="<?php _e('Sizes will be smaller or equal to the corresponding value. For example, if you set the resize dimensions at 1000x1200, an image of 2000x3000px will be resized to 800x1200px while an image of 3000x2000px will be resized to 1000x667px','shortpixel-image-optimiser');?>">
907
  </div>
908
  </td>
909
  </tr>
917
  <script>
918
  jQuery(document).ready(function () {
919
  ShortPixel.setupGeneralTab(document.wp_shortpixel_options.compressionType,
920
+ Math.min(924, <?php echo($minSizes['width']);?>),
921
+ Math.min(924, <?php echo($minSizes['height']);?>));
922
  });
923
  </script>
924
  <?php }
930
  $hasNextGen = $this->ctrl->hasNextGen();
931
  $frontBootstrap = ($settings->frontBootstrap ? 'checked' : '');
932
  $includeNextGen = ($settings->includeNextGen ? 'checked' : '');
933
+ $cmyk2rgb = ($this->ctrl->getCMYKtoRGBconversion() ? 'checked' : '');
934
  $createWebp = ($settings->createWebp ? 'checked' : '');
935
  $createWebpMarkup = ($settings->createWebpMarkup ? 'checked' : '');
936
  $autoMediaLibrary = ($settings->autoMediaLibrary ? 'checked' : '');
937
  $optimizeRetina = ($settings->optimizeRetina ? 'checked' : '');
938
+ $optimizeUnlisted = ($settings->optimizeUnlisted ? 'checked' : '');
939
  $optimizePdfs = ($settings->optimizePdfs ? 'checked' : '');
940
  $excludePatterns = "";
941
  if($settings->excludePatterns) {
1021
  <input type="submit" name="saveAdv" id="saveAdvAddFolder" class="button button-primary" title="<?php _e('Add Folder','shortpixel-image-optimiser');?>" value="<?php _e('Add Folder','shortpixel-image-optimiser');?>">
1022
  <p class="settings-info">
1023
  <?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');?>
1024
+ <a href="https://blog.shortpixel.com/optimize-images-outside-media-library/" target="_blank" class="shortpixel-help-link">
1025
+ <span class="dashicons dashicons-editor-help"></span><?php _e('More info','shortpixel-image-optimiser');?>
1026
+ </a>
1027
  </p>
1028
  <div class="sp-modal-shade sp-folder-picker-shade">
1029
  <div class="shortpixel-modal">
1056
  <td>
1057
  <input name="png2jpg" type="checkbox" id="resize" <?php echo( $convertPng2Jpg );?>> <?php _e('Automatically convert the PNG images to JPEG if possible.','shortpixel-image-optimiser');?>
1058
  <p class="settings-info">
1059
+ <?php _e('Converts all PNGs that don\'t have transparent pixels to JPEG. This can dramatically reduce the file size, especially if you have camera pictures that are saved in PNG format. <strong>PNGs with transparency will not be converted.</strong> The plugin will also search for references of the image in posts and will replace them.','shortpixel-image-optimiser');?>
1060
  </p>
1061
  </td>
1062
  </tr>
1063
+ <tr>
1064
+ <th scope="row"><label for="cmyk2rgb"><?php _e('CMYK to RGB conversion','shortpixel-image-optimiser');?></label></th>
1065
+ <td>
1066
+ <input name="cmyk2rgb" type="checkbox" id="cmyk2rgb" <?php echo( $cmyk2rgb );?>><?php _e('Adjust your images\' colours for computer and mobile screen display.','shortpixel-image-optimiser');?>
1067
+ <p class="settings-info"><?php _e('Images for the web only need RGB format and converting them from CMYK to RGB makes them smaller.','shortpixel-image-optimiser');?></p>
1068
+ </td>
1069
+ </tr>
1070
  <tr>
1071
  <th scope="row"><label for="createWebp"><?php _e('WebP versions','shortpixel-image-optimiser');?></label></th>
1072
  <td>
1073
  <input name="createWebp" type="checkbox" id="createWebp" <?php echo( $createWebp );?>> <?php _e('Create also <a href="http://blog.shortpixel.com/how-webp-images-can-speed-up-your-site/" target="_blank">WebP versions</a> of the images <strong>for free</strong>.','shortpixel-image-optimiser');?>
1074
  <p class="settings-info">
1075
  <?php _e('WebP images can be up to three times smaller than PNGs and 25% smaller than JPGs. Choosing this option <strong>does not use up additional credits</strong>.','shortpixel-image-optimiser');?>
1076
+ <a href="http://blog.shortpixel.com/how-webp-images-can-speed-up-your-site/" target="_blank" class="shortpixel-help-link">
1077
+ <span class="dashicons dashicons-editor-help"></span><?php _e('More info','shortpixel-image-optimiser');?>
1078
+ </a>
1079
  </p>
1080
  </td>
1081
  </tr>
1093
  <td>
1094
  <input name="optimizeRetina" type="checkbox" id="optimizeRetina" <?php echo( $optimizeRetina );?>> <?php _e('Optimize also the Retina images (@2x) if they exist.','shortpixel-image-optimiser');?>
1095
  <p class="settings-info">
1096
+ <?php _e('If you have a Retina plugin that generates Retina-specific images (@2x), ShortPixel can optimize them too, alongside the regular Media Library images and thumbnails.','shortpixel-image-optimiser');?>
1097
+ <a href="http://blog.shortpixel.com/how-to-use-optimized-retina-images-on-your-wordpress-site-for-best-user-experience-on-apple-devices/" target="_blank" class="shortpixel-help-link">
1098
+ <span class="dashicons dashicons-editor-help"></span><?php _e('More info','shortpixel-image-optimiser');?>
1099
+ </a>
1100
+ </p>
1101
+ </td>
1102
+ </tr>
1103
+ <tr>
1104
+ <th scope="row"><label for="optimizeUnlisted"><?php _e('Optimize other thumbs','shortpixel-image-optimiser');?></label></th>
1105
+ <td>
1106
+ <input name="optimizeUnlisted" type="checkbox" id="optimizeUnlisted" <?php echo( $optimizeUnlisted );?>> <?php _e('Optimize also the unlisted thumbs if found.','shortpixel-image-optimiser');?>
1107
+ <p class="settings-info">
1108
+ <?php _e('Some plugins create thumbnails which are not registered in the metadata but instead only create them alongside the other thumbnails. Let ShortPixel optimize them as well.','shortpixel-image-optimiser');?>
1109
  </p>
1110
  </td>
1111
  </tr>
1323
  }
1324
  $successText .= ($data['webpCount'] ? "<br>+" . $data['webpCount'] . __(" WebP images", 'shortpixel-image-optimiser') : "")
1325
  . "<br>EXIF: " . ($data['exifKept'] ? __('kept','shortpixel-image-optimiser') : __('removed','shortpixel-image-optimiser'))
1326
+ . ($data['png2jpg'] ? '<br>' . __('Converted from PNG','shortpixel-image-optimiser'): '')
1327
  . "<br>" . __("Optimized on", 'shortpixel-image-optimiser') . ": " . $data['date']
1328
  . $missingThumbs;
1329
  }
1334
 
1335
  break;
1336
  }
1337
+ //if($extended) {
1338
+ // echo("<br><br>METADATA: <pre>");print_r(wp_get_attachment_metadata($id));echo("</pre>");
1339
+ //}
1340
  ?>
1341
  </div>
1342
  <?php
1343
  }
1344
 
1345
  public function getSuccessText($percent, $bonus, $type, $thumbsOpt = 0, $thumbsTotal = 0, $retinasOpt = 0) {
1346
+ return ($percent && $percent > 0 ? __('Reduced by','shortpixel-image-optimiser') . ' <strong>' . $percent . '%</strong> ' : '')
1347
  .(!$bonus ? ' ('.$type.')':'')
1348
  .($bonus && $percent ? '<br>' : '')
1349
  .($bonus ? __('Bonus processing','shortpixel-image-optimiser') : '')
1401
  <a class='button button-smaller' href='admin.php?action=shortpixel_check_quota'>"
1402
  . __('Check&nbsp;&nbsp;Quota','shortpixel-image-optimiser') .
1403
  "</a></div>
1404
+ <div class='sp-column-info'>" . $message . " " . __('Quota Exceeded','shortpixel-image-optimiser') . "</div>";
1405
  }
1406
 
1407
  public function outputComparerHTML() {?>
1409
  <div id="spUploadCompare" class="shortpixel-modal shortpixel-hide">
1410
  <div class="sp-modal-title">
1411
  <button type="button" class="sp-close-button">&times;</button>
1412
+ <?php _e('Compare Images', 'shortpixel-image-optimiser');?>
1413
  </div>
1414
  <div class="sp-modal-body sptw-modal-spinner" style="height:400px;padding:0;">
1415
  <div class="shortpixel-slider" style="z-index:2000;">
class/wp-short-pixel.php CHANGED
@@ -14,6 +14,8 @@ class WPShortPixel {
14
  private $hasNextGen = false;
15
  private $spMetaDao = null;
16
 
 
 
17
  public static $PROCESSABLE_EXTENSIONS = array('jpg', 'jpeg', 'gif', 'png', 'pdf');
18
 
19
  public function __construct() {
@@ -21,6 +23,10 @@ class WPShortPixel {
21
  session_start();
22
  }
23
 
 
 
 
 
24
  load_plugin_textdomain('shortpixel-image-optimiser', false, plugin_basename(dirname( SHORTPIXEL_PLUGIN_FILE )).'/lang');
25
 
26
  $isAdminUser = current_user_can( 'manage_options' );
@@ -76,6 +82,7 @@ class WPShortPixel {
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' ) );
@@ -102,6 +109,7 @@ class WPShortPixel {
102
  add_action( 'wp_ajax_shortpixel_dismiss_notice', array(&$this, 'dismissAdminNotice'));
103
  add_action( 'wp_ajax_shortpixel_dismiss_media_alert', array(&$this, 'dismissMediaAlert'));
104
  //check quota
 
105
  add_action('admin_action_shortpixel_check_quota', array(&$this, 'handleCheckQuota'));
106
  //This adds the constants used in PHP to be available also in JS
107
  add_action( 'admin_footer', array( &$this, 'shortPixelJS') );
@@ -188,6 +196,9 @@ class WPShortPixel {
188
 
189
  public function displayAdminNotices() {
190
  $dismissed = $this->_settings->dismissedNotices ? $this->_settings->dismissedNotices : array();
 
 
 
191
  if(!$this->_settings->verifiedKey) {
192
  $now = time();
193
  $act = $this->_settings->activationDate ? $this->_settings->activationDate : $now;
@@ -207,13 +218,21 @@ class WPShortPixel {
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)) {
@@ -234,6 +253,9 @@ class WPShortPixel {
234
  $dismissed = $this->_settings->dismissedNotices ? $this->_settings->dismissedNotices : array();
235
  $dismissed[$noticeId] = true;
236
  $this->_settings->dismissedNotices = $dismissed;
 
 
 
237
  die(json_encode(array("Status" => 'success', "Message" => 'Notice ID: ' . $noticeId . ' dismissed')));
238
  }
239
 
@@ -251,12 +273,12 @@ class WPShortPixel {
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
 
@@ -326,9 +348,9 @@ class WPShortPixel {
326
  AJAX_URL: '<?php echo admin_url('admin-ajax.php'); ?>'
327
  };
328
  </script> <?php
329
- wp_enqueue_style('short-pixel.css', plugins_url('/res/css/short-pixel.css',SHORTPIXEL_PLUGIN_FILE), array(), SHORTPIXEL_IMAGE_OPTIMISER_VERSION);
330
 
331
- wp_register_script('short-pixel.js', plugins_url('/res/js/short-pixel.js',SHORTPIXEL_PLUGIN_FILE), array(), SHORTPIXEL_IMAGE_OPTIMISER_VERSION);
332
  $jsTranslation = array(
333
  'optimizeWithSP' => __( 'Optimize with ShortPixel', 'shortpixel-image-optimiser' ),
334
  'changeMLToListMode' => __( 'In order to access the ShortPixel Optimization actions and info, please change to {0}List View{1}List View{2}Dismiss{3}', 'shortpixel-image-optimiser' ),
@@ -352,12 +374,12 @@ class WPShortPixel {
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');
357
 
358
- wp_enqueue_script('jquery.knob.js', plugins_url('/res/js/jquery.knob.js',SHORTPIXEL_PLUGIN_FILE) );
359
- wp_enqueue_script('jquery.tooltip.js', plugins_url('/res/js/jquery.tooltip.js',SHORTPIXEL_PLUGIN_FILE) );
360
- wp_enqueue_script('punycode.js', plugins_url('/res/js/punycode.js',SHORTPIXEL_PLUGIN_FILE) );
361
  }
362
 
363
  function toolbar_shortpixel_processing( $wp_admin_bar ) {
@@ -457,6 +479,10 @@ class WPShortPixel {
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)) {
@@ -472,12 +498,13 @@ class WPShortPixel {
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
@@ -489,21 +516,35 @@ class WPShortPixel {
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
@@ -519,46 +560,68 @@ class WPShortPixel {
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
  }
@@ -578,14 +641,28 @@ class WPShortPixel {
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
@@ -602,25 +679,45 @@ class WPShortPixel {
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
  }
@@ -628,6 +725,97 @@ class WPShortPixel {
628
  return $meta;
629
  }
630
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
631
  /**
632
  * this is hooked onto the NextGen upload
633
  * @param type $image
@@ -714,7 +902,7 @@ class WPShortPixel {
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);
718
  $maxResults = SHORTPIXEL_MAX_RESULTS_QUERY * 2;
719
  $restored = array();
720
 
@@ -765,7 +953,7 @@ class WPShortPixel {
765
  $idList = array();
766
  $itemList = array();
767
  for ($sanityCheck = 0, $crtStartQueryID = $startQueryID;
768
- ($crtStartQueryID >= $endQueryID) && (count($itemList) < 3) && ($sanityCheck < 150); $sanityCheck++) {
769
 
770
  self::log("GETDB: current StartID: " . $crtStartQueryID);
771
 
@@ -782,7 +970,7 @@ class WPShortPixel {
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;
@@ -826,6 +1014,7 @@ class WPShortPixel {
826
  $crtStartQueryID = $startQueryID = $itemMetaData->post_id - 1; //decrement it so we don't select it again
827
  $res = WpShortPixelMediaLbraryAdapter::countAllProcessableFiles($this->_settings->optimizePdfs, $leapStart, $crtStartQueryID);
828
  $skippedAlreadyProcessed += $res["mainProcessedFiles"] - $res["mainProc".($this->getCompressionType() == 1 ? "Lossy" : "Lossless")."Files"];
 
829
  $this->prioQ->setStartBulkId($startQueryID);
830
  } else {
831
  $crtStartQueryID--;
@@ -839,10 +1028,11 @@ class WPShortPixel {
839
  * @return type
840
  */
841
  //TODO muta in bulkProvider - prio
842
- public function getFromPrioAndCheck() {
843
- $items = array();
844
  foreach ($this->prioQ->getFromPrioAndCheck() as $id) {
845
  $items[] = new ShortPixelMetaFacade($id);
 
846
  }
847
  return $items;
848
  }
@@ -850,7 +1040,7 @@ class WPShortPixel {
850
  private function checkKey($ID) {
851
  if( $this->_settings->verifiedKey == false) {
852
  if($ID == null){
853
- $ids = $this->getFromPrioAndCheck();
854
  $itemHandler = (count($ids) > 0 ? $ids[0] : null);
855
  }
856
  $response = array("Status" => ShortPixelAPI::STATUS_NO_KEY, "ImageID" => $itemHandler ? $itemHandler->getId() : "-1", "Message" => __('Missing API Key','shortpixel-image-optimiser'));
@@ -888,7 +1078,7 @@ class WPShortPixel {
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()
@@ -906,8 +1096,8 @@ class WPShortPixel {
906
  }
907
 
908
  //1: get 3 ids to process. Take them with priority from the queue
909
- $ids = $this->getFromPrioAndCheck();
910
- if(count($ids) < 3 ) { //take from bulk if bulk processing active
911
  if($this->prioQ->bulkRunning()) {
912
  $res = $this->getBulkItemsFromDb();
913
  $bulkItems = $res['items'];
@@ -946,7 +1136,7 @@ class WPShortPixel {
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++) {
@@ -956,6 +1146,8 @@ class WPShortPixel {
956
  try {
957
  self::log("HIP: 1 sendToProcessing: ".$crtItemHandler->getId());
958
  $URLsAndPATHs = $this->sendToProcessing($crtItemHandler, $compType, $tmpMeta->getThumbsTodo());
 
 
959
  if(!$itemHandler) { //save for later use
960
  $itemHandler = $ids[$i];
961
  $firstUrlAndPaths = $URLsAndPATHs;
@@ -968,7 +1160,7 @@ class WPShortPixel {
968
  }
969
  }
970
  }
971
-
972
  if (!$itemHandler){
973
  //if searching, than the script is searching for not processed items and found none yet, should be relaunced
974
  if(isset($res['searching']) && $res['searching']) {
@@ -976,7 +1168,7 @@ class WPShortPixel {
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
  }
@@ -984,6 +1176,7 @@ class WPShortPixel {
984
  self::log("HIP: 2 Prio Queue: ".json_encode($this->prioQ->get()));
985
  //3: $itemHandler contains the first element of the list
986
  $itemId = $itemHandler->getQueuedId();
 
987
  $result = $this->_apiInterface->processImage($firstUrlAndPaths['URLs'], $firstUrlAndPaths['PATHs'], $itemHandler);
988
 
989
  $result["ImageID"] = $itemId;
@@ -1041,14 +1234,14 @@ class WPShortPixel {
1041
  }
1042
 
1043
  if(strlen($thumb) && $this->_settings->backupImages && $this->_settings->processThumbnails) {
1044
- $backupUrl = content_url() . "/" . SHORTPIXEL_UPLOADS_NAME . "/" . SHORTPIXEL_BACKUP . "/";
1045
  //$urlBkPath = $this->_apiInterface->returnSubDir(get_attached_file($ID));
1046
  $urlBkPath = ShortPixelMetaFacade::returnSubDir($meta->getPath(), ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE);
1047
  $bkThumb = $backupUrl . $urlBkPath . $thumb;
1048
  }
1049
  if(strlen($thumb)) {
1050
  $uploadsUrl = ShortPixelMetaFacade::getHomeUrl();
1051
- $urlPath = ShortPixelMetaFacade::returnSubDir($meta->getPath(), ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE);
1052
  //$urlPath = implode("/", array_slice($filePath, 0, count($filePath) - 1));
1053
  $thumb = $uploadsUrl . $urlPath . $thumb;
1054
  }
@@ -1080,6 +1273,7 @@ class WPShortPixel {
1080
  elseif ($result["Status"] == ShortPixelAPI::STATUS_ERROR) {
1081
  if($meta->getRetries() > SHORTPIXEL_MAX_ERR_RETRIES) {
1082
  if(! $this->prioQ->remove($itemId) ){
 
1083
  $this->advanceBulk($meta->getId());
1084
  }
1085
  if($itemHandler->getType() == ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE) {
@@ -1108,7 +1302,8 @@ class WPShortPixel {
1108
  //put this one in the failed images list - to show the user at the end
1109
  $prio = $this->prioQ->addToFailed($itemHandler->getQueuedId());
1110
  }
1111
- $this->advanceBulk($meta->getId());
 
1112
  if($itemHandler->getType() == ShortPixelMetaFacade::CUSTOM_TYPE) {
1113
  $result["CustomImageLink"] = ShortPixelMetaFacade::getHomeUrl() . $meta->getWebPath();
1114
  }
@@ -1168,11 +1363,11 @@ class WPShortPixel {
1168
  private function sendToProcessing($itemHandler, $compressionType = false, $onlyThumbs = false) {
1169
 
1170
  //for the moment deactivate the conversion for existing images
1171
- if(false && $itemHandler->getType() == ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE) { //currently only for ML
1172
  $rawMeta = $this->checkConvertMediaPng2Jpg($itemHandler->getRawMeta(), $itemHandler->getId());
1173
 
1174
  if(isset($rawMeta['type']) && $rawMeta['type'] == 'image/jpeg') {
1175
- $itemHandler->setRawMeta($rawMeta);
1176
  }
1177
  }
1178
 
@@ -1181,7 +1376,8 @@ class WPShortPixel {
1181
 
1182
  $meta = $itemHandler->getMeta();
1183
  //find thumbs that are not listed in the metadata and add them in the sizes array
1184
- if($itemHandler->getType() == ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE) {
 
1185
  $mainFile = $meta->getPath();
1186
 
1187
  $foundThumbs = WpShortPixelMediaLbraryAdapter::findThumbs($mainFile);
@@ -1330,8 +1526,8 @@ class WPShortPixel {
1330
 
1331
  private function getBackupFolderInternal($file) {
1332
  $fileExtension = strtolower(substr($file,strrpos($file,".")+1));
1333
- $SubDir = ShortPixelMetaFacade::returnSubDir($file, ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE);
1334
- $SubDirOld = ShortPixelMetaFacade::returnSubDirOld($file, ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE);
1335
 
1336
  if ( !file_exists(SHORTPIXEL_BACKUP_FOLDER . '/' . $SubDir . ShortPixelAPI::MB_basename($file))
1337
  && !file_exists(SHORTPIXEL_BACKUP_FOLDER . '/' . date("Y") . "/" . date("m") . "/" . ShortPixelAPI::MB_basename($file)) ) {
@@ -1387,8 +1583,19 @@ class WPShortPixel {
1387
  $meta = wp_get_attachment_metadata($attachmentID);
1388
  }
1389
  $pathInfo = pathinfo($file);
1390
-
1391
- $bkFolder = $this->getBackupFolderAny($file, isset($meta["sizes"]) ? $meta["sizes"] : array());
 
 
 
 
 
 
 
 
 
 
 
1392
  $bkFile = trailingslashit($bkFolder) . ShortPixelAPI::MB_basename($file);
1393
 
1394
  //first check if the file is readable by the current user - otherwise it will be unaccessible for the web browser
@@ -1402,8 +1609,8 @@ class WPShortPixel {
1402
  $main = true;
1403
  }
1404
  $thumbsPaths = array();
1405
- if( !empty($meta['file']) && is_array($meta["sizes"]) ) {
1406
- foreach($meta["sizes"] as $size => $imageData) {
1407
  $dest = $pathInfo['dirname'] . '/' . $imageData['file'];
1408
  $source = trailingslashit($bkFolder) . $imageData['file'];
1409
  if(!file_exists($source)) continue; // if thumbs were not optimized, then the backups will not be there.
@@ -1445,14 +1652,28 @@ class WPShortPixel {
1445
  }
1446
  unset($crtMeta["ShortPixelImprovement"]);
1447
  unset($crtMeta['ShortPixel']);
 
1448
  if($width && $height) {
1449
  $crtMeta['width'] = $width;
1450
  $crtMeta['height'] = $height;
1451
  }
 
 
 
 
 
 
 
 
 
 
 
 
1452
  wp_update_attachment_metadata($ID, $crtMeta);
1453
  }
1454
  unset($meta["ShortPixelImprovement"]);
1455
  unset($meta['ShortPixel']);
 
1456
 
1457
  } catch(Exception $e) {
1458
  //what to do, what to do?
@@ -1587,6 +1808,10 @@ class WPShortPixel {
1587
  // we are done
1588
  }
1589
 
 
 
 
 
1590
  public function handleDeleteAttachmentInBackup($ID) {
1591
  $file = get_attached_file($ID);
1592
  $meta = wp_get_attachment_metadata($ID);
@@ -1594,7 +1819,7 @@ class WPShortPixel {
1594
  if(self::_isProcessable($ID) != false) //we use the static isProcessable to bypass the exclude patterns
1595
  {
1596
  try {
1597
- $SubDir = ShortPixelMetaFacade::returnSubDir($file, ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE);
1598
 
1599
  @unlink(SHORTPIXEL_BACKUP_FOLDER . '/' . $SubDir . ShortPixelAPI::MB_basename($file));
1600
 
@@ -1624,6 +1849,35 @@ class WPShortPixel {
1624
  die();
1625
  }
1626
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1627
  public function checkQuotaAndAlert($quotaData = null, $recheck = false) {
1628
  if(!$quotaData) {
1629
  $quotaData = $this->getQuotaInformation();
@@ -1633,33 +1887,8 @@ class WPShortPixel {
1633
  return $quotaData;
1634
  }
1635
  //$tempus = microtime(true);
1636
-
1637
- if( is_array($this->_settings->currentStats)
1638
- && $this->_settings->currentStats['optimizePdfs'] == $this->_settings->optimizePdfs
1639
- && (time() - $this->_settings->currentStats['time'] < 300))
1640
- {
1641
- $imageCount = $this->_settings->currentStats;
1642
- } else {
1643
- $imageCount = WpShortPixelMediaLbraryAdapter::countAllProcessableFiles($this->_settings->optimizePdfs);
1644
- $imageCount['time'] = time();
1645
- $imageCount['optimizePdfs'] = $this->_settings->optimizePdfs;
1646
- $imageCount['quotaData'] = $quotaData;
1647
- $this->_settings->currentStats = $imageCount;
1648
- }
1649
-
1650
  //echo("Count took (seconds): " . (microtime(true) - $tempus));
1651
- foreach($imageCount as $key => $val) {
1652
- $quotaData[$key] = $val;
1653
- }
1654
-
1655
- if($this->_settings->hasCustomFolders) {
1656
- $customImageCount = $this->spMetaDao->countAllProcessableFiles();
1657
- foreach($customImageCount as $key => $val) {
1658
- $quotaData[$key] = isset($quotaData[$key])
1659
- ? (is_array($quotaData[$key]) ? array_merge($quotaData[$key], $val) : $quotaData[$key] + $val)
1660
- : $val;
1661
- }
1662
- }
1663
 
1664
  if($quotaData['APICallsQuotaNumeric'] + $quotaData['APICallsQuotaOneTimeNumeric'] > $quotaData['APICallsMadeNumeric'] + $quotaData['APICallsMadeOneTimeNumeric']) {
1665
  $this->_settings->quotaExceeded = '0';
@@ -1759,7 +1988,7 @@ class WPShortPixel {
1759
 
1760
  if(isset($_POST['bulkProcessStop']))
1761
  {//stop an ongoing bulk processing
1762
- $this->prioQ->cancelBulk();
1763
  if($this->_settings->hasCustomFolders && $this->spMetaDao->getPendingMetaCount()) {
1764
  $this->_settings->customBulkPaused = 1;
1765
  }
@@ -1959,7 +2188,7 @@ class WPShortPixel {
1959
  $rawMeta = $handle->getRawMeta();
1960
  $backupUrl = content_url() . "/" . SHORTPIXEL_UPLOADS_NAME . "/" . SHORTPIXEL_BACKUP . "/";
1961
  $uploadsUrl = ShortPixelMetaFacade::getHomeUrl();
1962
- $urlBkPath = ShortPixelMetaFacade::returnSubDir($meta->getPath(), ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE);
1963
  $ret['origUrl'] = $backupUrl . $urlBkPath . $meta->getName();
1964
  $ret['optUrl'] = $uploadsUrl . $urlBkPath . $meta->getName();
1965
  $ret['width'] = $rawMeta['width'];
@@ -1968,38 +2197,86 @@ class WPShortPixel {
1968
  die(json_encode((object)$ret));
1969
  }
1970
 
1971
- public function proposeUpgrade() {
1972
  if ( !current_user_can( 'manage_options' ) ) {
1973
  wp_die(__('You do not have sufficient permissions to access this page.','shortpixel-image-optimiser'));
1974
  }
 
 
 
1975
 
1976
- if( is_array($this->_settings->currentStats)
1977
- && $this->_settings->currentStats['optimizePdfs'] == $this->_settings->optimizePdfs
1978
- && (time() - $this->_settings->currentStats['time'] < 300))
1979
- {
1980
- $stats = $this->_settings->currentStats;
1981
- } else {
1982
- $stats = WpShortPixelMediaLbraryAdapter::countAllProcessableFiles($this->_settings->optimizePdfs);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1983
  }
 
 
 
 
 
 
 
 
 
 
1984
 
1985
  //$proposal = wp_remote_post($this->_settings->httpProto . "://shortpixel.com/propose-upgrade-frag", array(
1986
- 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>");
1987
- $proposal = wp_remote_post("http://dev.shortpixel.com/propose-upgrade-frag", array(
1988
  'method' => 'POST',
1989
  'timeout' => 10,
1990
  'redirection' => 5,
1991
  'httpversion' => '1.0',
1992
  'blocking' => true,
1993
  'headers' => array(),
1994
- 'body' => json_encode(array(
1995
  'plugin_version' => SHORTPIXEL_IMAGE_OPTIMISER_VERSION,
1996
  'key' => $this->_settings->apiKey,
 
 
 
 
 
 
 
 
 
1997
  'm1' => $stats['totalM1'],
1998
  'm2' => $stats['totalM2'],
1999
  'm3' => $stats['totalM3'],
2000
- 'm3' => $stats['totalM4'],
2001
- 'filesTodo' => $stats['totalFiles'] - $stats['totalProcessedFiles']
2002
- )),
 
 
 
2003
  'cookies' => array()
2004
  ));
2005
  if(is_wp_error( $proposal )) {
@@ -2049,7 +2326,7 @@ class WPShortPixel {
2049
  } else {
2050
  $notice = array("status" => "error", "msg" => $ex->getMessage());
2051
  }
2052
- }
2053
  }
2054
  }
2055
  return $customFolders;
@@ -2060,9 +2337,9 @@ class WPShortPixel {
2060
  wp_die(__('You do not have sufficient permissions to access this page.','shortpixel-image-optimiser'));
2061
  }
2062
 
2063
- wp_enqueue_style('sp-file-tree.css', plugins_url('/res/css/sp-file-tree.css',SHORTPIXEL_PLUGIN_FILE) );
2064
- wp_enqueue_script('sp-file-tree.js', plugins_url('/res/js/sp-file-tree.js',SHORTPIXEL_PLUGIN_FILE) );
2065
-
2066
  //die(var_dump($_POST));
2067
  $noticeHTML = "";
2068
  $notice = null;
@@ -2199,6 +2476,7 @@ class WPShortPixel {
2199
  $this->_settings->createWebp = (isset($_POST['createWebp']) ? 1: 0);
2200
  $this->_settings->createWebpMarkup = (isset($_POST['createWebpMarkup']) ? 1: 0);
2201
  $this->_settings->optimizeRetina = (isset($_POST['optimizeRetina']) ? 1: 0);
 
2202
  $this->_settings->optimizePdfs = (isset($_POST['optimizePdfs']) ? 1: 0);
2203
  $this->_settings->png2jpg = (isset($_POST['png2jpg']) ? 1: 0);
2204
 
@@ -2248,7 +2526,7 @@ class WPShortPixel {
2248
  if(isset($_POST['emptyBackup'])) {
2249
  $this->emptyBackup();
2250
  }
2251
-
2252
  $quotaData = $this->checkQuotaAndAlert(isset($validityData) ? $validityData : null, isset($_GET['checkquota']));
2253
 
2254
  if($this->hasNextGen) {
@@ -2397,7 +2675,16 @@ class WPShortPixel {
2397
  "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 api.shortpixel.com (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. ','shortpixel-image-optimiser'),
2398
  "APICallsMade" => __('Information unavailable. Please check your API key.','shortpixel-image-optimiser'),
2399
  "APICallsQuota" => __('Information unavailable. Please check your API key.','shortpixel-image-optimiser'),
 
 
 
 
 
 
 
 
2400
  "DomainCheck" => 'NOT Accessible');
 
2401
 
2402
  if(is_object($response) && get_class($response) == 'WP_Error') {
2403
 
@@ -2434,8 +2721,8 @@ class WPShortPixel {
2434
  if($lastStatus && $lastStatus['Status'] == ShortPixelAPI::STATUS_NO_KEY) {
2435
  $this->_settings->bulkLastStatus = null;
2436
  }
2437
-
2438
- return array(
2439
  "APIKeyValid" => true,
2440
  "APICallsMade" => number_format($data->APICallsMade) . __(' images','shortpixel-image-optimiser'),
2441
  "APICallsQuota" => number_format($data->APICallsQuota) . __(' images','shortpixel-image-optimiser'),
@@ -2449,6 +2736,12 @@ class WPShortPixel {
2449
  "APILastRenewalDate" => $data->DateSubscription,
2450
  "DomainCheck" => (isset($data->DomainCheck) ? $data->DomainCheck : null)
2451
  );
 
 
 
 
 
 
2452
  }
2453
 
2454
  public function resetQuotaExceeded() {
@@ -2505,7 +2798,7 @@ class WPShortPixel {
2505
  $sizesCount = isset($data['sizes']) ? WpShortPixelMediaLbraryAdapter::countNonWebpSizes($data['sizes']) : 0;
2506
 
2507
  $renderData['status'] = $fileExtension == "pdf" ? 'pdfOptimized' : 'imgOptimized';
2508
- $renderData['percent'] = $data['ShortPixelImprovement'];
2509
  $renderData['bonus'] = ($data['ShortPixelImprovement'] < 5);
2510
  $renderData['backup'] = $this->getBackupFolderAny($file, $sizesCount? $data['sizes'] : array());
2511
  $renderData['type'] = isset($data['ShortPixel']['type']) ? $data['ShortPixel']['type'] : '';
@@ -2516,6 +2809,7 @@ class WPShortPixel {
2516
  $renderData['thumbsMissing'] = isset($data['ShortPixel']['thumbsMissing']) ? $data['ShortPixel']['thumbsMissing'] : array();
2517
  $renderData['retinasOpt'] = isset($data['ShortPixel']['retinasOpt']) ? $data['ShortPixel']['retinasOpt'] : null;
2518
  $renderData['exifKept'] = isset($data['ShortPixel']['exifKept']) ? $data['ShortPixel']['exifKept'] : null;
 
2519
  $renderData['date'] = isset($data['ShortPixel']['date']) ? $data['ShortPixel']['date'] : null;
2520
  $renderData['quotaExceeded'] = $quotaExceeded;
2521
  $webP = 0;
@@ -2572,13 +2866,18 @@ class WPShortPixel {
2572
  $renderData['message'] = ($fileExtension == "pdf" ? 'PDF' : __('Image','shortpixel-image-optimiser'))
2573
  . __(' not processed.','shortpixel-image-optimiser')
2574
  . ' (<a href="https://shortpixel.com/image-compression-test?site-url=' . urlencode(ShortPixelMetaFacade::safeGetAttachmentUrl($id)) . '" target="_blank">'
2575
- . __('Test for free','shortpixel-image-optimiser') . '</a>)';
2576
  }
2577
 
2578
  $this->view->renderCustomColumn($id, $renderData, $extended);
2579
  }
2580
  }
2581
 
 
 
 
 
 
2582
  function shortpixelInfoBox() {
2583
  if(get_post_type( ) == 'attachment') {
2584
  add_meta_box(
@@ -2719,8 +3018,8 @@ class WPShortPixel {
2719
 
2720
  static public function _isProcessablePath($path, $excludeExtensions = array(), $excludePatterns = array()) {
2721
  $pathParts = pathinfo($path);
2722
- $ext = $pathParts['extension'];
2723
- if( isset($ext) && in_array(strtolower($ext), array_diff(self::$PROCESSABLE_EXTENSIONS, $excludeExtensions))) {
2724
  //apply patterns defined by user to exclude some file names or paths
2725
  if(!$excludePatterns || !is_array($excludePatterns)) { return true; }
2726
  foreach($excludePatterns as $item) {
@@ -2850,7 +3149,7 @@ class WPShortPixel {
2850
  $get_intermediate_image_sizes = get_intermediate_image_sizes();
2851
 
2852
  // Create the full array with sizes and crop info
2853
- foreach( $get_intermediate_image_sizes as $_size ) {
2854
  if ( in_array( $_size, array( 'thumbnail', 'medium', 'large' ) ) ) {
2855
  $width = max($width, get_option( $_size . '_size_w' ));
2856
  $height = max($height, get_option( $_size . '_size_h' ));
14
  private $hasNextGen = false;
15
  private $spMetaDao = null;
16
 
17
+ private $jsSuffix = '.min.js';
18
+
19
  public static $PROCESSABLE_EXTENSIONS = array('jpg', 'jpeg', 'gif', 'png', 'pdf');
20
 
21
  public function __construct() {
23
  session_start();
24
  }
25
 
26
+ if (SHORTPIXEL_DEBUG === true) {
27
+ $this->jsSuffix = '.js'; //use unminified versions for easier debugging
28
+ }
29
+
30
  load_plugin_textdomain('shortpixel-image-optimiser', false, plugin_basename(dirname( SHORTPIXEL_PLUGIN_FILE )).'/lang');
31
 
32
  $isAdminUser = current_user_can( 'manage_options' );
82
  add_action('wp_ajax_shortpixel_get_backup_size', array(&$this, 'getBackupSize'));
83
  add_action('wp_ajax_shortpixel_get_comparer_data', array(&$this, 'getComparerData'));
84
 
85
+ add_action('wp_ajax_shortpixel_new_api_key', array(&$this, 'newApiKey'));
86
  add_action('wp_ajax_shortpixel_propose_upgrade', array(&$this, 'proposeUpgrade'));
87
 
88
  add_action( 'delete_attachment', array( &$this, 'handleDeleteAttachmentInBackup' ) );
109
  add_action( 'wp_ajax_shortpixel_dismiss_notice', array(&$this, 'dismissAdminNotice'));
110
  add_action( 'wp_ajax_shortpixel_dismiss_media_alert', array(&$this, 'dismissMediaAlert'));
111
  //check quota
112
+ add_action('wp_ajax_shortpixel_check_quota', array(&$this, 'handleCheckQuota'));
113
  add_action('admin_action_shortpixel_check_quota', array(&$this, 'handleCheckQuota'));
114
  //This adds the constants used in PHP to be available also in JS
115
  add_action( 'admin_footer', array( &$this, 'shortPixelJS') );
196
 
197
  public function displayAdminNotices() {
198
  $dismissed = $this->_settings->dismissedNotices ? $this->_settings->dismissedNotices : array();
199
+ unset($dismissed['unlisted']); //reset a specific notice
200
+ $this->_settings->dismissedNotices = $dismissed;
201
+
202
  if(!$this->_settings->verifiedKey) {
203
  $now = time();
204
  $act = $this->_settings->activationDate ? $this->_settings->activationDate : $now;
218
  ShortPixelView::displayActivationNotice('compat', $conflictPlugins);
219
  }
220
  }
221
+ if( !isset($dismissed['unlisted']) && !$this->_settings->optimizeUnlisted
222
+ && isset($this->_settings->currentStats['foundUnlistedThumbs']) && $this->_settings->currentStats['foundUnlistedThumbs']) {
223
+ ShortPixelView::displayActivationNotice('unlisted', $this->_settings->currentStats['foundUnlistedThumbs']);
224
+
225
+ }
226
+ //if(false)
227
+ if(!is_array($this->_settings->currentStats) || isset($_GET['checkquota'])) {
228
+ $this->getQuotaInformation();
229
+ }
230
  if($this->_settings->verifiedKey
231
+ && (!isset($dismissed['upgmonth']) || !isset($dismissed['upgbulk']))
232
  && $this->_settings->currentStats['optimizePdfs'] == $this->_settings->optimizePdfs ) {
233
  $screen = get_current_screen();
234
+ $stats = $this->countAllIfNeeded($this->_settings->currentStats, 300);
235
+ $quotaData = $stats;
236
 
237
  //this is for bulk page - alert on the total credits for total images
238
  if( $screen && $screen->id == 'media_page_wp-short-pixel-bulk' && $this->bulkUpgradeNeeded($stats)) {
253
  $dismissed = $this->_settings->dismissedNotices ? $this->_settings->dismissedNotices : array();
254
  $dismissed[$noticeId] = true;
255
  $this->_settings->dismissedNotices = $dismissed;
256
+ if($_GET['notice_id'] == 'unlisted' && isset($_GET['notice_data']) && $_GET['notice_data'] == 'true') {
257
+ $this->_settings->optimizeUnlisted = 1;
258
+ }
259
  die(json_encode(array("Status" => 'success', "Message" => 'Notice ID: ' . $noticeId . ' dismissed')));
260
  }
261
 
273
  }
274
 
275
  protected function monthlyUpgradeNeeded($stats) {
276
+ $quotaData = $stats;
277
  return $this->getMonthAvg($stats) > $quotaData['APICallsQuotaNumeric'] + ($quotaData['APICallsQuotaOneTimeNumeric'] - $quotaData['APICallsMadeOneTimeNumeric'])/6 + 20;
278
  }
279
 
280
  protected function bulkUpgradeNeeded($stats) {
281
+ $quotaData = $stats;
282
  return $stats['totalFiles'] - $stats['totalProcessedFiles'] > $quotaData['APICallsQuotaNumeric'] + $quotaData['APICallsQuotaOneTimeNumeric'] - $quotaData['APICallsMadeNumeric'] - $quotaData['APICallsMadeOneTimeNumeric'];
283
  }
284
 
348
  AJAX_URL: '<?php echo admin_url('admin-ajax.php'); ?>'
349
  };
350
  </script> <?php
351
+ wp_enqueue_style('short-pixel.min.css', plugins_url('/res/css/short-pixel.min.css',SHORTPIXEL_PLUGIN_FILE), array(), SHORTPIXEL_IMAGE_OPTIMISER_VERSION);
352
 
353
+ wp_register_script('short-pixel' . $this->jsSuffix, plugins_url('/res/js/short-pixel' . $this->jsSuffix,SHORTPIXEL_PLUGIN_FILE), array(), SHORTPIXEL_IMAGE_OPTIMISER_VERSION);
354
  $jsTranslation = array(
355
  'optimizeWithSP' => __( 'Optimize with ShortPixel', 'shortpixel-image-optimiser' ),
356
  'changeMLToListMode' => __( 'In order to access the ShortPixel Optimization actions and info, please change to {0}List View{1}List View{2}Dismiss{3}', 'shortpixel-image-optimiser' ),
374
  'confirmBulkRestore' => __( "Are you sure you want to restore from backup all the images in your Media Library optimized with ShortPixel?", 'shortpixel-image-optimiser' ),
375
  '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' )
376
  );
377
+ wp_localize_script( 'short-pixel' . $this->jsSuffix, '_spTr', $jsTranslation );
378
+ wp_enqueue_script('short-pixel' . $this->jsSuffix);
379
 
380
+ wp_enqueue_script('jquery.knob.min.js', plugins_url('/res/js/jquery.knob.min.js',SHORTPIXEL_PLUGIN_FILE) );
381
+ wp_enqueue_script('jquery.tooltip.min.js', plugins_url('/res/js/jquery.tooltip.min.js',SHORTPIXEL_PLUGIN_FILE) );
382
+ wp_enqueue_script('punycode.min.js', plugins_url('/res/js/punycode.min.js',SHORTPIXEL_PLUGIN_FILE) );
383
  }
384
 
385
  function toolbar_shortpixel_processing( $wp_admin_bar ) {
479
  //else
480
  //self::log("IMG: Auto-analyzing file ID #{$ID}");
481
 
482
+ if(isset($meta['ShortPixelImprovement'])) {
483
+ return $meta;// some plugins (e.g. WP e-Commerce) call the wp_attachment_metadata on just editing the image...
484
+ }
485
+
486
  self::log("Handle Media Library Image Upload #{$ID}");
487
 
488
  if(!$this->_settings->optimizePdfs && 'pdf' === pathinfo(get_attached_file($ID), PATHINFO_EXTENSION)) {
498
  {//the kind of file we can process. goody.
499
 
500
  $this->prioQ->push($ID);
501
+ $itemHandler = new ShortPixelMetaFacade($ID);
502
+ $itemHandler->setRawMeta($meta);
503
  //that's a hack for watermarking plugins, don't send the image right away to processing, only add it in the queue
504
  include_once( ABSPATH . 'wp-admin/includes/plugin.php' );
505
  if( !is_plugin_active('image-watermark/image-watermark.php')
506
+ && !is_plugin_active('amazon-s3-and-cloudfront/wordpress-s3.php')
507
  && !is_plugin_active('easy-watermark/index.php')) {
 
 
508
  try {
509
  $URLsAndPATHs = $this->getURLsAndPATHs($itemHandler);
510
  //send a processing request right after a file was uploaded, do NOT wait for response
516
  //self::log("IMG: sent: " . json_encode($URLsAndPATHs));
517
  }
518
  $meta['ShortPixel']['WaitingProcessing'] = true;
519
+
520
+ // check if the image was converted from PNG upon uploading.
521
+ if($itemHandler->getType() == ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE) {//for the moment
522
+ $imagePath = $itemHandler->getMeta()->getPath();
523
+ if(isset($this->_settings->convertedPng2Jpg[$imagePath])) {
524
+ $conv = $this->_settings->convertedPng2Jpg;
525
+ $params = $conv[$imagePath];
526
+ unset($conv[$imagePath]);
527
+ $this->_settings->convertedPng2Jpg == $conv;
528
+ $meta['ShortPixelPng2Jpg'] = array('originalFile' => $params['pngFile'], 'originalSizes' => array(),
529
+ 'backup' => $params['backup'], 'optimizationPercent' => $params['optimizationPercent']);
530
+ }
531
+ }
532
+
533
  return $meta;
534
  }
535
  }//end handleMediaLibraryImageUpload
536
 
537
  protected function canConvertPng2Jpg($image) {
538
  $transparent = 0;
 
539
  if (ord(file_get_contents($image, false, null, 25, 1)) & 4) {
540
  $transparent = 1;
541
  }
542
+ $contents = file_get_contents($image);
543
  if (stripos($contents, 'PLTE') !== false && stripos($contents, 'tRNS') !== false) {
544
  $transparent = 1;
545
  }
546
  $transparent_pixel = $img = $bg = false;
547
+ if (!$transparent) {
548
  $img = imagecreatefrompng($image);
549
  $w = imagesx($img); // Get the width of the image
550
  $h = imagesy($img); // Get the height of the image
560
  }
561
  }
562
 
563
+ //pass on the img too, if it was already loaded from PNG, matter of performance
564
+ return array('notTransparent' => !$transparent && !$transparent_pixel, 'img' => $img);
565
  }
566
 
567
  /**
568
  *
569
+ * @param array $params
570
+ * @param string $backupPath
571
+ * @param string $suffixRegex for example [0-9]+x[0-9]+ - a thumbnail suffix - to add the counter of file name collisions files before that suffix (img-2-150x150.jpg).
572
+ * @param image $img
573
  * @return string
574
  */
575
+ protected function doConvertPng2Jpg($params, $backup, $suffixRegex = false, $img = false) {
576
+ $image = $params['file'];
577
  if(!$img) {
578
+ $img = imagecreatefrompng($image);
579
  }
580
+
581
  $bg = imagecreatetruecolor(imagesx($img), imagesy($img));
582
+ if(!$bg) return $params;
583
  imagefill($bg, 0, 0, imagecolorallocate($bg, 255, 255, 255));
584
  imagealphablending($bg, 1);
585
  imagecopy($bg, $img, 0, 0, 0, 0, imagesx($img), imagesy($img));
586
+ $newPath = preg_replace("/\.png$/i", ".jpg", $image);
587
+ $newUrl = preg_replace("/\.png$/i", ".jpg", $params['url']);
588
  for ($i = 1; file_exists($newPath); $i++) {
589
  if($suffixRegex) {
590
+ $newPath = preg_replace("/(" . $suffixRegex . ")\.png$/i", $i . '-$1.jpg', $image);
591
  }else {
592
+ $newPath = preg_replace("/\.png$/i", "-" . $i . ".jpg", $image);
593
  }
594
  }
595
  if (imagejpeg($bg, $newPath, 90)) {
596
  $newSize = filesize($newPath);
597
+ $origSize = filesize($image);
598
  if($newSize > $origSize * 0.95) {
599
  //if the image is not 5% smaller, don't bother.
600
  unlink($newPath);
601
  return $params;
602
  }
603
+ //backup?
604
+ if($backup) {
605
+ $imageForBk = trailingslashit(dirname($image)) . ShortPixelAPI::MB_basename($newPath, '.jpg') . '.png';
606
+ @rename($image, $imageForBk);
607
+ if(!file_exists($imageForBk)) {
608
+ unlink($newPath);
609
+ return $params;
610
+ }
611
+ $image = $imageForBk;
612
+ $ret = ShortPixelAPI::backupImage($image, array($image));
613
+ if($ret['Status'] !== ShortPixelAPI::STATUS_SUCCESS) {
614
+ unlink($newPath);
615
+ return $params;
616
+ }
617
+ }
618
+ unlink($image);
619
  $params['file'] = $newPath;
620
+ $params['original_file'] = $image;
621
  $params['url'] = $newUrl;
622
  $params['type'] = 'image/jpeg';
623
+ $params['png_size'] = $origSize;
624
+ $params['jpg_size'] = $newSize;
625
  }
626
  return $params;
627
  }
641
  $image = $params['file'];
642
  self::log("Convert Media PNG to JPG on upload: {$image}");
643
 
644
+ $ret = $this->canConvertPng2Jpg($image);
645
+ if ($ret['notTransparent']) {
646
+ $paramsC = $this->doConvertPng2Jpg($params, $this->_settings->backupImages, false, $ret['img']);
647
+ if($paramsC['type'] == 'image/jpeg') {
648
+ // we don't have metadata, so save the information in a temporary map
649
+ $conv = $this->_settings->convertedPng2Jpg;
650
+ //do a cleanup first
651
+ foreach($conv as $key => $val) {
652
+ if(time() - $val['timestamp'] > 3600) unset($conv[$key]);
653
+ }
654
+ $conv[$paramsC['file']] = array('pngFile' => $paramsC['original_file'], 'backup' => $this->_settings->backupImages,
655
+ 'optimizationPercent' => round(100.0 * (1.00 - $paramsC['jpg_size'] / $paramsC['png_size'])),
656
+ 'timestamp' => time());
657
+ $this->_settings->convertedPng2Jpg = $conv;
658
+ }
659
+ return $paramsC;
660
  }
661
  return $params;
662
  }
663
 
664
  /**
665
+ * convert PNG to JPEG if possible - already existing image in Media Library
666
  *
667
  * @param type $meta
668
  * @param type $ID
679
  $image = $meta['file'];
680
  $imagePath = get_attached_file($ID);
681
  $basePath = trailingslashit(str_replace($image, "", $imagePath));
682
+ $imageUrl = wp_get_attachment_url($ID);
683
+ $baseUrl = trailingslashit(str_replace($image, "", $imageUrl));
684
+
685
+ $ret = $this->canConvertPng2Jpg($imagePath);
686
+ if (!$ret['notTransparent']) {
687
+ return $meta; //cannot convert it
688
+ }
689
 
690
+ $ret = $this->doConvertPng2Jpg(array('file' => $imagePath, 'url' => false, 'type' => 'image/png'), $this->_settings->backupImages, false, $ret['img']);
 
 
691
  //echo("CONVERT: " . $imagePath); var_dump($ret);
692
 
693
  if ($ret['type'] == 'image/jpeg') {
694
+ //convert to the new URLs the urls in the existing posts.
695
+ $baseRelPath = trailingslashit(dirname($image));
696
+ $this->png2JpgUpdateUrls(array(), $imageUrl, $baseUrl . $baseRelPath . wp_basename($ret['file']));
697
+ $pngSize = $ret['png_size'];
698
+ $jpgSize = $ret['jpg_size'];
699
+ $imagePath = isset($ret['original_file']) ? $ret['original_file'] : $imagePath;
700
+
701
  //conversion succeeded for the main image, update meta and proceed to thumbs. (It could also not succeed if the converted file is not smaller)
702
  $meta['file'] = str_replace($basePath, '', $ret['file']);
703
+ $meta['type'] = 'image/jpeg';
704
 
705
+ $originalSizes = isset($meta['sizes']) ? $meta['sizes'] : array();
706
+ foreach($meta['sizes'] as $size => $info) {
707
+ $rett = $this->doConvertPng2Jpg(array('file' => $basePath . $baseRelPath . $info['file'], 'url' => false, 'type' => 'image/png'),
708
+ $this->_settings->backupImages, "[0-9]+x[0-9]+");
709
  if ($rett['type'] == 'image/jpeg') {
710
  $meta['sizes'][$size]['file'] = wp_basename($rett['file']);
711
  $meta['sizes'][$size]['mime-type'] = 'image/jpeg';
712
+ $pngSize += $ret['png_size'];
713
+ $jpgSize += $ret['jpg_size'];
714
+ $originalSizes[$size]['file'] = wp_basename($rett['file'], '.jpg') . '.png';
715
+ $this->png2JpgUpdateUrls(array(), $baseUrl . $baseRelPath . $info['file'], $baseUrl . $baseRelPath . wp_basename($rett['file']));
716
  }
717
+ }
718
+ $meta['ShortPixelPng2Jpg'] = array('originalFile' => $imagePath, 'originalSizes' => $originalSizes,
719
+ 'backup' => $this->_settings->backupImages,
720
+ 'optimizationPercent' => round(100.0 * (1.00 - $jpgSize / $pngSize)));
721
  update_attached_file($ID, $meta['file']);
722
  wp_update_attachment_metadata($ID, $meta);
723
  }
725
  return $meta;
726
  }
727
 
728
+ /**
729
+ * taken from Velvet Blues Update URLs plugin
730
+ * @param $options
731
+ * @param $oldurl
732
+ * @param $newurl
733
+ * @return array
734
+ */
735
+ protected function png2JpgUpdateUrls($options,$oldurl,$newurl){
736
+ global $wpdb;
737
+ $results = array();
738
+ $queries = array(
739
+ 'content' => array("UPDATE $wpdb->posts SET post_content = replace(post_content, %s, %s)", __('Content Items (Posts, Pages, Custom Post Types, Revisions)','hortpixel-image-optimiser') ),
740
+ 'excerpts' => array("UPDATE $wpdb->posts SET post_excerpt = replace(post_excerpt, %s, %s)", __('Excerpts','hortpixel-image-optimiser') ),
741
+ 'attachments' => array("UPDATE $wpdb->posts SET guid = replace(guid, %s, %s) WHERE post_type = 'attachment'", __('Attachments','hortpixel-image-optimiser') ),
742
+ 'links' => array("UPDATE $wpdb->links SET link_url = replace(link_url, %s, %s)", __('Links','hortpixel-image-optimiser') ),
743
+ 'custom' => array("UPDATE $wpdb->postmeta SET meta_value = replace(meta_value, %s, %s)", __('Custom Fields','hortpixel-image-optimiser') ),
744
+ 'guids' => array("UPDATE $wpdb->posts SET guid = replace(guid, %s, %s)", __('GUIDs','hortpixel-image-optimiser') )
745
+ );
746
+ if(count($options) == 0) {
747
+ $options = array_keys($queries);
748
+ }
749
+ foreach($options as $option){
750
+ if( $option == 'custom' ){
751
+ $n = 0;
752
+ $row_count = $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->postmeta" );
753
+ $page_size = 10000;
754
+ $pages = ceil( $row_count / $page_size );
755
+
756
+ for( $page = 0; $page < $pages; $page++ ) {
757
+ $current_row = 0;
758
+ $start = $page * $page_size;
759
+ $end = $start + $page_size;
760
+ $pmquery = "SELECT * FROM $wpdb->postmeta WHERE meta_value <> ''";
761
+ $items = $wpdb->get_results( $pmquery );
762
+ foreach( $items as $item ){
763
+ $value = $item->meta_value;
764
+ if( trim($value) == '' )
765
+ continue;
766
+
767
+ $edited = $this->png2JpgUnserializeReplace( $oldurl, $newurl, $value );
768
+
769
+ if( $edited != $value ){
770
+ $fix = $wpdb->query("UPDATE $wpdb->postmeta SET meta_value = '".$edited."' WHERE meta_id = ".$item->meta_id );
771
+ if( $fix )
772
+ $n++;
773
+ }
774
+ }
775
+ }
776
+ $results[$option] = array($n, $queries[$option][1]);
777
+ }
778
+ else{
779
+ $result = $wpdb->query( $wpdb->prepare( $queries[$option][0], $oldurl, $newurl) );
780
+ $results[$option] = array($result, $queries[$option][1]);
781
+ }
782
+ }
783
+ return $results;
784
+ }
785
+
786
+ /**
787
+ * taken from Velvet Blues Update URLs plugin
788
+ * @param string $from
789
+ * @param string $to
790
+ * @param string $data
791
+ * @param bool|false $serialised
792
+ * @return array|mixed|string
793
+ */
794
+ function png2JpgUnserializeReplace( $from = '', $to = '', $data = '', $serialised = false ) {
795
+ try {
796
+ if ( false !== is_serialized( $data ) ) {
797
+ $unserialized = unserialize( $data );
798
+ $data = $this->png2JpgUnserializeReplace( $from, $to, $unserialized, true );
799
+ }
800
+ elseif ( is_array( $data ) ) {
801
+ $_tmp = array( );
802
+ foreach ( $data as $key => $value ) {
803
+ $_tmp[ $key ] = $this->png2JpgUnserializeReplace( $from, $to, $value, false );
804
+ }
805
+ $data = $_tmp;
806
+ unset( $_tmp );
807
+ }
808
+ else {
809
+ if ( is_string( $data ) )
810
+ $data = str_replace( $from, $to, $data );
811
+ }
812
+ if ( $serialised )
813
+ return serialize( $data );
814
+ } catch( Exception $error ) {
815
+ }
816
+ return $data;
817
+ }
818
+
819
  /**
820
  * this is hooked onto the NextGen upload
821
  * @param type $image
902
  $this->prioQ->resetPrio();
903
 
904
  $startTime = time();
905
+ $maxTime = min(30, (is_numeric(SHORTPIXEL_MAX_EXECUTION_TIME) && SHORTPIXEL_MAX_EXECUTION_TIME > 10 ? SHORTPIXEL_MAX_EXECUTION_TIME - 5 : 25));
906
  $maxResults = SHORTPIXEL_MAX_RESULTS_QUERY * 2;
907
  $restored = array();
908
 
953
  $idList = array();
954
  $itemList = array();
955
  for ($sanityCheck = 0, $crtStartQueryID = $startQueryID;
956
+ ($crtStartQueryID >= $endQueryID) && (count($itemList) < SHORTPIXEL_PRESEND_ITEMS) && ($sanityCheck < 150); $sanityCheck++) {
957
 
958
  self::log("GETDB: current StartID: " . $crtStartQueryID);
959
 
970
  $crtStartQueryID -= SHORTPIXEL_MAX_RESULTS_QUERY;
971
  $startQueryID = $crtStartQueryID;
972
  if(!count($idList)) { //none found so far, so decrease the start ID
973
+ self::log("GETDB: empty slice. setStartBulkID to $startQueryID");
974
  $this->prioQ->setStartBulkId($startQueryID);
975
  }
976
  continue;
1014
  $crtStartQueryID = $startQueryID = $itemMetaData->post_id - 1; //decrement it so we don't select it again
1015
  $res = WpShortPixelMediaLbraryAdapter::countAllProcessableFiles($this->_settings->optimizePdfs, $leapStart, $crtStartQueryID);
1016
  $skippedAlreadyProcessed += $res["mainProcessedFiles"] - $res["mainProc".($this->getCompressionType() == 1 ? "Lossy" : "Lossless")."Files"];
1017
+ self::log("GETDB: empty list. setStartBulkID to $startQueryID");
1018
  $this->prioQ->setStartBulkId($startQueryID);
1019
  } else {
1020
  $crtStartQueryID--;
1028
  * @return type
1029
  */
1030
  //TODO muta in bulkProvider - prio
1031
+ public function getFromPrioAndCheck($limit = PHP_INT_MAX) {
1032
+ $items = array();$i = 1;
1033
  foreach ($this->prioQ->getFromPrioAndCheck() as $id) {
1034
  $items[] = new ShortPixelMetaFacade($id);
1035
+ if($i++ > $limit) { break; }
1036
  }
1037
  return $items;
1038
  }
1040
  private function checkKey($ID) {
1041
  if( $this->_settings->verifiedKey == false) {
1042
  if($ID == null){
1043
+ $ids = $this->getFromPrioAndCheck(1);
1044
  $itemHandler = (count($ids) > 0 ? $ids[0] : null);
1045
  }
1046
  $response = array("Status" => ShortPixelAPI::STATUS_NO_KEY, "ImageID" => $itemHandler ? $itemHandler->getId() : "-1", "Message" => __('Missing API Key','shortpixel-image-optimiser'));
1078
 
1079
  $rawPrioQ = $this->prioQ->get();
1080
  if(count($rawPrioQ)) { self::log("HIP: 0 Priority Queue: ".json_encode($rawPrioQ)); }
1081
+ self::log("HIP: 0 Bulk running? " . $this->prioQ->bulkRunning() . " START " . $this->_settings->startBulkId . " STOP " . $this->_settings->stopBulkId);
1082
 
1083
  //handle the bulk restore and cleanup first - these are fast operations taking precedece over optimization
1084
  if( $this->prioQ->bulkRunning()
1096
  }
1097
 
1098
  //1: get 3 ids to process. Take them with priority from the queue
1099
+ $ids = $this->getFromPrioAndCheck(SHORTPIXEL_PRESEND_ITEMS);
1100
+ if(count($ids) < SHORTPIXEL_PRESEND_ITEMS ) { //take from bulk if bulk processing active
1101
  if($this->prioQ->bulkRunning()) {
1102
  $res = $this->getBulkItemsFromDb();
1103
  $bulkItems = $res['items'];
1136
  //die("za stop 2");
1137
 
1138
  //self::log("HIP: 1 Prio Queue: ".json_encode($this->prioQ->get()));
1139
+ if(count($ids)) {$idl='';foreach($ids as $i){$idl.=$i->getId().' ';} self::log("HIP: 1 Selected IDs: $idl");}
1140
 
1141
  //2: Send up to 3 files to the server for processing
1142
  for($i = 0, $itemHandler = false; $ids !== false && $i < min(3, count($ids)); $i++) {
1146
  try {
1147
  self::log("HIP: 1 sendToProcessing: ".$crtItemHandler->getId());
1148
  $URLsAndPATHs = $this->sendToProcessing($crtItemHandler, $compType, $tmpMeta->getThumbsTodo());
1149
+ //self::log("HIP: 1 METADATA: ".json_encode($crtItemHandler->getRawMeta()));
1150
+ //self::log("HIP: 1 URLs and PATHs: ".json_encode($URLsAndPATHs));
1151
  if(!$itemHandler) { //save for later use
1152
  $itemHandler = $ids[$i];
1153
  $firstUrlAndPaths = $URLsAndPATHs;
1160
  }
1161
  }
1162
  }
1163
+
1164
  if (!$itemHandler){
1165
  //if searching, than the script is searching for not processed items and found none yet, should be relaunced
1166
  if(isset($res['searching']) && $res['searching']) {
1168
  "Message" => __('Searching images to optimize... ','shortpixel-image-optimiser') . $this->prioQ->getStartBulkId() . '->' . $this->prioQ->getStopBulkId() )));
1169
  }
1170
  //in this case the queue is really empty
1171
+ self::log("HIP: 1 STOP BULK");
1172
  $bulkEverRan = $this->prioQ->stopBulk();
1173
  $this->sendEmptyQueue();
1174
  }
1176
  self::log("HIP: 2 Prio Queue: ".json_encode($this->prioQ->get()));
1177
  //3: $itemHandler contains the first element of the list
1178
  $itemId = $itemHandler->getQueuedId();
1179
+ self::log("HIP: 2 Process Image: ".json_encode($itemHandler->getId()));
1180
  $result = $this->_apiInterface->processImage($firstUrlAndPaths['URLs'], $firstUrlAndPaths['PATHs'], $itemHandler);
1181
 
1182
  $result["ImageID"] = $itemId;
1234
  }
1235
 
1236
  if(strlen($thumb) && $this->_settings->backupImages && $this->_settings->processThumbnails) {
1237
+ $backupUrl = SHORTPIXEL_UPLOADS_URL . "/" . SHORTPIXEL_BACKUP . "/";
1238
  //$urlBkPath = $this->_apiInterface->returnSubDir(get_attached_file($ID));
1239
  $urlBkPath = ShortPixelMetaFacade::returnSubDir($meta->getPath(), ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE);
1240
  $bkThumb = $backupUrl . $urlBkPath . $thumb;
1241
  }
1242
  if(strlen($thumb)) {
1243
  $uploadsUrl = ShortPixelMetaFacade::getHomeUrl();
1244
+ $urlPath = ShortPixelMetaFacade::returnSubDir($meta->getPath());
1245
  //$urlPath = implode("/", array_slice($filePath, 0, count($filePath) - 1));
1246
  $thumb = $uploadsUrl . $urlPath . $thumb;
1247
  }
1273
  elseif ($result["Status"] == ShortPixelAPI::STATUS_ERROR) {
1274
  if($meta->getRetries() > SHORTPIXEL_MAX_ERR_RETRIES) {
1275
  if(! $this->prioQ->remove($itemId) ){
1276
+ self::log("HIP RES: advanceBulk - too many retries for $itemId - skipping.");
1277
  $this->advanceBulk($meta->getId());
1278
  }
1279
  if($itemHandler->getType() == ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE) {
1302
  //put this one in the failed images list - to show the user at the end
1303
  $prio = $this->prioQ->addToFailed($itemHandler->getQueuedId());
1304
  }
1305
+ self::log("HIP RES: skipping $itemId");
1306
+ $this->advanceBulk($meta->getId());
1307
  if($itemHandler->getType() == ShortPixelMetaFacade::CUSTOM_TYPE) {
1308
  $result["CustomImageLink"] = ShortPixelMetaFacade::getHomeUrl() . $meta->getWebPath();
1309
  }
1363
  private function sendToProcessing($itemHandler, $compressionType = false, $onlyThumbs = false) {
1364
 
1365
  //for the moment deactivate the conversion for existing images
1366
+ if($itemHandler->getType() == ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE) { //currently only for ML
1367
  $rawMeta = $this->checkConvertMediaPng2Jpg($itemHandler->getRawMeta(), $itemHandler->getId());
1368
 
1369
  if(isset($rawMeta['type']) && $rawMeta['type'] == 'image/jpeg') {
1370
+ $itemHandler->getMeta(true);
1371
  }
1372
  }
1373
 
1376
 
1377
  $meta = $itemHandler->getMeta();
1378
  //find thumbs that are not listed in the metadata and add them in the sizes array
1379
+ if( $itemHandler->getType() == ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE
1380
+ && $this->_settings->optimizeUnlisted) {
1381
  $mainFile = $meta->getPath();
1382
 
1383
  $foundThumbs = WpShortPixelMediaLbraryAdapter::findThumbs($mainFile);
1526
 
1527
  private function getBackupFolderInternal($file) {
1528
  $fileExtension = strtolower(substr($file,strrpos($file,".")+1));
1529
+ $SubDir = ShortPixelMetaFacade::returnSubDir($file);
1530
+ $SubDirOld = ShortPixelMetaFacade::returnSubDirOld($file);
1531
 
1532
  if ( !file_exists(SHORTPIXEL_BACKUP_FOLDER . '/' . $SubDir . ShortPixelAPI::MB_basename($file))
1533
  && !file_exists(SHORTPIXEL_BACKUP_FOLDER . '/' . date("Y") . "/" . date("m") . "/" . ShortPixelAPI::MB_basename($file)) ) {
1583
  $meta = wp_get_attachment_metadata($attachmentID);
1584
  }
1585
  $pathInfo = pathinfo($file);
1586
+ $sizes = isset($meta["sizes"]) ? $meta["sizes"] : array();
1587
+
1588
+ //check if the images were converted from PNG
1589
+ $png2jpgMain = isset($meta['ShortPixelPng2Jpg']['originalFile']) ? $meta['ShortPixelPng2Jpg']['originalFile'] : false;
1590
+ $jpgFile = false; $jpgSizes = array();
1591
+ $png2jpgSizes = $png2jpgMain ? $meta['ShortPixelPng2Jpg']['originalSizes'] : array();
1592
+ $bkFolder = $this->getBackupFolderAny($file, $sizes);
1593
+ if($png2jpgMain) {
1594
+ $jpgFile = $file;
1595
+ $file = $png2jpgMain;
1596
+ $jpgSizes = $sizes;
1597
+ $sizes = $png2jpgSizes;
1598
+ }
1599
  $bkFile = trailingslashit($bkFolder) . ShortPixelAPI::MB_basename($file);
1600
 
1601
  //first check if the file is readable by the current user - otherwise it will be unaccessible for the web browser
1609
  $main = true;
1610
  }
1611
  $thumbsPaths = array();
1612
+ if( !empty($meta['file']) && count($sizes) ) {
1613
+ foreach($sizes as $size => $imageData) {
1614
  $dest = $pathInfo['dirname'] . '/' . $imageData['file'];
1615
  $source = trailingslashit($bkFolder) . $imageData['file'];
1616
  if(!file_exists($source)) continue; // if thumbs were not optimized, then the backups will not be there.
1652
  }
1653
  unset($crtMeta["ShortPixelImprovement"]);
1654
  unset($crtMeta['ShortPixel']);
1655
+ unset($crtMeta['ShortPixelPng2Jpg']);
1656
  if($width && $height) {
1657
  $crtMeta['width'] = $width;
1658
  $crtMeta['height'] = $height;
1659
  }
1660
+ if($png2jpgMain) {
1661
+ if($png2jpgSizes) {
1662
+ $crtMeta['file'] = trailingslashit(dirname($crtMeta['file'])) . ShortPixelAPI::MB_basename($file);
1663
+ update_attached_file($ID, $crtMeta['file']);
1664
+ $crtMeta['sizes'] = $png2jpgSizes;
1665
+ } else {
1666
+ //this was an image converted on upload, regenerate the thumbs using the PNG main image BUT deactivate temporarily the filter!!
1667
+ remove_filter( 'wp_generate_attachment_metadata', 'shortPixelHandleImageUploadHook');
1668
+ $crtMeta = wp_generate_attachment_metadata($ID, $png2jpgMain);
1669
+ add_filter( 'wp_generate_attachment_metadata', 'shortPixelHandleImageUploadHook', 10, 2 );
1670
+ }
1671
+ }
1672
  wp_update_attachment_metadata($ID, $crtMeta);
1673
  }
1674
  unset($meta["ShortPixelImprovement"]);
1675
  unset($meta['ShortPixel']);
1676
+ unset($meta['ShortPixelPng2Jpg']);
1677
 
1678
  } catch(Exception $e) {
1679
  //what to do, what to do?
1808
  // we are done
1809
  }
1810
 
1811
+ public function handleCheckQuotaAjax() {
1812
+ $this->getQuotaInformation();
1813
+ }
1814
+
1815
  public function handleDeleteAttachmentInBackup($ID) {
1816
  $file = get_attached_file($ID);
1817
  $meta = wp_get_attachment_metadata($ID);
1819
  if(self::_isProcessable($ID) != false) //we use the static isProcessable to bypass the exclude patterns
1820
  {
1821
  try {
1822
+ $SubDir = ShortPixelMetaFacade::returnSubDir($file);
1823
 
1824
  @unlink(SHORTPIXEL_BACKUP_FOLDER . '/' . $SubDir . ShortPixelAPI::MB_basename($file));
1825
 
1849
  die();
1850
  }
1851
 
1852
+ public function countAllIfNeeded($quotaData, $time) {
1853
+ if( !(defined('SHORTPIXEL_DEBUG') && SHORTPIXEL_DEBUG === true) && is_array($this->_settings->currentStats)
1854
+ && $this->_settings->currentStats['optimizePdfs'] == $this->_settings->optimizePdfs
1855
+ && isset($this->_settings->currentStats['time'])
1856
+ && (time() - $this->_settings->currentStats['time'] < $time))
1857
+ {
1858
+ return $this->_settings->currentStats;
1859
+ } else {
1860
+ $imageCount = WpShortPixelMediaLbraryAdapter::countAllProcessableFiles($this->_settings->optimizePdfs);
1861
+ $quotaData['time'] = time();
1862
+ $quotaData['optimizePdfs'] = $this->_settings->optimizePdfs;
1863
+ //$quotaData['quotaData'] = $quotaData;
1864
+ foreach($imageCount as $key => $val) {
1865
+ $quotaData[$key] = $val;
1866
+ }
1867
+
1868
+ if($this->_settings->hasCustomFolders) {
1869
+ $customImageCount = $this->spMetaDao->countAllProcessableFiles();
1870
+ foreach($customImageCount as $key => $val) {
1871
+ $quotaData[$key] = isset($quotaData[$key])
1872
+ ? (is_array($quotaData[$key]) ? array_merge($quotaData[$key], $val) : $quotaData[$key] + $val)
1873
+ : $val;
1874
+ }
1875
+ }
1876
+ $this->_settings->currentStats = $quotaData;
1877
+ return $quotaData;
1878
+ }
1879
+ }
1880
+
1881
  public function checkQuotaAndAlert($quotaData = null, $recheck = false) {
1882
  if(!$quotaData) {
1883
  $quotaData = $this->getQuotaInformation();
1887
  return $quotaData;
1888
  }
1889
  //$tempus = microtime(true);
1890
+ $quotaData = $this->countAllIfNeeded($quotaData, 300);
 
 
 
 
 
 
 
 
 
 
 
 
 
1891
  //echo("Count took (seconds): " . (microtime(true) - $tempus));
 
 
 
 
 
 
 
 
 
 
 
 
1892
 
1893
  if($quotaData['APICallsQuotaNumeric'] + $quotaData['APICallsQuotaOneTimeNumeric'] > $quotaData['APICallsMadeNumeric'] + $quotaData['APICallsMadeOneTimeNumeric']) {
1894
  $this->_settings->quotaExceeded = '0';
1988
 
1989
  if(isset($_POST['bulkProcessStop']))
1990
  {//stop an ongoing bulk processing
1991
+ $this->prioQ->stopBulk();
1992
  if($this->_settings->hasCustomFolders && $this->spMetaDao->getPendingMetaCount()) {
1993
  $this->_settings->customBulkPaused = 1;
1994
  }
2188
  $rawMeta = $handle->getRawMeta();
2189
  $backupUrl = content_url() . "/" . SHORTPIXEL_UPLOADS_NAME . "/" . SHORTPIXEL_BACKUP . "/";
2190
  $uploadsUrl = ShortPixelMetaFacade::getHomeUrl();
2191
+ $urlBkPath = ShortPixelMetaFacade::returnSubDir($meta->getPath());
2192
  $ret['origUrl'] = $backupUrl . $urlBkPath . $meta->getName();
2193
  $ret['optUrl'] = $uploadsUrl . $urlBkPath . $meta->getName();
2194
  $ret['width'] = $rawMeta['width'];
2197
  die(json_encode((object)$ret));
2198
  }
2199
 
2200
+ public function newApiKey() {
2201
  if ( !current_user_can( 'manage_options' ) ) {
2202
  wp_die(__('You do not have sufficient permissions to access this page.','shortpixel-image-optimiser'));
2203
  }
2204
+ if( $this->_settings->verifiedKey ) {
2205
+ die(json_encode((object)array('Status' => 'success', 'Details' => $this->_settings->apiKey)));
2206
+ }
2207
 
2208
+ $newKey = wp_remote_post("https://shortpixel.com/free-sign-up-plugin", array(
2209
+ 'method' => 'POST',
2210
+ 'timeout' => 10,
2211
+ 'redirection' => 5,
2212
+ 'httpversion' => '1.0',
2213
+ 'blocking' => true,
2214
+ 'headers' => array(),
2215
+ 'body' => array(
2216
+ 'plugin_version' => SHORTPIXEL_IMAGE_OPTIMISER_VERSION,
2217
+ 'email' => isset($_POST['email']) ? trim($_POST['email']) : null,
2218
+ 'ip' => isset($_SERVER["HTTP_X_FORWARDED_FOR"]) ? $_SERVER["HTTP_X_FORWARDED_FOR"]: $_SERVER['REMOTE_ADDR'],
2219
+ //'XDEBUG_SESSION_START' => 'session_name'
2220
+ )));
2221
+
2222
+
2223
+
2224
+ if ( is_object($newKey) && get_class($newKey) == 'WP_Error' ) {
2225
+ die(json_encode((object)array('Status' => 'fail', 'Details' => '503')));
2226
+ }
2227
+ elseif ( isset($response['response']['code']) && $response['response']['code'] <> 200 ) {
2228
+ die(json_encode((object)array('Status' => 'fail', 'Details' => $response['response']['code'])));
2229
+ }
2230
+ $response = (object)$this->_apiInterface->parseResponse($newKey);
2231
+ if($response->Status == 'success') {
2232
+ $key = trim($response->Details);
2233
+ $validityData = $this->getQuotaInformation($key, true, true);
2234
+ if($validityData['APIKeyValid']) {
2235
+ $this->_settings->apiKey = $key;
2236
+ $this->_settings->verifiedKey = true;
2237
+ }
2238
  }
2239
+ die(json_encode($response));
2240
+
2241
+ }
2242
+
2243
+ public function proposeUpgrade() {
2244
+ if ( !current_user_can( 'manage_options' ) ) {
2245
+ wp_die(__('You do not have sufficient permissions to access this page.','shortpixel-image-optimiser'));
2246
+ }
2247
+
2248
+ $stats = $this->countAllIfNeeded($this->_settings->currentStats, 300);
2249
 
2250
  //$proposal = wp_remote_post($this->_settings->httpProto . "://shortpixel.com/propose-upgrade-frag", array(
2251
+ //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>");
2252
+ $proposal = wp_remote_post("https://shortpixel.com/propose-upgrade-frag", array(
2253
  'method' => 'POST',
2254
  'timeout' => 10,
2255
  'redirection' => 5,
2256
  'httpversion' => '1.0',
2257
  'blocking' => true,
2258
  'headers' => array(),
2259
+ 'body' => array("params" => json_encode(array(
2260
  'plugin_version' => SHORTPIXEL_IMAGE_OPTIMISER_VERSION,
2261
  'key' => $this->_settings->apiKey,
2262
+ //'m1' => 4125, 'm2' => 3392, 'm3' => 3511, 'm4' => 2921, 'filesTodo' => 23143, 'estimated' => 'true'
2263
+ //'m1' => 3125, 'm2' => 2392, 'm3' => 2511, 'm4' => 1921, 'filesTodo' => 23143, 'estimated' => 'true'
2264
+ //'m1' => 1925, 'm2' => 1392, 'm3' => 1511, 'm4' => 1721, 'filesTodo' => 30143, 'estimated' => 'false'
2265
+ //'m1' => 2125, 'm2' => 1392, 'm3' => 1511, 'm4' => 1921, 'filesTodo' => 13143, 'estimated' => 'false'
2266
+ //'m1' => 13125, 'm2' => 22392, 'm3' => 12511, 'm4' => 31921, 'filesTodo' => 93143, 'estimated' => 'true'
2267
+ //'m1' => 925, 'm2' => 592, 'm3' => 711, 'm4' => 121, 'filesTodo' => 2143, 'estimated' => 'true'
2268
+ //'m1' => 4625, 'm2' => 4592, 'm3' => 4711, 'm4' => 4121, 'filesTodo' => 51143, 'estimated' => 'true'
2269
+ //'m1' => 4625, 'm2' => 4592, 'm3' => 4711, 'm4' => 4121, 'filesTodo' => 41143, 'estimated' => 'true'
2270
+ //'m1' => 7625, 'm2' => 6592, 'm3' => 6711, 'm4' => 5121, 'filesTodo' => 41143, 'estimated' => 'true'
2271
  'm1' => $stats['totalM1'],
2272
  'm2' => $stats['totalM2'],
2273
  'm3' => $stats['totalM3'],
2274
+ 'm4' => $stats['totalM4'],
2275
+ 'filesTodo' => $stats['totalFiles'] - $stats['totalProcessedFiles'],
2276
+ 'estimated' => $this->_settings->optimizeUnlisted || $this->_settings->optimizeRetina ? 'true' : 'false',
2277
+ /* */
2278
+ 'iconsUrl' => base64_encode(plugins_url('/shortpixel-image-optimiser/res/img'))
2279
+ ))),
2280
  'cookies' => array()
2281
  ));
2282
  if(is_wp_error( $proposal )) {
2326
  } else {
2327
  $notice = array("status" => "error", "msg" => $ex->getMessage());
2328
  }
2329
+ }
2330
  }
2331
  }
2332
  return $customFolders;
2337
  wp_die(__('You do not have sufficient permissions to access this page.','shortpixel-image-optimiser'));
2338
  }
2339
 
2340
+ wp_enqueue_style('sp-file-tree.min.css', plugins_url('/res/css/sp-file-tree.min.css',SHORTPIXEL_PLUGIN_FILE) );
2341
+ wp_enqueue_script('sp-file-tree.min.js', plugins_url('/res/js/sp-file-tree.min.js',SHORTPIXEL_PLUGIN_FILE) );
2342
+
2343
  //die(var_dump($_POST));
2344
  $noticeHTML = "";
2345
  $notice = null;
2476
  $this->_settings->createWebp = (isset($_POST['createWebp']) ? 1: 0);
2477
  $this->_settings->createWebpMarkup = (isset($_POST['createWebpMarkup']) ? 1: 0);
2478
  $this->_settings->optimizeRetina = (isset($_POST['optimizeRetina']) ? 1: 0);
2479
+ $this->_settings->optimizeUnlisted = (isset($_POST['optimizeUnlisted']) ? 1: 0);
2480
  $this->_settings->optimizePdfs = (isset($_POST['optimizePdfs']) ? 1: 0);
2481
  $this->_settings->png2jpg = (isset($_POST['png2jpg']) ? 1: 0);
2482
 
2526
  if(isset($_POST['emptyBackup'])) {
2527
  $this->emptyBackup();
2528
  }
2529
+
2530
  $quotaData = $this->checkQuotaAndAlert(isset($validityData) ? $validityData : null, isset($_GET['checkquota']));
2531
 
2532
  if($this->hasNextGen) {
2675
  "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 api.shortpixel.com (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. ','shortpixel-image-optimiser'),
2676
  "APICallsMade" => __('Information unavailable. Please check your API key.','shortpixel-image-optimiser'),
2677
  "APICallsQuota" => __('Information unavailable. Please check your API key.','shortpixel-image-optimiser'),
2678
+ "APICallsMadeOneTime" => 0,
2679
+ "APICallsQuotaOneTime" => 0,
2680
+ "APICallsMadeNumeric" => 0,
2681
+ "APICallsQuotaNumeric" => 0,
2682
+ "APICallsMadeOneTimeNumeric" => 0,
2683
+ "APICallsQuotaOneTimeNumeric" => 0,
2684
+ "APICallsRemaining" => 0,
2685
+ "APILastRenewalDate" => 0,
2686
  "DomainCheck" => 'NOT Accessible');
2687
+ $defaultData = is_array($this->_settings->currentStats) ? array_merge( $this->_settings->currentStats, $defaultData) : $defaultData;
2688
 
2689
  if(is_object($response) && get_class($response) == 'WP_Error') {
2690
 
2721
  if($lastStatus && $lastStatus['Status'] == ShortPixelAPI::STATUS_NO_KEY) {
2722
  $this->_settings->bulkLastStatus = null;
2723
  }
2724
+
2725
+ $dataArray = array(
2726
  "APIKeyValid" => true,
2727
  "APICallsMade" => number_format($data->APICallsMade) . __(' images','shortpixel-image-optimiser'),
2728
  "APICallsQuota" => number_format($data->APICallsQuota) . __(' images','shortpixel-image-optimiser'),
2736
  "APILastRenewalDate" => $data->DateSubscription,
2737
  "DomainCheck" => (isset($data->DomainCheck) ? $data->DomainCheck : null)
2738
  );
2739
+
2740
+ $crtStats = is_array($this->_settings->currentStats) ? array_merge( $this->_settings->currentStats, $dataArray) : $dataArray;
2741
+ $crtStats['optimizePdfs'] = $this->_settings->optimizePdfs;
2742
+ $this->_settings->currentStats = $crtStats;
2743
+
2744
+ return $dataArray;
2745
  }
2746
 
2747
  public function resetQuotaExceeded() {
2798
  $sizesCount = isset($data['sizes']) ? WpShortPixelMediaLbraryAdapter::countNonWebpSizes($data['sizes']) : 0;
2799
 
2800
  $renderData['status'] = $fileExtension == "pdf" ? 'pdfOptimized' : 'imgOptimized';
2801
+ $renderData['percent'] = $this->optimizationPercentIfPng2Jpg($data);
2802
  $renderData['bonus'] = ($data['ShortPixelImprovement'] < 5);
2803
  $renderData['backup'] = $this->getBackupFolderAny($file, $sizesCount? $data['sizes'] : array());
2804
  $renderData['type'] = isset($data['ShortPixel']['type']) ? $data['ShortPixel']['type'] : '';
2809
  $renderData['thumbsMissing'] = isset($data['ShortPixel']['thumbsMissing']) ? $data['ShortPixel']['thumbsMissing'] : array();
2810
  $renderData['retinasOpt'] = isset($data['ShortPixel']['retinasOpt']) ? $data['ShortPixel']['retinasOpt'] : null;
2811
  $renderData['exifKept'] = isset($data['ShortPixel']['exifKept']) ? $data['ShortPixel']['exifKept'] : null;
2812
+ $renderData['png2jpg'] = isset($data['ShortPixelPng2Jpg']);
2813
  $renderData['date'] = isset($data['ShortPixel']['date']) ? $data['ShortPixel']['date'] : null;
2814
  $renderData['quotaExceeded'] = $quotaExceeded;
2815
  $webP = 0;
2866
  $renderData['message'] = ($fileExtension == "pdf" ? 'PDF' : __('Image','shortpixel-image-optimiser'))
2867
  . __(' not processed.','shortpixel-image-optimiser')
2868
  . ' (<a href="https://shortpixel.com/image-compression-test?site-url=' . urlencode(ShortPixelMetaFacade::safeGetAttachmentUrl($id)) . '" target="_blank">'
2869
+ . __('Test&nbsp;for&nbsp;free','shortpixel-image-optimiser') . '</a>)';
2870
  }
2871
 
2872
  $this->view->renderCustomColumn($id, $renderData, $extended);
2873
  }
2874
  }
2875
 
2876
+ function optimizationPercentIfPng2Jpg($meta) {
2877
+ $png2jpgPercent = isset($meta['ShortPixelPng2Jpg']['optimizationPercent']) ? $meta['ShortPixelPng2Jpg']['optimizationPercent'] : 0;
2878
+ return number_format(100.0 - (100.0 - $png2jpgPercent) * (100.0 - $meta['ShortPixelImprovement']) / 100.0, 2);
2879
+ }
2880
+
2881
  function shortpixelInfoBox() {
2882
  if(get_post_type( ) == 'attachment') {
2883
  add_meta_box(
3018
 
3019
  static public function _isProcessablePath($path, $excludeExtensions = array(), $excludePatterns = array()) {
3020
  $pathParts = pathinfo($path);
3021
+ $ext = isset($pathParts['extension']) ? $pathParts['extension'] : false;
3022
+ if( $ext && in_array(strtolower($ext), array_diff(self::$PROCESSABLE_EXTENSIONS, $excludeExtensions))) {
3023
  //apply patterns defined by user to exclude some file names or paths
3024
  if(!$excludePatterns || !is_array($excludePatterns)) { return true; }
3025
  foreach($excludePatterns as $item) {
3149
  $get_intermediate_image_sizes = get_intermediate_image_sizes();
3150
 
3151
  // Create the full array with sizes and crop info
3152
+ if(is_array($get_intermediate_image_sizes)) foreach( $get_intermediate_image_sizes as $_size ) {
3153
  if ( in_array( $_size, array( 'thumbnail', 'medium', 'large' ) ) ) {
3154
  $width = max($width, get_option( $_size . '_size_w' ));
3155
  $height = max($height, get_option( $_size . '_size_h' ));
class/wp-shortpixel-settings.php CHANGED
@@ -28,6 +28,7 @@ class WPShortPixelSettings {
28
  'createWebp' => array('key' => 'wp-short-create-webp', 'default' => null),
29
  'createWebpMarkup' => array('key' => 'wp-short-pixel-create-webp-markup', 'default' => null),
30
  'optimizeRetina' => array('key' => 'wp-short-pixel-optimize-retina', 'default' => 1),
 
31
  'backupImages' => array('key' => 'wp-short-backup_images', 'default' => 1),
32
  'resizeImages' => array('key' => 'wp-short-pixel-resize-images', 'default' => false),
33
  'resizeType' => array('key' => 'wp-short-pixel-resize-type', 'default' => null),
@@ -64,6 +65,7 @@ class WPShortPixelSettings {
64
  'activationNotice' => array('key' => 'wp-short-pixel-activation-notice', 'default' => null),
65
  'mediaLibraryViewMode' => array('key' => 'wp-short-pixel-view-mode', 'default' => null),
66
  'redirectedSettings' => array('key' => 'wp-short-pixel-redirected-settings', 'default' => null),
 
67
 
68
  //bulk state machine
69
  'bulkType' => array('key' => 'wp-short-pixel-bulk-type', 'default' => null),
@@ -124,14 +126,15 @@ class WPShortPixelSettings {
124
 
125
  public static function onActivate() {
126
  if(!self::getOpt('wp-short-pixel-verifiedKey', false)) {
127
- update_option('wp-short-pixel-activation-notice', true);
128
  }
129
- update_option( 'wp-short-pixel-activation-date', time());
130
  delete_option( 'wp-short-pixel-bulk-last-status');
 
131
  $dismissed = get_option('wp-short-pixel-dismissed-notices', array());
132
  if(isset($dismissed['compat'])) {
133
  unset($dismissed['compat']);
134
- update_option('wp-short-pixel-dismissed-notices', $dismissed);
135
  }
136
 
137
  }
@@ -170,17 +173,48 @@ class WPShortPixelSettings {
170
  $key = self::$_optionsMap[$key]['key'];
171
  }
172
  if(get_option($key) === false) {
173
- add_option( $key, $default, '', 'yes' );
174
  }
175
  return get_option($key);
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
  }
28
  'createWebp' => array('key' => 'wp-short-create-webp', 'default' => null),
29
  'createWebpMarkup' => array('key' => 'wp-short-pixel-create-webp-markup', 'default' => null),
30
  'optimizeRetina' => array('key' => 'wp-short-pixel-optimize-retina', 'default' => 1),
31
+ 'optimizeUnlisted' => array('key' => 'wp-short-pixel-optimize-unlisted', 'default' => 0),
32
  'backupImages' => array('key' => 'wp-short-backup_images', 'default' => 1),
33
  'resizeImages' => array('key' => 'wp-short-pixel-resize-images', 'default' => false),
34
  'resizeType' => array('key' => 'wp-short-pixel-resize-type', 'default' => null),
65
  'activationNotice' => array('key' => 'wp-short-pixel-activation-notice', 'default' => null),
66
  'mediaLibraryViewMode' => array('key' => 'wp-short-pixel-view-mode', 'default' => null),
67
  'redirectedSettings' => array('key' => 'wp-short-pixel-redirected-settings', 'default' => null),
68
+ 'convertedPng2Jpg' => array('key' => 'wp-short-pixel-converted-png2jpg', 'default' => array()),
69
 
70
  //bulk state machine
71
  'bulkType' => array('key' => 'wp-short-pixel-bulk-type', 'default' => null),
126
 
127
  public static function onActivate() {
128
  if(!self::getOpt('wp-short-pixel-verifiedKey', false)) {
129
+ update_option('wp-short-pixel-activation-notice', true, 'no');
130
  }
131
+ update_option( 'wp-short-pixel-activation-date', time(), 'no');
132
  delete_option( 'wp-short-pixel-bulk-last-status');
133
+ delete_option( 'wp-short-pixel-current-total-files');
134
  $dismissed = get_option('wp-short-pixel-dismissed-notices', array());
135
  if(isset($dismissed['compat'])) {
136
  unset($dismissed['compat']);
137
+ update_option('wp-short-pixel-dismissed-notices', $dismissed, 'no');
138
  }
139
 
140
  }
173
  $key = self::$_optionsMap[$key]['key'];
174
  }
175
  if(get_option($key) === false) {
176
+ add_option( $key, $default, '', 'no' );
177
  }
178
  return get_option($key);
179
  }
180
 
181
  public function setOpt($key, $val) {
182
+ $ret = update_option($key, $val, 'no');
183
+
184
  //hack for the situation when the option would just not update....
185
+ if($ret === false && !is_array($val) && $val != get_option($key)) {
186
  delete_option($key);
187
+ $alloptions = wp_load_alloptions();
188
+ if ( isset( $alloptions[$key] ) ) {
189
+ wp_cache_delete( 'alloptions', 'options' );
190
+ } else {
191
+ wp_cache_delete( $key, 'options' );
192
+ }
193
+ add_option($key, $val, '', 'no');
194
+
195
+ // still not? try the DB way...
196
+ if($ret === false && $val != get_option($key)) {
197
+ global $wpdb;
198
+ $sql = "SELECT * FROM {$wpdb->prefix}options WHERE option_name = '" . $key . "'";
199
+ $rows = $wpdb->get_results($sql);
200
+ if(count($rows) === 0) {
201
+ $wpdb->insert($wpdb->prefix.'options',
202
+ array("option_name" => $key, "option_value" => (is_array($val) ? serialize($val) : $val), "autoload" => "no"),
203
+ array("option_name" => "%s", "option_value" => (is_numeric($val) ? "%d" : "%s")));
204
+ } else { //update
205
+ $sql = "update {$wpdb->prefix}options SET option_value=" .
206
+ (is_array($val)
207
+ ? "'" . serialize($val) . "'"
208
+ : (is_numeric($val) ? $val : "'" . $val . "'")) . " WHERE option_name = '" . $key . "'";
209
+ $rows = $wpdb->get_results($sql);
210
+ }
211
+
212
+ if($val != get_option($key)) {
213
+ //tough luck, gonna use the bomb...
214
+ wp_cache_flush();
215
+ add_option($key, $val, '', 'no');
216
+ }
217
+ }
218
  }
219
  }
220
  }
readme.txt CHANGED
@@ -3,7 +3,8 @@ 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.2
 
7
  License: GPLv2 or later
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
 
@@ -227,6 +228,18 @@ The ShortPixel team is here to help. <a href="https://shortpixel.com/contact">Co
227
 
228
  == Changelog ==
229
 
 
 
 
 
 
 
 
 
 
 
 
 
230
  = 4.7.2 =
231
  * fix wrong use of _ function which displayed warning
232
 
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
+ Requires PHP: 5.3
7
+ Stable tag: 4.8.0
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
228
 
229
  == Changelog ==
230
 
231
+ = 4.8.0 =
232
+ * propose best plans options for optimizing all images
233
+ * option to optimize or not the found unlisted thumbs, alert the user about them.
234
+ * convert png to jpeg also when doing bulk if option set. Also search for usages of the image and replace the URLs in the content.
235
+ * fix compatbility problem with S3 Offload which caused sending two different sets of URLs for an image.
236
+ * trim site_url output - found a client case where it ended with a tab...
237
+ * all wp_options with autoload=no
238
+ * minify all js and css files
239
+ * performance improvements for the picture tag generation
240
+ * retina versions of the icons
241
+ * fix "Optimize 0 thumbnails" in column menu generated from Javascript.
242
+
243
  = 4.7.2 =
244
  * fix wrong use of _ function which displayed warning
245
 
res/css/short-pixel.css CHANGED
@@ -416,6 +416,10 @@ div.shortpixel-modal .sptw-modal-spinner {
416
  .wp-core-ui .bulk-play a.button .bulk-btn-txt span.total {
417
  font-size: 1.4em;
418
  }
 
 
 
 
419
  .bulk-progress {
420
  padding: 20px 32px 17px;
421
  background-color: #ffffff;
@@ -545,6 +549,9 @@ p.settings-info {
545
  color: #818181;
546
  font-size:13px !important;
547
  }
 
 
 
548
 
549
  /* TABS CONTROLS */
550
  article.sp-tabs {
@@ -622,6 +629,10 @@ article.sp-tabs section h2 {
622
  transition: all 500ms ease;
623
  }
624
  */
 
 
 
 
625
  /* Resources */
626
  @media(min-width: 1000px) {
627
  section#tab-resources .col-md-6 {
416
  .wp-core-ui .bulk-play a.button .bulk-btn-txt span.total {
417
  font-size: 1.4em;
418
  }
419
+ .short-pixel-notice-icon {
420
+ float:left;
421
+ margin: 10px 10px 10px 0;
422
+ }
423
  .bulk-progress {
424
  padding: 20px 32px 17px;
425
  background-color: #ffffff;
549
  color: #818181;
550
  font-size:13px !important;
551
  }
552
+ p.settings-info.shortpixel-settings-error {
553
+ color: #c32525;
554
+ }
555
 
556
  /* TABS CONTROLS */
557
  article.sp-tabs {
629
  transition: all 500ms ease;
630
  }
631
  */
632
+ .shortpixel-help-link span.dashicons{
633
+ text-decoration: none;
634
+ margin-top: -1px;
635
+ }
636
  /* Resources */
637
  @media(min-width: 1000px) {
638
  section#tab-resources .col-md-6 {
res/css/short-pixel.min.css ADDED
@@ -0,0 +1 @@
 
1
+ .sp-dropbtn.button{padding:1px 24px 20px 5px;font-size:20px;cursor:pointer}.sp-dropdown{position:relative;display:inline-block}.sp-dropdown-content{display:none;right:0;position:absolute;background-color:#f9f9f9;min-width:190px;box-shadow:0 8px 16px 0 rgba(0,0,0,0.2);z-index:1}.sp-dropdown-content a{color:black;padding:12px 16px;text-decoration:none;display:block}.sp-dropdown-content a:hover{background-color:#f1f1f1}.sp-dropdown.sp-show .sp-dropdown-content{display:block}div.fb-like{transform:scale(1.3);-ms-transform:scale(1.3);-webkit-transform:scale(1.3);-o-transform:scale(1.3);-moz-transform:scale(1.3);transform-origin:bottom left;-ms-transform-origin:bottom left;-webkit-transform-origin:bottom left;-moz-transform-origin:bottom left;-webkit-transform-origin:bottom left}.wp-core-ui .button.button-alert,.wp-core-ui .button.button-alert:hover{background:#f79797}.wp-core-ui .button.remove-folder-button{min-width:120px}.sp-notice{background:#fff;border-left:4px solid #fff;-webkit-box-shadow:0 1px 1px 0 rgba(0,0,0,.1);box-shadow:0 1px 1px 0 rgba(0,0,0,.1);padding:1px 12px}@media(max-width:1249px){.sp-notice{margin:5px 15px 2px}}.sp-notice-info{border-left-color:#00a0d2}.sp-notice-success{border-left-color:#46b450}li.sp-conflict-plugins-list{line-height:28px;list-style:disc;margin-left:20px}li.sp-conflict-plugins-list a.button{margin-left:10px}div.short-pixel-bulk-page input.dial{font-size:16px!important}div.short-pixel-bulk-page h1{margin-bottom:20px}div.bulk-progress div.sp-h2{margin-top:0;margin-bottom:10px;font-size:23px;font-weight:400;padding:9px 15px 4px 0;line-height:29px}div.bulk-progress-partners{margin-top:20px}div.bulk-progress.bulk-progress-partners a div{display:inline-block;vertical-align:top;line-height:50px;margin-left:30px;font-size:1.2em}div.bulk-progress .bulk-progress-indicator,div.sp-quota-exceeded-alert .bulk-progress-indicator{display:inline-block;text-align:center;padding:0 10px;margin-left:10px;float:left;height:90px;overflow:hidden;border:1px solid #1caecb}div.wrap.short-pixel-bulk-page .bulk-notice-container{margin-top:15px;position:absolute;width:500px}div.wrap.short-pixel-bulk-page .bulk-notice-container .bulk-notice-msg{text-align:center;margin:10px 0 0 32px;overflow:hidden;border:1px solid #1caecb;background-color:#9ddbe0;border-radius:5px;padding:7px 10px 10px;display:none;max-width:600px;margin-right:20px}div.wrap.short-pixel-bulk-page .bulk-notice-container .bulk-notice-msg.bulk-error{border:1px solid #b5914d;background-color:#ffe996;margin-right:20px}div.wrap.short-pixel-bulk-page .bulk-notice-container .bulk-notice-msg.bulk-error.bulk-error-fatal{border:1px solid #c32525;background-color:#ff969d}div.wrap.short-pixel-bulk-page .bulk-notice-msg img{float:left;margin-top:3px;margin-right:5px}div.sp-bulk-summary{float:right;margin:8px 5px 3px 20px}input.dial{box-shadow:none}.shortpixel-table .column-filename{max-width:32em;width:40%}.shortpixel-table .column-folder{max-width:20em;width:20%}.shortpixel-table .column-media_type{max-width:8em;width:10%}.shortpixel-table .column-status{max-width:16em;width:15%}.shortpixel-table .column-options{max-width:16em;width:15%}.form-table table.shortpixel-folders-list tr{background-color:#eee}.form-table table.shortpixel-folders-list td{padding:5px 10px}div.shortpixel-rate-us{display:inline-block;margin-left:10px;vertical-align:top;font-weight:bold}div.shortpixel-rate-us>a{vertical-align:middle;padding:1px 5px 0;text-align:center;display:inline-block}div.shortpixel-rate-us>a>span{display:inline-block;vertical-align:top;margin-top:5px}div.shortpixel-rate-us>a>img{padding-top:7px}div.shortpixel-rate-us>a:active,div.shortpixel-rate-us>a:hover,div.shortpixel-rate-us>a:focus{outline:0;border-style:none}.sp-loading-small{margin-top:2px;float:left;margin-right:5px}li.shortpixel-toolbar-processing>a.ab-item>div,#wpadminbar li.shortpixel-toolbar-processing>a.ab-item>div{height:33px;margin-top:-1px;padding:0 3px}li.shortpixel-toolbar-processing>a.ab-item>div>img,#wpadminbar li.shortpixel-toolbar-processing>a.ab-item>div>img{margin-right:2px;margin-top:6px}li.shortpixel-toolbar-processing>a.ab-item>div>span.shp-alert,#wpadminbar li.shortpixel-toolbar-processing>a.ab-item>div>span.shp-alert{display:none}li.shortpixel-toolbar-processing.shortpixel-alert>a.ab-item>div>span.shp-alert,#wpadminbar li.shortpixel-toolbar-processing.shortpixel-alert>a.ab-item>div>span.shp-alert{display:inline;font-size:26px;color:red;font-weight:bold;vertical-align:top}li.shortpixel-toolbar-processing.shortpixel-alert>a.ab-item>div,#wpadminbar li.shortpixel-toolbar-processing.shortpixel-alert>a.ab-item>div{background-image:none}.sp-quota-exceeded-alert{background-color:#fff;border-left:4px solid #f00;box-shadow:0 1px 1px 0 rgba(0,0,0,0.1);padding:1px 12px}.shortpixel-hide{display:none}.shortpixel-clearfix{width:100%;float:left}div.sp-modal-shade{display:none;position:fixed;z-index:10;left:0;top:0;width:100%;height:100%;overflow:auto;background-color:#000;background-color:rgba(0,0,0,0.4)}div.shortpixel-modal{background-color:#fefefe;margin:8% auto;padding:20px;border:1px solid #888;width:30%;min-width:300px}div.shortpixel-modal .sp-close-button,div.shortpixel-modal .sp-close-upgrade-button{float:right;margin-top:0;background:transparent;border:0;font-size:22px;line-height:10px;cursor:pointer}.twentytwenty-horizontal .twentytwenty-before-label:before,.twentytwenty-horizontal .twentytwenty-after-label:before{font-family:inherit;font-size:16px}div.sp-modal-title{font-size:22px}div.sp-modal-body{margin-top:20px}.short-pixel-bulk-page p{margin:.6em 0}div.shortpixel-modal .sptw-modal-spinner{background-image:url("../img/spinner2.gif");background-repeat:no-repeat;background-position:center}.short-pixel-bulk-page form.start{display:table;content:" ";width:98%;background-color:white;padding:10px 10px 0;position:relative}.bulk-stats-container{display:inline-block;min-width:450px;width:45%;float:left;padding-right:50px;font-size:1.1em;line-height:1.5em}.bulk-text-container{display:inline-block;min-width:440px;width:45%;float:left;padding-right:50px}.bulk-text-container h3{border-bottom:1px solid #a8a8a8;margin-bottom:.5em;padding-bottom:.5em}.bulk-wide{display:inline-block;width:90%;float:left;margin-top:25px}.bulk-stats-container .bulk-label{width:220px;display:inline-block}.bulk-stats-container .bulk-val{width:50px;display:inline-block;text-align:right}.bulk-stats-container .bulk-total{font-weight:bold;margin-top:10px;margin-bottom:10px}.wp-core-ui .bulk-play{display:inline;width:310px;float:left;margin-bottom:20px}.wp-core-ui .bulk-play.bulk-nothing-optimize{font-weight:bold;color:#0080b2;border:1px solid;border-radius:5px;margin-top:60px;padding:5px 12px}.wp-core-ui .bulk-play a.button{height:60px;margin-top:27px;width:290px;overflow:hidden}.wp-core-ui .column-wp-shortPixel .sp-column-actions{max-width:140px;float:right;text-align:right}.wp-core-ui .column-wp-shortPixel .sp-column-actions .button.button-smaller{margin-right:0}.wp-core-ui .column-wp-shortPixel .button.button-smaller{font-size:13px;padding:0 5px;margin-bottom:4px;height:20px;line-height:16px;float:right}.wp-core-ui .bulk-play a.button .bulk-btn-img{float:left;display:inline-block;padding-top:6px}.wp-core-ui .bulk-play a.button .bulk-btn-txt{float:left;display:inline-block;text-align:right;line-height:1.3em;margin:11px 10px}.wp-core-ui .bulk-play a.button .bulk-btn-txt span.label{font-size:1.6em}.wp-core-ui .bulk-play a.button .bulk-btn-txt span.total{font-size:1.4em}.short-pixel-notice-icon{float:left;margin:10px 10px 10px 0}.bulk-progress{padding:20px 32px 17px;background-color:#fff}.bulk-progress.bulk-stats>div{display:inline-block}.bulk-progress.bulk-stats>div.label{width:320px}.bulk-progress.bulk-stats>div.stat-value{width:80px;text-align:right}.progress{background-color:#ecedee;height:30px;position:relative;width:60%;display:inline-block;margin-right:28px}.progress .progress-img{position:absolute;top:-10px;z-index:2;margin-left:-35px;line-height:48px;font-size:22px;font-weight:bold}.progress .progress-img span{vertical-align:top;margin-left:-7px}.progress .progress-left{background-color:#1cbecb;bottom:0;left:0;position:absolute;top:0;z-index:1;font-size:22px;font-weight:bold;line-height:28px;text-align:center;color:#fff}.bulk-estimate{font-size:20px;line-height:30px;vertical-align:top;display:inline-block}.wp-core-ui .button-primary.bulk-cancel{float:right;height:30px}.short-pixel-block-title{font-size:22px;font-weight:bold;margin-bottom:15px;text-align:center;margin-bottom:30px}.sp-floating-block.bulk-slider-container{display:none}.sp-floating-block.sp-notice.bulk-notices-parent{padding:0;margin:0;float:right;margin-right:500px!important}.bulk-slider-container{margin-top:20px;min-height:300px;overflow:hidden}.bulk-slider-container h2{margin-bottom:15px}.bulk-slider-container span.filename{font-weight:normal}.bulk-slider{display:table;margin:0 auto}.bulk-slider .bulk-slide{margin:0 auto;padding-left:120px;display:inline-block;font-weight:bold}.bulk-slider .img-original,.bulk-slider .img-optimized{display:inline-block;margin-right:20px;text-align:center}.bulk-slider .img-original div,.bulk-slider .img-optimized div{max-height:450px;overflow:hidden}.bulk-slider .img-original img,.bulk-slider .img-optimized img{max-width:300px}.bulk-slider .img-info{display:inline-block;vertical-align:top;font-size:48px;max-width:150px;padding:10px 0 0 20px}.bulk-slide-images{display:inline-block;border:1px solid #1caecb;padding:15px 0 0 20px}p.settings-info{padding-top:0;color:#818181;font-size:13px!important}p.settings-info.shortpixel-settings-error{color:#c32525}article.sp-tabs{position:relative;display:block;width:100%;height:1100px;margin:2em auto}article.sp-tabs section{position:absolute;display:block;top:1.8em;left:0;height:1100px;width:94%;padding:10px 20px;background-color:#ddd;box-shadow:0 3px 3px rgba(0,0,0,0.1);z-index:0}article.sp-tabs section:first-child{z-index:1}article.sp-tabs section h2{position:absolute;font-size:1.3em;font-weight:normal;width:180px;height:1.8em;top:-1.8em;left:10px;padding:0;margin:0;color:#999;background-color:#ddd}article.sp-tabs section:nth-child(2) h2{left:192px}article.sp-tabs section:nth-child(3) h2{left:374px}article.sp-tabs section:nth-child(4) h2{left:556px}article.sp-tabs section h2 a{display:block;width:100%;line-height:1.8em;text-align:center;text-decoration:none;color:#23282d;outline:0 none}article.sp-tabs section h2 a:focus,article.sp-tabs section#tab-resources a:focus{box-shadow:none;outline:0}article.sp-tabs section.sel-tab,article.sp-tabs section.sel-tab h2{color:#333;background-color:#fff;z-index:2}.shortpixel-help-link span.dashicons{text-decoration:none;margin-top:-1px}@media(min-width:1000px){section#tab-resources .col-md-6{display:inline-block;width:45%}}@media(max-width:999px){section#tab-resources .col-sm-12{display:inline-block;width:100%}}section#tab-resources .text-center{text-align:center}section#tab-resources p{font-size:16px}.wrap.short-pixel-bulk-page{margin-right:0}.sp-container{overflow:hidden;display:block;width:100%}.sp-floating-block{overflow:hidden;display:inline-block;float:left;margin-right:1.1%!important}.sp-full-width{width:98.8%;box-sizing:border-box}.sp-double-width{width:65.52%;box-sizing:border-box}.sp-single-width{width:32.23%;box-sizing:border-box}@media(max-width:1759px){.sp-floating-block{margin-right:1.3%!important}.sp-double-width,.sp-full-width{width:98.65%}.sp-single-width{width:48.7%}}@media(max-width:1249px){.sp-floating-block{margin-right:2%!important}.sp-double-width,.sp-full-width,.sp-single-width{width:97%}}.sp-tabs h2:before{content:none}#wpadminbar .shortpixel-toolbar-processing .cssload-container{width:100%;height:24px;text-align:center;position:absolute;top:0;left:-1px}#wpadminbar .shortpixel-toolbar-processing.shortpixel-quota-exceeded .cssload-container{display:none}#wpadminbar .shortpixel-toolbar-processing .cssload-speeding-wheel{width:24px;height:24px;opacity:.7;margin:0 auto;border:4px solid #1cbfcb;border-radius:50%;border-left-color:transparent;animation:cssload-spin 2000ms infinite linear;-o-animation:cssload-spin 2000ms infinite linear;-ms-animation:cssload-spin 2000ms infinite linear;-webkit-animation:cssload-spin 2000ms infinite linear;-moz-animation:cssload-spin 2000ms infinite linear}@keyframes cssload-spin{100%{transform:rotate(360deg);transform:rotate(360deg)}}@-o-keyframes cssload-spin{100%{-o-transform:rotate(360deg);transform:rotate(360deg)}}@-ms-keyframes cssload-spin{100%{-ms-transform:rotate(360deg);transform:rotate(360deg)}}@-webkit-keyframes cssload-spin{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@-moz-keyframes cssload-spin{100%{-moz-transform:rotate(360deg);transform:rotate(360deg)}}
res/css/sp-file-tree.min.css ADDED
@@ -0,0 +1,2 @@
 
 
1
+
2
+ div.sp-folder-picker{margin:20px 0;border:1px solid #888;max-height:400px;overflow:auto}UL.jqueryFileTree LI.directory.selected{background-color:#209fd2}UL.jqueryFileTree{font-family:Verdana,sans-serif;font-size:11px;line-height:18px;padding:0;margin:0;display:none}UL.jqueryFileTree LI{list-style:none;padding:0;padding-left:20px;margin:0;white-space:nowrap}UL.jqueryFileTree LI.directory{background:url(../img/file-tree/directory.png) left top no-repeat}UL.jqueryFileTree LI.directory-locked{background:url(../img/file-tree/directory-lock.png) left top no-repeat}UL.jqueryFileTree LI.expanded{background:url(../img/file-tree/folder_open.png) left top no-repeat}UL.jqueryFileTree LI.file{background:url(../img/file-tree/file.png) left top no-repeat}UL.jqueryFileTree LI.file-locked{background:url(../img/file-tree/file-lock.png) left top no-repeat!important}UL.jqueryFileTree LI.wait{background:url(../img/file-tree/spinner.gif) left top no-repeat}UL.jqueryFileTree LI.selected>a{font-weight:bold}UL.jqueryFileTree LI.ext_3gp{background:url(../img/file-tree/film.png) left top no-repeat}UL.jqueryFileTree LI.ext_afp{background:url(../img/file-tree/code.png) left top no-repeat}UL.jqueryFileTree LI.ext_afpa{background:url(../img/file-tree/code.png) left top no-repeat}UL.jqueryFileTree LI.ext_asp{background:url(../img/file-tree/code.png) left top no-repeat}UL.jqueryFileTree LI.ext_aspx{background:url(../img/file-tree/code.png) left top no-repeat}UL.jqueryFileTree LI.ext_avi{background:url(../img/file-tree/film.png) left top no-repeat}UL.jqueryFileTree LI.ext_bat{background:url(../img/file-tree/application.png) left top no-repeat}UL.jqueryFileTree LI.ext_bmp{background:url(../img/file-tree/picture.png) left top no-repeat}UL.jqueryFileTree LI.ext_c{background:url(../img/file-tree/code.png) left top no-repeat}UL.jqueryFileTree LI.ext_cfm{background:url(../img/file-tree/code.png) left top no-repeat}UL.jqueryFileTree LI.ext_cgi{background:url(../img/file-tree/code.png) left top no-repeat}UL.jqueryFileTree LI.ext_com{background:url(../img/file-tree/application.png) left top no-repeat}UL.jqueryFileTree LI.ext_cpp{background:url(../img/file-tree/code.png) left top no-repeat}UL.jqueryFileTree LI.ext_css{background:url(../img/file-tree/css.png) left top no-repeat}UL.jqueryFileTree LI.ext_doc{background:url(../img/file-tree/doc.png) left top no-repeat}UL.jqueryFileTree LI.ext_exe{background:url(../img/file-tree/application.png) left top no-repeat}UL.jqueryFileTree LI.ext_gif{background:url(../img/file-tree/picture.png) left top no-repeat}UL.jqueryFileTree LI.ext_fla{background:url(../img/file-tree/flash.png) left top no-repeat}UL.jqueryFileTree LI.ext_h{background:url(../img/file-tree/code.png) left top no-repeat}UL.jqueryFileTree LI.ext_htm{background:url(../img/file-tree/html.png) left top no-repeat}UL.jqueryFileTree LI.ext_html{background:url(../img/file-tree/html.png) left top no-repeat}UL.jqueryFileTree LI.ext_jar{background:url(../img/file-tree/java.png) left top no-repeat}UL.jqueryFileTree LI.ext_jpg{background:url(../img/file-tree/picture.png) left top no-repeat}UL.jqueryFileTree LI.ext_jpeg{background:url(../img/file-tree/picture.png) left top no-repeat}UL.jqueryFileTree LI.ext_js{background:url(../img/file-tree/script.png) left top no-repeat}UL.jqueryFileTree LI.ext_lasso{background:url(../img/file-tree/code.png) left top no-repeat}UL.jqueryFileTree LI.ext_log{background:url(../img/file-tree/txt.png) left top no-repeat}UL.jqueryFileTree LI.ext_m4p{background:url(../img/file-tree/music.png) left top no-repeat}UL.jqueryFileTree LI.ext_mov{background:url(../img/file-tree/film.png) left top no-repeat}UL.jqueryFileTree LI.ext_mp3{background:url(../img/file-tree/music.png) left top no-repeat}UL.jqueryFileTree LI.ext_mp4{background:url(../img/file-tree/film.png) left top no-repeat}UL.jqueryFileTree LI.ext_mpg{background:url(../img/file-tree/film.png) left top no-repeat}UL.jqueryFileTree LI.ext_mpeg{background:url(../img/file-tree/film.png) left top no-repeat}UL.jqueryFileTree LI.ext_ogg{background:url(../img/file-tree/music.png) left top no-repeat}UL.jqueryFileTree LI.ext_ogv{background:url(../img/file-tree/film.png) left top no-repeat}UL.jqueryFileTree LI.ext_pcx{background:url(../img/file-tree/picture.png) left top no-repeat}UL.jqueryFileTree LI.ext_pdf{background:url(../img/file-tree/pdf.png) left top no-repeat}UL.jqueryFileTree LI.ext_php{background:url(../img/file-tree/php.png) left top no-repeat}UL.jqueryFileTree LI.ext_png{background:url(../img/file-tree/picture.png) left top no-repeat}UL.jqueryFileTree LI.ext_ppt{background:url(../img/file-tree/ppt.png) left top no-repeat}UL.jqueryFileTree LI.ext_psd{background:url(../img/file-tree/psd.png) left top no-repeat}UL.jqueryFileTree LI.ext_pl{background:url(../img/file-tree/script.png) left top no-repeat}UL.jqueryFileTree LI.ext_py{background:url(../img/file-tree/script.png) left top no-repeat}UL.jqueryFileTree LI.ext_rb{background:url(../img/file-tree/ruby.png) left top no-repeat}UL.jqueryFileTree LI.ext_rbx{background:url(../img/file-tree/ruby.png) left top no-repeat}UL.jqueryFileTree LI.ext_rhtml{background:url(../img/file-tree/ruby.png) left top no-repeat}UL.jqueryFileTree LI.ext_rpm{background:url(../img/file-tree/linux.png) left top no-repeat}UL.jqueryFileTree LI.ext_ruby{background:url(../img/file-tree/ruby.png) left top no-repeat}UL.jqueryFileTree LI.ext_sql{background:url(../img/file-tree/db.png) left top no-repeat}UL.jqueryFileTree LI.ext_swf{background:url(../img/file-tree/flash.png) left top no-repeat}UL.jqueryFileTree LI.ext_tif{background:url(../img/file-tree/picture.png) left top no-repeat}UL.jqueryFileTree LI.ext_tiff{background:url(../img/file-tree/picture.png) left top no-repeat}UL.jqueryFileTree LI.ext_txt{background:url(../img/file-tree/txt.png) left top no-repeat}UL.jqueryFileTree LI.ext_vb{background:url(../img/file-tree/code.png) left top no-repeat}UL.jqueryFileTree LI.ext_wav{background:url(../img/file-tree/music.png) left top no-repeat}UL.jqueryFileTree LI.ext_webm{background:url(../img/file-tree/film.png) left top no-repeat}UL.jqueryFileTree LI.ext_wmv{background:url(../img/file-tree/film.png) left top no-repeat}UL.jqueryFileTree LI.ext_xls{background:url(../img/file-tree/xls.png) left top no-repeat}UL.jqueryFileTree LI.ext_xml{background:url(../img/file-tree/code.png) left top no-repeat}UL.jqueryFileTree LI.ext_zip{background:url(../img/file-tree/zip.png) left top no-repeat}UL.jqueryFileTree A{color:#333;text-decoration:none;display:inline-block;padding:0 2px;cursor:pointer}UL.jqueryFileTree A:hover{background:#BDF}
res/css/twentytwenty.min.css ADDED
@@ -0,0 +1,2 @@
 
 
1
+
2
+ .twentytwenty-horizontal .twentytwenty-handle:before,.twentytwenty-horizontal .twentytwenty-handle:after,.twentytwenty-vertical .twentytwenty-handle:before,.twentytwenty-vertical .twentytwenty-handle:after{content:" ";display:block;background:white;position:absolute;z-index:30;-webkit-box-shadow:0 0 12px rgba(51,51,51,0.5);-moz-box-shadow:0 0 12px rgba(51,51,51,0.5);box-shadow:0 0 12px rgba(51,51,51,0.5)}.twentytwenty-horizontal .twentytwenty-handle:before,.twentytwenty-horizontal .twentytwenty-handle:after{width:3px;height:9999px;left:50%;margin-left:-1.5px}.twentytwenty-vertical .twentytwenty-handle:before,.twentytwenty-vertical .twentytwenty-handle:after{width:9999px;height:3px;top:50%;margin-top:-1.5px}.twentytwenty-before-label,.twentytwenty-after-label,.twentytwenty-overlay{position:absolute;top:0;width:100%;height:100%}.twentytwenty-before-label,.twentytwenty-after-label,.twentytwenty-overlay{-webkit-transition-duration:.5s;-moz-transition-duration:.5s;transition-duration:.5s}.twentytwenty-before-label,.twentytwenty-after-label{-webkit-transition-property:opacity;-moz-transition-property:opacity;transition-property:opacity}.twentytwenty-before-label:before,.twentytwenty-after-label:before{color:white;font-size:13px;letter-spacing:.1em}.twentytwenty-before-label:before{background:rgba(82,82,82,0.9) none repeat scroll 0 0}.twentytwenty-after-label:before{background:rgba(28,190,203,0.9) none repeat scroll 0 0}.twentytwenty-before-label:before,.twentytwenty-after-label:before{position:absolute;line-height:38px;padding:0 20px;-webkit-border-radius:2px;-moz-border-radius:2px;font-family:montserratbold;font-weight:bold}.twentytwenty-horizontal .twentytwenty-before-label:before,.twentytwenty-horizontal .twentytwenty-after-label:before{top:20px}.twentytwenty-vertical .twentytwenty-before-label:before,.twentytwenty-vertical .twentytwenty-after-label:before{left:50%;margin-left:-45px;text-align:center;width:90px}.twentytwenty-left-arrow,.twentytwenty-right-arrow,.twentytwenty-up-arrow,.twentytwenty-down-arrow{width:0;height:0;border:6px inset transparent;position:absolute}.twentytwenty-left-arrow,.twentytwenty-right-arrow{top:50%;margin-top:-6px}.twentytwenty-up-arrow,.twentytwenty-down-arrow{left:50%;margin-left:-6px}.twentytwenty-container{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;z-index:0;overflow:hidden;position:relative;-webkit-user-select:none;-moz-user-select:none}.twentytwenty-container img{max-width:100%;position:absolute;top:0;display:block}.twentytwenty-container.active .twentytwenty-overlay,.twentytwenty-container.active :hover.twentytwenty-overlay{background:rgba(0,0,0,0)}.twentytwenty-container.active .twentytwenty-overlay .twentytwenty-before-label,.twentytwenty-container.active .twentytwenty-overlay .twentytwenty-after-label,.twentytwenty-container.active :hover.twentytwenty-overlay .twentytwenty-before-label,.twentytwenty-container.active :hover.twentytwenty-overlay .twentytwenty-after-label{opacity:0}.twentytwenty-container *{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}.twentytwenty-before-label{opacity:.7}.twentytwenty-before-label:before{content:"ORIGINAL"}.twentytwenty-after-label{opacity:.7}.twentytwenty-after-label:before{content:"SHORTPIXEL"}.twentytwenty-horizontal .twentytwenty-before-label:before{left:20px}.twentytwenty-horizontal .twentytwenty-after-label:before{right:20px}.twentytwenty-vertical .twentytwenty-before-label:before{top:10px}.twentytwenty-vertical .twentytwenty-after-label:before{bottom:10px}.twentytwenty-overlay{-webkit-transition-property:background;-moz-transition-property:background;transition-property:background;background:rgba(0,0,0,0);z-index:25}.twentytwenty-overlay:hover{background:rgba(0,0,0,0)}.twentytwenty-overlay:hover .twentytwenty-after-label{opacity:1}.twentytwenty-overlay:hover .twentytwenty-before-label{opacity:1}.twentytwenty-before{z-index:20}.twentytwenty-after{z-index:10}.twentytwenty-handle{height:38px;width:38px;position:absolute;left:50%;top:50%;margin-left:-22px;margin-top:-22px;border:3px solid white;-webkit-border-radius:1000px;-moz-border-radius:1000px;border-radius:1000px;-webkit-box-shadow:0 0 12px rgba(51,51,51,0.5);-moz-box-shadow:0 0 12px rgba(51,51,51,0.5);box-shadow:0 0 12px rgba(51,51,51,0.5);z-index:40;cursor:pointer}.twentytwenty-horizontal .twentytwenty-handle:before{bottom:50%;margin-bottom:22px;-webkit-box-shadow:0 3px 0 white,0px 0 12px rgba(51,51,51,0.5);-moz-box-shadow:0 3px 0 white,0px 0 12px rgba(51,51,51,0.5);box-shadow:0 3px 0 white,0px 0 12px rgba(51,51,51,0.5)}.twentytwenty-horizontal .twentytwenty-handle:after{top:50%;margin-top:22px;-webkit-box-shadow:0 -3px 0 white,0px 0 12px rgba(51,51,51,0.5);-moz-box-shadow:0 -3px 0 white,0px 0 12px rgba(51,51,51,0.5);box-shadow:0 -3px 0 white,0px 0 12px rgba(51,51,51,0.5)}.twentytwenty-vertical .twentytwenty-handle:before{left:50%;margin-left:22px;-webkit-box-shadow:3px 0 0 white,0px 0 12px rgba(51,51,51,0.5);-moz-box-shadow:3px 0 0 white,0px 0 12px rgba(51,51,51,0.5);box-shadow:3px 0 0 white,0px 0 12px rgba(51,51,51,0.5)}.twentytwenty-vertical .twentytwenty-handle:after{right:50%;margin-right:22px;-webkit-box-shadow:-3px 0 0 white,0px 0 12px rgba(51,51,51,0.5);-moz-box-shadow:-3px 0 0 white,0px 0 12px rgba(51,51,51,0.5);box-shadow:-3px 0 0 white,0px 0 12px rgba(51,51,51,0.5)}.twentytwenty-left-arrow{border-right:6px solid white;left:50%;margin-left:-17px}.twentytwenty-right-arrow{border-left:6px solid white;right:50%;margin-right:-17px}.twentytwenty-up-arrow{border-bottom:6px solid white;top:50%;margin-top:-17px}.twentytwenty-down-arrow{border-top:6px solid white;bottom:50%;margin-bottom:-17px}
res/img/logo-pdf@2x.png ADDED
Binary file
res/img/resize-inner@2x.png ADDED
Binary file
res/img/resize-outer@2x.png ADDED
Binary file
res/img/robo-cool.png ADDED
Binary file
res/img/robo-cool@2x.png@ ADDED
Binary file
res/img/robo-magnifier.png ADDED
Binary file
res/img/robo-magnifier@2x.png ADDED
Binary file
res/img/robo-notes.png ADDED
Binary file
res/img/robo-notes@2x.png ADDED
Binary file
res/img/robo-scared.png ADDED
Binary file
res/img/robo-scared@2x.png ADDED
Binary file
res/img/robo-slider@2x.png ADDED
Binary file
res/js/jquery.knob.min.js ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+
2
+ /*!jQuery Knob*/
3
+ (function(a){if(typeof exports==="object"){module.exports=a(require("jquery"))}else{if(typeof define==="function"&&define.amd){define(["jquery"],a)}else{a(jQuery)}}}(function(d){var b={},a=Math.max,c=Math.min;b.c={};b.c.d=d(document);b.c.t=function(f){return f.originalEvent.touches.length-1};b.o=function(){var e=this;this.o=null;this.$=null;this.i=null;this.g=null;this.v=null;this.cv=null;this.x=0;this.y=0;this.w=0;this.h=0;this.$c=null;this.c=null;this.t=0;this.isInit=false;this.fgColor=null;this.pColor=null;this.dH=null;this.cH=null;this.eH=null;this.rH=null;this.scale=1;this.relative=false;this.relativeWidth=false;this.relativeHeight=false;this.$div=null;this.run=function(){var f=function(i,h){var g;for(g in h){e.o[g]=h[g]}e._carve().init();e._configure()._draw()};if(this.$.data("kontroled")){return}this.$.data("kontroled",true);this.extend();this.o=d.extend({min:this.$.data("min")!==undefined?this.$.data("min"):0,max:this.$.data("max")!==undefined?this.$.data("max"):100,stopper:true,readOnly:this.$.data("readonly")||(this.$.attr("readonly")==="readonly"),cursor:this.$.data("cursor")===true&&30||this.$.data("cursor")||0,thickness:this.$.data("thickness")&&Math.max(Math.min(this.$.data("thickness"),1),0.01)||0.35,lineCap:this.$.data("linecap")||"butt",width:this.$.data("width")||200,height:this.$.data("height")||200,displayInput:this.$.data("displayinput")==null||this.$.data("displayinput"),displayPrevious:this.$.data("displayprevious"),fgColor:this.$.data("fgcolor")||"#87CEEB",inputColor:this.$.data("inputcolor"),font:this.$.data("font")||"Arial",fontWeight:this.$.data("font-weight")||"bold",inline:false,step:this.$.data("step")||1,rotation:this.$.data("rotation"),draw:null,change:null,cancel:null,release:null,format:function(g){return g},parse:function(g){return parseFloat(g)}},this.o);this.o.flip=this.o.rotation==="anticlockwise"||this.o.rotation==="acw";if(!this.o.inputColor){this.o.inputColor=this.o.fgColor}if(this.$.is("fieldset")){this.v={};this.i=this.$.find("input");this.i.each(function(g){var h=d(this);e.i[g]=h;e.v[g]=e.o.parse(h.val());h.bind("change blur",function(){var i={};i[g]=h.val();e.val(e._validate(i))})});this.$.find("legend").remove()}else{this.i=this.$;this.v=this.o.parse(this.$.val());this.v===""&&(this.v=this.o.min);this.$.bind("change blur",function(){e.val(e._validate(e.o.parse(e.$.val())))})}!this.o.displayInput&&this.$.hide();this.$c=d(document.createElement("canvas")).attr({width:this.o.width,height:this.o.height});this.$div=d('<div style="'+(this.o.inline?"display:inline;":"")+"width:"+this.o.width+"px;height:"+this.o.height+'px;"></div>');this.$.wrap(this.$div).before(this.$c);this.$div=this.$.parent();if(typeof G_vmlCanvasManager!=="undefined"){G_vmlCanvasManager.initElement(this.$c[0])}this.c=this.$c[0].getContext?this.$c[0].getContext("2d"):null;if(!this.c){throw {name:"CanvasNotSupportedException",message:"Canvas not supported. Please use excanvas on IE8.0.",toString:function(){return this.name+": "+this.message}}}this.scale=(window.devicePixelRatio||1)/(this.c.webkitBackingStorePixelRatio||this.c.mozBackingStorePixelRatio||this.c.msBackingStorePixelRatio||this.c.oBackingStorePixelRatio||this.c.backingStorePixelRatio||1);this.relativeWidth=this.o.width%1!==0&&this.o.width.indexOf("%");this.relativeHeight=this.o.height%1!==0&&this.o.height.indexOf("%");this.relative=this.relativeWidth||this.relativeHeight;this._carve();if(this.v instanceof Object){this.cv={};this.copy(this.v,this.cv)}else{this.cv=this.v}this.$.bind("configure",f).parent().bind("configure",f);this._listen()._configure()._xy().init();this.isInit=true;this.$.val(this.o.format(this.v));this._draw();return this};this._carve=function(){if(this.relative){var f=this.relativeWidth?this.$div.parent().width()*parseInt(this.o.width)/100:this.$div.parent().width(),g=this.relativeHeight?this.$div.parent().height()*parseInt(this.o.height)/100:this.$div.parent().height();this.w=this.h=Math.min(f,g)}else{this.w=this.o.width;this.h=this.o.height}this.$div.css({width:this.w+"px",height:this.h+"px"});this.$c.attr({width:this.w,height:this.h});if(this.scale!==1){this.$c[0].width=this.$c[0].width*this.scale;this.$c[0].height=this.$c[0].height*this.scale;this.$c.width(this.w);this.$c.height(this.h)}return this};this._draw=function(){var f=true;e.g=e.c;e.clear();e.dH&&(f=e.dH());f!==false&&e.draw()};this._touch=function(f){var g=function(i){var h=e.xy2val(i.originalEvent.touches[e.t].pageX,i.originalEvent.touches[e.t].pageY);if(h==e.cv){return}if(e.cH&&e.cH(h)===false){return}e.change(e._validate(h));e._draw()};this.t=b.c.t(f);g(f);b.c.d.bind("touchmove.k",g).bind("touchend.k",function(){b.c.d.unbind("touchmove.k touchend.k");e.val(e.cv)});return this};this._mouse=function(g){var f=function(i){var h=e.xy2val(i.pageX,i.pageY);if(h==e.cv){return}if(e.cH&&(e.cH(h)===false)){return}e.change(e._validate(h));e._draw()};f(g);b.c.d.bind("mousemove.k",f).bind("keyup.k",function(h){if(h.keyCode===27){b.c.d.unbind("mouseup.k mousemove.k keyup.k");if(e.eH&&e.eH()===false){return}e.cancel()}}).bind("mouseup.k",function(h){b.c.d.unbind("mousemove.k mouseup.k keyup.k");e.val(e.cv)});return this};this._xy=function(){var f=this.$c.offset();this.x=f.left;this.y=f.top;return this};this._listen=function(){if(!this.o.readOnly){this.$c.bind("mousedown",function(f){f.preventDefault();e._xy()._mouse(f)}).bind("touchstart",function(f){f.preventDefault();e._xy()._touch(f)});this.listen()}else{this.$.attr("readonly","readonly")}if(this.relative){d(window).resize(function(){e._carve().init();e._draw()})}return this};this._configure=function(){if(this.o.draw){this.dH=this.o.draw}if(this.o.change){this.cH=this.o.change}if(this.o.cancel){this.eH=this.o.cancel}if(this.o.release){this.rH=this.o.release}if(this.o.displayPrevious){this.pColor=this.h2rgba(this.o.fgColor,"0.4");this.fgColor=this.h2rgba(this.o.fgColor,"0.6")}else{this.fgColor=this.o.fgColor}return this};this._clear=function(){this.$c[0].width=this.$c[0].width};this._validate=function(f){var g=(~~(((f<0)?-0.5:0.5)+(f/this.o.step)))*this.o.step;return Math.round(g*100)/100};this.listen=function(){};this.extend=function(){};this.init=function(){};this.change=function(f){};this.val=function(f){};this.xy2val=function(f,g){};this.draw=function(){};this.clear=function(){this._clear()};this.h2rgba=function(i,f){var g;i=i.substring(1,7);g=[parseInt(i.substring(0,2),16),parseInt(i.substring(2,4),16),parseInt(i.substring(4,6),16)];return"rgba("+g[0]+","+g[1]+","+g[2]+","+f+")"};this.copy=function(j,h){for(var g in j){h[g]=j[g]}}};b.Dial=function(){b.o.call(this);this.startAngle=null;this.xy=null;this.radius=null;this.lineWidth=null;this.cursorExt=null;this.w2=null;this.PI2=2*Math.PI;this.extend=function(){this.o=d.extend({bgColor:this.$.data("bgcolor")||"#EEEEEE",angleOffset:this.$.data("angleoffset")||0,angleArc:this.$.data("anglearc")||360,inline:true},this.o)};this.val=function(e,f){if(null!=e){e=this.o.parse(e);if(f!==false&&e!=this.v&&this.rH&&this.rH(e)===false){return}this.cv=this.o.stopper?a(c(e,this.o.max),this.o.min):e;this.v=this.cv;this.$.val(this.o.format(this.v));this._draw()}else{return this.v}};this.xy2val=function(e,h){var f,g;f=Math.atan2(e-(this.x+this.w2),-(h-this.y-this.w2))-this.angleOffset;if(this.o.flip){f=this.angleArc-f-this.PI2}if(this.angleArc!=this.PI2&&(f<0)&&(f>-0.5)){f=0}else{if(f<0){f+=this.PI2}}g=(f*(this.o.max-this.o.min)/this.angleArc)+this.o.min;this.o.stopper&&(g=a(c(g,this.o.max),this.o.min));return g};this.listen=function(){var h=this,g,f,l=function(q){q.preventDefault();var p=q.originalEvent,n=p.detail||p.wheelDeltaX,m=p.detail||p.wheelDeltaY,o=h._validate(h.o.parse(h.$.val()))+(n>0||m>0?h.o.step:n<0||m<0?-h.o.step:0);o=a(c(o,h.o.max),h.o.min);h.val(o,false);if(h.rH){clearTimeout(g);g=setTimeout(function(){h.rH(o);g=null},100);if(!f){f=setTimeout(function(){if(g){h.rH(o)}f=null},200)}}},j,k,e=1,i={37:-h.o.step,38:h.o.step,39:h.o.step,40:-h.o.step};this.$.bind("keydown",function(o){var n=o.keyCode;if(n>=96&&n<=105){n=o.keyCode=n-48}j=parseInt(String.fromCharCode(n));if(isNaN(j)){(n!==13)&&n!==8&&n!==9&&n!==189&&(n!==190||h.$.val().match(/\./))&&o.preventDefault();if(d.inArray(n,[37,38,39,40])>-1){o.preventDefault();var m=h.o.parse(h.$.val())+i[n]*e;h.o.stopper&&(m=a(c(m,h.o.max),h.o.min));h.change(h._validate(m));h._draw();k=window.setTimeout(function(){e*=2},30)}}}).bind("keyup",function(m){if(isNaN(j)){if(k){window.clearTimeout(k);k=null;e=1;h.val(h.$.val())}}else{(h.$.val()>h.o.max&&h.$.val(h.o.max))||(h.$.val()<h.o.min&&h.$.val(h.o.min))}});this.$c.bind("mousewheel DOMMouseScroll",l);this.$.bind("mousewheel DOMMouseScroll",l)};this.init=function(){if(this.v<this.o.min||this.v>this.o.max){this.v=this.o.min}this.$.val(this.v);this.w2=this.w/2;this.cursorExt=this.o.cursor/100;this.xy=this.w2*this.scale;this.lineWidth=this.xy*this.o.thickness;this.lineCap=this.o.lineCap;this.radius=this.xy-this.lineWidth/2;this.o.angleOffset&&(this.o.angleOffset=isNaN(this.o.angleOffset)?0:this.o.angleOffset);this.o.angleArc&&(this.o.angleArc=isNaN(this.o.angleArc)?this.PI2:this.o.angleArc);this.angleOffset=this.o.angleOffset*Math.PI/180;this.angleArc=this.o.angleArc*Math.PI/180;this.startAngle=1.5*Math.PI+this.angleOffset;this.endAngle=1.5*Math.PI+this.angleOffset+this.angleArc;var e=a(String(Math.abs(this.o.max)).length,String(Math.abs(this.o.min)).length,2)+2;this.o.displayInput&&this.i.css({width:((this.w/2+4)>>0)+"px",height:((this.w/3)>>0)+"px",position:"absolute","vertical-align":"middle","margin-top":((this.w/3)>>0)+"px","margin-left":"-"+((this.w*3/4+2)>>0)+"px",border:0,background:"none",font:this.o.fontWeight+" "+((this.w/e)>>0)+"px "+this.o.font,"text-align":"center",color:this.o.inputColor||this.o.fgColor,padding:"0px","-webkit-appearance":"none"})||this.i.css({width:"0px",visibility:"hidden"})};this.change=function(e){this.cv=e;this.$.val(this.o.format(e))};this.angle=function(e){return(e-this.o.min)*this.angleArc/(this.o.max-this.o.min)};this.arc=function(f){var e,g;f=this.angle(f);if(this.o.flip){e=this.endAngle+0.00001;g=e-f-0.00001}else{e=this.startAngle-0.00001;g=e+f+0.00001}this.o.cursor&&(e=g-this.cursorExt)&&(g=g+this.cursorExt);return{s:e,e:g,d:this.o.flip&&!this.o.cursor}};this.draw=function(){var h=this.g,e=this.arc(this.cv),f,g=1;h.lineWidth=this.lineWidth;h.lineCap=this.lineCap;if(this.o.bgColor!=="none"){h.beginPath();h.strokeStyle=this.o.bgColor;h.arc(this.xy,this.xy,this.radius,this.endAngle-0.00001,this.startAngle+0.00001,true);h.stroke()}if(this.o.displayPrevious){f=this.arc(this.v);h.beginPath();h.strokeStyle=this.pColor;h.arc(this.xy,this.xy,this.radius,f.s,f.e,f.d);h.stroke();g=this.cv==this.v}h.beginPath();h.strokeStyle=g?this.o.fgColor:this.fgColor;h.arc(this.xy,this.xy,this.radius,e.s,e.e,e.d);h.stroke()};this.cancel=function(){this.val(this.v)}};d.fn.dial=d.fn.knob=function(e){return this.each(function(){var f=new b.Dial();f.o=e;f.$=d(this);f.run()}).parent()}}));
res/js/jquery.tooltip.min.js ADDED
@@ -0,0 +1,2 @@
 
 
1
+
2
+ (function(a){a.fn.spTooltip=function(d){a.fn.spTooltip.defaultsSettings={attributeName:"title",borderColor:"#ccc",borderSize:"1",cancelClick:0,followMouse:1,height:"auto",hoverIntent:{sensitivity:7,interval:100,timeout:0},loader:0,loaderHeight:0,loaderImagePath:"",loaderWidth:0,positionTop:12,positionLeft:12,width:"auto",titleAttributeContent:"",tooltipBGColor:"#fff",tooltipBGImage:"none",tooltipHTTPType:"get",tooltipPadding:10,tooltipSource:"attribute",tooltipSourceID:"",tooltipSourceURL:"",tooltipID:"tooltip"};var e=a.extend({},a.fn.spTooltip.defaultsSettings,d||{});var g=function(k){var h=0;var l=0;if(!k){var k=window.event}if(k.pageX||k.pageY){h=k.pageX;l=k.pageY}else{if(k.clientX||k.clientY){h=k.clientX+document.body.scrollLeft+document.documentElement.scrollLeft;l=k.clientY+document.body.scrollTop+document.documentElement.scrollTop}}var j={x:h+e.positionLeft,y:l+e.positionTop,w:a("#"+e.tooltipID).width(),h:a("#"+e.tooltipID).height()};var i={x:a(window).scrollLeft(),y:a(window).scrollTop(),w:a(window).width()-20,h:a(window).height()-20};if(j.y+j.h>i.y+i.h&&j.x+j.w>i.x+i.w){j.x=(j.x-j.w)-45;j.y=(j.y-j.h)-45}else{if(j.x+j.w>i.x+i.w){j.x=j.x-(((j.x+j.w)-(i.x+i.w))+20)}else{if(j.y+j.h>i.y+i.h){j.y=j.y-(((j.y+j.h)-(i.y+i.h))+20)}}}a("#"+e.tooltipID).css({left:j.x+"px",top:j.y+"px"})};var f=function(){a("#tooltipLoader").remove();a("#"+e.tooltipID+" #tooltipContent").show();if(a.browser.version=="6.0"){a("#"+e.tooltipID).append('<iframe id="tooltipIE6FixIframe" style="width:'+(a("#"+e.tooltipID).width()+parseFloat(e.borderSize)+parseFloat(e.borderSize)+20)+"px;height:"+(a("#"+e.tooltipID).height()+parseFloat(e.borderSize)+parseFloat(e.borderSize)+20)+"px;position:absolute;top:-"+e.borderSize+"px;left:-"+e.borderSize+'px;filter:alpha(opacity=0);"src="blank.html"></iframe>')}};var b=function(h){a("#"+e.tooltipID).fadeOut("fast").trigger("unload").remove();if(a(h).filter("[title]")){a(h).attr("title",e.titleAttributeContent)}};var c=function(h){var i={};h.replace(/b([^&=]*)=([^&=]*)b/g,function(j,k,l){if(typeof i[k]!="undefined"){i[k]+=","+l}else{i[k]=l}});return i};return this.each(function(i){if(e.cancelClick){a(this).bind("click",function(){return false})}if(a.fn.hoverIntent){a(this).hoverIntent({sensitivity:e.hoverIntent.sensitivity,interval:e.hoverIntent.interval,over:h,timeout:e.hoverIntent.timeout,out:j})}else{a(this).hover(h,j)}function h(n){a("body").append('<div id="'+e.tooltipID+'" style="background-repeat:no-repeat;background-image:url('+e.tooltipBGImage+");padding:"+e.tooltipPadding+"px;display:none;height:"+e.height+";width:"+e.width+";background-color:"+e.tooltipBGColor+";border:"+e.borderSize+"px solid "+e.borderColor+'; position:absolute;z-index:100000000000;"><div id="tooltipContent" style="display:none;"></div></div>');var l=a("#"+e.tooltipID);var o=a("#"+e.tooltipID+" #tooltipContent");if(e.loader&&e.loaderImagePath!=""){l.append('<div id="tooltipLoader" style="width:'+e.loaderWidth+"px;height:"+e.loaderHeight+'px;"><img src="'+e.loaderImagePath+'" /></div>')}if(a(this).attr("title")){e.titleAttributeContent=a(this).attr("title");a(this).attr("title","")}if(a(this).is("input")){a(this).focus(function(){b(this)})}n.preventDefault();g(n);l.show();e.tooltipSourceID=a(this).attr("href")||e.tooltipSourceID;e.tooltipSourceURL=a(this).attr("href")||e.tooltipSourceURL;switch(e.tooltipSource){case"attribute":o.text(e.titleAttributeContent);f();break;case"inline":o.html(a(e.tooltipSourceID).children());l.unload(function(){a(e.tooltipSourceID).html(o.children())});f();break;case"ajax":if(e.tooltipHTTPType=="post"){var m,k;if(e.tooltipSourceURL.indexOf("?")!==-1){m=e.windowSourceURL.substr(0,e.windowSourceURL.indexOf("?"));k=c(e.tooltipSourceURL)}else{m=e.tooltipSourceURL;k={}}o.load(m,k,function(){f()})}else{if(e.tooltipSourceURL.indexOf("?")==-1){e.tooltipSourceURL+="?"}o.load(e.tooltipSourceURL+"&random="+(new Date().getTime()),function(){f()})}break}return false}function j(k){b(this);return false}if(e.followMouse){a(this).bind("mousemove",function(k){g(k);return false})}})}})(jQuery);
res/js/jquery.twentytwenty.min.js ADDED
@@ -0,0 +1,2 @@
 
 
1
+
2
+ (function(a){a.fn.twentytwenty=function(b){var b=a.extend({default_offset_pct:0.5,orientation:"horizontal",slider_move:"drag"},b);return this.each(function(){var h=b.default_offset_pct;var e=a(this);var c=b.orientation;var q=(c==="vertical")?"down":"left";var d=(c==="vertical")?"up":"right";e.wrap("<div class='twentytwenty-wrapper twentytwenty-"+c+"'></div>");e.append("<div class='twentytwenty-overlay'></div>");var r=e.find("img:first");var o=e.find("img:last");e.append("<div class='twentytwenty-handle'></div>");var f=e.find(".twentytwenty-handle");f.append("<span class='twentytwenty-"+q+"-arrow'></span>");f.append("<span class='twentytwenty-"+d+"-arrow'></span>");e.addClass("twentytwenty-container");r.addClass("twentytwenty-before");o.addClass("twentytwenty-after");var j=e.find(".twentytwenty-overlay");j.append("<div class='twentytwenty-before-label'></div>");j.append("<div class='twentytwenty-after-label'></div>");var l=e.find("div.twentytwenty-before-label");var k=e.find("div.twentytwenty-after-label");var i=function(t){var s=r.width();var u=r.height();return{w:s+"px",h:u+"px",cw:(t*s)+"px",ch:(t*u)+"px",}};var g=function(s){if(c==="vertical"){r.css("clip","rect(0,"+s.w+","+s.ch+",0)")}else{r.css("clip","rect(0,"+s.cw+","+s.h+",0)");l.css("clip","rect(0,"+s.cw+","+s.h+",0)");k.css("clip","rect(0,"+s.w+","+s.h+","+s.cw+")")}e.css("height",s.h)};var n=function(s){var t=i(s);f.css((c==="vertical")?"top":"left",(c==="vertical")?t.ch:t.cw);g(t)};a(window).on("resize.twentytwenty",function(s){n(h)});var m=0;var p=0;if(b.slider_move=="drag"){f.on("movestart",function(s){if(((s.distX>s.distY&&s.distX<-s.distY)||(s.distX<s.distY&&s.distX>-s.distY))&&c!=="vertical"){s.preventDefault()}else{if(((s.distX<s.distY&&s.distX<-s.distY)||(s.distX>s.distY&&s.distX>-s.distY))&&c==="vertical"){s.preventDefault()}}e.addClass("active");m=e.offset().left;offsetY=e.offset().top;p=r.width();imgHeight=r.height()});f.on("moveend",function(s){e.removeClass("active")});f.on("move",function(s){if(e.hasClass("active")){h=(c==="vertical")?(s.pageY-offsetY)/imgHeight:(s.pageX-m)/p;if(h<0){h=0}if(h>1){h=1}n(h)}})}else{e.mousemove(function(s){h=(c==="vertical")?(s.pageY-e.offset().top)/r.height():(s.pageX-e.offset().left)/r.width();if(h<0){h=0}if(h>1){h=1}n(h)})}e.find("img").on("mousedown",function(s){s.preventDefault()});a(window).trigger("resize.twentytwenty")})}})(jQuery);
res/js/punycode.min.js ADDED
File without changes
res/js/short-pixel.js CHANGED
@@ -42,8 +42,16 @@ var ShortPixel = function() {
42
  }
43
  }
44
 
 
 
 
 
45
  function updateSignupEmail() {
46
- jQuery('#request_key').attr('href', jQuery('#request_key').attr('href').split('?')[0] + '?pluginemail=' + jQuery('#pluginemail').val());
 
 
 
 
47
  }
48
 
49
  function validateKey(){
@@ -157,6 +165,13 @@ var ShortPixel = function() {
157
  });
158
  }
159
 
 
 
 
 
 
 
 
160
  function onBulkThumbsCheck(check) {
161
  if(check.checked) {
162
  jQuery("#with-thumbs").css('display', 'inherit');
@@ -207,7 +222,7 @@ var ShortPixel = function() {
207
  if(fileName.substr(fileName.lastIndexOf('.') + 1).toLowerCase() == 'pdf') {
208
  jQuery('.sp-action-compare', successActions).remove();
209
  }
210
- if(thumbsCount == 0) {
211
  successActions.html(successActions.html().replace('__SP_THUMBS_TOTAL__', thumbsTotal));
212
  } else {
213
  jQuery('.sp-action-optimize-thumbs', successActions).remove();
@@ -275,6 +290,43 @@ var ShortPixel = function() {
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');
@@ -297,8 +349,26 @@ var ShortPixel = function() {
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");
@@ -424,12 +494,12 @@ var ShortPixel = function() {
424
  .attr({
425
  type: 'text/css',
426
  rel: 'stylesheet',
427
- href: this.WP_PLUGIN_URL + '/res/css/twentytwenty.css'
428
  });
429
  this.comparerData.cssLoaded = 2;
430
  }
431
  if(this.comparerData.jsLoaded === false) {
432
- jQuery.getScript(this.WP_PLUGIN_URL + '/res/js/jquery.twentytwenty.js', function(){
433
  ShortPixel.comparerData.jsLoaded = 2;
434
  if(ShortPixel.comparerData.origUrl.length > 0) {
435
  ShortPixel.displayComparerPopup(ShortPixel.comparerData.width, ShortPixel.comparerData.height, ShortPixel.comparerData.origUrl, ShortPixel.comparerData.optUrl);
@@ -500,6 +570,7 @@ var ShortPixel = function() {
500
 
501
  return {
502
  setOptions : setOptions,
 
503
  updateSignupEmail : updateSignupEmail,
504
  validateKey : validateKey,
505
  enableResize : enableResize,
@@ -510,6 +581,7 @@ var ShortPixel = function() {
510
  adjustSettingsTabs : adjustSettingsTabsHeight,
511
  onBulkThumbsCheck : onBulkThumbsCheck,
512
  dismissMediaAlert : dismissMediaAlert,
 
513
  percentDial : percentDial,
514
  successMsg : successMsg,
515
  successActions : successActions,
@@ -518,8 +590,10 @@ var ShortPixel = function() {
518
  initFolderSelector : initFolderSelector,
519
  browseContent : browseContent,
520
  getBackupSize : getBackupSize,
 
521
  proposeUpgrade : proposeUpgrade,
522
  closeProposeUpgrade : closeProposeUpgrade,
 
523
  bulkShowLengthyMsg : bulkShowLengthyMsg,
524
  bulkHideLengthyMsg : bulkHideLengthyMsg,
525
  bulkShowMaintenanceMsg : bulkShowMaintenanceMsg,
@@ -541,7 +615,8 @@ var ShortPixel = function() {
541
  optUrl : false,
542
  width : 0,
543
  height : 0
544
- }
 
545
  }
546
  }();
547
 
42
  }
43
  }
44
 
45
+ function isEmailValid(email) {
46
+ return /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/.test(email);
47
+ }
48
+
49
  function updateSignupEmail() {
50
+ var email = jQuery('#pluginemail').val();
51
+ if(ShortPixel.isEmailValid(email)) {
52
+ jQuery('#request_key').removeClass('disabled');
53
+ }
54
+ jQuery('#request_key').attr('href', jQuery('#request_key').attr('href').split('?')[0] + '?pluginemail=' + email);
55
  }
56
 
57
  function validateKey(){
165
  });
166
  }
167
 
168
+ function checkQuota() {
169
+ var data = { action : 'shortpixel_check_quota'};
170
+ jQuery.get(ShortPixel.AJAX_URL, data, function() {
171
+ console.log("quota refreshed");
172
+ });
173
+ }
174
+
175
  function onBulkThumbsCheck(check) {
176
  if(check.checked) {
177
  jQuery("#with-thumbs").css('display', 'inherit');
222
  if(fileName.substr(fileName.lastIndexOf('.') + 1).toLowerCase() == 'pdf') {
223
  jQuery('.sp-action-compare', successActions).remove();
224
  }
225
+ if(thumbsCount == 0 && thumbsTotal > 0) {
226
  successActions.html(successActions.html().replace('__SP_THUMBS_TOTAL__', thumbsTotal));
227
  } else {
228
  jQuery('.sp-action-optimize-thumbs', successActions).remove();
290
  return browseResponse;
291
  }
292
 
293
+ function newApiKey(event) {
294
+ jQuery('#request_key').addClass('disabled');
295
+ jQuery('#pluginemail_spinner').addClass('is-active');
296
+ ShortPixel.updateSignupEmail();
297
+ if (ShortPixel.isEmailValid(jQuery('#pluginemail').val())) {
298
+ jQuery('#pluginemail-error').css('display', 'none');
299
+ var browseData = { 'action': 'shortpixel_new_api_key',
300
+ 'email': jQuery('#pluginemail').val()};
301
+ jQuery.ajax({
302
+ type: "POST",
303
+ async: false,
304
+ url: ShortPixel.AJAX_URL,
305
+ data: browseData,
306
+ success: function(response) {
307
+ data = JSON.parse(response);
308
+ if(data["Status"] == 'success') {
309
+ event.preventDefault();
310
+ window.location.reload();
311
+ } else if(data["Status"] == 'invalid') {
312
+ jQuery('#pluginemail-error').html('<b>' + data['Details'] + '</b>');
313
+ jQuery('#pluginemail-error').css('display', '');
314
+ jQuery('#pluginemail-info').css('display', 'none');
315
+ event.preventDefault();
316
+ } else {
317
+ }
318
+ }
319
+ });
320
+ jQuery('#request_key').removeAttr('onclick');
321
+ } else {
322
+ jQuery('#pluginemail-error').css('display', '');
323
+ jQuery('#pluginemail-info').css('display', 'none');
324
+ event.preventDefault();
325
+ }
326
+ jQuery('#request_key').removeClass('disabled');
327
+ jQuery('#pluginemail_spinner').removeClass('is-active');
328
+ }
329
+
330
  function proposeUpgrade() {
331
  //first open the popup window with the spinner
332
  jQuery("#shortPixelProposeUpgrade .sp-modal-body").addClass('sptw-modal-spinner');
349
  function closeProposeUpgrade() {
350
  jQuery("#shortPixelProposeUpgradeShade").css("display", "none");
351
  jQuery("#shortPixelProposeUpgrade").addClass('shortpixel-hide');
352
+ if(ShortPixel.toRefresh) {
353
+ ShortPixel.recheckQuota();
354
+ }
355
  }
356
 
357
+ function includeUnlisted() {
358
+ jQuery("#short-pixel-notice-unlisted").hide();
359
+ jQuery("#optimizeUnlisted").prop('checked', true);
360
+ var data = { action : 'shortpixel_dismiss_notice',
361
+ notice_id: 'unlisted',
362
+ notice_data: 'true'};
363
+ jQuery.get(ShortPixel.AJAX_URL, data, function(response) {
364
+ data = JSON.parse(response);
365
+ if(data["Status"] == ShortPixel.STATUS_SUCCESS) {
366
+ console.log("dismissed");
367
+ }
368
+ });
369
+ }
370
+
371
+
372
  function initFolderSelector() {
373
  jQuery(".select-folder-button").click(function(){
374
  jQuery(".sp-folder-picker-shade").css("display", "block");
494
  .attr({
495
  type: 'text/css',
496
  rel: 'stylesheet',
497
+ href: this.WP_PLUGIN_URL + '/res/css/twentytwenty.min.css'
498
  });
499
  this.comparerData.cssLoaded = 2;
500
  }
501
  if(this.comparerData.jsLoaded === false) {
502
+ jQuery.getScript(this.WP_PLUGIN_URL + '/res/js/jquery.twentytwenty.min.js', function(){
503
  ShortPixel.comparerData.jsLoaded = 2;
504
  if(ShortPixel.comparerData.origUrl.length > 0) {
505
  ShortPixel.displayComparerPopup(ShortPixel.comparerData.width, ShortPixel.comparerData.height, ShortPixel.comparerData.origUrl, ShortPixel.comparerData.optUrl);
570
 
571
  return {
572
  setOptions : setOptions,
573
+ isEmailValid : isEmailValid,
574
  updateSignupEmail : updateSignupEmail,
575
  validateKey : validateKey,
576
  enableResize : enableResize,
581
  adjustSettingsTabs : adjustSettingsTabsHeight,
582
  onBulkThumbsCheck : onBulkThumbsCheck,
583
  dismissMediaAlert : dismissMediaAlert,
584
+ checkQuota : checkQuota,
585
  percentDial : percentDial,
586
  successMsg : successMsg,
587
  successActions : successActions,
590
  initFolderSelector : initFolderSelector,
591
  browseContent : browseContent,
592
  getBackupSize : getBackupSize,
593
+ newApiKey : newApiKey,
594
  proposeUpgrade : proposeUpgrade,
595
  closeProposeUpgrade : closeProposeUpgrade,
596
+ includeUnlisted : includeUnlisted,
597
  bulkShowLengthyMsg : bulkShowLengthyMsg,
598
  bulkHideLengthyMsg : bulkHideLengthyMsg,
599
  bulkShowMaintenanceMsg : bulkShowMaintenanceMsg,
615
  optUrl : false,
616
  width : 0,
617
  height : 0
618
+ },
619
+ toRefresh : false
620
  }
621
  }();
622
 
res/js/short-pixel.min.js ADDED
@@ -0,0 +1 @@
 
1
+ jQuery(document).ready(function(a){if(jQuery("table.wp-list-table.media").length>0){jQuery('select[name^="action"] option:last-child').before('<option value="short-pixel-bulk">'+_spTr.optimizeWithSP+"</option>")}ShortPixel.setOptions(ShortPixelConstants);if(jQuery("#backup-folder-size").length){jQuery("#backup-folder-size").html(ShortPixel.getBackupSize())}if(ShortPixel.MEDIA_ALERT=="todo"&&jQuery("div.media-frame.mode-grid").length>0){jQuery("div.media-frame.mode-grid").before('<div id="short-pixel-media-alert" class="notice notice-warning"><p>'+_spTr.changeMLToListMode.format('<a href="upload.php?mode=list" class="view-list"><span class="screen-reader-text">'," </span>",'</a><a class="alignright" href="javascript:ShortPixel.dismissMediaAlert();">',"</a>")+"</p></div>")}jQuery(window).on("beforeunload",function(){if(ShortPixel.bulkProcessor==true){clearBulkProcessor()}});checkQuotaExceededAlert();checkBulkProgress()});var ShortPixel=function(){function l(M){for(var N in M){ShortPixel[N]=M[N]}}function s(M){return/^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/.test(M)}function m(){var M=jQuery("#pluginemail").val();if(ShortPixel.isEmailValid(M)){jQuery("#request_key").removeClass("disabled")}jQuery("#request_key").attr("href",jQuery("#request_key").attr("href").split("?")[0]+"?pluginemail="+M)}function a(){jQuery("#valid").val("validate");jQuery("#wp_shortpixel_options").submit()}jQuery("#key").keypress(function(M){if(M.which==13){jQuery("#valid").val("validate")}});function H(M){if(jQuery(M).is(":checked")){jQuery("#width,#height").removeAttr("disabled")}else{jQuery("#width,#height").attr("disabled","disabled")}}function e(M,O,Q){for(var N=0,P=null;N<M.length;N++){M[N].onclick=function(){if(this!==P){P=this}alert(_spTr.alertOnlyAppliesToNewImages)}}ShortPixel.enableResize("#resize");jQuery("#resize").change(function(){H(this)});jQuery(".resize-sizes").blur(function(S){var T=jQuery(this);var R=jQuery("#min-"+T.attr("name")).val();if(T.val()<Math.min(R,1024)){if(R>1024){alert(_spTr.pleaseDoNotSetLesser1024.format(T.attr("name")))}else{alert(_spTr.pleaseDoNotSetLesserSize.format(T.attr("name"),T.attr("name"),R))}S.preventDefault();T.val(this.defaultValue);T.focus()}else{this.defaultValue=T.val()}})}function t(){jQuery("input.remove-folder-button").click(function(){var N=jQuery(this).data("value");var M=confirm(_spTr.areYouSureStopOptimizing.format(N));if(M==true){jQuery("#removeFolder").val(N);jQuery("#wp_shortpixel_options").submit()}});jQuery("input.recheck-folder-button").click(function(){var N=jQuery(this).data("value");var M=confirm(_spTr.areYouSureStopOptimizing.format(N));if(M==true){jQuery("#recheckFolder").val(N);jQuery("#wp_shortpixel_options").submit()}})}function G(M){var N=jQuery("#"+(M.checked?"total":"main")+"ToProcess").val();jQuery("div.bulk-play span.total").text(N);jQuery("#displayTotal").text(N)}function w(N){var M=jQuery("section#"+N);if(M.length>0){jQuery("section").removeClass("sel-tab");jQuery("section#"+N).addClass("sel-tab")}}function x(){var M=jQuery("section#tab-settings .wp-shortpixel-options").height()+90;M=Math.max(M,jQuery("section#tab-adv-settings .wp-shortpixel-options").height()+20);M=Math.max(M,jQuery("section#tab-resources .area1").height()+60);jQuery("#shortpixel-settings-tabs").css("height",M);jQuery("#shortpixel-settings-tabs section").css("height",M)}function I(){var M={action:"shortpixel_dismiss_media_alert"};jQuery.get(ShortPixel.AJAX_URL,M,function(N){M=JSON.parse(N);if(M.Status=="success"){jQuery("#short-pixel-media-alert").hide();console.log("dismissed")}})}function j(){var M={action:"shortpixel_check_quota"};jQuery.get(ShortPixel.AJAX_URL,M,function(){console.log("quota refreshed")})}function z(M){if(M.checked){jQuery("#with-thumbs").css("display","inherit");jQuery("#without-thumbs").css("display","none")}else{jQuery("#without-thumbs").css("display","inherit");jQuery("#with-thumbs").css("display","none")}}function b(Q,O,N,P,M){return(O>0?"<div class='sp-column-info'>"+_spTr.reducedBy+" <strong><span class='percent'>"+O+"%</span></strong> ":"")+(O>0&&O<5?"<br>":"")+(O<5?_spTr.bonusProcessing:"")+(N.length>0?" ("+N+")":"")+(0+P>0?"<br>"+_spTr.plusXthumbsOpt.format(P):"")+(0+M>0?"<br>"+_spTr.plusXretinasOpt.format(M):"")+"</div>"}function o(N,M){jQuery(N).knob({readOnly:true,width:M,height:M,fgColor:"#1CAECB",format:function(O){return O+"%"}})}function c(T,O,R,Q,N,S){if(N==1){var P=jQuery(".sp-column-actions-template").clone();if(!P.length){return false}var M;if(O.length==0){M=["lossy","lossless"]}else{M=["lossy","glossy","lossless"].filter(function(U){return !(U==O)})}P.html(P.html().replace(/__SP_ID__/g,T));if(S.substr(S.lastIndexOf(".")+1).toLowerCase()=="pdf"){jQuery(".sp-action-compare",P).remove()}if(R==0&&Q>0){P.html(P.html().replace("__SP_THUMBS_TOTAL__",Q))}else{jQuery(".sp-action-optimize-thumbs",P).remove();jQuery(".sp-dropbtn",P).removeClass("button-primary")}P.html(P.html().replace(/__SP_FIRST_TYPE__/g,M[0]));P.html(P.html().replace(/__SP_SECOND_TYPE__/g,M[1]));return P.html()}return""}function h(Q,P){Q=Q.substring(2);if(jQuery(".shortpixel-other-media").length){var O=["optimize","retry","restore","redo","quota","view"];for(var N=0,M=O.length;N<M;N++){jQuery("#"+O[N]+"_"+Q).css("display","none")}for(var N=0,M=P.length;N<M;N++){jQuery("#"+P[N]+"_"+Q).css("display","")}}}function i(M){ShortPixel.retries++;if(isNaN(ShortPixel.retries)){ShortPixel.retries=1}if(ShortPixel.retries<6){console.log("Invalid response from server (Error: "+M+"). Retrying pass "+(ShortPixel.retries+1)+"...");setTimeout(checkBulkProgress,5000)}else{ShortPixel.bulkShowError(-1,"Invalid response from server received 6 times. Please retry later by reloading this page, or <a href='https://shortpixel.com/contact' target='_blank'>contact support</a>. (Error: "+M+")","");console.log("Invalid response from server 6 times. Giving up.")}}function k(M){M.action="shortpixel_browse_content";var N="";jQuery.ajax({type:"POST",url:ShortPixel.AJAX_URL,data:M,success:function(O){N=O},async:false});return N}function d(){var M={action:"shortpixel_get_backup_size"};var N="";jQuery.ajax({type:"POST",url:ShortPixel.AJAX_URL,data:M,success:function(O){N=O},async:false});return N}function f(N){jQuery("#request_key").addClass("disabled");jQuery("#pluginemail_spinner").addClass("is-active");ShortPixel.updateSignupEmail();if(ShortPixel.isEmailValid(jQuery("#pluginemail").val())){jQuery("#pluginemail-error").css("display","none");var M={action:"shortpixel_new_api_key",email:jQuery("#pluginemail").val()};jQuery.ajax({type:"POST",async:false,url:ShortPixel.AJAX_URL,data:M,success:function(O){data=JSON.parse(O);if(data.Status=="success"){N.preventDefault();window.location.reload()}else{if(data.Status=="invalid"){jQuery("#pluginemail-error").html("<b>"+data.Details+"</b>");jQuery("#pluginemail-error").css("display","");jQuery("#pluginemail-info").css("display","none");N.preventDefault()}else{}}}});jQuery("#request_key").removeAttr("onclick")}else{jQuery("#pluginemail-error").css("display","");jQuery("#pluginemail-info").css("display","none");N.preventDefault()}jQuery("#request_key").removeClass("disabled");jQuery("#pluginemail_spinner").removeClass("is-active")}function J(){jQuery("#shortPixelProposeUpgrade .sp-modal-body").addClass("sptw-modal-spinner");jQuery("#shortPixelProposeUpgrade .sp-modal-body").html("");jQuery("#shortPixelProposeUpgradeShade").css("display","block");jQuery("#shortPixelProposeUpgrade").removeClass("shortpixel-hide");var M={action:"shortpixel_propose_upgrade"};jQuery.ajax({type:"POST",url:ShortPixel.AJAX_URL,data:M,success:function(N){jQuery("#shortPixelProposeUpgrade .sp-modal-body").removeClass("sptw-modal-spinner");jQuery("#shortPixelProposeUpgrade .sp-modal-body").html(N)}})}function D(){jQuery("#shortPixelProposeUpgradeShade").css("display","none");jQuery("#shortPixelProposeUpgrade").addClass("shortpixel-hide");if(ShortPixel.toRefresh){ShortPixel.recheckQuota()}}function u(){jQuery("#short-pixel-notice-unlisted").hide();jQuery("#optimizeUnlisted").prop("checked",true);var M={action:"shortpixel_dismiss_notice",notice_id:"unlisted",notice_data:"true"};jQuery.get(ShortPixel.AJAX_URL,M,function(N){M=JSON.parse(N);if(M.Status==ShortPixel.STATUS_SUCCESS){console.log("dismissed")}})}function n(){jQuery(".select-folder-button").click(function(){jQuery(".sp-folder-picker-shade").css("display","block");jQuery(".sp-folder-picker").fileTree({script:ShortPixel.browseContent,multiFolder:false})});jQuery(".shortpixel-modal input.select-folder-cancel").click(function(){jQuery(".sp-folder-picker-shade").css("display","none")});jQuery(".shortpixel-modal input.select-folder").click(function(){var M=jQuery("UL.jqueryFileTree LI.directory.selected A").attr("rel").trim();if(M){var N=jQuery("#customFolderBase").val()+M;if(N.slice(-1)=="/"){N=N.slice(0,-1)}jQuery("#addCustomFolder").val(N);jQuery("#addCustomFolderView").val(N);jQuery(".sp-folder-picker-shade").css("display","none")}else{alert("Please select a folder from the list.")}})}function C(Q,P,O){var N=jQuery(".bulk-notice-msg.bulk-lengthy");if(N.length==0){return}var M=jQuery("a",N);M.text(P);if(O){M.attr("href",O)}else{M.attr("href",M.data("href").replace("__ID__",Q))}N.css("display","block")}function y(){jQuery(".bulk-notice-msg.bulk-lengthy").css("display","none")}function v(M){var N=jQuery(".bulk-notice-msg.bulk-"+M);if(N.length==0){return}N.css("display","block")}function K(M){jQuery(".bulk-notice-msg.bulk-"+M).css("display","none")}function r(S,Q,R,P){var M=jQuery("#bulk-error-template");if(M.length==0){return}var O=M.clone();O.attr("id","bulk-error-"+S);if(S==-1){jQuery("span.sp-err-title",O).remove();O.addClass("bulk-error-fatal")}else{jQuery("img",O).remove();jQuery("#bulk-error-".id).remove()}jQuery("span.sp-err-content",O).html(Q);var N=jQuery("a.sp-post-link",O);if(P){N.attr("href",P)}else{N.attr("href",N.attr("href").replace("__ID__",S))}N.text(R);M.after(O);O.css("display","block")}function A(M,N){if(!confirm(_spTr["confirmBulk"+M])){N.stopPropagation();N.preventDefault();return false}return true}function q(M){jQuery(M).parent().parent().remove()}function E(M){return M.substring(0,2)=="C-"}function F(){window.location.href=window.location.href+(window.location.href.indexOf("?")>0?"&":"?")+"checkquota=1"}function g(N){N.preventDefault();if(!this.menuCloseEvent){jQuery(window).click(function(O){if(!O.target.matches(".sp-dropbtn")){jQuery(".sp-dropdown.sp-show").removeClass("sp-show")}});this.menuCloseEvent=true}var M=N.target.parentElement.classList.contains("sp-show");jQuery(".sp-dropdown.sp-show").removeClass("sp-show");if(!M){N.target.parentElement.classList.add("sp-show")}}function L(M){this.comparerData.origUrl=false;if(this.comparerData.cssLoaded===false){jQuery("<link>").appendTo("head").attr({type:"text/css",rel:"stylesheet",href:this.WP_PLUGIN_URL+"/res/css/twentytwenty.min.css"});this.comparerData.cssLoaded=2}if(this.comparerData.jsLoaded===false){jQuery.getScript(this.WP_PLUGIN_URL+"/res/js/jquery.twentytwenty.min.js",function(){ShortPixel.comparerData.jsLoaded=2;if(ShortPixel.comparerData.origUrl.length>0){ShortPixel.displayComparerPopup(ShortPixel.comparerData.width,ShortPixel.comparerData.height,ShortPixel.comparerData.origUrl,ShortPixel.comparerData.optUrl)}});this.comparerData.jsLoaded=1;jQuery(".sp-close-button").click(ShortPixel.closeComparerPopup)}if(this.comparerData.origUrl===false){jQuery.ajax({type:"POST",url:ShortPixel.AJAX_URL,data:{action:"shortpixel_get_comparer_data",id:M},success:function(N){data=JSON.parse(N);jQuery.extend(ShortPixel.comparerData,data);if(ShortPixel.comparerData.jsLoaded==2){ShortPixel.displayComparerPopup(ShortPixel.comparerData.width,ShortPixel.comparerData.height,ShortPixel.comparerData.origUrl,ShortPixel.comparerData.optUrl)}}});this.comparerData.origUrl=""}}function B(Q,O,N,P){var T=Q;var S=(O<150||Q<350);var R=jQuery(S?"#spUploadCompareSideBySide":"#spUploadCompare");if(!S){jQuery("#spCompareSlider").html('<img class="spUploadCompareOriginal"/><img class="spUploadCompareOptimized"/>')}Q=Math.max(350,Math.min(800,(Q<350?(Q+25)*2:(O<150?Q+25:Q))));O=Math.max(150,(S?(T>350?2*(O+45):O+45):O*Q/T));jQuery(".sp-modal-body",R).css("width",Q);jQuery(".shortpixel-slider",R).css("width",Q);R.css("width",Q);jQuery(".sp-modal-body",R).css("height",O);R.css("display","block");R.parent().css("display","block");if(!S){jQuery("#spCompareSlider").twentytwenty({slider_move:"mousemove"})}jQuery(document).on("keyup.sp_modal_active",ShortPixel.closeComparerPopup);var M=jQuery(".spUploadCompareOptimized",R);jQuery(".spUploadCompareOriginal",R).attr("src",N);setTimeout(function(){jQuery(window).trigger("resize")},1000);M.load(function(){jQuery(window).trigger("resize")});M.attr("src",P)}function p(M){jQuery("#spUploadCompareSideBySide").parent().css("display","none");jQuery("#spUploadCompareSideBySide").css("display","none");jQuery("#spUploadCompare").css("display","none");jQuery(document).unbind("keyup.sp_modal_active")}return{setOptions:l,isEmailValid:s,updateSignupEmail:m,validateKey:a,enableResize:H,setupGeneralTab:e,setupAdvancedTab:t,checkThumbsUpdTotal:G,switchSettingsTab:w,adjustSettingsTabs:x,onBulkThumbsCheck:z,dismissMediaAlert:I,checkQuota:j,percentDial:o,successMsg:b,successActions:c,otherMediaUpdateActions:h,retry:i,initFolderSelector:n,browseContent:k,getBackupSize:d,newApiKey:f,proposeUpgrade:J,closeProposeUpgrade:D,includeUnlisted:u,bulkShowLengthyMsg:C,bulkHideLengthyMsg:y,bulkShowMaintenanceMsg:v,bulkHideMaintenanceMsg:K,bulkShowError:r,confirmBulkAction:A,removeBulkMsg:q,isCustomImageId:E,recheckQuota:F,openImageMenu:g,menuCloseEvent:false,loadComparer:L,displayComparerPopup:B,closeComparerPopup:p,comparerData:{cssLoaded:false,jsLoaded:false,origUrl:false,optUrl:false,width:0,height:0},toRefresh:false}}();function showToolBarAlert(c,b){var a=jQuery("li.shortpixel-toolbar-processing");switch(c){case ShortPixel.STATUS_QUOTA_EXCEEDED:if(window.location.href.search("wp-short-pixel-bulk")>0&&jQuery(".sp-quota-exceeded-alert").length==0){location.reload();return}a.addClass("shortpixel-alert");a.addClass("shortpixel-quota-exceeded");jQuery("a",a).attr("href","options-general.php?page=wp-shortpixel");jQuery("a div",a).attr("title","ShortPixel quota exceeded. Click for details.");break;case ShortPixel.STATUS_SKIP:a.addClass("shortpixel-alert shortpixel-processing");jQuery("a div",a).attr("title",b);break;case ShortPixel.STATUS_FAIL:a.addClass("shortpixel-alert shortpixel-processing");jQuery("a div",a).attr("title",b);break;case ShortPixel.STATUS_NO_KEY:a.addClass("shortpixel-alert");a.addClass("shortpixel-quota-exceeded");jQuery("a",a).attr("href","options-general.php?page=wp-shortpixel");jQuery("a div",a).attr("title","Get API Key");break;case ShortPixel.STATUS_SUCCESS:case ShortPixel.STATUS_RETRY:a.addClass("shortpixel-processing");a.removeClass("shortpixel-alert");jQuery("a",a).removeAttr("target");jQuery("a",a).attr("href",jQuery("a img",a).attr("success-url"))}a.removeClass("shortpixel-hide")}function hideToolBarAlert(){jQuery("li.shortpixel-toolbar-processing.shortpixel-processing").addClass("shortpixel-hide")}function hideQuotaExceededToolBarAlert(){jQuery("li.shortpixel-toolbar-processing.shortpixel-quota-exceeded").addClass("shortpixel-hide")}function checkQuotaExceededAlert(){if(typeof shortPixelQuotaExceeded!="undefined"){if(shortPixelQuotaExceeded==1){showToolBarAlert(ShortPixel.STATUS_QUOTA_EXCEEDED)}else{hideQuotaExceededToolBarAlert()}}}function checkBulkProgress(){var b=function(f){if(!d){d=true;return f}return"/"};var d=false;var a=window.location.href.toLowerCase().replace(/\/\//g,b);d=false;var c=ShortPixel.WP_ADMIN_URL.toLowerCase().replace(/\/\//g,b);if(a.search(c)<0){var e=document.createElement("a");e.href=a;a=a.replace(e.protocol+"//"+e.hostname,e.protocol+"//"+e.hostname.split(".").map(function(f){return sp_punycode.toASCII(f)}).join("."))}if(a.search(c+"upload.php")<0&&a.search(c+"edit.php")<0&&a.search(c+"edit-tags.php")<0&&a.search(c+"post-new.php")<0&&a.search(c+"post.php")<0&&a.search("page=nggallery-manage-gallery")<0&&(ShortPixel.FRONT_BOOTSTRAP==0||a.search(c)==0)){hideToolBarAlert();return}if(ShortPixel.bulkProcessor==true&&window.location.href.search("wp-short-pixel-bulk")<0&&typeof localStorage.bulkPage!=="undefined"&&localStorage.bulkPage>0){ShortPixel.bulkProcessor=false}if(window.location.href.search("wp-short-pixel-bulk")>=0){ShortPixel.bulkProcessor=true;localStorage.bulkTime=Math.floor(Date.now()/1000);localStorage.bulkPage=1}if(ShortPixel.bulkProcessor==true||typeof localStorage.bulkTime=="undefined"||Math.floor(Date.now()/1000)-localStorage.bulkTime>90){ShortPixel.bulkProcessor=true;localStorage.bulkPage=(window.location.href.search("wp-short-pixel-bulk")>=0?1:0);localStorage.bulkTime=Math.floor(Date.now()/1000);console.log(localStorage.bulkTime);checkBulkProcessingCallApi()}else{setTimeout(checkBulkProgress,5000)}}function checkBulkProcessingCallApi(){var a={action:"shortpixel_image_processing"};jQuery.ajax({type:"POST",url:ShortPixel.AJAX_URL,data:a,success:function(g){if(g.length>0){var i=null;try{var i=JSON.parse(g)}catch(k){ShortPixel.retry(k.message);return}ShortPixel.retries=0;var d=i.ImageID;var j=(jQuery("div.short-pixel-bulk-page").length>0);switch(i.Status){case ShortPixel.STATUS_NO_KEY:setCellMessage(d,i.Message,'<a class=\'button button-smaller button-primary\' href="https://shortpixel.com/wp-apikey" target="_blank">'+_spTr.getApiKey+"</a>");showToolBarAlert(ShortPixel.STATUS_NO_KEY);break;case ShortPixel.STATUS_QUOTA_EXCEEDED:setCellMessage(d,i.Message,"<a class='button button-smaller button-primary' href=\"https://shortpixel.com/login/"+ShortPixel.API_KEY+'" target="_blank">'+_spTr.extendQuota+"</a><a class='button button-smaller' href='admin.php?action=shortpixel_check_quota'>"+_spTr.check__Quota+"</a>");showToolBarAlert(ShortPixel.STATUS_QUOTA_EXCEEDED);if(i.Stop==false){setTimeout(checkBulkProgress,5000)}ShortPixel.otherMediaUpdateActions(d,["quota","view"]);break;case ShortPixel.STATUS_FAIL:setCellMessage(d,i.Message,"<a class='button button-smaller button-primary' href=\"javascript:manualOptimization('"+d+"', false)\">"+_spTr.retry+"</a>");if(j){ShortPixel.bulkShowError(d,i.Message,i.Filename,i.CustomImageLink);showToolBarAlert(ShortPixel.STATUS_FAIL,i.Message);if(i.BulkPercent){progressUpdate(i.BulkPercent,i.BulkMsg)}ShortPixel.otherMediaUpdateActions(d,["retry","view"])}console.log(i.Message);setTimeout(checkBulkProgress,5000);break;case ShortPixel.STATUS_EMPTY_QUEUE:console.log(i.Message);clearBulkProcessor();hideToolBarAlert();var c=jQuery("#bulk-progress");if(j&&c.length&&i.BulkStatus!="2"){progressUpdate(100,"Bulk finished!");jQuery("a.bulk-cancel").attr("disabled","disabled");hideSlider();setTimeout(function(){window.location.reload()},3000)}break;case ShortPixel.STATUS_SUCCESS:if(j){ShortPixel.bulkHideLengthyMsg();ShortPixel.bulkHideMaintenanceMsg()}var l=i.PercentImprovement;showToolBarAlert(ShortPixel.STATUS_SUCCESS,"");var b=ShortPixel.isCustomImageId(d)?"":ShortPixel.successActions(d,i.Type,i.ThumbsCount,i.ThumbsTotal,i.BackupEnabled,i.Filename);setCellMessage(d,ShortPixel.successMsg(d,l,i.Type,i.ThumbsCount,i.RetinasCount),b);var h=jQuery(["restore","view","redolossy","redoglossy","redolossless"]).not(["redo"+i.Type]).get();ShortPixel.otherMediaUpdateActions(d,h);var f=new PercentageAnimator("#sp-msg-"+d+" span.percent",l);f.animate(l);if(j&&typeof i.Thumb!=="undefined"){if(i.BulkPercent){progressUpdate(i.BulkPercent,i.BulkMsg)}if(i.Thumb.length>0){sliderUpdate(d,i.Thumb,i.BkThumb,i.PercentImprovement,i.Filename);if(typeof i.AverageCompression!=="undefined"&&0+i.AverageCompression>0){jQuery("#sp-avg-optimization").html('<input type="text" class="dial" value="'+Math.round(i.AverageCompression)+'"/>');ShortPixel.percentDial("#sp-avg-optimization .dial",60)}}}console.log("Server response: "+g);if(j&&typeof i.BulkPercent!=="undefined"){progressUpdate(i.BulkPercent,i.BulkMsg)}setTimeout(checkBulkProgress,5000);break;case ShortPixel.STATUS_SKIP:if(i.Silent!==1){ShortPixel.bulkShowError(d,i.Message,i.Filename,i.CustomImageLink)}case ShortPixel.STATUS_ERROR:if(typeof i.Message!=="undefined"){showToolBarAlert(ShortPixel.STATUS_SKIP,i.Message+" Image ID: "+d);setCellMessage(d,i.Message,"")}ShortPixel.otherMediaUpdateActions(d,["retry","view"]);case ShortPixel.STATUS_RETRY:console.log("Server response: "+g);showToolBarAlert(ShortPixel.STATUS_RETRY,"");if(j&&typeof i.BulkPercent!=="undefined"){progressUpdate(i.BulkPercent,i.BulkMsg)}if(j&&i.Count>3){ShortPixel.bulkShowLengthyMsg(d,i.Filename,i.CustomImageLink)}setTimeout(checkBulkProgress,5000);break;case ShortPixel.STATUS_MAINTENANCE:ShortPixel.bulkShowMaintenanceMsg("maintenance");setTimeout(checkBulkProgress,60000);break;case ShortPixel.STATUS_QUEUE_FULL:ShortPixel.bulkShowMaintenanceMsg("queue-full");setTimeout(checkBulkProgress,60000);break;default:ShortPixel.retry("Unknown status "+i.Status+". Retrying...");break}}},error:function(b){ShortPixel.retry(b.statusText)}})}function clearBulkProcessor(){ShortPixel.bulkProcessor=false;localStorage.bulkTime=0;if(window.location.href.search("wp-short-pixel-bulk")>=0){localStorage.bulkPage=0}}function setCellMessage(d,a,c){var b=jQuery("#sp-msg-"+d);if(b.length>0){b.html("<div class='sp-column-actions'>"+c+"</div><div class='sp-column-info'>"+a+"</div>");b.css("color","")}b=jQuery("#sp-cust-msg-"+d);if(b.length>0){b.html("<div class='sp-column-info'>"+a+"</div>")}}function manualOptimization(c,a){setCellMessage(c,"<img src='"+ShortPixel.WP_PLUGIN_URL+"/res/img/loading.gif' class='sp-loading-small'>Image waiting to be processed","");jQuery("li.shortpixel-toolbar-processing").removeClass("shortpixel-hide");jQuery("li.shortpixel-toolbar-processing").addClass("shortpixel-processing");var b={action:"shortpixel_manual_optimization",image_id:c,cleanup:a};jQuery.get(ShortPixel.AJAX_URL,b,function(d){b=JSON.parse(d);if(b.Status==ShortPixel.STATUS_SUCCESS){setTimeout(checkBulkProgress,2000)}else{setCellMessage(c,typeof b.Message!=="undefined"?b.Message:_spTr.thisContentNotProcessable,"")}})}function reoptimize(c,a){setCellMessage(c,"<img src='"+ShortPixel.WP_PLUGIN_URL+"/res/img/loading.gif' class='sp-loading-small'>Image waiting to be reprocessed","");jQuery("li.shortpixel-toolbar-processing").removeClass("shortpixel-hide");jQuery("li.shortpixel-toolbar-processing").addClass("shortpixel-processing");var b={action:"shortpixel_redo",attachment_ID:c,type:a};jQuery.get(ShortPixel.AJAX_URL,b,function(d){b=JSON.parse(d);if(b.Status==ShortPixel.STATUS_SUCCESS){setTimeout(checkBulkProgress,2000)}else{$msg=typeof b.Message!=="undefined"?b.Message:_spTr.thisContentNotProcessable;setCellMessage(c,$msg,"");showToolBarAlert(ShortPixel.STATUS_FAIL,$msg)}})}function optimizeThumbs(b){setCellMessage(b,"<img src='"+ShortPixel.WP_PLUGIN_URL+"/res/img/loading.gif' class='sp-loading-small'>"+_spTr.imageWaitOptThumbs,"");jQuery("li.shortpixel-toolbar-processing").removeClass("shortpixel-hide");jQuery("li.shortpixel-toolbar-processing").addClass("shortpixel-processing");var a={action:"shortpixel_optimize_thumbs",attachment_ID:b};jQuery.get(ShortPixel.AJAX_URL,a,function(c){a=JSON.parse(c);if(a.Status==ShortPixel.STATUS_SUCCESS){setTimeout(checkBulkProgress,2000)}else{setCellMessage(b,typeof a.Message!=="undefined"?a.Message:_spTr.thisContentNotProcessable,"")}})}function dismissShortPixelNoticeExceed(b){jQuery("#wp-admin-bar-shortpixel_processing").hide();var a={action:"shortpixel_dismiss_notice",notice_id:"exceed"};jQuery.get(ShortPixel.AJAX_URL,a,function(c){a=JSON.parse(c);if(a.Status==ShortPixel.STATUS_SUCCESS){console.log("dismissed")}});b.preventDefault()}function dismissShortPixelNotice(b){jQuery("#short-pixel-notice-"+b).hide();var a={action:"shortpixel_dismiss_notice",notice_id:b};jQuery.get(ShortPixel.AJAX_URL,a,function(c){a=JSON.parse(c);if(a.Status==ShortPixel.STATUS_SUCCESS){console.log("dismissed")}})}function PercentageAnimator(b,a){this.animationSpeed=10;this.increment=2;this.curPercentage=0;this.targetPercentage=a;this.outputSelector=b;this.animate=function(c){this.targetPercentage=c;setTimeout(PercentageTimer.bind(null,this),this.animationSpeed)}}function PercentageTimer(a){if(a.curPercentage-a.targetPercentage<-a.increment){a.curPercentage+=a.increment}else{if(a.curPercentage-a.targetPercentage>a.increment){a.curPercentage-=a.increment}else{a.curPercentage=a.targetPercentage}}jQuery(a.outputSelector).text(a.curPercentage+"%");if(a.curPercentage!=a.targetPercentage){setTimeout(PercentageTimer.bind(null,a),a.animationSpeed)}}function progressUpdate(c,b){var a=jQuery("#bulk-progress");if(a.length){jQuery(".progress-left",a).css("width",c+"%");jQuery(".progress-img",a).css("left",c+"%");if(c>24){jQuery(".progress-img span",a).html("");jQuery(".progress-left",a).html(c+"%")}else{jQuery(".progress-img span",a).html(c+"%");jQuery(".progress-left",a).html("")}jQuery(".bulk-estimate").html(b)}}function sliderUpdate(g,c,d,e,b){var f=jQuery(".bulk-slider div.bulk-slide:first-child");if(f.length===0){return}if(f.attr("id")!="empty-slide"){f.hide()}f.css("z-index",1000);jQuery(".bulk-img-opt",f).attr("src","");if(typeof d==="undefined"){d=""}if(d.length>0){jQuery(".bulk-img-orig",f).attr("src","")}var a=f.clone();a.attr("id","slide-"+g);jQuery(".bulk-img-opt",a).attr("src",c);if(d.length>0){jQuery(".img-original",a).css("display","inline-block");jQuery(".bulk-img-orig",a).attr("src",d)}else{jQuery(".img-original",a).css("display","none")}jQuery(".bulk-opt-percent",a).html('<input type="text" class="dial" value="'+e+'"/>');jQuery(".bulk-slider").append(a);ShortPixel.percentDial("#"+a.attr("id")+" .dial",100);jQuery(".bulk-slider-container span.filename").html("&nbsp;&nbsp;"+b);if(f.attr("id")=="empty-slide"){f.remove();jQuery(".bulk-slider-container").css("display","block")}else{f.animate({left:f.width()+f.position().left},"slow","swing",function(){f.remove();a.fadeIn("slow")})}}function hideSlider(){jQuery(".bulk-slider-container").css("display","none")}function showStats(){var a=jQuery(".bulk-stats");if(a.length>0){}}if(!(typeof String.prototype.format=="function")){String.prototype.format=function(){var b=this,a=arguments.length;while(a--){b=b.replace(new RegExp("\\{"+a+"\\}","gm"),arguments[a])}return b}};
res/js/sp-file-tree.min.js ADDED
@@ -0,0 +1,2 @@
 
 
1
+
2
+ var bind=function(a,b){return function(){return a.apply(b,arguments)}};(function(b,a){var c;c=(function(){function d(g,e,j){this.onEvent=bind(this.onEvent,this);var f,i,h;f=b(g);i=this;h={root:"/",script:"/files/filetree",folderEvent:"click",expandSpeed:500,collapseSpeed:500,expandEasing:"swing",collapseEasing:"swing",multiFolder:true,loadMessage:"Loading...",errorMessage:"Unable to get file tree information",multiSelect:false,onlyFolders:false,onlyFiles:false,preventLinkAction:false};this.jqft={container:f};this.options=b.extend(h,e);this.callback=j;this.data={};f.html('<ul class="jqueryFileTree start"><li class="wait">'+this.options.loadMessage+"<li></ul>");i.showTree(f,escape(this.options.root),function(){return i._trigger("filetreeinitiated",{})});f.delegate("li a",this.options.folderEvent,i.onEvent)}d.prototype.onEvent=function(h){var f,k,j,i,e,g;f=b(h.target);e=this.options;i=this.jqft;k=this;j=this.callback;k.data={};k.data.li=f.closest("li");k.data.type=(g=k.data.li.hasClass("directory"))!=null?g:{directory:"file"};k.data.value=f.text();k.data.rel=f.prop("rel");k.data.container=i.container;if(e.preventLinkAction){h.preventDefault()}if(f.parent().hasClass("directory")){k.jqft.container.find("LI.directory").removeClass("selected");f.parent().addClass("selected");if(f.parent().hasClass("collapsed")){if(!e.multiFolder){f.parent().parent().find("UL").slideUp({duration:e.collapseSpeed,easing:e.collapseEasing});f.parent().parent().find("LI.directory").removeClass("expanded").addClass("collapsed")}f.parent().removeClass("collapsed").addClass("expanded");f.parent().find("UL").remove();return k.showTree(f.parent(),f.attr("rel"),function(){k._trigger("filetreeexpanded",k.data);return j!=null})}else{return f.parent().find("UL").slideUp({duration:e.collapseSpeed,easing:e.collapseEasing,start:function(){return k._trigger("filetreecollapse",k.data)},complete:function(){f.parent().removeClass("expanded").addClass("collapsed");k._trigger("filetreecollapsed",k.data);return j!=null}})}}else{if(!e.multiSelect){i.container.find("li").removeClass("selected");f.parent().addClass("selected")}else{if(f.parent().find("input").is(":checked")){f.parent().find("input").prop("checked",false);f.parent().removeClass("selected")}else{f.parent().find("input").prop("checked",true);f.parent().addClass("selected")}}k._trigger("filetreeclicked",k.data);return typeof j==="function"?j(f.attr("rel")):void 0}};d.prototype.showTree=function(f,g,n){var m,i,h,e,j,l,k;m=b(f);l=this.options;i=this;m.addClass("wait");b(".jqueryFileTree.start").remove();h={dir:g,onlyFolders:l.onlyFolders,onlyFiles:l.onlyFiles,multiSelect:l.multiSelect};j=function(p){var o;m.find(".start").html("");m.removeClass("wait").append(p);if(l.root===g){m.find("UL:hidden").show(typeof callback!=="undefined"&&callback!==null)}else{if(jQuery.easing[l.expandEasing]===void 0){console.log("Easing library not loaded. Include jQueryUI or 3rd party lib.");l.expandEasing="swing"}m.find("UL:hidden").slideDown({duration:l.expandSpeed,easing:l.expandEasing,start:function(){return i._trigger("filetreeexpand",i.data)},complete:n})}o=b('[rel="'+decodeURIComponent(g)+'"]').parent();if(l.multiSelect&&o.children("input").is(":checked")){o.find("ul li input").each(function(){b(this).prop("checked",true);return b(this).parent().addClass("selected")})}return false};e=function(){m.find(".start").html("");m.removeClass("wait").append("<p>"+l.errorMessage+"</p>");return false};if(typeof l.script==="function"){k=l.script(h);if(typeof k==="string"||k instanceof jQuery){return j(k)}else{return e()}}else{return b.ajax({url:l.script,type:"POST",dataType:"HTML",data:h}).done(function(o){return j(o)}).fail(function(){return e()})}};d.prototype._trigger=function(f,g){var e;e=this.jqft.container;return e.triggerHandler(f,g)};return d})();return b.fn.extend({fileTree:function(d,e){return this.each(function(){var g,f;g=b(this);f=g.data("fileTree");if(!f){g.data("fileTree",(f=new c(this,d,e)))}if(typeof d==="string"){return f[option].apply(f)}})}})})(window.jQuery,window);
shortpixel_api.php CHANGED
@@ -248,7 +248,7 @@ class ShortPixelAPI {
248
 
249
  if(!isset($APIresponse['Status'])) {
250
  WpShortPixel::log("API Response Status unfound : " . json_encode($APIresponse));
251
- return array("Status" => self::STATUS_FAIL, "Message" => __('Unrecognized API response. Please contact support.','shortpixel-image-optimiser'));
252
  } else {
253
  switch($APIresponse['Status']->Code)
254
  {
@@ -367,6 +367,46 @@ class ShortPixelAPI {
367
  }
368
  return $returnMessage;
369
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
370
 
371
  /**
372
  * handles a successful optimization, setting metadata and handling download for each file in the set
@@ -379,7 +419,7 @@ class ShortPixelAPI {
379
  private function handleSuccess($APIresponse, $PATHs, $itemHandler, $compressionType) {
380
  $counter = $savedSpace = $originalSpace = $optimizedSpace = $averageCompression = 0;
381
  $NoBackup = true;
382
-
383
  $fileType = ( $compressionType ) ? "LossySize" : "LoselessSize";
384
 
385
  //download each file from array and process it
@@ -416,50 +456,17 @@ class ShortPixelAPI {
416
  }
417
 
418
  //figure out in what SubDir files should land
419
- //$fullSubDir = str_replace(wp_normalize_path(get_home_path()), "", wp_normalize_path(dirname($itemHandler->getMeta()->getPath()))) . '/';
420
- //$SubDir = ShortPixelMetaFacade::returnSubDir($itemHandler->getMeta()->getPath(), $itemHandler->getType());
421
  $mainPath = $itemHandler->getMeta()->getPath();
422
- $fullSubDir = ShortPixelMetaFacade::returnSubDir($mainPath, $itemHandler->getType());
423
 
424
  //if backup is enabled - we try to save the images
425
  if( $this->_settings->backupImages )
426
  {
427
- $source = $PATHs; //array with final paths for these files
428
-
429
- if( !file_exists(SHORTPIXEL_BACKUP_FOLDER) && !@mkdir(SHORTPIXEL_BACKUP_FOLDER, 0777, true) ) {//creates backup folder if it doesn't exist
430
- return array("Status" => self::STATUS_FAIL, "Message" => __('Backup folder does not exist and it cannot be created','shortpixel-image-optimiser'));
431
- }
432
- //create subdir in backup folder if needed
433
- @mkdir( SHORTPIXEL_BACKUP_FOLDER . '/' . $fullSubDir, 0777, true);
434
-
435
- foreach ( $source as $fileID => $filePATH )//create destination files array
436
- {
437
- $destination[$fileID] = SHORTPIXEL_BACKUP_FOLDER . '/' . $fullSubDir . self::MB_basename($source[$fileID]);
438
- }
439
- //die("IZ BACKUP: " . SHORTPIXEL_BACKUP_FOLDER . '/' . $SubDir . var_dump($destination));
440
-
441
- //now that we have original files and where we should back them up we attempt to do just that
442
- if(is_writable(SHORTPIXEL_BACKUP_FOLDER))
443
- {
444
- foreach ( $destination as $fileID => $filePATH )
445
- {
446
- if ( !file_exists($filePATH) )
447
- {
448
- if ( !@copy($source[$fileID], $filePATH) )
449
- {//file couldn't be saved in backup folder
450
- $msg = sprintf(__('Cannot save file <i>%s</i> in backup directory','shortpixel-image-optimiser'),self::MB_basename($source[$fileID]));
451
- $itemHandler->incrementRetries(1, self::ERR_SAVE_BKP, $msg);
452
- return array("Status" => self::STATUS_FAIL, "Message" => $msg);
453
- }
454
- }
455
- }
456
- $NoBackup = true;
457
- } else {//cannot write to the backup dir, return with an error
458
- $msg = __('Cannot save file in backup directory','shortpixel-image-optimiser');
459
- $itemHandler->incrementRetries(1, self::ERR_SAVE_BKP, $msg);
460
- return array("Status" => self::STATUS_FAIL, "Message" => $msg);
461
  }
462
-
463
  }//end backup section
464
 
465
  $writeFailed = 0;
@@ -537,7 +544,7 @@ class ShortPixelAPI {
537
  $msg = sprintf(__('Optimized version of %s file(s) couldn\'t be updated.','shortpixel-image-optimiser'),$writeFailed);
538
  //#ShortPixelAPI::SaveMessageinMetadata($ID, 'Error: optimized version of ' . $writeFailed . ' file(s) couldn\'t be updated.');
539
  $itemHandler->incrementRetries(1, self::ERR_SAVE, $msg);
540
- update_option('bulkProcessingStatus', "error");
541
  return array("Status" => self::STATUS_FAIL, "Code" =>"write-fail", "Message" => $msg);
542
  }
543
  } elseif( 0 + $fileData->PercentImprovement < 5) {
@@ -558,15 +565,17 @@ class ShortPixelAPI {
558
  if($meta->getThumbsTodo()) {
559
  $percentImprovement = $meta->getImprovementPercent();
560
  }
 
 
561
  $meta->setMessage($originalSpace
562
- ? number_format(100.0 - 100.0 * $optimizedSpace / $originalSpace, 2)
563
  : "Couldn't compute thumbs optimization percent. Main image: " . $percentImprovement);
564
  WPShortPixel::log("HANDLE SUCCESS: Image optimization: ".$meta->getMessage());
565
  $meta->setCompressionType($compressionType);
566
  $meta->setCompressedSize(@filesize($meta->getPath()));
567
  $meta->setKeepExif($this->_settings->keepExif);
568
  $meta->setTsOptimized(date("Y-m-d H:i:s"));
569
- $meta->setThumbsOptList(array_unique(array_merge($meta->getThumbsOptList(), $thumbsOptList)));
570
  $meta->setThumbsOpt(($meta->getThumbsTodo() || $this->_settings->processThumbnails) ? count($meta->getThumbsOptList()) : 0);
571
  $meta->setRetinasOpt($retinas);
572
  $meta->setThumbsTodo(false);
@@ -589,7 +598,10 @@ class ShortPixelAPI {
589
  //we reset the retry counter in case of success
590
  $this->_settings->apiRetries = 0;
591
 
592
- return array("Status" => self::STATUS_SUCCESS, "Message" => 'Success: No pixels remained unsqueezed :-)', "PercentImprovement" => $meta->getMessage());
 
 
 
593
  }//end handleSuccess
594
 
595
  /**
248
 
249
  if(!isset($APIresponse['Status'])) {
250
  WpShortPixel::log("API Response Status unfound : " . json_encode($APIresponse));
251
+ return array("Status" => self::STATUS_FAIL, "Message" => __('Unrecognized API response. Please contact support. (SERVER RESPONSE: ' . $response . ')','shortpixel-image-optimiser'));
252
  } else {
253
  switch($APIresponse['Status']->Code)
254
  {
367
  }
368
  return $returnMessage;
369
  }
370
+
371
+ public static function backupImage($mainPath, $PATHs) {
372
+ //$fullSubDir = str_replace(wp_normalize_path(get_home_path()), "", wp_normalize_path(dirname($itemHandler->getMeta()->getPath()))) . '/';
373
+ //$SubDir = ShortPixelMetaFacade::returnSubDir($itemHandler->getMeta()->getPath(), $itemHandler->getType());
374
+ $fullSubDir = ShortPixelMetaFacade::returnSubDir($mainPath);
375
+ $source = $PATHs; //array with final paths for these files
376
+
377
+ if( !file_exists(SHORTPIXEL_BACKUP_FOLDER) && !@mkdir(SHORTPIXEL_BACKUP_FOLDER, 0777, true) ) {//creates backup folder if it doesn't exist
378
+ return array("Status" => self::STATUS_FAIL, "Message" => __('Backup folder does not exist and it cannot be created','shortpixel-image-optimiser'));
379
+ }
380
+ //create subdir in backup folder if needed
381
+ @mkdir( SHORTPIXEL_BACKUP_FOLDER . '/' . $fullSubDir, 0777, true);
382
+
383
+ foreach ( $source as $fileID => $filePATH )//create destination files array
384
+ {
385
+ $destination[$fileID] = SHORTPIXEL_BACKUP_FOLDER . '/' . $fullSubDir . self::MB_basename($source[$fileID]);
386
+ }
387
+ //die("IZ BACKUP: " . SHORTPIXEL_BACKUP_FOLDER . '/' . $SubDir . var_dump($destination));
388
+
389
+ //now that we have original files and where we should back them up we attempt to do just that
390
+ if(is_writable(SHORTPIXEL_BACKUP_FOLDER))
391
+ {
392
+ foreach ( $destination as $fileID => $filePATH )
393
+ {
394
+ if ( !file_exists($filePATH) )
395
+ {
396
+ if ( !@copy($source[$fileID], $filePATH) )
397
+ {//file couldn't be saved in backup folder
398
+ $msg = sprintf(__('Cannot save file <i>%s</i> in backup directory','shortpixel-image-optimiser'),self::MB_basename($source[$fileID]));
399
+ return array("Status" => self::STATUS_FAIL, "Message" => $msg);
400
+ }
401
+ }
402
+ }
403
+ return array("Status" => self::STATUS_SUCCESS);
404
+ }
405
+ else {//cannot write to the backup dir, return with an error
406
+ $msg = __('Cannot save file in backup directory','shortpixel-image-optimiser');
407
+ return array("Status" => self::STATUS_FAIL, "Message" => $msg);
408
+ }
409
+ }
410
 
411
  /**
412
  * handles a successful optimization, setting metadata and handling download for each file in the set
419
  private function handleSuccess($APIresponse, $PATHs, $itemHandler, $compressionType) {
420
  $counter = $savedSpace = $originalSpace = $optimizedSpace = $averageCompression = 0;
421
  $NoBackup = true;
422
+
423
  $fileType = ( $compressionType ) ? "LossySize" : "LoselessSize";
424
 
425
  //download each file from array and process it
456
  }
457
 
458
  //figure out in what SubDir files should land
 
 
459
  $mainPath = $itemHandler->getMeta()->getPath();
 
460
 
461
  //if backup is enabled - we try to save the images
462
  if( $this->_settings->backupImages )
463
  {
464
+ $backupStatus = self::backupImage($mainPath, $PATHs);
465
+ if($backupStatus == self::STATUS_FAIL) {
466
+ $itemHandler->incrementRetries(1, self::ERR_SAVE_BKP, $backupStatus["Message"]);
467
+ return $backupStatus;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
468
  }
469
+ $NoBackup = false;
470
  }//end backup section
471
 
472
  $writeFailed = 0;
544
  $msg = sprintf(__('Optimized version of %s file(s) couldn\'t be updated.','shortpixel-image-optimiser'),$writeFailed);
545
  //#ShortPixelAPI::SaveMessageinMetadata($ID, 'Error: optimized version of ' . $writeFailed . ' file(s) couldn\'t be updated.');
546
  $itemHandler->incrementRetries(1, self::ERR_SAVE, $msg);
547
+ $this->_settings->bulkProcessingStatus = "error";
548
  return array("Status" => self::STATUS_FAIL, "Code" =>"write-fail", "Message" => $msg);
549
  }
550
  } elseif( 0 + $fileData->PercentImprovement < 5) {
565
  if($meta->getThumbsTodo()) {
566
  $percentImprovement = $meta->getImprovementPercent();
567
  }
568
+ $png2jpg = $meta->getPng2Jpg();
569
+ $png2jpg = is_array($png2jpg) ? $png2jpg['optimizationPercent'] : 0;
570
  $meta->setMessage($originalSpace
571
+ ? number_format(100.0 * (1.0 - $optimizedSpace / $originalSpace), 2)
572
  : "Couldn't compute thumbs optimization percent. Main image: " . $percentImprovement);
573
  WPShortPixel::log("HANDLE SUCCESS: Image optimization: ".$meta->getMessage());
574
  $meta->setCompressionType($compressionType);
575
  $meta->setCompressedSize(@filesize($meta->getPath()));
576
  $meta->setKeepExif($this->_settings->keepExif);
577
  $meta->setTsOptimized(date("Y-m-d H:i:s"));
578
+ $meta->setThumbsOptList(is_array($meta->getThumbsOptList()) ? array_unique(array_merge($meta->getThumbsOptList(), $thumbsOptList)) : $thumbsOptList);
579
  $meta->setThumbsOpt(($meta->getThumbsTodo() || $this->_settings->processThumbnails) ? count($meta->getThumbsOptList()) : 0);
580
  $meta->setRetinasOpt($retinas);
581
  $meta->setThumbsTodo(false);
598
  //we reset the retry counter in case of success
599
  $this->_settings->apiRetries = 0;
600
 
601
+ return array("Status" => self::STATUS_SUCCESS, "Message" => 'Success: No pixels remained unsqueezed :-)',
602
+ "PercentImprovement" => $originalSpace
603
+ ? number_format(100.0 * (1.0 - (1.0 - $png2jpg / 100.0) * $optimizedSpace / $originalSpace), 2)
604
+ : "Couldn't compute thumbs optimization percent. Main image: " . $percentImprovement);
605
  }//end handleSuccess
606
 
607
  /**
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.7.2
7
  * Author: ShortPixel
8
  * Author URI: https://shortpixel.com
9
  * Text Domain: shortpixel-image-optimiser
@@ -18,7 +18,7 @@ define('SHORTPIXEL_PLUGIN_FILE', __FILE__);
18
 
19
  define('SHORTPIXEL_AFFILIATE_CODE', '');
20
 
21
- define('SHORTPIXEL_IMAGE_OPTIMISER_VERSION', "4.7.1");
22
  define('SHORTPIXEL_MAX_TIMEOUT', 10);
23
  define('SHORTPIXEL_VALIDATE_MAX_TIMEOUT', 15);
24
  define('SHORTPIXEL_BACKUP', 'ShortpixelBackups');
@@ -29,12 +29,15 @@ 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
 
34
  require_once(ABSPATH . 'wp-admin/includes/file.php');
35
 
36
  $sp__uploads = wp_upload_dir();
37
  define('SHORTPIXEL_UPLOADS_BASE', $sp__uploads['basedir']);
 
38
  define('SHORTPIXEL_UPLOADS_NAME', basename(is_main_site() ? SHORTPIXEL_UPLOADS_BASE : dirname(dirname(SHORTPIXEL_UPLOADS_BASE))));
39
  $sp__backupBase = is_main_site() ? SHORTPIXEL_UPLOADS_BASE : dirname(dirname(SHORTPIXEL_UPLOADS_BASE));
40
  define('SHORTPIXEL_BACKUP_FOLDER', $sp__backupBase . '/' . SHORTPIXEL_BACKUP);
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.8.0
7
  * Author: ShortPixel
8
  * Author URI: https://shortpixel.com
9
  * Text Domain: shortpixel-image-optimiser
18
 
19
  define('SHORTPIXEL_AFFILIATE_CODE', '');
20
 
21
+ define('SHORTPIXEL_IMAGE_OPTIMISER_VERSION', "4.8.0");
22
  define('SHORTPIXEL_MAX_TIMEOUT', 10);
23
  define('SHORTPIXEL_VALIDATE_MAX_TIMEOUT', 15);
24
  define('SHORTPIXEL_BACKUP', 'ShortpixelBackups');
29
  define('SHORTPIXEL_MAX_THUMBS', 100);
30
  }
31
 
32
+ define('SHORTPIXEL_PRESEND_ITEMS', 3);
33
+
34
  define('SHORTPIXEL_MAX_EXECUTION_TIME', ini_get('max_execution_time'));
35
 
36
  require_once(ABSPATH . 'wp-admin/includes/file.php');
37
 
38
  $sp__uploads = wp_upload_dir();
39
  define('SHORTPIXEL_UPLOADS_BASE', $sp__uploads['basedir']);
40
+ define('SHORTPIXEL_UPLOADS_URL', $sp__uploads['baseurl']);
41
  define('SHORTPIXEL_UPLOADS_NAME', basename(is_main_site() ? SHORTPIXEL_UPLOADS_BASE : dirname(dirname(SHORTPIXEL_UPLOADS_BASE))));
42
  $sp__backupBase = is_main_site() ? SHORTPIXEL_UPLOADS_BASE : dirname(dirname(SHORTPIXEL_UPLOADS_BASE));
43
  define('SHORTPIXEL_BACKUP_FOLDER', $sp__backupBase . '/' . SHORTPIXEL_BACKUP);