ShortPixel Image Optimizer - Version 4.14.4

Version Description

Release date: 19th August 2019 * Check if unlisted thumbnails present for already optimized images (in case the thumbnails were added later) in Media Library list and when doing bulk. This also integrates with the Unicode plugin. * If JSON PHP module not present, add a proper error * Fixed: bulk error "WordPress database error You have an error in your SQL syntax" on some installs * Fixed: Warning: count() Parameter must be an array. * Language 0 new strings added, 0 updated, 0 fuzzied, and 0 obsoleted

=

Download this release

Release Info

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

Code changes from version 4.14.3 to 4.14.4

build/shortpixel/PackageLoader.php CHANGED
@@ -14,6 +14,8 @@ class PackageLoader
14
  {
15
  $this->dir = $dir;
16
  $composer = $this->getComposerFile();
 
 
17
  if(isset($composer["autoload"]["psr-4"])){
18
  $this->loadPSR4($composer['autoload']['psr-4']);
19
  }
@@ -59,9 +61,10 @@ class PackageLoader
59
  if ($psr4) {
60
  $classname = str_replace($namespace, "", $classname);
61
  }
62
- $filename = preg_replace("#\\\\#", "/", $classname).".php";
 
63
  foreach ($classpaths as $classpath) {
64
- $fullpath = $this->dir."/".$classpath."/$filename";
65
  if (file_exists($fullpath)) {
66
  include_once $fullpath;
67
  }
14
  {
15
  $this->dir = $dir;
16
  $composer = $this->getComposerFile();
17
+
18
+
19
  if(isset($composer["autoload"]["psr-4"])){
20
  $this->loadPSR4($composer['autoload']['psr-4']);
21
  }
61
  if ($psr4) {
62
  $classname = str_replace($namespace, "", $classname);
63
  }
64
+ $filename = preg_replace("#\\\\#", "", $classname).".php";
65
+
66
  foreach ($classpaths as $classpath) {
67
+ $fullpath = trailingslashit($dir) . trailingslashit($classpath) .$filename;
68
  if (file_exists($fullpath)) {
69
  include_once $fullpath;
70
  }
build/shortpixel/composer.json CHANGED
@@ -1 +1 @@
1
- {"name":"ShortPixel\/shortpixelmodules","description":"ShortPixel submodules","type":"function","autoload":{"psr-4":{"ShortPixel\\ShortPixelLogger\\":"log\/src\/","ShortPixel\\Notices\\":"notices\/src\/"}}}
1
+ {"name":"ShortPixel\/shortpixelmodules","description":"ShortPixel submodules","type":"function","autoload":{"psr-4":{"ShortPixel\\ShortPixelLogger":"log\/src","ShortPixel\\Notices":"notices\/src"}}}
build/shortpixel/log/composer.json CHANGED
@@ -1,7 +1,7 @@
1
  {
2
  "name": "shortpixel/log",
3
  "description": "ShortPixel Logging",
4
- "version": "1.1",
5
  "type": "library",
6
  "license": "MIT",
7
  "authors": [
@@ -13,6 +13,6 @@
13
  "minimum-stability": "dev",
14
  "require": {},
15
  "autoload": {
16
- "psr-4": { "ShortPixel\\ShortPixelLogger\\" : "src/" }
17
  }
18
  }
1
  {
2
  "name": "shortpixel/log",
3
  "description": "ShortPixel Logging",
4
+ "version": "1.1.2",
5
  "type": "library",
6
  "license": "MIT",
7
  "authors": [
13
  "minimum-stability": "dev",
14
  "require": {},
15
  "autoload": {
16
+ "psr-4": { "ShortPixel\\ShortPixelLogger\\" : "src" }
17
  }
18
  }
build/shortpixel/log/src/ShortPixelLogger.php CHANGED
@@ -52,7 +52,7 @@ namespace ShortPixel\ShortPixelLogger;
52
  if ($this->logPath === false)
53
  {
54
  $upload_dir = wp_upload_dir(null,false,false);
55
- $this->logPath = $upload_dir['basedir'] . '/' . $this->namespace . ".log";
56
  }
57
 
58
  if (isset($_REQUEST['SHORTPIXEL_DEBUG'])) // manual takes precedence over constants
@@ -130,7 +130,7 @@ namespace ShortPixel\ShortPixelLogger;
130
 
131
  public function setLogPath($logPath)
132
  {
133
- $this->logPath = $logPath;
134
  }
135
  protected static function addLog($message, $level, $data = array())
136
  {
@@ -170,7 +170,8 @@ namespace ShortPixel\ShortPixelLogger;
170
 
171
  $line = $this->formatLine($items);
172
 
173
- if ($this->logPath)
 
174
  {
175
  file_put_contents($this->logPath,$line, FILE_APPEND);
176
  }
52
  if ($this->logPath === false)
53
  {
54
  $upload_dir = wp_upload_dir(null,false,false);
55
+ $this->logPath = $this->setLogPath($upload_dir['basedir'] . '/' . $this->namespace . ".log");
56
  }
57
 
58
  if (isset($_REQUEST['SHORTPIXEL_DEBUG'])) // manual takes precedence over constants
130
 
131
  public function setLogPath($logPath)
132
  {
133
+ $this->logPath = $logPath;
134
  }
135
  protected static function addLog($message, $level, $data = array())
136
  {
170
 
171
  $line = $this->formatLine($items);
172
 
173
+ // try to write to file. Don't write if directory doesn't exists (leads to notices)
174
+ if ($this->logPath && is_dir(dirname($this->logPath) ))
175
  {
176
  file_put_contents($this->logPath,$line, FILE_APPEND);
177
  }
build/shortpixel/notices/composer.json CHANGED
@@ -26,6 +26,6 @@
26
  ],
27
 
28
  "autoload": {
29
- "psr-4": { "ShortPixel\\Notices\\" : "src/" }
30
  }
31
  }
26
  ],
27
 
28
  "autoload": {
29
+ "psr-4": { "ShortPixel\\Notices\\" : "src" }
30
  }
31
  }
class/controller/filesystem_controller.php CHANGED
@@ -9,10 +9,16 @@ use ShortPixel\ShortpixelLogger\ShortPixelLogger as Log;
9
  */
10
  Class FileSystemController extends ShortPixelController
11
  {
 
 
12
  public function __construct()
13
  {
14
  $this->loadModel('file');
15
  $this->loadModel('directory');
 
 
 
 
16
  }
17
 
18
  /** Get FileModel for a certain path. This can exist or not
@@ -61,6 +67,44 @@ Class FileSystemController extends ShortPixelController
61
  else {
62
  return false;
63
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
64
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65
  }
 
 
 
66
  }
9
  */
10
  Class FileSystemController extends ShortPixelController
11
  {
12
+ protected $env;
13
+
14
  public function __construct()
15
  {
16
  $this->loadModel('file');
17
  $this->loadModel('directory');
18
+ $this->loadModel('environment');
19
+
20
+ $this->env = new EnvironmentModel();
21
+
22
  }
23
 
24
  /** Get FileModel for a certain path. This can exist or not
67
  else {
68
  return false;
69
  }
70
+ }
71
+
72
+ /** Not in use yet, do not use. Future replacement. */
73
+ public function createBackUpFolder($folder = SHORTPIXEL_BACKUP_FOLDER)
74
+ {
75
+
76
+ }
77
+
78
+ /** Utility function that tries to convert a file-path to a webURL.
79
+ *
80
+ * If possible, rely on other better methods to find URL ( e.g. via WP functions ).
81
+ */
82
+ public function pathToUrl(FileModel $file)
83
+ {
84
+ $filepath = $file->getFullPath();
85
+ $directory = $file->getFileDir();
86
+
87
+ // $relpath = $directory->getRelativePath();
88
+ //$relfile =
89
 
90
+ // stolen from wp_get_attachment_url
91
+ if ( ( $uploads = wp_get_upload_dir() ) && false === $uploads['error'] ) {
92
+ // Check that the upload base exists in the file location.
93
+ if ( 0 === strpos( $file, $uploads['basedir'] ) ) {
94
+ // Replace file location with url location.
95
+ $url = str_replace( $uploads['basedir'], $uploads['baseurl'], $filepath );
96
+ } elseif ( false !== strpos( $file, 'wp-content/uploads' ) ) {
97
+ // Get the directory name relative to the basedir (back compat for pre-2.7 uploads)
98
+ $url = trailingslashit( $uploads['baseurl'] . '/' . _wp_get_attachment_relative_path( $file ) ) . wp_basename( $filepath );
99
+ } else {
100
+ // It's a newly-uploaded file, therefore $file is relative to the basedir.
101
+ $url = $uploads['baseurl'] . "/$filepath";
102
+ }
103
+ }
104
+
105
+ return $url;
106
  }
107
+
108
+
109
+
110
  }
class/db/shortpixel-meta-facade.php CHANGED
@@ -1,4 +1,5 @@
1
  <?php
 
2
 
3
  class ShortPixelMetaFacade {
4
  const MEDIA_LIBRARY_TYPE = 1;
@@ -100,7 +101,8 @@ class ShortPixelMetaFacade {
100
  return $rawMeta;
101
  }
102
 
103
- function updateMeta($newMeta = null, $replaceThumbs = false) {
 
104
  if($newMeta) {
105
  $this->meta = $newMeta;
106
  }
@@ -112,6 +114,7 @@ class ShortPixelMetaFacade {
112
  }
113
  elseif($this->type == ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE) {
114
  $duplicates = ShortPixelMetaFacade::getWPMLDuplicates($this->ID);
 
115
  foreach($duplicates as $_ID) {
116
  $rawMeta = $this->sanitizeMeta(wp_get_attachment_metadata($_ID));
117
 
@@ -210,11 +213,15 @@ class ShortPixelMetaFacade {
210
  if($_ID == $this->ID) {
211
  $this->rawMeta = $rawMeta;
212
  }
213
- }
214
  }
215
  }
216
 
217
- function cleanupMeta($fakeOptPending = false) {
 
 
 
 
218
  if($this->type == ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE) {
219
  if(!isset($this->rawMeta)) {
220
  $rawMeta = $this->sanitizeMeta(wp_get_attachment_metadata($this->getId()));
@@ -232,6 +239,17 @@ class ShortPixelMetaFacade {
232
  unset($rawMeta['ShortPixel']);
233
  unset($rawMeta['ShortPixelPng2Jpg']);
234
  }
 
 
 
 
 
 
 
 
 
 
 
235
  unset($this->meta);
236
  update_post_meta($this->ID, '_wp_attachment_metadata', $rawMeta);
237
  //wp_update_attachment_metadata($this->ID, $rawMeta);
@@ -430,6 +448,23 @@ class ShortPixelMetaFacade {
430
  $origPath = $tPath = str_replace(ShortPixelAPI::MB_basename($path), $thumbnailInfo['file'], $path);
431
  $file_exists = apply_filters('shortpixel_image_exists', file_exists($origPath), $origPath, $this->ID);
432
  $tUrl = str_replace(ShortPixelAPI::MB_basename($url), $thumbnailInfo['file'], $url);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
433
  if ( !$file_exists && !file_exists($tPath) ) {
434
  $tPath = SHORTPIXEL_UPLOADS_BASE . substr($tPath, strpos($tPath, $StichString) + strlen($StichString));
435
  }
@@ -463,7 +498,7 @@ class ShortPixelMetaFacade {
463
  }
464
  }
465
  if(!count($sizes)) {
466
- WPShortPixel::log("getURLsAndPATHs: no meta sizes for ID " . $this->ID . " : " . json_encode($this->rawMeta));
467
  }
468
 
469
  if($onlyThumbs && $mainExists && count($urlList) >= 1) { //remove the main image
@@ -687,7 +722,7 @@ class ShortPixelMetaFacade {
687
  $file = wp_normalize_path($file);
688
 
689
  // $sp__uploads = wp_upload_dir();
690
-
691
  if(strstr($file, $hp)) {
692
  $path = str_replace( $hp, "", $file);
693
  } elseif( strstr($file, dirname( WP_CONTENT_DIR ))) { //in some situations the content dir is not inside the root, check this also (ex. single.shortpixel.com)
1
  <?php
2
+ use ShortPixel\ShortPixelLogger\ShortPixelLogger as Log;
3
 
4
  class ShortPixelMetaFacade {
5
  const MEDIA_LIBRARY_TYPE = 1;
101
  return $rawMeta;
102
  }
103
 
104
+ // @todo Find out the use of this function. Doesn't update_meta unless it's WPML.
105
+ public function updateMeta($newMeta = null, $replaceThumbs = false) {
106
  if($newMeta) {
107
  $this->meta = $newMeta;
108
  }
114
  }
115
  elseif($this->type == ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE) {
116
  $duplicates = ShortPixelMetaFacade::getWPMLDuplicates($this->ID);
117
+ Log::addDebug('Update Meta Duplicates Query', array($duplicates));
118
  foreach($duplicates as $_ID) {
119
  $rawMeta = $this->sanitizeMeta(wp_get_attachment_metadata($_ID));
120
 
213
  if($_ID == $this->ID) {
214
  $this->rawMeta = $rawMeta;
215
  }
216
+ } // duplicates loop
217
  }
218
  }
219
 
220
+
221
+ /** Clean meta set by Shortpixel
222
+ * This function only hits with images that were optimized, pending or have an error state.
223
+ */
224
+ public function cleanupMeta($fakeOptPending = false) {
225
  if($this->type == ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE) {
226
  if(!isset($this->rawMeta)) {
227
  $rawMeta = $this->sanitizeMeta(wp_get_attachment_metadata($this->getId()));
239
  unset($rawMeta['ShortPixel']);
240
  unset($rawMeta['ShortPixelPng2Jpg']);
241
  }
242
+ if (isset($rawMeta['sizes'])) // search for custom sizes set by SP.
243
+ {
244
+ foreach($rawMeta['sizes'] as $size => $data)
245
+ {
246
+ if (strpos($size, ShortPixelMeta::FOUND_THUMB_PREFIX) !== false)
247
+ {
248
+ unset($rawMeta['sizes'][$size]);
249
+ Log::addDebug('Unset sp-found- size' . $size);
250
+ }
251
+ }
252
+ }
253
  unset($this->meta);
254
  update_post_meta($this->ID, '_wp_attachment_metadata', $rawMeta);
255
  //wp_update_attachment_metadata($this->ID, $rawMeta);
448
  $origPath = $tPath = str_replace(ShortPixelAPI::MB_basename($path), $thumbnailInfo['file'], $path);
449
  $file_exists = apply_filters('shortpixel_image_exists', file_exists($origPath), $origPath, $this->ID);
450
  $tUrl = str_replace(ShortPixelAPI::MB_basename($url), $thumbnailInfo['file'], $url);
451
+
452
+ // Working on low-key replacement for path handling via FileSystemController.
453
+ // This specific fix is related to the possibility of URLs' in metadata
454
+ if ( !$file_exists && !file_exists($tPath) )
455
+ {
456
+ $fs = new \ShortPixel\FileSystemController();
457
+ $file = $fs->getFile($thumbnailInfo['file']);
458
+
459
+ if ($file->exists())
460
+ {
461
+ $tPath = $file->getFullPath();
462
+ $fsUrl = $fs->pathToUrl($file);
463
+ if ($fsUrl !== false)
464
+ $tUrl = $fsUrl; // more secure way of getting url
465
+ }
466
+ }
467
+
468
  if ( !$file_exists && !file_exists($tPath) ) {
469
  $tPath = SHORTPIXEL_UPLOADS_BASE . substr($tPath, strpos($tPath, $StichString) + strlen($StichString));
470
  }
498
  }
499
  }
500
  if(!count($sizes)) {
501
+ Log::addInfo("getURLsAndPATHs: no meta sizes for ID " . $this->ID . " : " . json_encode($this->rawMeta));
502
  }
503
 
504
  if($onlyThumbs && $mainExists && count($urlList) >= 1) { //remove the main image
722
  $file = wp_normalize_path($file);
723
 
724
  // $sp__uploads = wp_upload_dir();
725
+
726
  if(strstr($file, $hp)) {
727
  $path = str_replace( $hp, "", $file);
728
  } elseif( strstr($file, dirname( WP_CONTENT_DIR ))) { //in some situations the content dir is not inside the root, check this also (ex. single.shortpixel.com)
class/db/wp-shortpixel-media-library-adapter.php CHANGED
@@ -1,7 +1,6 @@
1
  <?php
2
  use ShortPixel\ShortpixelLogger\ShortPixelLogger as Log;
3
 
4
-
5
  class WpShortPixelMediaLbraryAdapter {
6
 
7
  //count all the processable files in media library (while limiting the results to max 10000)
@@ -57,7 +56,6 @@ class WpShortPixelMediaLbraryAdapter {
57
  foreach ( $filesList as $file )
58
  {
59
  $totalFilesThis = $processedFilesThis = 0;
60
- //if($file->post_id == 945) {var_dump($file);}
61
 
62
  if ( $file->meta_key == "_wp_attached_file" )
63
  {//count pdf files only
@@ -87,9 +85,9 @@ class WpShortPixelMediaLbraryAdapter {
87
  || $attachment['ShortPixelImprovement'] === 0.0 || $attachment['ShortPixelImprovement'] === "0"))
88
  {
89
  $foundThumbs = WpShortPixelMediaLbraryAdapter::findThumbs($filePath);
 
90
  $foundCount = count($foundThumbs);
91
- //echo(" <br>&gt; $counter CHECKING FILE THUMBS: FOUND $foundCount "
92
- // . ($foundCount > $sizesCount ? " DIFFERENT ($sizesCount)!" : ""));
93
  if(count($foundThumbs) > $sizesCount) {
94
  $unlisted = array();
95
  foreach($foundThumbs as $found) {
@@ -98,7 +96,6 @@ class WpShortPixelMediaLbraryAdapter {
98
  $unlisted[] = wp_basename($found);
99
  }
100
  }
101
- //echo( " UNLISTED for {$file->post_id} : " . json_encode($unlisted));
102
  $foundUnlistedThumbs = (object)array("id" => $file->post_id, "name" => wp_basename($attachment['file']), "unlisted" => $unlisted);
103
  }
104
  } else {
@@ -248,7 +245,7 @@ class WpShortPixelMediaLbraryAdapter {
248
  return $result;
249
  }
250
 
251
- public static function getPostMetaJoinLess($startId, $endId, $limit)
252
  {
253
  global $wpdb;
254
  $time = microtime(true);
@@ -273,17 +270,21 @@ class WpShortPixelMediaLbraryAdapter {
273
 
274
  return $metaresult;
275
  }
276
-
277
  public static function getPostsJoinLessReverse($startId, $endId, $limit)
278
  {
279
  global $wpdb;
280
- $time = microtime(true);
281
 
282
  $sqlmeta = "SELECT DISTINCT post_id FROM " . $wpdb->prefix . "postmeta where (meta_key = %s or meta_key = %s) and post_id <= %d and post_id >= %d order by post_id DESC LIMIT %d";
283
  $sqlmeta = $wpdb->prepare($sqlmeta, '_wp_attached_file', '_wp_attachment_metadata', $startId, $endId, $limit);
284
 
285
  $result = $wpdb->get_col($sqlmeta);
286
 
 
 
 
 
287
  $id_placeholders = implode( ', ', array_fill( 0, count( $result ), '%d'));
288
 
289
  $sql = 'SELECT ID from ' . $wpdb->prefix . 'posts where ID in (' . $id_placeholders . ') ORDER BY ID DESC';
@@ -293,9 +294,7 @@ class WpShortPixelMediaLbraryAdapter {
293
 
294
  $postAr = array_intersect($result, $postresult);
295
 
296
- $time_end = microtime(true);
297
- // Log::addDebug('Post Meta JoinLESS **REVERSE** query took ' . ($time_end-$time) . ' sec. - Result count ' . count($postAr), array($sql, $sqlmeta));
298
-
299
  return $postAr;
300
  }
301
 
@@ -319,6 +318,8 @@ class WpShortPixelMediaLbraryAdapter {
319
  return count(self::getSizesNotExcluded($sizes, $exclude));
320
  }
321
 
 
 
322
  public static function cleanupFoundThumbs($itemHandler) {
323
  $meta = $itemHandler->getMeta();
324
  $sizesAll = $meta->getThumbs();
@@ -335,47 +336,101 @@ class WpShortPixelMediaLbraryAdapter {
335
  }
336
  $meta->setThumbs($sizes);
337
  $itemHandler->updateMeta($meta, true);
338
- }
339
 
 
 
 
 
 
340
  public static function findThumbs($mainFile) {
341
- $ext = pathinfo($mainFile, PATHINFO_EXTENSION);
342
- $base = substr($mainFile, 0, strlen($mainFile) - strlen($ext) - 1);
343
- $pattern = '/' . preg_quote($base, '/') . '-\d+x\d+\.'. $ext .'/';
344
- $thumbsCandidates = @glob($base . "-*." . $ext);
 
345
  $thumbs = array();
346
- if(is_array($thumbsCandidates)) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
347
  foreach($thumbsCandidates as $th) {
348
  if(preg_match($pattern, $th)) {
349
  $thumbs[]= $th;
350
  }
351
- }
352
  if( defined('SHORTPIXEL_CUSTOM_THUMB_SUFFIXES') ){
353
- $suffixes = defined('SHORTPIXEL_CUSTOM_THUMB_SUFFIXES') ? explode(',', SHORTPIXEL_CUSTOM_THUMB_SUFFIXES) : array();
354
- foreach ($suffixes as $suffix){
355
- $pattern = '/' . preg_quote($base, '/') . '-\d+x\d+'. $suffix . '\.'. $ext .'/';
356
- foreach($thumbsCandidates as $th) {
357
- if(preg_match($pattern, $th)) {
358
- $thumbs[]= $th;
359
- }
360
- }
 
 
 
 
 
361
  }
362
  }
363
  if( defined('SHORTPIXEL_CUSTOM_THUMB_INFIXES') ){
364
  $infixes = explode(',', SHORTPIXEL_CUSTOM_THUMB_INFIXES);
365
- foreach ($infixes as $infix){
366
- $thumbsCandidates = @glob($base . $infix . "-*." . $ext);
367
- $pattern = '/' . preg_quote($base, '/') . $infix . '-\d+x\d+' . '\.'. $ext .'/';
368
- foreach($thumbsCandidates as $th) {
369
- if(preg_match($pattern, $th)) {
370
- $thumbs[]= $th;
371
- }
372
- }
 
 
 
 
 
373
  }
374
  }
375
- }
376
  return $thumbs;
377
  }
378
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
379
  public static function getOptimalChunkSize($table = 'posts') {
380
  global $wpdb;
381
  //get an aproximate but fast row count.
1
  <?php
2
  use ShortPixel\ShortpixelLogger\ShortPixelLogger as Log;
3
 
 
4
  class WpShortPixelMediaLbraryAdapter {
5
 
6
  //count all the processable files in media library (while limiting the results to max 10000)
56
  foreach ( $filesList as $file )
57
  {
58
  $totalFilesThis = $processedFilesThis = 0;
 
59
 
60
  if ( $file->meta_key == "_wp_attached_file" )
61
  {//count pdf files only
85
  || $attachment['ShortPixelImprovement'] === 0.0 || $attachment['ShortPixelImprovement'] === "0"))
86
  {
87
  $foundThumbs = WpShortPixelMediaLbraryAdapter::findThumbs($filePath);
88
+
89
  $foundCount = count($foundThumbs);
90
+
 
91
  if(count($foundThumbs) > $sizesCount) {
92
  $unlisted = array();
93
  foreach($foundThumbs as $found) {
96
  $unlisted[] = wp_basename($found);
97
  }
98
  }
 
99
  $foundUnlistedThumbs = (object)array("id" => $file->post_id, "name" => wp_basename($attachment['file']), "unlisted" => $unlisted);
100
  }
101
  } else {
245
  return $result;
246
  }
247
 
248
+ /* public static function getPostMetaJoinLess($startId, $endId, $limit)
249
  {
250
  global $wpdb;
251
  $time = microtime(true);
270
 
271
  return $metaresult;
272
  }
273
+ */
274
  public static function getPostsJoinLessReverse($startId, $endId, $limit)
275
  {
276
  global $wpdb;
277
+ //$time = microtime(true);
278
 
279
  $sqlmeta = "SELECT DISTINCT post_id FROM " . $wpdb->prefix . "postmeta where (meta_key = %s or meta_key = %s) and post_id <= %d and post_id >= %d order by post_id DESC LIMIT %d";
280
  $sqlmeta = $wpdb->prepare($sqlmeta, '_wp_attached_file', '_wp_attachment_metadata', $startId, $endId, $limit);
281
 
282
  $result = $wpdb->get_col($sqlmeta);
283
 
284
+ // no postmeta present, i.e. empty installation
285
+ if (count($result) == 0)
286
+ return array();
287
+
288
  $id_placeholders = implode( ', ', array_fill( 0, count( $result ), '%d'));
289
 
290
  $sql = 'SELECT ID from ' . $wpdb->prefix . 'posts where ID in (' . $id_placeholders . ') ORDER BY ID DESC';
294
 
295
  $postAr = array_intersect($result, $postresult);
296
 
297
+ //$time_end = microtime(true);
 
 
298
  return $postAr;
299
  }
300
 
318
  return count(self::getSizesNotExcluded($sizes, $exclude));
319
  }
320
 
321
+ /** @todo Seems not to be in use - Only referenced from wp-short-pixel handling */
322
+ /*
323
  public static function cleanupFoundThumbs($itemHandler) {
324
  $meta = $itemHandler->getMeta();
325
  $sizesAll = $meta->getThumbs();
336
  }
337
  $meta->setThumbs($sizes);
338
  $itemHandler->updateMeta($meta, true);
339
+ } */
340
 
341
+ /** Find thumbnails that are not listed in the image metadata
342
+ * These are usually thumbnails generated by other plugins
343
+ * @param $mainFile String Full path the main Image of which to get thumbnails
344
+ * @return Array Array of thumbnails or empty array
345
+ */
346
  public static function findThumbs($mainFile) {
347
+ // Old
348
+ /* $ext = pathinfo($mainFile, PATHINFO_EXTENSION); // gets the extension
349
+ $base = substr($mainFile, 0, strlen($mainFile) - strlen($ext) - 1); // removes the extension
350
+ $pattern = '/' . preg_quote($base, '/') . '-\d+x\d+\.'. $ext .'/'; // tries to match between basename and extension
351
+ */
352
  $thumbs = array();
353
+
354
+ // New
355
+ $fs = new \ShortPixel\FileSystemController();
356
+ $file = $fs->getFile($mainFile);
357
+ $dirPath = $file->getFileDir()->getPath();
358
+
359
+ $base = $file->getFileBase();
360
+ $ext = $file->getExtension();
361
+ $pattern = '/' . preg_quote($base, '/') . '-\d+x\d+\.'. $ext .'/';
362
+
363
+ $thumbs = array_merge($thumbs, self::getFilesByPattern($dirPath, $pattern));
364
+
365
+ /*$dirIterator = new \DirectoryIterator($dirPath);
366
+ $regExIterator = new \RegexIterator($dirIterator, $pattern);
367
+
368
+ foreach($regExIterator as $fileinfo)
369
+ {
370
+ $thumbs[] = $fileinfo->getPath();
371
+ } */
372
+
373
+ /*
374
+ $thumbsCandidates = @glob($base . "-*." . $ext); */
375
+ // $thumbs = array();
376
+ /* if(is_array($thumbsCandidates)) {
377
  foreach($thumbsCandidates as $th) {
378
  if(preg_match($pattern, $th)) {
379
  $thumbs[]= $th;
380
  }
381
+ } */
382
  if( defined('SHORTPIXEL_CUSTOM_THUMB_SUFFIXES') ){
383
+ $suffixes = explode(',', SHORTPIXEL_CUSTOM_THUMB_SUFFIXES);
384
+ if (is_array($suffixes))
385
+ {
386
+ foreach ($suffixes as $suffix){
387
+
388
+ $pattern = '/' . preg_quote($base, '/') . '-\d+x\d+'. $suffix . '\.'. $ext .'/';
389
+ $thumbs = array_merge($thumbs, self::getFilesByPattern($dirPath, $pattern));
390
+ /*foreach($thumbsCandidates as $th) {
391
+ if(preg_match($pattern, $th)) {
392
+ $thumbs[]= $th;
393
+ }
394
+ } */
395
+ }
396
  }
397
  }
398
  if( defined('SHORTPIXEL_CUSTOM_THUMB_INFIXES') ){
399
  $infixes = explode(',', SHORTPIXEL_CUSTOM_THUMB_INFIXES);
400
+ if (is_array($infixes))
401
+ {
402
+ foreach ($infixes as $infix){
403
+ //$thumbsCandidates = @glob($base . $infix . "-*." . $ext);
404
+ $pattern = '/' . preg_quote($base, '/') . $infix . '-\d+x\d+' . '\.'. $ext .'/';
405
+ $thumbs = array_merge($thumbs, self::getFilesByPattern($dirPath, $pattern));
406
+
407
+ /*foreach($thumbsCandidates as $th) {
408
+ if(preg_match($pattern, $th)) {
409
+ $thumbs[]= $th;
410
+ }
411
+ } */
412
+ }
413
  }
414
  }
415
+ // }
416
  return $thumbs;
417
  }
418
 
419
+ private static function getFilesByPattern($path, $pattern)
420
+ {
421
+
422
+ $dirIterator = new \DirectoryIterator($path);
423
+ $regExIterator = new \RegexIterator($dirIterator, $pattern);
424
+
425
+ $images = array();
426
+ foreach($regExIterator as $fileinfo)
427
+ {
428
+ $images[] = $fileinfo->getPathname();
429
+ }
430
+
431
+ return $images;
432
+ }
433
+
434
  public static function getOptimalChunkSize($table = 'posts') {
435
  global $wpdb;
436
  //get an aproximate but fast row count.
class/model/apikey_model.php CHANGED
@@ -67,8 +67,6 @@ class ApiKeyModel extends ShortPixelModel
67
 
68
  $valid = $this->checkKey($key);
69
 
70
-
71
- Log::addDebug('Checked Key', array('valid' => $valid, 'verified' => $this->key_is_verified));
72
  return $valid;
73
  }
74
 
@@ -106,7 +104,7 @@ class ApiKeyModel extends ShortPixelModel
106
  */
107
  public function checkKey($key)
108
  {
109
- Log::addDebug("Model, checking key ". $key . ' not -' . $this->apiKeyTried);
110
  if (strlen($key) == 0)
111
  {
112
  // first-timers, redirect to nokey screen
67
 
68
  $valid = $this->checkKey($key);
69
 
 
 
70
  return $valid;
71
  }
72
 
104
  */
105
  public function checkKey($key)
106
  {
107
+ //Log::addDebug("Model, checking key ". $key . ' not -' . $this->apiKeyTried);
108
  if (strlen($key) == 0)
109
  {
110
  // first-timers, redirect to nokey screen
class/model/directory_model.php CHANGED
@@ -5,6 +5,7 @@ use ShortPixel\ShortpixelLogger\ShortPixelLogger as Log;
5
  /* Model for Directories
6
  *
7
  * For all low-level operations on directories
 
8
  *
9
  */
10
 
@@ -24,7 +25,7 @@ class DirectoryModel extends ShortPixelModel
24
  {
25
  //$this->new_directory_permission = octdec(06440);
26
  $this->path = wp_normalize_path(trailingslashit($path));
27
- Log::addDebug("DirectoryModel LoadPath - " . $this->path);
28
  if (file_exists($this->path))
29
  {
30
  $this->exists();
@@ -37,6 +38,10 @@ class DirectoryModel extends ShortPixelModel
37
  return (string) $this->path;
38
  }
39
 
 
 
 
 
40
  public function getPath()
41
  {
42
  return $this->path;
@@ -54,6 +59,24 @@ class DirectoryModel extends ShortPixelModel
54
  return $this->is_writable;
55
  }
56
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
57
  /** Checks the directory
58
  *
59
  */
@@ -61,7 +84,7 @@ class DirectoryModel extends ShortPixelModel
61
  {
62
  if (! $this->exists())
63
  {
64
- Log::addDebug('Direct does not exists. Try to create recursive ' . $this->path . ' with ' . $this->new_directory_permission);
65
  $result = @mkdir($this->path, $this->new_directory_permission , true);
66
  if (! $result)
67
  {
5
  /* Model for Directories
6
  *
7
  * For all low-level operations on directories
8
+ * Private model of FileSystemController. Please get your directories via there.
9
  *
10
  */
11
 
25
  {
26
  //$this->new_directory_permission = octdec(06440);
27
  $this->path = wp_normalize_path(trailingslashit($path));
28
+
29
  if (file_exists($this->path))
30
  {
31
  $this->exists();
38
  return (string) $this->path;
39
  }
40
 
41
+ /** Returns path *with* trailing slash
42
+ *
43
+ * @return String Path with trailing slash
44
+ */
45
  public function getPath()
46
  {
47
  return $this->path;
59
  return $this->is_writable;
60
  }
61
 
62
+ /** Try to obtain the path, minus the installation directory.
63
+ * @return Mixed False if this didn't work, Path as string without basedir if it did.
64
+ */
65
+ public function getRelativePath()
66
+ {
67
+ $upload_dir = wp_upload_dir(null, false);
68
+
69
+ Log::addDebug('Upload Dir - ', array($upload_dir));
70
+ $relativePath = str_replace($upload_dir['basedir'], '', $this->getPath());
71
+
72
+ // if relativePath has less amount of characters, changes are this worked.
73
+ if (strlen($this->getPath()) > strlen($relativePath))
74
+ {
75
+ return $relativePath;
76
+ }
77
+ return false;
78
+ }
79
+
80
  /** Checks the directory
81
  *
82
  */
84
  {
85
  if (! $this->exists())
86
  {
87
+ Log::addInfo('Direct does not exists. Try to create recursive ' . $this->path . ' with ' . $this->new_directory_permission);
88
  $result = @mkdir($this->path, $this->new_directory_permission , true);
89
  if (! $result)
90
  {
class/model/file_model.php CHANGED
@@ -17,20 +17,33 @@ class FileModel extends ShortPixelModel
17
 
18
  // File info
19
  protected $fullpath;
20
- protected $filename;
 
21
  protected $directory;
22
  protected $extension;
23
 
24
  // File Status
25
  protected $exists = false;
26
  protected $is_writable = false;
 
27
 
28
  protected $backupDirectory;
29
 
 
 
 
 
30
  /** Creates a file model object. FileModel files don't need to exist on FileSystem */
31
  public function __construct($path)
32
  {
33
- $this->fullpath = wp_normalize_path($path);
 
 
 
 
 
 
 
34
  $this->setFileInfo();
35
  }
36
 
@@ -45,10 +58,10 @@ class FileModel extends ShortPixelModel
45
  {
46
  $this->exists = true;
47
  $info = pathinfo($this->fullpath);
48
- $this->filename = isset($info['basename']) ? $info['basename'] : null;
49
- $this->extension = isset($info['extension']) ? $info['extension'] : null;
 
50
  $this->directory = isset($info['dirname']) ? new DirectoryModel($info['dirname']) : null;
51
- Log::addDebug('File info', array($info));
52
  $this->is_writable = is_writable($this->fullpath);
53
  }
54
  else {
@@ -58,30 +71,11 @@ class FileModel extends ShortPixelModel
58
  if (is_null($this->filename))
59
  $this->filename = basename($this->fullpath);
60
 
61
- if (is_null($this->directory))
62
  $this->directory = new DirectoryModel(dirname($this->fullpath));
63
  }
64
  }
65
 
66
- // Util function to get location of backup Directory.
67
- private function getBackupDirectory()
68
- {
69
- if (is_null($this->backupDirectory))
70
- {
71
- $backup_dir = str_replace(get_home_path(), "", $this->directory->getPath());
72
- Log::addDebug('Bkup ' . get_home_path() . ' ' . $this->directory->getPath() . '-->' . $backup_dir );
73
- $backupDirectory = SHORTPIXEL_BACKUP_FOLDER . '/' . $backup_dir;
74
- $directory = new DirectoryModel($backupDirectory);
75
-
76
- if (! $directory->exists()) // check if exists. FileModel should not attempt to create.
77
- return false;
78
-
79
- $this->backupDirectory = $directory;
80
- }
81
-
82
- return $this->backupDirectory;
83
- }
84
-
85
  public function exists()
86
  {
87
  $this->exists = file_exists($this->fullpath);
@@ -121,6 +115,10 @@ class FileModel extends ShortPixelModel
121
  return false;
122
  }
123
 
 
 
 
 
124
  public function getFileDir()
125
  {
126
  return $this->directory;
@@ -132,21 +130,48 @@ class FileModel extends ShortPixelModel
132
  */
133
  public function copy(FileModel $destination)
134
  {
135
- $status = copy($this->getFullPath(), $destination->getFullPath());
 
 
 
 
 
 
 
 
 
 
 
136
  if (! $status)
137
- Log::addWarn('Could not copy file ' . $this->getFullPath() . ' to' . $destination->getFullPath());
138
  else {
139
  $destination->setFileInfo(); // refresh info.
140
  }
 
 
141
  return $status;
142
  }
143
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
144
  /** Deletes current file
145
  * This uses the WP function since it has a filter that might be useful
146
  */
147
  public function delete()
148
  {
149
- \wp_delete_file($this->fullpath);
150
  if (! file_exists($this->fullpath))
151
  {
152
  $this->setFileInfo(); // update info
@@ -168,12 +193,160 @@ class FileModel extends ShortPixelModel
168
  return $this->filename;
169
  }
170
 
 
 
 
 
 
171
  public function getExtension()
172
  {
173
  return $this->extension;
174
  }
175
 
176
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
177
 
178
  /*
179
  // do this before putting the meta down, since maybeDump check for last timestamp
17
 
18
  // File info
19
  protected $fullpath;
20
+ protected $filename; // filename + extension
21
+ protected $filebase; // filename without extension
22
  protected $directory;
23
  protected $extension;
24
 
25
  // File Status
26
  protected $exists = false;
27
  protected $is_writable = false;
28
+ protected $status;
29
 
30
  protected $backupDirectory;
31
 
32
+ const FILE_OK = 1;
33
+ const FILE_UNKNOWN_ERROR = 2;
34
+
35
+
36
  /** Creates a file model object. FileModel files don't need to exist on FileSystem */
37
  public function __construct($path)
38
  {
39
+ $processed_path = $this->processPath($path);
40
+ if ($processed_path !== false)
41
+ $this->fullpath = $processed_path; // set processed path if that went alright
42
+ else {
43
+ $this->fullpath = $path; // fallback, but there should be error state
44
+ }
45
+
46
+ // $this->fullpath =
47
  $this->setFileInfo();
48
  }
49
 
58
  {
59
  $this->exists = true;
60
  $info = pathinfo($this->fullpath);
61
+ $this->filename = isset($info['basename']) ? $info['basename'] : null; // filename + extension
62
+ $this->filebase = isset($info['filename']) ? $info['filename'] : null; // only filename
63
+ $this->extension = isset($info['extension']) ? $info['extension'] : null; // only (last) extension
64
  $this->directory = isset($info['dirname']) ? new DirectoryModel($info['dirname']) : null;
 
65
  $this->is_writable = is_writable($this->fullpath);
66
  }
67
  else {
71
  if (is_null($this->filename))
72
  $this->filename = basename($this->fullpath);
73
 
74
+ if (is_null($this->directory) && ! is_null($this->filename) && strlen($this->filename) > 0)
75
  $this->directory = new DirectoryModel(dirname($this->fullpath));
76
  }
77
  }
78
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79
  public function exists()
80
  {
81
  $this->exists = file_exists($this->fullpath);
115
  return false;
116
  }
117
 
118
+ /** Returns the Directory Model this file resides in
119
+ *
120
+ * @return DirectoryModel Directorymodel Object
121
+ */
122
  public function getFileDir()
123
  {
124
  return $this->directory;
130
  */
131
  public function copy(FileModel $destination)
132
  {
133
+ $sourcePath = $this->getFullPath();
134
+ $destinationPath = $destination->getFullPath();
135
+
136
+ if (! strlen($sourcePath) > 0 || ! strlen($destinationPath) > 0)
137
+ {
138
+ Log::addWarn('Attempted Copy on Empty Path', array($sourcePath, $destinationPath));
139
+ return false;
140
+ }
141
+
142
+ $is_new = ($destination->exists()) ? false : true;
143
+ $status = copy($sourcePath, $destinationPath);
144
+
145
  if (! $status)
146
+ Log::addWarn('Could not copy file ' . $sourcePath . ' to' . $destinationPath);
147
  else {
148
  $destination->setFileInfo(); // refresh info.
149
  }
150
+ //
151
+ do_action('shortpixel/filesystem/addfile', array($destinationPath, $destination, $this, $is_new));
152
  return $status;
153
  }
154
 
155
+ /** Move a file to somewhere
156
+ * This uses copy and delete functions and will fail if any of those fail.
157
+ * @param $destination String Full Path to new file.
158
+ */
159
+ public function move(FileModel $destination)
160
+ {
161
+ $result = false;
162
+ if ($this->copy($destination))
163
+ {
164
+ $result = $this->delete();
165
+ }
166
+ return $result;
167
+ }
168
+
169
  /** Deletes current file
170
  * This uses the WP function since it has a filter that might be useful
171
  */
172
  public function delete()
173
  {
174
+ \wp_delete_file($this->fullpath); // delete file hook via wp_delet_file
175
  if (! file_exists($this->fullpath))
176
  {
177
  $this->setFileInfo(); // update info
193
  return $this->filename;
194
  }
195
 
196
+ public function getFileBase()
197
+ {
198
+ return $this->filebase;
199
+ }
200
+
201
  public function getExtension()
202
  {
203
  return $this->extension;
204
  }
205
 
206
+ /* Util function to get location of backup Directory.
207
+ * @return Boolean | DirectModel Returns false if directory is not properly set, otherwhise with a new directoryModel
208
+ */
209
+ private function getBackupDirectory()
210
+ {
211
+ if (is_null($this->directory))
212
+ {
213
+ return false;
214
+ }
215
+ if (is_null($this->backupDirectory))
216
+ {
217
+ $backup_dir = str_replace(get_home_path(), "", $this->directory->getPath());
218
+ $backupDirectory = SHORTPIXEL_BACKUP_FOLDER . '/' . $backup_dir;
219
+ $directory = new DirectoryModel($backupDirectory);
220
+
221
+ if (! $directory->exists()) // check if exists. FileModel should not attempt to create.
222
+ return false;
223
+
224
+ $this->backupDirectory = $directory;
225
+ }
226
+
227
+ return $this->backupDirectory;
228
+ }
229
+
230
+ /* Internal function to check if path is a real path
231
+ * - Test for URL's based on http / https
232
+ * - Test if given path is absolute, from the filesystem root.
233
+ * @param $path String The file path
234
+ * @param String The Fixed filepath.
235
+ */
236
+ protected function processPath($path)
237
+ {
238
+ $path = trim($path);
239
+
240
+ if ($this->pathIsUrl($path))
241
+ {
242
+ $path = $this->UrlToPath($path);
243
+ }
244
+
245
+ if ($path === false)
246
+ return false;
247
+
248
+ $path = wp_normalize_path($path);
249
+
250
+ // if path does not contain basepath.
251
+ if (strpos($path, ABSPATH) === false && strpos($path, $this->getUploadPath()) === false)
252
+ $path = $this->relativeToFullPath($path);
253
+
254
+ /* This needs some check here on malformed path's, but can't be test for existing since that's not a requirement.
255
+ if (file_exists($path) === false) // failed to process path to something workable.
256
+ {
257
+ // Log::addInfo('Failed to process path', array($path));
258
+ $path = false;
259
+ } */
260
+
261
+ return $path;
262
+ }
263
+
264
+ private function pathIsUrl($path)
265
+ {
266
+ $is_http = (substr($path, 0, 4) == 'http') ? true : false;
267
+ $is_https = (substr($path, 0, 5) == 'https') ? true : false;
268
+ $is_neutralscheme = (substr($path, 0, 1) == '//') ? true : false; // when URL is relative like //wp-content/etc
269
+ $has_urldots = (strpos($path, '://') !== false) ? true : false;
270
+
271
+ if ($is_http || $is_https || $is_neutralscheme || $has_urldots)
272
+ return true;
273
+ else {
274
+ return false;
275
+ }
276
+
277
+ }
278
+
279
+ private function UrlToPath($url)
280
+ {
281
+ //$uploadDir = wp_upload_dir();
282
+ $site_url = str_replace('http:', '', get_site_url(null, '', 'http'));
283
+ $url = str_replace(array('http:', 'https:'), '', $url);
284
+
285
+ if (strpos($url, $site_url) !== false)
286
+ {
287
+ // try to replace URL for Path
288
+ $path = str_replace($site_url, rtrim(ABSPATH,'/'), $url);
289
+ if (! $this->pathIsUrl($path)) // test again.
290
+ {
291
+ return $path;
292
+ }
293
+ }
294
+
295
+ return false; // seems URL from other server, can't file that.
296
+ }
297
+
298
+ /** Tries to find the full path for a perceived relative path.
299
+ *
300
+ * Relative path is detected on basis of WordPress ABSPATH. If this doesn't appear in the file path, it might be a relative path.
301
+ * Function checks for expections on this rule ( tmp path ) and returns modified - or not - path.
302
+ * @param $path The path for the file_exists
303
+ * @returns String The updated path, if that was possible.
304
+ */
305
+ private function relativeToFullPath($path)
306
+ {
307
+ // A file with no path, can never be created to a fullpath.
308
+ if (strlen($path) == 0)
309
+ return $path;
310
+
311
+ // Test if our 'relative' path is not a path to /tmp directory.
312
+
313
+ // This ini value might not exist.
314
+ $tempdirini = ini_get('upload_tmp_dir');
315
+ if ( (strlen($tempdirini) > 0) && strpos($path, $tempdirini) !== false)
316
+ return $path;
317
+
318
+ $tempdir = sys_get_temp_dir();
319
+ if ( (strlen($tempdir) > 0) && strpos($path, $tempdir) !== false)
320
+ return $path;
321
+
322
+ // Path contains upload basedir. This happens when upload dir is outside of usual WP.
323
+ if (strpos($path, $this->getUploadPath()) !== false)
324
+ {
325
+ return $path;
326
+ }
327
+
328
+ // if the file plainly exists, it's usable /**
329
+ if (file_exists($path))
330
+ {
331
+ return $path;
332
+ }
333
+
334
+ // this is probably a bit of a sharp corner to take.
335
+ // if path starts with / remove it due to trailingslashing ABSPATH
336
+ $path = ltrim($path, '/');
337
+ $fullpath = trailingslashit(ABSPATH) . $path;
338
+ return $fullpath;
339
+ }
340
+
341
+ private function getUploadPath()
342
+ {
343
+ $upload_dir = wp_upload_dir(null, false);
344
+ $basedir = $upload_dir['basedir'];
345
+
346
+ return $basedir;
347
+ }
348
+
349
+ } // FileModel Class
350
 
351
  /*
352
  // do this before putting the meta down, since maybeDump check for last timestamp
class/model/shortpixel-folder.php CHANGED
@@ -60,6 +60,7 @@ class ShortPixelFolder extends ShortPixelEntity{
60
 
61
  }
62
 
 
63
  public static function deleteFolder($dirname) {
64
  if (is_dir($dirname))
65
  $dir_handle = opendir($dirname);
60
 
61
  }
62
 
63
+ /** @todo This function is double with wp-short-pixel - deleteDir */
64
  public static function deleteFolder($dirname) {
65
  if (is_dir($dirname))
66
  $dir_handle = opendir($dirname);
class/model/shortpixel-meta.php CHANGED
@@ -38,7 +38,7 @@ class ShortPixelMeta extends ShortPixelEntity{
38
  const FOUND_THUMB_PREFIX = 'sp-found-';
39
 
40
  // [BS] Attempt to shed some light on Meta Status on File.
41
- // Anything lower than 0 is a processing error.
42
  const FILE_STATUS_UNPROCESSED = 0;
43
  const FILE_STATUS_PENDING = 1;
44
  const FILE_STATUS_SUCCESS = 2;
@@ -163,6 +163,7 @@ class ShortPixelMeta extends ShortPixelEntity{
163
  return $this->thumbsOptList;
164
  }
165
 
 
166
  function setThumbsOptList($thumbsOptList) {
167
  $this->thumbsOptList = $thumbsOptList;
168
  }
38
  const FOUND_THUMB_PREFIX = 'sp-found-';
39
 
40
  // [BS] Attempt to shed some light on Meta Status on File.
41
+ // Anything lower than 0 is a processing error.
42
  const FILE_STATUS_UNPROCESSED = 0;
43
  const FILE_STATUS_PENDING = 1;
44
  const FILE_STATUS_SUCCESS = 2;
163
  return $this->thumbsOptList;
164
  }
165
 
166
+ /** @todo There is only one function using this in Shortpixel API, but getting the values from the same class */
167
  function setThumbsOptList($thumbsOptList) {
168
  $this->thumbsOptList = $thumbsOptList;
169
  }
class/view/shortpixel_view.php CHANGED
@@ -212,6 +212,7 @@ class ShortPixelView {
212
  //$this->ctrl->outputHSBeacon();
213
  \ShortPixel\HelpScout::outputBeacon($this->ctrl->getApiKey());
214
 
 
215
  $this->bulkType = $this->ctrl->getPrioQ()->getBulkTypeForDisplay(); // adding to the mess
216
  $hider = ($this->bulkType == ShortPixelQueue::BULK_TYPE_RESTORE) ? 'sp-hidden' : '';
217
  ?>
@@ -1698,17 +1699,19 @@ class ShortPixelView {
1698
  <?php _e('Cleanup&Retry','shortpixel-image-optimiser');?>
1699
  </a> <?php
1700
  } else {
 
1701
  if($data['status'] == 'retry' && (isset($data['backup']) && $data['backup']) ) { ?>
1702
- <div style="overflow:hidden">
1703
  <a class="button button-smaller sp-action-restore" href="admin.php?action=shortpixel_restore_backup&attachment_ID=<?php echo($id)?>" style="margin-left:5px;"
1704
  title="<?php _e('Restore Image from Backup', 'shortpixel-image-optimiser') ?>">
1705
  <?php _e('Cleanup','shortpixel-image-optimiser');?>
1706
  </a>
 
1707
  <?php } ?>
1708
  <a class='button button-smaller button-primary' href="javascript:manualOptimization('<?php echo($id)?>', false)">
1709
  <?php _e('Retry','shortpixel-image-optimiser');?>
1710
  </a>
1711
- </div>
1712
  <?php
1713
  }
1714
  break;
@@ -1754,7 +1757,7 @@ class ShortPixelView {
1754
  // echo("<br><br>METADATA: <pre>");print_r(wp_get_attachment_metadata($id));echo("</pre>");
1755
  //}
1756
  ?>
1757
- </div>
1758
  <?php
1759
  }
1760
 
@@ -1844,8 +1847,8 @@ class ShortPixelView {
1844
  Compare Images
1845
  </div>
1846
  <div class="sp-modal-body" style="height:400px;padding:0;">
1847
- <div class="shortpixel-slider"style="text-align: center;">
1848
- <div class="side-by-side" style="text-align: center; display:inline-block;">
1849
  <img class="spUploadCompareOriginal" style="margin: 10px"/><br>
1850
  Original
1851
  </div>
212
  //$this->ctrl->outputHSBeacon();
213
  \ShortPixel\HelpScout::outputBeacon($this->ctrl->getApiKey());
214
 
215
+
216
  $this->bulkType = $this->ctrl->getPrioQ()->getBulkTypeForDisplay(); // adding to the mess
217
  $hider = ($this->bulkType == ShortPixelQueue::BULK_TYPE_RESTORE) ? 'sp-hidden' : '';
218
  ?>
1699
  <?php _e('Cleanup&Retry','shortpixel-image-optimiser');?>
1700
  </a> <?php
1701
  } else {
1702
+
1703
  if($data['status'] == 'retry' && (isset($data['backup']) && $data['backup']) ) { ?>
1704
+ <div style="overflow:hidden">
1705
  <a class="button button-smaller sp-action-restore" href="admin.php?action=shortpixel_restore_backup&attachment_ID=<?php echo($id)?>" style="margin-left:5px;"
1706
  title="<?php _e('Restore Image from Backup', 'shortpixel-image-optimiser') ?>">
1707
  <?php _e('Cleanup','shortpixel-image-optimiser');?>
1708
  </a>
1709
+ </div>
1710
  <?php } ?>
1711
  <a class='button button-smaller button-primary' href="javascript:manualOptimization('<?php echo($id)?>', false)">
1712
  <?php _e('Retry','shortpixel-image-optimiser');?>
1713
  </a>
1714
+
1715
  <?php
1716
  }
1717
  break;
1757
  // echo("<br><br>METADATA: <pre>");print_r(wp_get_attachment_metadata($id));echo("</pre>");
1758
  //}
1759
  ?>
1760
+ </div> <!--- // RenderCustomColumn -->
1761
  <?php
1762
  }
1763
 
1847
  Compare Images
1848
  </div>
1849
  <div class="sp-modal-body" style="height:400px;padding:0;">
1850
+ <div class="shortpixel-slider" style="text-align: center;">
1851
+ <div class="side-by-side" style="text-align: center; display:inline-block;">
1852
  <img class="spUploadCompareOriginal" style="margin: 10px"/><br>
1853
  Original
1854
  </div>
class/wp-short-pixel.php CHANGED
@@ -24,7 +24,7 @@ class WPShortPixel {
24
 
25
  public function __construct() {
26
  $this->timer = time();
27
-
28
 
29
  if (Log::debugIsActive()) {
30
  $this->jsSuffix = '.js'; //use unminified versions for easier debugging
@@ -158,22 +158,6 @@ class WPShortPixel {
158
 
159
  $this->migrateBackupFolder();
160
 
161
- // [BS] Quite dangerous to do this in any constructor. Can hit if request is ajax to name something
162
- // @todo This is intended to run only once, on activation. ( it does )
163
- /*if(!$this->_settings->redirectedSettings && !$this->_settings->verifiedKey && (!function_exists("is_multisite") || !is_multisite())) {
164
- $this->_settings->redirectedSettings = 1;
165
- wp_redirect(admin_url("options-general.php?page=wp-shortpixel-settings"));
166
- exit();
167
- }
168
- elseif (function_exists('is_multisite') && is_multisite() && !$this->_settings->verifiedKey)
169
- { // @todo not optimal, License key needs it's own model to do checks upon.
170
- $scontrolname = \shortPixelTools::namespaceit("SettingsController");
171
- $scontrol = new $scontrolname();
172
- $scontrol->setShortPixel($this);
173
- $scontrol->checkKey();
174
- } */
175
-
176
- //
177
 
178
  // only load backed, or when frontend processing is enabled.
179
  if (is_admin() || $this->_settings->frontBootstrap )
@@ -189,12 +173,6 @@ class WPShortPixel {
189
  $this->__construct();
190
  }
191
 
192
- // @hook admin menu
193
- // @todo move to plugin class
194
- public function registerSettingsPage() {
195
-
196
- }
197
-
198
  // @hook admin menu
199
  // @todo move to plugin class
200
  function registerAdminPage( ) {
@@ -1057,6 +1035,9 @@ class WPShortPixel {
1057
  // [BS] Request StartQueryID everytime to query for updated AdvanceBulk status
1058
  $crtStartQueryID = $this->prioQ->getStartBulkId();
1059
  $resultsPostMeta = WpShortPixelMediaLbraryAdapter::getPostMetaSlice($crtStartQueryID, $endQueryID, $maxResults);
 
 
 
1060
  if ( empty($resultsPostMeta) ) {
1061
  // check for custom work
1062
  $pendingCustomMeta = $this->spMetaDao->getPendingBulkRestore(SHORTPIXEL_MAX_RESULTS_QUERY * 2);
@@ -1081,11 +1062,14 @@ class WPShortPixel {
1081
  $item = new ShortPixelMetaFacade($crtStartQueryID);
1082
  $meta = $item->getMeta();//wp_get_attachment_metadata($crtStartQueryID);
1083
 
1084
- if($meta->getStatus() == 2 || $meta->getStatus() == 1) {
1085
- if($meta->getStatus() == 2 && $this->prioQ->getBulkType() == ShortPixelQueue::BULK_TYPE_RESTORE) {
1086
  $res = $this->doRestore($crtStartQueryID); //this is restore, the real
 
 
1087
  } else {
1088
  //this is only meta cleanup, no files are replaced (BACKUP REMAINS IN PLACE TOO)
 
1089
  $item->cleanupMeta($this->prioQ->getBulkType() == ShortPixelQueue::BULK_TYPE_CLEANUP_PENDING);
1090
  $res = true;
1091
  }
@@ -1184,7 +1168,7 @@ class WPShortPixel {
1184
  $meta = $item->getMeta();//wp_get_attachment_metadata($crtStartQueryID);
1185
  if($timeoutThreshold > 15) Log::addInfo("GETDB is SO SLOW. Got meta.");
1186
 
1187
- if($meta->getStatus() != 2) {
1188
  $addIt = (strpos($meta->getMessage(), __('Image files are missing.', 'shortpixel-image-optimiser')) === false);
1189
 
1190
  if(!$addIt) {
@@ -1211,16 +1195,19 @@ class WPShortPixel {
1211
  }
1212
  }
1213
  elseif( $this->_settings->processThumbnails && $meta->getThumbsOpt() !== null //thumbs were chosen in settings
1214
- && ($meta->getThumbsOpt() == 0 && count($meta->getThumbs()) > 0 //no thumbnails optimized
1215
- || is_array($meta->getThumbsOptList())
1216
  && count(array_diff(array_keys(WpShortPixelMediaLbraryAdapter::getSizesNotExcluded($meta->getThumbs(), $this->_settings->excludeSizes)),
1217
- $meta->getThumbsOptList()))
1218
  || ( $this->_settings->optimizeUnlisted
1219
  && count(array_diff(WpShortPixelMediaLbraryAdapter::findThumbs($meta->getPath()), $meta->getThumbsOptList()))
1220
  )
1221
  )
1222
  ) {
 
 
1223
  $URLsAndPATHs = $item->getURLsAndPATHs(true, true, $this->_settings->optimizeRetina, $this->_settings->excludeSizes);
 
1224
  if(count($URLsAndPATHs["URLs"])) {
1225
  $meta->setThumbsTodo(true);
1226
  $item->updateMeta($meta);//wp_update_attachment_metadata($crtStartQueryID, $meta);
@@ -1229,12 +1216,9 @@ class WPShortPixel {
1229
  if(count($itemList) > SHORTPIXEL_PRESEND_ITEMS) break;
1230
  }
1231
  }
1232
- /* New query selects this out, also no metadata returned.
1233
- elseif($itemMetaData->meta_key == '_wp_attachment_metadata') { //count skipped
1234
- $skippedAlreadyProcessed++;
1235
- }
1236
- */
1237
  }
 
1238
  }
1239
  if(!count($idList) && $crtStartQueryID <= $startQueryID) {
1240
  //daca n-am adaugat niciuna pana acum, n-are sens sa mai selectez zona asta de id-uri in bulk-ul asta.
@@ -1646,8 +1630,103 @@ class WPShortPixel {
1646
  $result["BulkMsg"] = $this->bulkProgressMessage($deltaBulkPercent, $minutesRemaining);
1647
  }
1648
 
1649
- private function sendToProcessing($itemHandler, $compressionType = false, $onlyThumbs = false) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1650
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1651
  //conversion of PNG 2 JPG for existing images
1652
  if($itemHandler->getType() == ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE) { //currently only for ML
1653
  $rawMeta = $this->checkConvertMediaPng2Jpg($itemHandler);
@@ -1662,50 +1741,7 @@ class WPShortPixel {
1662
 
1663
  $meta = $itemHandler->getMeta();
1664
  //find thumbs that are not listed in the metadata and add them in the sizes array
1665
- if( $itemHandler->getType() == ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE
1666
- && $this->_settings->optimizeUnlisted) {
1667
- $mainFile = $meta->getPath();
1668
-
1669
- $foundThumbs = WpShortPixelMediaLbraryAdapter::findThumbs($mainFile);
1670
- //first identify which thumbs are not in the sizes
1671
- $sizes = $meta->getThumbs();
1672
- $mimeType = false;
1673
- foreach($foundThumbs as $id => $found) {
1674
- //get the mime-type from one of the thumbs metas
1675
- foreach($sizes as $size) {
1676
- if(pathinfo($mainFile, PATHINFO_EXTENSION) !== pathinfo($size['file'], PATHINFO_EXTENSION)){
1677
- continue;
1678
- }
1679
- if(isset($size['mime-type'])) { //situation from support case #9351 Ramesh Mehay
1680
- $mimeType = $size['mime-type'];
1681
- }
1682
- if($size['file'] === ShortPixelAPI::MB_basename($found)) {
1683
- $foundThumbs[$id] = false;
1684
- }
1685
- }
1686
- }
1687
- // add the unfound ones to the sizes array
1688
- $ind = 1;
1689
- while (isset($sizes[ShortPixelMeta::FOUND_THUMB_PREFIX . str_pad("".$ind, 2, '0', STR_PAD_LEFT)])) $ind++;
1690
- $start = $ind;
1691
- foreach($foundThumbs as $found) {
1692
- if($found !== false) {
1693
- $size = getimagesize($found);
1694
- $sizes[ShortPixelMeta::FOUND_THUMB_PREFIX . str_pad("".$ind, 2, '0', STR_PAD_LEFT)]= array( // it's a file that has no corresponding thumb so it's the WEBP for the main file
1695
- 'file' => ShortPixelAPI::MB_basename($found),
1696
- 'width' => $size[0],
1697
- 'height' => $size[1],
1698
- 'mime-type' => $mimeType
1699
- );
1700
- $ind++;
1701
- }
1702
- }
1703
- if($ind > $start) { // at least one thumbnail added, update
1704
- $meta->setThumbs($sizes);
1705
- $itemHandler->updateMeta($meta);
1706
- $URLsAndPATHs = $this->getURLsAndPATHs($itemHandler, NULL, $onlyThumbs);
1707
- }
1708
- }
1709
 
1710
  //find any missing thumbs files and mark them as such
1711
  $miss = $meta->getThumbsMissing();
@@ -1865,6 +1901,7 @@ class WPShortPixel {
1865
  }
1866
 
1867
  //WP/LR Sync plugin integration
 
1868
  public function onWpLrUpdateMedia($imageId, $galleryIdsUnused) {
1869
  $meta = wp_get_attachment_metadata($imageId);
1870
  if(is_array($meta)) {
@@ -1955,7 +1992,7 @@ class WPShortPixel {
1955
  /** Sets file permissions
1956
  * @param string $file FileName
1957
  * @return boolean Success
1958
- * TODO - Move to File Model
1959
  */
1960
  protected function setFilePerms($file) {
1961
  //die(getenv('USERNAME') ? getenv('USERNAME') : getenv('USER'));
@@ -1979,7 +2016,7 @@ class WPShortPixel {
1979
  return true;
1980
  }
1981
 
1982
- //TODO specific to Media Lib., move accordingly
1983
  protected function doRestore($attachmentID, $rawMeta = null) {
1984
  do_action("shortpixel_before_restore_image", $attachmentID);
1985
 
@@ -2094,6 +2131,7 @@ class WPShortPixel {
2094
  && 0 + $crtMeta["ShortPixelImprovement"] < 5 && $this->_settings->under5Percent > 0) {
2095
  $this->_settings->under5Percent = $this->_settings->under5Percent - 1; // - (isset($crtMeta["ShortPixel"]["thumbsOpt"]) ? $crtMeta["ShortPixel"]["thumbsOpt"] : 0);
2096
  }
 
2097
  unset($crtMeta["ShortPixelImprovement"]);
2098
  unset($crtMeta['ShortPixel']);
2099
  unset($crtMeta['ShortPixelPng2Jpg']);
@@ -2142,6 +2180,8 @@ class WPShortPixel {
2142
  return false;
2143
  }
2144
 
 
 
2145
  do_action("shortpixel_after_restore_image", $attachmentID);
2146
  return $rawMeta;
2147
  }
@@ -3098,6 +3138,8 @@ class WPShortPixel {
3098
  RewriteCond %{HTTP_USER_AGENT} "Google Page Speed Insights" [OR]
3099
  # OR does this browser explicitly support webp
3100
  RewriteCond %{HTTP_ACCEPT} image/webp
 
 
3101
  # AND is the request a jpg or png?
3102
  RewriteCond %{REQUEST_URI} ^(.+)\.(?:jpe?g|png)$
3103
  # AND does a .ext.webp image exist?
@@ -3109,6 +3151,7 @@ class WPShortPixel {
3109
  RewriteCond %{HTTP_USER_AGENT} Chrome [OR]
3110
  RewriteCond %{HTTP_USER_AGENT} "Google Page Speed Insights" [OR]
3111
  RewriteCond %{HTTP_ACCEPT} image/webp
 
3112
  # AND is the request a jpg or png? (also grab the basepath %1 to match in the next rule)
3113
  RewriteCond %{REQUEST_URI} ^(.+)\.(?:jpe?g|png)$
3114
  # AND does a .ext.webp image exist?
@@ -3412,7 +3455,7 @@ class WPShortPixel {
3412
  $renderData['invType'] = ShortPixelAPI::getCompressionTypeName($this->getOtherCompressionTypes(ShortPixelAPI::getCompressionTypeCode($renderData['type'])));
3413
  $renderData['thumbsTotal'] = $sizesCount;
3414
  $renderData['thumbsOpt'] = isset($data['ShortPixel']['thumbsOpt']) ? $data['ShortPixel']['thumbsOpt'] : $sizesCount;
3415
- $renderData['thumbsToOptimize'] = count($thumbsToOptimizeList);
3416
  $renderData['thumbsToOptimizeList'] = $thumbsToOptimizeList;
3417
  $renderData['thumbsOptList'] = $thumbsOptList;
3418
  $renderData['excludeSizes'] = isset($data['ShortPixel']['excludeSizes']) ? $data['ShortPixel']['excludeSizes'] : null;
@@ -3486,31 +3529,58 @@ class WPShortPixel {
3486
  }
3487
 
3488
  /**
3489
- * return the thumbnails that remain to optimize and the total count of sizes registered in metdata (and not excluded)
3490
- * @param $data
3491
  * @param $file
3492
- * @return array
3493
  */
3494
- function getThumbsToOptimize($data, $file) {
 
 
 
3495
  $sizesCount = isset($data['sizes']) ? WpShortPixelMediaLbraryAdapter::countSizesNotExcluded($data['sizes']) : 0;
3496
- $basedir = trailingslashit(dirname($file));
3497
  $thumbsOptList = isset($data['ShortPixel']['thumbsOptList']) ? $data['ShortPixel']['thumbsOptList'] : array();
 
 
3498
  if($sizesCount && $this->_settings->processThumbnails) {
3499
 
3500
- $thumbsToOptimizeList = array();
3501
- $found = $this->_settings->optimizeUnlisted ? WpShortPixelMediaLbraryAdapter::findThumbs($file) : array();
3502
 
3503
  $exclude = $this->_settings->excludeSizes;
3504
  $exclude = is_array($exclude) ? $exclude : array();
3505
  foreach($data['sizes'] as $size => $sizeData) {
3506
- unset($found[\array_search($basedir . $sizeData['file'], $found)]);
3507
- if(!in_array($size, $exclude) && !in_array($sizeData['file'], $thumbsOptList)) {
3508
- $thumbsToOptimizeList[] = $sizeData['file'];
 
 
 
 
 
 
 
 
 
 
 
3509
  }
3510
  }
3511
- $found = array_diff($found, $thumbsOptList);
3512
- foreach($found as $item) {
3513
- $thumbsToOptimizeList[] = wp_basename($item);
 
 
 
 
 
 
 
 
 
 
 
3514
  }
3515
  }
3516
  return array($thumbsToOptimizeList, $sizesCount);
@@ -3833,6 +3903,7 @@ class WPShortPixel {
3833
  /** Remove a directory
3834
  * @param string $dirPath Path of directory to remove.
3835
  * @todo Part of folder model.
 
3836
  */
3837
  public static function deleteDir($dirPath) {
3838
  if (substr($dirPath, strlen($dirPath) - 1, 1) != '/') {
24
 
25
  public function __construct() {
26
  $this->timer = time();
27
+
28
 
29
  if (Log::debugIsActive()) {
30
  $this->jsSuffix = '.js'; //use unminified versions for easier debugging
158
 
159
  $this->migrateBackupFolder();
160
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
161
 
162
  // only load backed, or when frontend processing is enabled.
163
  if (is_admin() || $this->_settings->frontBootstrap )
173
  $this->__construct();
174
  }
175
 
 
 
 
 
 
 
176
  // @hook admin menu
177
  // @todo move to plugin class
178
  function registerAdminPage( ) {
1035
  // [BS] Request StartQueryID everytime to query for updated AdvanceBulk status
1036
  $crtStartQueryID = $this->prioQ->getStartBulkId();
1037
  $resultsPostMeta = WpShortPixelMediaLbraryAdapter::getPostMetaSlice($crtStartQueryID, $endQueryID, $maxResults);
1038
+ // @todo Implement new Slicer.
1039
+ // $resultsPostMeta = WpShortPixelMediaLbraryAdapter::getPostsJoinLessReverse($crtStartQueryID, $endQueryID, $maxResults);
1040
+
1041
  if ( empty($resultsPostMeta) ) {
1042
  // check for custom work
1043
  $pendingCustomMeta = $this->spMetaDao->getPendingBulkRestore(SHORTPIXEL_MAX_RESULTS_QUERY * 2);
1062
  $item = new ShortPixelMetaFacade($crtStartQueryID);
1063
  $meta = $item->getMeta();//wp_get_attachment_metadata($crtStartQueryID);
1064
 
1065
+ if($meta->getStatus() == ShortPixelMeta::FILE_STATUS_SUCCESS || $meta->getStatus() == ShortPixelMeta::FILE_STATUS_PENDING ) {
1066
+ if($meta->getStatus() == ShortPixelMeta::FILE_STATUS_SUCCESS && $this->prioQ->getBulkType() == ShortPixelQueue::BULK_TYPE_RESTORE) {
1067
  $res = $this->doRestore($crtStartQueryID); //this is restore, the real
1068
+ // after restore, scrub the rests.
1069
+ $item->cleanupMeta($this->prioQ->getBulkType() == ShortPixelQueue::BULK_TYPE_CLEANUP_PENDING);
1070
  } else {
1071
  //this is only meta cleanup, no files are replaced (BACKUP REMAINS IN PLACE TOO)
1072
+
1073
  $item->cleanupMeta($this->prioQ->getBulkType() == ShortPixelQueue::BULK_TYPE_CLEANUP_PENDING);
1074
  $res = true;
1075
  }
1168
  $meta = $item->getMeta();//wp_get_attachment_metadata($crtStartQueryID);
1169
  if($timeoutThreshold > 15) Log::addInfo("GETDB is SO SLOW. Got meta.");
1170
 
1171
+ if($meta->getStatus() != ShortPixelMeta::FILE_STATUS_SUCCESS) {
1172
  $addIt = (strpos($meta->getMessage(), __('Image files are missing.', 'shortpixel-image-optimiser')) === false);
1173
 
1174
  if(!$addIt) {
1195
  }
1196
  }
1197
  elseif( $this->_settings->processThumbnails && $meta->getThumbsOpt() !== null //thumbs were chosen in settings
1198
+ && ( ($meta->getThumbsOpt() == 0 && count($meta->getThumbs()) > 0) //no thumbnails optimized
1199
+ || (is_array($meta->getThumbsOptList())
1200
  && count(array_diff(array_keys(WpShortPixelMediaLbraryAdapter::getSizesNotExcluded($meta->getThumbs(), $this->_settings->excludeSizes)),
1201
+ $meta->getThumbsOptList())))
1202
  || ( $this->_settings->optimizeUnlisted
1203
  && count(array_diff(WpShortPixelMediaLbraryAdapter::findThumbs($meta->getPath()), $meta->getThumbsOptList()))
1204
  )
1205
  )
1206
  ) {
1207
+
1208
+ $changes = $this->addUnlistedThumbs($item); // search for unlisted thumbs, if that is the setting.
1209
  $URLsAndPATHs = $item->getURLsAndPATHs(true, true, $this->_settings->optimizeRetina, $this->_settings->excludeSizes);
1210
+ Log::addDebug('Gathering URLS AND PATHS', array($URLsAndPATHs));
1211
  if(count($URLsAndPATHs["URLs"])) {
1212
  $meta->setThumbsTodo(true);
1213
  $item->updateMeta($meta);//wp_update_attachment_metadata($crtStartQueryID, $meta);
1216
  if(count($itemList) > SHORTPIXEL_PRESEND_ITEMS) break;
1217
  }
1218
  }
1219
+
 
 
 
 
1220
  }
1221
+
1222
  }
1223
  if(!count($idList) && $crtStartQueryID <= $startQueryID) {
1224
  //daca n-am adaugat niciuna pana acum, n-are sens sa mai selectez zona asta de id-uri in bulk-ul asta.
1630
  $result["BulkMsg"] = $this->bulkProgressMessage($deltaBulkPercent, $minutesRemaining);
1631
  }
1632
 
1633
+ /** Check for unlisted thumbsnail settings and checks if this file has unlisted thumbs present.
1634
+ * Will update meta. if any are found.
1635
+ * @param ShortPixelMetaFacade $itemHandler ShortpixelMetaFacade item handler.
1636
+ * @return int Number of additions to the sizes Metadata.
1637
+ */
1638
+ private function addUnlistedThumbs($itemHandler)
1639
+ {
1640
+ // must be media library, setting must be on.
1641
+ if($itemHandler->getType() != ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE
1642
+ || ! $this->_settings->optimizeUnlisted) {
1643
+ return 0;
1644
+ }
1645
+
1646
+ $meta = $itemHandler->getMeta();
1647
+ $thumbs = WpShortPixelMediaLbraryAdapter::findThumbs($meta->getPath());
1648
+
1649
+ $fs = new \ShortPixel\FileSystemController();
1650
+ $mainFile = $fs->getFile($meta->getPath());
1651
+
1652
+ // Find Thumbs returns *full file path*
1653
+ $foundThumbs = WpShortPixelMediaLbraryAdapter::findThumbs($mainFile->getFullPath());
1654
+
1655
+ // no thumbs, then done.
1656
+ if (count($foundThumbs) == 0)
1657
+ return 0;
1658
+
1659
+ //first identify which thumbs are not in the sizes
1660
+ $sizes = $meta->getThumbs();
1661
+ $mimeType = false;
1662
+
1663
+ $allSizes = array();
1664
+ $basepath = $mainFile->getFileDir()->getPath();
1665
+
1666
+ foreach($sizes as $size) {
1667
+ // Thumbs should have filename only. This is shortpixel-meta ! Not metadata!
1668
+ // Provided filename can be unexpected (URL, fullpath), so first do check, get filename, then check the full path
1669
+ $sizeFileCheck = $fs->getFile($size['file']);
1670
+ $sizeFilePath = $basepath . $sizeFileCheck->getFileName();
1671
+ $sizeFile = $fs->getFile($sizeFilePath);
1672
+
1673
+ //get the mime-type from one of the thumbs metas
1674
+ if(isset($size['mime-type'])) { //situation from support case #9351 Ramesh Mehay
1675
+ $mimeType = $size['mime-type'];
1676
+ }
1677
+ Log::addDebug('Add Unlisted, add size' . $sizeFile->getFullPath() );
1678
+ $allSizes[] = $sizeFile;
1679
+ }
1680
+
1681
+ foreach($foundThumbs as $id => $found) {
1682
+ $foundFile = $fs->getFile($found);
1683
 
1684
+
1685
+ foreach($allSizes as $sizeFile) {
1686
+ if ($sizeFile->getExtension() !== $foundFile->getExtension())
1687
+ {
1688
+ continue;
1689
+ }
1690
+
1691
+ if ($sizeFile->getFileName() === $foundFile->getFileName())
1692
+ {
1693
+ $foundThumbs[$id] = false;
1694
+ }
1695
+ }
1696
+ }
1697
+ // add the unfound ones to the sizes array
1698
+ $ind = 1;
1699
+ $counter = 0;
1700
+ // Assumption:: there is no point in adding to this array since findThumbs should find *all* thumbs that are relevant to this image.
1701
+ /*while (isset($sizes[ShortPixelMeta::FOUND_THUMB_PREFIX . str_pad("".$start, 2, '0', STR_PAD_LEFT)]))
1702
+ {
1703
+ $start++;
1704
+ } */
1705
+ // $start = $ind;
1706
+
1707
+ foreach($foundThumbs as $found) {
1708
+ if($found !== false) {
1709
+ Log::addDebug('Adding File to sizes -> ' . $found);
1710
+ $size = getimagesize($found);
1711
+ $sizes[ShortPixelMeta::FOUND_THUMB_PREFIX . str_pad("".$ind, 2, '0', STR_PAD_LEFT)]= array( // it's a file that has no corresponding thumb so it's the WEBP for the main file
1712
+ 'file' => ShortPixelAPI::MB_basename($found),
1713
+ 'width' => $size[0],
1714
+ 'height' => $size[1],
1715
+ 'mime-type' => $mimeType
1716
+ );
1717
+ $ind++;
1718
+ $counter++;
1719
+ }
1720
+ }
1721
+ if($ind > 1) { // at least one thumbnail added, update
1722
+ $meta->setThumbs($sizes);
1723
+ $itemHandler->updateMeta($meta);
1724
+ }
1725
+
1726
+ return $counter;
1727
+ } // addUnlistedThumbs
1728
+
1729
+ private function sendToProcessing($itemHandler, $compressionType = false, $onlyThumbs = false) {
1730
  //conversion of PNG 2 JPG for existing images
1731
  if($itemHandler->getType() == ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE) { //currently only for ML
1732
  $rawMeta = $this->checkConvertMediaPng2Jpg($itemHandler);
1741
 
1742
  $meta = $itemHandler->getMeta();
1743
  //find thumbs that are not listed in the metadata and add them in the sizes array
1744
+ $changes = $this->addUnlistedThumbs($itemHandler);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1745
 
1746
  //find any missing thumbs files and mark them as such
1747
  $miss = $meta->getThumbsMissing();
1901
  }
1902
 
1903
  //WP/LR Sync plugin integration
1904
+ // @todo Move this function to externals.
1905
  public function onWpLrUpdateMedia($imageId, $galleryIdsUnused) {
1906
  $meta = wp_get_attachment_metadata($imageId);
1907
  if(is_array($meta)) {
1992
  /** Sets file permissions
1993
  * @param string $file FileName
1994
  * @return boolean Success
1995
+ * @TODO - Move to File Model
1996
  */
1997
  protected function setFilePerms($file) {
1998
  //die(getenv('USERNAME') ? getenv('USERNAME') : getenv('USER'));
2016
  return true;
2017
  }
2018
 
2019
+ // @TODO specific to Media Lib., move accordingly
2020
  protected function doRestore($attachmentID, $rawMeta = null) {
2021
  do_action("shortpixel_before_restore_image", $attachmentID);
2022
 
2131
  && 0 + $crtMeta["ShortPixelImprovement"] < 5 && $this->_settings->under5Percent > 0) {
2132
  $this->_settings->under5Percent = $this->_settings->under5Percent - 1; // - (isset($crtMeta["ShortPixel"]["thumbsOpt"]) ? $crtMeta["ShortPixel"]["thumbsOpt"] : 0);
2133
  }
2134
+ /** @todo This logic belongs the cleanUpMeta. not DRY */
2135
  unset($crtMeta["ShortPixelImprovement"]);
2136
  unset($crtMeta['ShortPixel']);
2137
  unset($crtMeta['ShortPixelPng2Jpg']);
2180
  return false;
2181
  }
2182
 
2183
+ /** It's being dumped because settings like .webp can be cached */
2184
+ $this->maybeDumpFromProcessedOnServer($itemHandler, $toUnlink);
2185
  do_action("shortpixel_after_restore_image", $attachmentID);
2186
  return $rawMeta;
2187
  }
3138
  RewriteCond %{HTTP_USER_AGENT} "Google Page Speed Insights" [OR]
3139
  # OR does this browser explicitly support webp
3140
  RewriteCond %{HTTP_ACCEPT} image/webp
3141
+ # AND NOT MS EDGE 42/17 - doesnt work.
3142
+ RewriteCond %{HTTP_USER_AGENT} !Edge/17
3143
  # AND is the request a jpg or png?
3144
  RewriteCond %{REQUEST_URI} ^(.+)\.(?:jpe?g|png)$
3145
  # AND does a .ext.webp image exist?
3151
  RewriteCond %{HTTP_USER_AGENT} Chrome [OR]
3152
  RewriteCond %{HTTP_USER_AGENT} "Google Page Speed Insights" [OR]
3153
  RewriteCond %{HTTP_ACCEPT} image/webp
3154
+ RewriteCond %{HTTP_USER_AGENT} !Edge/17
3155
  # AND is the request a jpg or png? (also grab the basepath %1 to match in the next rule)
3156
  RewriteCond %{REQUEST_URI} ^(.+)\.(?:jpe?g|png)$
3157
  # AND does a .ext.webp image exist?
3455
  $renderData['invType'] = ShortPixelAPI::getCompressionTypeName($this->getOtherCompressionTypes(ShortPixelAPI::getCompressionTypeCode($renderData['type'])));
3456
  $renderData['thumbsTotal'] = $sizesCount;
3457
  $renderData['thumbsOpt'] = isset($data['ShortPixel']['thumbsOpt']) ? $data['ShortPixel']['thumbsOpt'] : $sizesCount;
3458
+ $renderData['thumbsToOptimize'] = (is_array($thumbsToOptimizeList)) ? count($thumbsToOptimizeList) : 0;
3459
  $renderData['thumbsToOptimizeList'] = $thumbsToOptimizeList;
3460
  $renderData['thumbsOptList'] = $thumbsOptList;
3461
  $renderData['excludeSizes'] = isset($data['ShortPixel']['excludeSizes']) ? $data['ShortPixel']['excludeSizes'] : null;
3529
  }
3530
 
3531
  /**
3532
+ * return the thumbnails that remain to optimize and the total count of sizes registered in metadata (and not excluded)
3533
+ * @param $data @todo Define what is data
3534
  * @param $file
3535
+ * @return array Array of Thumbs to Optimize - only the filename - , and count of sizes not excluded ...
3536
  */
3537
+ function getThumbsToOptimize($data, $filepath) {
3538
+ $fs = new \ShortPixel\FileSystemController();
3539
+ $mainfile = $fs->getFile($filepath);
3540
+
3541
  $sizesCount = isset($data['sizes']) ? WpShortPixelMediaLbraryAdapter::countSizesNotExcluded($data['sizes']) : 0;
3542
+ $basedir = $mainfile->getFileDir()->getPath();
3543
  $thumbsOptList = isset($data['ShortPixel']['thumbsOptList']) ? $data['ShortPixel']['thumbsOptList'] : array();
3544
+ $thumbsToOptimizeList = array(); // is returned, so should be defined before if.
3545
+
3546
  if($sizesCount && $this->_settings->processThumbnails) {
3547
 
3548
+ // findThumbs returns fullfilepath.
3549
+ $found = $this->_settings->optimizeUnlisted ? WpShortPixelMediaLbraryAdapter::findThumbs($mainfile->getFullPath()) : array();
3550
 
3551
  $exclude = $this->_settings->excludeSizes;
3552
  $exclude = is_array($exclude) ? $exclude : array();
3553
  foreach($data['sizes'] as $size => $sizeData) {
3554
+ unset($found[\array_search($basedir . $sizeData['file'], $found)]); // @todo what is this intended to do?
3555
+
3556
+ // sizeData['file'] is *only* filename *but* can be wrong data, URL due to plugins. So check first, only get filename ( since it is supposed to fail with only a filename path ) and then reload.
3557
+ $sizeFileCheck = $fs->getFile($sizeData['file']);
3558
+ $file = $fs->getFile($basedir . $sizeFileCheck->getFileName());
3559
+
3560
+ if ($file->getExtension() !== $mainfile->getExtension())
3561
+ {
3562
+ continue;
3563
+ }
3564
+
3565
+
3566
+ if(!in_array($size, $exclude) && !in_array($file->getFileName(), $thumbsOptList)) {
3567
+ $thumbsToOptimizeList[] = $file->getFileName();
3568
  }
3569
  }
3570
+ //$found = array_diff($found, $thumbsOptList); // Wrong comparison. Found is full file path, thumbsOptList is not.
3571
+ foreach($found as $path) {
3572
+ $file = $fs->getFile($path);
3573
+
3574
+ // prevent Webp and what not from showing up.
3575
+ if ($file->getExtension() !== $mainfile->getExtension())
3576
+ {
3577
+ continue;
3578
+ }
3579
+ // thumbs can already be in findThumbs.
3580
+ if (! in_array($file->getFileName(), $thumbsToOptimizeList) && ! in_array($file->getFileName(), $thumbsOptList) )
3581
+ {
3582
+ $thumbsToOptimizeList[] = $file->getFileName();
3583
+ }
3584
  }
3585
  }
3586
  return array($thumbsToOptimizeList, $sizesCount);
3903
  /** Remove a directory
3904
  * @param string $dirPath Path of directory to remove.
3905
  * @todo Part of folder model.
3906
+ * @todo Dangerous function to have exposed as public.
3907
  */
3908
  public static function deleteDir($dirPath) {
3909
  if (substr($dirPath, strlen($dirPath) - 1, 1) != '/') {
readme.txt CHANGED
@@ -4,7 +4,7 @@ Tags: compressor, image, compression, optimize, image optimizer, image optimiser
4
  Requires at least: 3.2.0
5
  Tested up to: 5.2
6
  Requires PHP: 5.3
7
- Stable tag: 4.14.3
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
@@ -21,7 +21,7 @@ ShortPixel is an easy to use, lightweight, install-and-forget-about-it <a href="
21
 
22
  Short Pixel uses minimal resources and works well with any shared, cloud, VPS or dedicated web hosting. It can optimize any image you have on your website even the images that aren't listed in Media Library like those in galleries like <a href="https://wordpress.org/plugins/nextgen-gallery/" target="_blank">NextGEN</a>, <a href="https://wordpress.org/plugins/modula-best-grid-gallery/" target="_blank">Modula</a> or added directly via FTP!
23
 
24
- Both lossy and lossless image compression is available for the most common image types (JPG, PNG, GIF and WebP) plus PDF files.
25
  We also offer **glossy** JPEG compression which is a very high quality lossy optimization algorithm. Specially designed for photographers!
26
  Optimized images mean better user experience, better PageSpeed Insights or GTmetrix results, better Google PageRank and more visitors.
27
 
@@ -246,6 +246,14 @@ define('SHORTPIXEL_CUSTOM_THUMB_INFIXES', '-uae'); will handle custom thumbnails
246
 
247
  == Changelog ==
248
 
 
 
 
 
 
 
 
 
249
  == 4.14.3 ==
250
 
251
  Release date: 22nd July 2019
4
  Requires at least: 3.2.0
5
  Tested up to: 5.2
6
  Requires PHP: 5.3
7
+ Stable tag: 4.14.4
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
21
 
22
  Short Pixel uses minimal resources and works well with any shared, cloud, VPS or dedicated web hosting. It can optimize any image you have on your website even the images that aren't listed in Media Library like those in galleries like <a href="https://wordpress.org/plugins/nextgen-gallery/" target="_blank">NextGEN</a>, <a href="https://wordpress.org/plugins/modula-best-grid-gallery/" target="_blank">Modula</a> or added directly via FTP!
23
 
24
+ Both lossy and lossless image compression are available for the most common image types (JPG, PNG, GIF and WebP) plus PDF files.
25
  We also offer **glossy** JPEG compression which is a very high quality lossy optimization algorithm. Specially designed for photographers!
26
  Optimized images mean better user experience, better PageSpeed Insights or GTmetrix results, better Google PageRank and more visitors.
27
 
246
 
247
  == Changelog ==
248
 
249
+ = 4.14.4 =
250
+ Release date: 19th August 2019
251
+ * Check if unlisted thumbnails present for already optimized images (in case the thumbnails were added later) in Media Library list and when doing bulk. This also integrates with the Unicode plugin.
252
+ * If JSON PHP module not present, add a proper error
253
+ * Fixed: bulk error "WordPress database error You have an error in your SQL syntax" on some installs
254
+ * Fixed: Warning: count() Parameter must be an array.
255
+ * Language – 0 new strings added, 0 updated, 0 fuzzied, and 0 obsoleted
256
+
257
  == 4.14.3 ==
258
 
259
  Release date: 22nd July 2019
res/js/jquery.tooltip.min.js CHANGED
@@ -1 +1 @@
1
- (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){k.preventDefault();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;console.log(e.tooltipSourceID);console.log(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);
1
+ !function(t){t.fn.spTooltip=function(o){t.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=t.extend({},t.fn.spTooltip.defaultsSettings,o||{}),i=function(o){o.preventDefault();var i=0,l=0;if(!o)o=window.event;o.pageX||o.pageY?(i=o.pageX,l=o.pageY):(o.clientX||o.clientY)&&(i=o.clientX+document.body.scrollLeft+document.documentElement.scrollLeft,l=o.clientY+document.body.scrollTop+document.documentElement.scrollTop);var n={x:i+e.positionLeft,y:l+e.positionTop,w:t("#"+e.tooltipID).width(),h:t("#"+e.tooltipID).height()},r={x:t(window).scrollLeft(),y:t(window).scrollTop(),w:t(window).width()-20,h:t(window).height()-20};n.y+n.h>r.y+r.h&&n.x+n.w>r.x+r.w?(n.x=n.x-n.w-45,n.y=n.y-n.h-45):n.x+n.w>r.x+r.w?n.x=n.x-(n.x+n.w-(r.x+r.w)+20):n.y+n.h>r.y+r.h&&(n.y=n.y-(n.y+n.h-(r.y+r.h)+20)),t("#"+e.tooltipID).css({left:n.x+"px",top:n.y+"px"})},l=function(){t("#tooltipLoader").remove(),t("#"+e.tooltipID+" #tooltipContent").show(),"6.0"==t.browser.version&&t("#"+e.tooltipID).append('<iframe id="tooltipIE6FixIframe" style="width:'+(t("#"+e.tooltipID).width()+parseFloat(e.borderSize)+parseFloat(e.borderSize)+20)+"px;height:"+(t("#"+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>')},n=function(o){t("#"+e.tooltipID).fadeOut("fast").trigger("unload").remove(),t(o).filter("[title]")&&t(o).attr("title",e.titleAttributeContent)},r=function(t){var o={};return t.replace(/b([^&=]*)=([^&=]*)b/g,function(t,e,i){void 0!==o[e]?o[e]+=","+i:o[e]=i}),o};return this.each(function(o){function p(o){t("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 p=t("#"+e.tooltipID),a=t("#"+e.tooltipID+" #tooltipContent");switch(e.loader&&""!=e.loaderImagePath&&p.append('<div id="tooltipLoader" style="width:'+e.loaderWidth+"px;height:"+e.loaderHeight+'px;"><img src="'+e.loaderImagePath+'" /></div>'),t(this).attr("title")&&(e.titleAttributeContent=t(this).attr("title"),t(this).attr("title","")),t(this).is("input")&&t(this).focus(function(){n(this)}),o.preventDefault(),i(o),p.show(),e.tooltipSourceID=t(this).attr("href")||e.tooltipSourceID,e.tooltipSourceURL=t(this).attr("href")||e.tooltipSourceURL,console.log(e.tooltipSourceID),console.log(e.tooltipSourceURL),e.tooltipSource){case"attribute":a.text(e.titleAttributeContent),l();break;case"inline":a.html(t(e.tooltipSourceID).children()),p.unload(function(){t(e.tooltipSourceID).html(a.children())}),l();break;case"ajax":if("post"==e.tooltipHTTPType){var d,c;-1!==e.tooltipSourceURL.indexOf("?")?(d=e.windowSourceURL.substr(0,e.windowSourceURL.indexOf("?")),c=r(e.tooltipSourceURL)):(d=e.tooltipSourceURL,c={}),a.load(d,c,function(){l()})}else-1==e.tooltipSourceURL.indexOf("?")&&(e.tooltipSourceURL+="?"),a.load(e.tooltipSourceURL+"&random="+(new Date).getTime(),function(){l()})}return!1}function a(t){return n(this),!1}e.cancelClick&&t(this).bind("click",function(){return!1}),t.fn.hoverIntent?t(this).hoverIntent({sensitivity:e.hoverIntent.sensitivity,interval:e.hoverIntent.interval,over:p,timeout:e.hoverIntent.timeout,out:a}):t(this).hover(p,a),e.followMouse&&t(this).bind("mousemove",function(t){return i(t),!1})})}}(jQuery);
res/js/shortpixel.js CHANGED
@@ -30,7 +30,7 @@ var ShortPixel = function() {
30
  if( ShortPixel.MEDIA_ALERT == 'todo' && jQuery('div.media-frame.mode-grid').length > 0) {
31
  //the media table is not in the list mode, alert the user
32
  jQuery('div.media-frame.mode-grid').before('<div id="short-pixel-media-alert" class="notice notice-warning"><p>'
33
- + _spTr.changeMLToListMode.format('<a href="upload.php?mode=list" class="view-list"><span class="screen-reader-text">',' </span>',
34
  '</a><a class="alignright" href="javascript:ShortPixel.dismissMediaAlert();">','</a>')
35
  + '</p></div>');
36
  }
@@ -128,9 +128,9 @@ var ShortPixel = function() {
128
  var niceName = jQuery("#min-" + elm.attr('name')).data('nicename');
129
  if(elm.val() < Math.min(minSize, 1024)) { // @todo is this correct? This will always be < 1024, and give first error
130
  if(minSize > 1024) {
131
- alert( _spTr.pleaseDoNotSetLesser1024.format(niceName) );
132
  } else {
133
- alert( _spTr.pleaseDoNotSetLesserSize.format(niceName, niceName, minSize) );
134
  }
135
  e.preventDefault();
136
  //elm.val(this.defaultValue);
@@ -173,7 +173,7 @@ var ShortPixel = function() {
173
  function setupAdvancedTab() {
174
  jQuery("input.remove-folder-button").click(function(){
175
  var path = jQuery(this).data("value");
176
- var r = confirm(_spTr.areYouSureStopOptimizing.format(path));
177
  if (r == true) {
178
  jQuery("#removeFolder").val(path);
179
  jQuery('#wp_shortpixel_options').submit();
@@ -181,7 +181,7 @@ var ShortPixel = function() {
181
  });
182
  jQuery("input.recheck-folder-button").click(function(){
183
  var path = jQuery(this).data("value");
184
- var r = confirm(_spTr.areYouSureStopOptimizing.format(path));
185
  if (r == true) {
186
  jQuery("#recheckFolder").val(path);
187
  jQuery('#wp_shortpixel_options').submit();
@@ -330,8 +330,8 @@ var ShortPixel = function() {
330
  + (percent > 0 && percent < 5 ? "<br>" : '')
331
  + (percent < 5 ? _spTr.bonusProcessing : '')
332
  + (type.length > 0 ? " ("+type+")" : "")
333
- + (0 + thumbsCount > 0 ? "<br>" + _spTr.plusXthumbsOpt.format(thumbsCount) :"")
334
- + (0 + retinasCount > 0 ? "<br>" + _spTr.plusXretinasOpt.format(retinasCount) :"")
335
  + "</div>";
336
  }
337
 
@@ -1001,7 +1001,7 @@ function checkBulkProcessingCallApi(){
1001
 
1002
  ShortPixel.returnedStatusSearching = 0;
1003
  }
1004
-
1005
 
1006
  switch (data["Status"]) {
1007
  case ShortPixel.STATUS_NO_KEY:
@@ -1378,14 +1378,22 @@ function showStats() {
1378
  }
1379
  }
1380
 
1381
- if (!(typeof String.prototype.format == 'function')) {
1382
- String.prototype.format = function() {
1383
- var s = this,
1384
- i = arguments.length;
1385
 
1386
- while (i--) {
1387
- s = s.replace(new RegExp('\\{' + i + '\\}', 'gm'), arguments[i]);
1388
- }
1389
- return s;
1390
- };
1391
- }
 
 
 
 
 
 
 
 
 
30
  if( ShortPixel.MEDIA_ALERT == 'todo' && jQuery('div.media-frame.mode-grid').length > 0) {
31
  //the media table is not in the list mode, alert the user
32
  jQuery('div.media-frame.mode-grid').before('<div id="short-pixel-media-alert" class="notice notice-warning"><p>'
33
+ + SPstringFormat(_spTr.changeMLToListMode,'<a href="upload.php?mode=list" class="view-list"><span class="screen-reader-text">',' </span>',
34
  '</a><a class="alignright" href="javascript:ShortPixel.dismissMediaAlert();">','</a>')
35
  + '</p></div>');
36
  }
128
  var niceName = jQuery("#min-" + elm.attr('name')).data('nicename');
129
  if(elm.val() < Math.min(minSize, 1024)) { // @todo is this correct? This will always be < 1024, and give first error
130
  if(minSize > 1024) {
131
+ alert( SPstringFormat(_spTr.pleaseDoNotSetLesser1024,niceName) );
132
  } else {
133
+ alert( SPstringFormat(_spTr.pleaseDoNotSetLesserSize, niceName, niceName, minSize) );
134
  }
135
  e.preventDefault();
136
  //elm.val(this.defaultValue);
173
  function setupAdvancedTab() {
174
  jQuery("input.remove-folder-button").click(function(){
175
  var path = jQuery(this).data("value");
176
+ var r = confirm( SPstringFormat(_spTr.areYouSureStopOptimizing, path) );
177
  if (r == true) {
178
  jQuery("#removeFolder").val(path);
179
  jQuery('#wp_shortpixel_options').submit();
181
  });
182
  jQuery("input.recheck-folder-button").click(function(){
183
  var path = jQuery(this).data("value");
184
+ var r = confirm( SPstringFormat(_spTr.areYouSureStopOptimizing, path));
185
  if (r == true) {
186
  jQuery("#recheckFolder").val(path);
187
  jQuery('#wp_shortpixel_options').submit();
330
  + (percent > 0 && percent < 5 ? "<br>" : '')
331
  + (percent < 5 ? _spTr.bonusProcessing : '')
332
  + (type.length > 0 ? " ("+type+")" : "")
333
+ + (0 + thumbsCount > 0 ? "<br>" + SPstringFormat(_spTr.plusXthumbsOpt, thumbsCount) :"")
334
+ + (0 + retinasCount > 0 ? "<br>" + SPstringFormat(_spTr.plusXretinasOpt, retinasCount) :"")
335
  + "</div>";
336
  }
337
 
1001
 
1002
  ShortPixel.returnedStatusSearching = 0;
1003
  }
1004
+
1005
 
1006
  switch (data["Status"]) {
1007
  case ShortPixel.STATUS_NO_KEY:
1378
  }
1379
  }
1380
 
1381
+ // first is string to replace, rest are arguments.
1382
+ function SPstringFormat() {
1383
+ var params = Array.prototype.slice.call(arguments);
 
1384
 
1385
+ if (params.length === 0)
1386
+ return;
1387
+
1388
+ var s = params.shift();
1389
+
1390
+ // skip the first one.
1391
+ for (i=0; i< params.length; i++) {
1392
+ s = s.replace(new RegExp('\\{' + i + '\\}', 'gm'), params[i]);
1393
+ }
1394
+ return s;
1395
+ };
1396
+ /** This doesn't go well with REACT environments */
1397
+ /*if (!(typeof String.prototype.format == 'function')) {
1398
+ String.prototype.format = stringFormat;
1399
+ } */
res/js/shortpixel.min.js CHANGED
@@ -1 +1 @@
1
- function showToolBarAlert(e,r,t){var o=jQuery("li.shortpixel-toolbar-processing");switch(e){case ShortPixel.STATUS_QUOTA_EXCEEDED:if(window.location.href.search("wp-short-pixel-bulk")>0&&0==jQuery(".sp-quota-exceeded-alert").length)return void location.reload();o.addClass("shortpixel-alert"),o.addClass("shortpixel-quota-exceeded"),jQuery("a",o).attr("href","options-general.php?page=wp-shortpixel-settings"),jQuery("a div",o).attr("title","ShortPixel quota exceeded. Click for details.");break;case ShortPixel.STATUS_SKIP:case ShortPixel.STATUS_FAIL:o.addClass("shortpixel-alert shortpixel-processing"),jQuery("a div",o).attr("title",r),void 0!==t&&jQuery("a",o).attr("href","post.php?post="+t+"&action=edit");break;case ShortPixel.STATUS_NO_KEY:o.addClass("shortpixel-alert"),o.addClass("shortpixel-quota-exceeded"),jQuery("a",o).attr("href","options-general.php?page=wp-shortpixel-settings"),jQuery("a div",o).attr("title","Get API Key");break;case ShortPixel.STATUS_SUCCESS:case ShortPixel.STATUS_RETRY:o.addClass("shortpixel-processing"),o.removeClass("shortpixel-alert"),jQuery("a",o).removeAttr("target"),jQuery("a",o).attr("href",jQuery("a img",o).attr("success-url"))}o.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(){"undefined"!=typeof shortPixelQuotaExceeded&&(1==shortPixelQuotaExceeded?showToolBarAlert(ShortPixel.STATUS_QUOTA_EXCEEDED):hideQuotaExceededToolBarAlert())}function checkBulkProgress(){var e=function(e){return r?"/":(r=!0,e)},r=!1,t=window.location.href.toLowerCase().replace(/\/\//g,e);r=!1;var o=ShortPixel.WP_ADMIN_URL.toLowerCase().replace(/\/\//g,e);t.search(o)<0&&(t=ShortPixel.convertPunycode(t),o=ShortPixel.convertPunycode(o)),t.search(o+"upload.php")<0&&t.search(o+"edit.php")<0&&t.search(o+"edit-tags.php")<0&&t.search(o+"post-new.php")<0&&t.search(o+"post.php")<0&&t.search("page=nggallery-manage-gallery")<0&&(0==ShortPixel.FRONT_BOOTSTRAP||0==t.search(o))?hideToolBarAlert():(1==ShortPixel.bulkProcessor&&window.location.href.search("wp-short-pixel-bulk")<0&&void 0!==localStorage.bulkPage&&localStorage.bulkPage>0&&(ShortPixel.bulkProcessor=!1),window.location.href.search("wp-short-pixel-bulk")>=0&&(ShortPixel.bulkProcessor=!0,localStorage.bulkTime=Math.floor(Date.now()/1e3),localStorage.bulkPage=1),1==ShortPixel.bulkProcessor||void 0===localStorage.bulkTime||Math.floor(Date.now()/1e3)-localStorage.bulkTime>90?(ShortPixel.bulkProcessor=!0,localStorage.bulkPage=window.location.href.search("wp-short-pixel-bulk")>=0?1:0,localStorage.bulkTime=Math.floor(Date.now()/1e3),console.log(localStorage.bulkTime),checkBulkProcessingCallApi()):setTimeout(checkBulkProgress,5e3))}function checkBulkProcessingCallApi(){jQuery.ajax({type:"POST",url:ShortPixel.AJAX_URL,data:{action:"shortpixel_image_processing"},success:function(e){if(e.length>0){r=null;try{var r=JSON.parse(e)}catch(e){return void ShortPixel.retry(e.message)}ShortPixel.retries=0;var t=r.ImageID,o=jQuery("div.short-pixel-bulk-page").length>0;switch(r.Status&&r.Status!=ShortPixel.STATUS_SEARCHING&&(ShortPixel.returnedStatusSearching>=2&&jQuery(".bulk-notice-msg.bulk-searching").hide(),ShortPixel.returnedStatusSearching=0),r.Status){case ShortPixel.STATUS_NO_KEY:setCellMessage(t,r.Message,"<a class='button button-smaller button-primary' href=\"https://shortpixel.com/wp-apikey"+ShortPixel.AFFILIATE+'" target="_blank">'+_spTr.getApiKey+"</a>"),showToolBarAlert(ShortPixel.STATUS_NO_KEY);break;case ShortPixel.STATUS_QUOTA_EXCEEDED:setCellMessage(t,r.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),0==r.Stop&&setTimeout(checkBulkProgress,5e3),ShortPixel.otherMediaUpdateActions(t,["quota","view"]);break;case ShortPixel.STATUS_FAIL:setCellMessage(t,r.Message,"<a class='button button-smaller button-primary' href=\"javascript:manualOptimization('"+t+"', false)\">"+_spTr.retry+"</a>"),showToolBarAlert(ShortPixel.STATUS_FAIL,r.Message,t),o&&(ShortPixel.bulkShowError(t,r.Message,r.Filename,r.CustomImageLink),r.BulkPercent&&progressUpdate(r.BulkPercent,r.BulkMsg),ShortPixel.otherMediaUpdateActions(t,["retry","view"])),console.log(r.Message),setTimeout(checkBulkProgress,5e3);break;case ShortPixel.STATUS_EMPTY_QUEUE:console.log(r.Message),clearBulkProcessor(),hideToolBarAlert();var s=jQuery("#bulk-progress");o&&s.length&&"2"!=r.BulkStatus&&(progressUpdate(100,"Bulk finished!"),jQuery("a.bulk-cancel").attr("disabled","disabled"),hideSlider(),setTimeout(function(){window.location.reload()},3e3));break;case ShortPixel.STATUS_SUCCESS:o&&(ShortPixel.bulkHideLengthyMsg(),ShortPixel.bulkHideMaintenanceMsg());var i=r.PercentImprovement;showToolBarAlert(ShortPixel.STATUS_SUCCESS,"");var a=ShortPixel.isCustomImageId(t)?"":ShortPixel.successActions(t,r.Type,r.ThumbsCount,r.ThumbsTotal,r.BackupEnabled,r.Filename);setCellMessage(t,ShortPixel.successMsg(t,i,r.Type,r.ThumbsCount,r.RetinasCount),a),jQuery("#post-"+t).length>0&&jQuery("#post-"+t).find(".filename").text(r.Filename),jQuery(".misc-pub-filename strong").length>0&&jQuery(".misc-pub-filename strong").text(r.Filename),ShortPixel.isCustomImageId(t)&&r.TsOptimized&&r.TsOptimized.length>0&&(console.log(t),jQuery(".date-"+t).text(r.TsOptimized));var l=jQuery(["restore","view","redolossy","redoglossy","redolossless"]).not(["redo"+r.Type]).get();ShortPixel.otherMediaUpdateActions(t,l);new PercentageAnimator("#sp-msg-"+t+" span.percent",i).animate(i),o&&void 0!==r.Thumb&&(r.BulkPercent&&progressUpdate(r.BulkPercent,r.BulkMsg),r.Thumb.length>0&&(sliderUpdate(t,r.Thumb,r.BkThumb,r.PercentImprovement,r.Filename),void 0!==r.AverageCompression&&0+r.AverageCompression>0&&(jQuery("#sp-avg-optimization").html('<input type="text" class="dial" value="'+Math.round(r.AverageCompression)+'"/>'),ShortPixel.percentDial("#sp-avg-optimization .dial",60)))),console.log("Server response: "+e),o&&void 0!==r.BulkPercent&&progressUpdate(r.BulkPercent,r.BulkMsg),setTimeout(checkBulkProgress,5e3);break;case ShortPixel.STATUS_SKIP:1!==r.Silent&&ShortPixel.bulkShowError(t,r.Message,r.Filename,r.CustomImageLink);case ShortPixel.STATUS_ERROR:void 0!==r.Message&&(showToolBarAlert(ShortPixel.STATUS_SKIP,r.Message+" Image ID: "+t),setCellMessage(t,r.Message,"")),ShortPixel.otherMediaUpdateActions(t,["retry","view"]);case ShortPixel.STATUS_RETRY:console.log("Server response: "+e),showToolBarAlert(ShortPixel.STATUS_RETRY,""),o&&void 0!==r.BulkPercent&&progressUpdate(r.BulkPercent,r.BulkMsg),o&&r.Count>3&&ShortPixel.bulkShowLengthyMsg(t,r.Filename,r.CustomImageLink),setTimeout(checkBulkProgress,5e3);break;case ShortPixel.STATUS_SEARCHING:console.log("Server response: "+e),ShortPixel.returnedStatusSearching++,ShortPixel.returnedStatusSearching>=2&&jQuery(".bulk-notice-msg.bulk-searching").show(),setTimeout(checkBulkProgress,2500);break;case ShortPixel.STATUS_MAINTENANCE:ShortPixel.bulkShowMaintenanceMsg("maintenance"),setTimeout(checkBulkProgress,6e4);break;case ShortPixel.STATUS_QUEUE_FULL:ShortPixel.bulkShowMaintenanceMsg("queue-full"),setTimeout(checkBulkProgress,6e4);break;default:ShortPixel.retry("Unknown status "+r.Status+". Retrying...")}}},error:function(e){ShortPixel.retry(e.statusText)}})}function clearBulkProcessor(){ShortPixel.bulkProcessor=!1,localStorage.bulkTime=0,window.location.href.search("wp-short-pixel-bulk")>=0&&(localStorage.bulkPage=0)}function setCellMessage(e,r,t){var o=jQuery("#sp-msg-"+e);o.length>0&&(o.html("<div class='sp-column-actions'>"+t+"</div><div class='sp-column-info'>"+r+"</div>"),o.css("color","")),(o=jQuery("#sp-cust-msg-"+e)).length>0&&o.html("<div class='sp-column-info'>"+r+"</div>")}function manualOptimization(e,r){setCellMessage(e,"<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").removeClass("shortpixel-alert"),jQuery("li.shortpixel-toolbar-processing").addClass("shortpixel-processing");var t={action:"shortpixel_manual_optimization",image_id:e,cleanup:r};jQuery.ajax({type:"GET",url:ShortPixel.AJAX_URL,data:t,success:function(r){var t=JSON.parse(r);t.Status==ShortPixel.STATUS_SUCCESS?setTimeout(checkBulkProgress,2e3):setCellMessage(e,void 0!==t.Message?t.Message:_spTr.thisContentNotProcessable,"")},error:function(r){t.action="shortpixel_check_status",jQuery.ajax({type:"GET",url:ShortPixel.AJAX_URL,data:t,success:function(r){var t=JSON.parse(r);t.Status!==ShortPixel.STATUS_SUCCESS&&setCellMessage(e,void 0!==t.Message?t.Message:_spTr.thisContentNotProcessable,"")}})}})}function reoptimize(e,r){setCellMessage(e,"<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 t={action:"shortpixel_redo",attachment_ID:e,type:r};jQuery.get(ShortPixel.AJAX_URL,t,function(r){(t=JSON.parse(r)).Status==ShortPixel.STATUS_SUCCESS?setTimeout(checkBulkProgress,2e3):($msg=void 0!==t.Message?t.Message:_spTr.thisContentNotProcessable,setCellMessage(e,$msg,""),showToolBarAlert(ShortPixel.STATUS_FAIL,$msg))})}function optimizeThumbs(e){setCellMessage(e,"<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 r={action:"shortpixel_optimize_thumbs",attachment_ID:e};jQuery.get(ShortPixel.AJAX_URL,r,function(t){(r=JSON.parse(t)).Status==ShortPixel.STATUS_SUCCESS?setTimeout(checkBulkProgress,2e3):setCellMessage(e,void 0!==r.Message?r.Message:_spTr.thisContentNotProcessable,"")})}function dismissShortPixelNoticeExceed(e){jQuery("#wp-admin-bar-shortpixel_processing").hide();var r={action:"shortpixel_dismiss_notice",notice_id:"exceed"};jQuery.get(ShortPixel.AJAX_URL,r,function(e){(r=JSON.parse(e)).Status==ShortPixel.STATUS_SUCCESS&&console.log("dismissed")}),e.preventDefault()}function dismissShortPixelNotice(e){jQuery("#short-pixel-notice-"+e).hide();var r={action:"shortpixel_dismiss_notice",notice_id:e};jQuery.get(ShortPixel.AJAX_URL,r,function(e){(r=JSON.parse(e)).Status==ShortPixel.STATUS_SUCCESS&&console.log("dismissed")})}function PercentageAnimator(e,r){this.animationSpeed=10,this.increment=2,this.curPercentage=0,this.targetPercentage=r,this.outputSelector=e,this.animate=function(e){this.targetPercentage=e,setTimeout(PercentageTimer.bind(null,this),this.animationSpeed)}}function PercentageTimer(e){e.curPercentage-e.targetPercentage<-e.increment?e.curPercentage+=e.increment:e.curPercentage-e.targetPercentage>e.increment?e.curPercentage-=e.increment:e.curPercentage=e.targetPercentage,jQuery(e.outputSelector).text(e.curPercentage+"%"),e.curPercentage!=e.targetPercentage&&setTimeout(PercentageTimer.bind(null,e),e.animationSpeed)}function progressUpdate(e,r){var t=jQuery("#bulk-progress");t.length&&(jQuery(".progress-left",t).css("width",e+"%"),jQuery(".progress-img",t).css("left",e+"%"),e>24?(jQuery(".progress-img span",t).html(""),jQuery(".progress-left",t).html(e+"%")):(jQuery(".progress-img span",t).html(e+"%"),jQuery(".progress-left",t).html("")),jQuery(".bulk-estimate").html(r))}function sliderUpdate(e,r,t,o,s){var i=jQuery(".bulk-slider div.bulk-slide:first-child");if(0!==i.length){"empty-slide"!=i.attr("id")&&i.hide(),i.css("z-index",1e3),jQuery(".bulk-img-opt",i).attr("src",""),void 0===t&&(t=""),t.length>0&&jQuery(".bulk-img-orig",i).attr("src","");var a=i.clone();a.attr("id","slide-"+e),jQuery(".bulk-img-opt",a).attr("src",r),t.length>0?(jQuery(".img-original",a).css("display","inline-block"),jQuery(".bulk-img-orig",a).attr("src",t)):jQuery(".img-original",a).css("display","none"),jQuery(".bulk-opt-percent",a).html('<input type="text" class="dial" value="'+o+'"/>'),jQuery(".bulk-slider").append(a),ShortPixel.percentDial("#"+a.attr("id")+" .dial",100),jQuery(".bulk-slider-container span.filename").html("&nbsp;&nbsp;"+s),"empty-slide"==i.attr("id")?(i.remove(),jQuery(".bulk-slider-container").css("display","block")):i.animate({left:i.width()+i.position().left},"slow","swing",function(){i.remove(),a.fadeIn("slow")})}}function hideSlider(){jQuery(".bulk-slider-container").css("display","none")}function showStats(){jQuery(".bulk-stats").length}jQuery(document).ready(function(){ShortPixel.init()});var ShortPixel=function(){function e(e){jQuery(e).is(":checked")?jQuery("#width,#height").removeAttr("disabled"):jQuery("#width,#height").attr("disabled","disabled")}function r(){jQuery("#shortpixel-hs-button-blind").remove(),jQuery("#shortpixel-hs-tools").remove(),jQuery("#hs-beacon").remove(),jQuery("#botbutton").remove(),jQuery("#shortpixel-hs-blind").remove()}return jQuery("#key").keypress(function(e){13==e.which&&jQuery("#valid").val("validate")}),{init:function(){void 0===ShortPixel.API_KEY&&(jQuery("table.wp-list-table.media").length>0&&jQuery('select[name^="action"] option:last-child').before('<option value="short-pixel-bulk">'+_spTr.optimizeWithSP+'</option><option value="short-pixel-bulk-lossy"> → '+_spTr.redoLossy+'</option><option value="short-pixel-bulk-glossy"> → '+_spTr.redoGlossy+'</option><option value="short-pixel-bulk-lossless"> → '+_spTr.redoLossless+'</option><option value="short-pixel-bulk-restore"> → '+_spTr.restoreOriginal+"</option>"),ShortPixel.setOptions(ShortPixelConstants[0]),jQuery("#backup-folder-size").length&&jQuery("#backup-folder-size").html(ShortPixel.getBackupSize()),"todo"==ShortPixel.MEDIA_ALERT&&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(){1==ShortPixel.bulkProcessor&&clearBulkProcessor()}),checkQuotaExceededAlert(),checkBulkProgress())},setOptions:function(e){for(var r in e)ShortPixel[r]=e[r]},isEmailValid:function(e){return/^\w+([\.+-]?\w+)*@\w+([\.-]?\w+)*(\.\w{1,63})+$/.test(e)},updateSignupEmail:function(){var e=jQuery("#pluginemail").val();ShortPixel.isEmailValid(e)&&jQuery("#request_key").removeClass("disabled"),jQuery("#request_key").attr("href",jQuery("#request_key").attr("href").split("?")[0]+"?pluginemail="+e)},enableResize:e,setupGeneralTab:function(){var r=0;void 0!==document.wp_shortpixel_options&&(r=document.wp_shortpixel_options.compressionType);for(var t=0,o=null;t<r.length;t++)r[t].onclick=function(){this!==o&&(o=this),void 0===ShortPixel.setupGeneralTabAlert&&(alert(_spTr.alertOnlyAppliesToNewImages),ShortPixel.setupGeneralTabAlert=1)};ShortPixel.enableResize("#resize"),jQuery("#resize").change(function(){e(this)}),jQuery(".resize-sizes").blur(function(e){var r=jQuery(e.target);if(ShortPixel.resizeSizesAlert!=r.val()){ShortPixel.resizeSizesAlert=r.val();var t=jQuery("#min-"+r.attr("name")).val(),o=jQuery("#min-"+r.attr("name")).data("nicename");r.val()<Math.min(t,1024)?(t>1024?alert(_spTr.pleaseDoNotSetLesser1024.format(o)):alert(_spTr.pleaseDoNotSetLesserSize.format(o,o,t)),e.preventDefault(),r.focus()):this.defaultValue=r.val()}}),jQuery(".shortpixel-confirm").click(function(e){return!!confirm(e.target.getAttribute("data-confirm"))||(e.preventDefault(),!1)}),jQuery('input[name="removeExif"], input[name="png2jpg"]').on("change",function(){ShortPixel.checkExifWarning()}),ShortPixel.checkExifWarning()},apiKeyChanged:function(){jQuery(".wp-shortpixel-options .shortpixel-key-valid").css("display","none"),jQuery(".wp-shortpixel-options button#validate").css("display","inline-block")},setupAdvancedTab:function(){jQuery("input.remove-folder-button").click(function(){var e=jQuery(this).data("value");1==confirm(_spTr.areYouSureStopOptimizing.format(e))&&(jQuery("#removeFolder").val(e),jQuery("#wp_shortpixel_options").submit())}),jQuery("input.recheck-folder-button").click(function(){var e=jQuery(this).data("value");1==confirm(_spTr.areYouSureStopOptimizing.format(e))&&(jQuery("#recheckFolder").val(e),jQuery("#wp_shortpixel_options").submit())})},checkThumbsUpdTotal:function(e){var r=jQuery("#"+(e.checked?"total":"main")+"ToProcess").val();jQuery("div.bulk-play span.total").text(r),jQuery("#displayTotal").text(r)},initSettings:function(){ShortPixel.adjustSettingsTabs(),ShortPixel.setupGeneralTab(),jQuery(window).resize(function(){ShortPixel.adjustSettingsTabs()}),jQuery("article.sp-tabs a.tab-link").click(function(e){var r=jQuery(e.target).data("id");ShortPixel.switchSettingsTab(r)}),jQuery("input[type=radio][name=deliverWebpType]").change(function(){"deliverWebpAltered"==this.value?window.confirm(_spTr.alertDeliverWebPAltered)?0==jQuery("input[type=radio][name=deliverWebpAlteringType]:checked").length&&jQuery("#deliverWebpAlteredWP").prop("checked",!0):jQuery(this).prop("checked",!1):"deliverWebpUnaltered"==this.value&&window.alert(_spTr.alertDeliverWebPUnaltered)})},switchSettingsTab:function(e){var r=e.replace("tab-",""),t="",o=jQuery("section#"+e);jQuery('input[name="display_part"]').val(r);var s=window.location.href.toString();if(s.indexOf("?")>0){var i=s.substring(0,s.indexOf("?"));i+="?"+jQuery.param({page:"wp-shortpixel-settings",part:r}),window.history.replaceState({},document.title,i)}if(o.length>0&&(jQuery("section").removeClass("sel-tab"),jQuery("section .wp-shortpixel-tab-content").fadeOut(50),jQuery(o).addClass("sel-tab"),ShortPixel.adjustSettingsTabs(),jQuery(o).find(".wp-shortpixel-tab-content").fadeIn(50)),void 0!==HS.beacon.suggest){switch(r){case"settings":t=shortpixel_suggestions_settings;break;case"adv-settings":t=shortpixel_suggestions_adv_settings;break;case"cloudflare":case"stats":t=shortpixel_suggestions_cloudflare}HS.beacon.suggest(t)}},adjustSettingsTabs:function(){var e=jQuery("section.sel-tab").height()+90;jQuery(".section-wrapper").css("height",e)},onBulkThumbsCheck:function(e){e.checked?(jQuery("#with-thumbs").css("display","inherit"),jQuery("#without-thumbs").css("display","none")):(jQuery("#without-thumbs").css("display","inherit"),jQuery("#with-thumbs").css("display","none"))},dismissMediaAlert:function(){var e={action:"shortpixel_dismiss_media_alert"};jQuery.get(ShortPixel.AJAX_URL,e,function(r){"success"==(e=JSON.parse(r)).Status&&jQuery("#short-pixel-media-alert").hide()})},closeHelpPane:r,dismissHelpPane:function(){r(),dismissShortPixelNotice("help")},checkQuota:function(){jQuery.get(ShortPixel.AJAX_URL,{action:"shortpixel_check_quota"},function(){console.log("quota refreshed")})},percentDial:function(e,r){jQuery(e).knob({readOnly:!0,width:r,height:r,fgColor:"#1CAECB",format:function(e){return e+"%"}})},successMsg:function(e,r,t,o,s){return(r>0?"<div class='sp-column-info'>"+_spTr.reducedBy+" <strong><span class='percent'>"+r+"%</span></strong> ":"")+(r>0&&r<5?"<br>":"")+(r<5?_spTr.bonusProcessing:"")+(t.length>0?" ("+t+")":"")+(0+o>0?"<br>"+_spTr.plusXthumbsOpt.format(o):"")+(0+s>0?"<br>"+_spTr.plusXretinasOpt.format(s):"")+"</div>"},successActions:function(e,r,t,o,s,i){if(1==s){var a=jQuery(".sp-column-actions-template").clone();if(!a.length)return!1;var l;return l=0==r.length?["lossy","lossless"]:["lossy","glossy","lossless"].filter(function(e){return!(e==r)}),a.html(a.html().replace(/__SP_ID__/g,e)),"pdf"==i.substr(i.lastIndexOf(".")+1).toLowerCase()&&jQuery(".sp-action-compare",a).remove(),0==t&&o>0?a.html(a.html().replace("__SP_THUMBS_TOTAL__",o)):(jQuery(".sp-action-optimize-thumbs",a).remove(),jQuery(".sp-dropbtn",a).removeClass("button-primary")),a.html(a.html().replace(/__SP_FIRST_TYPE__/g,l[0])),a.html(a.html().replace(/__SP_SECOND_TYPE__/g,l[1])),a.html()}return""},otherMediaUpdateActions:function(e,r){if(e=e.substring(2),jQuery(".shortpixel-other-media").length){for(var t=["optimize","retry","restore","redo","quota","view"],o=0,s=t.length;o<s;o++)jQuery("#"+t[o]+"_"+e).css("display","none");for(var o=0,s=r.length;o<s;o++)jQuery("#"+r[o]+"_"+e).css("display","")}},retry:function(e){ShortPixel.retries++,isNaN(ShortPixel.retries)&&(ShortPixel.retries=1),ShortPixel.retries<6?(console.log("Invalid response from server (Error: "+e+"). Retrying pass "+(ShortPixel.retries+1)+"..."),setTimeout(checkBulkProgress,5e3)):(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: "+e+")",""),console.log("Invalid response from server 6 times. Giving up."))},initFolderSelector:function(){jQuery(".select-folder-button").click(function(){jQuery(".sp-folder-picker-shade").fadeIn(100),jQuery(".shortpixel-modal.modal-folder-picker").show();var e=jQuery(".sp-folder-picker");e.parent().css("margin-left",-e.width()/2),e.fileTree({script:ShortPixel.browseContent,multiFolder:!1})}),jQuery(".shortpixel-modal input.select-folder-cancel, .sp-folder-picker-shade").click(function(){jQuery(".sp-folder-picker-shade").fadeOut(100),jQuery(".shortpixel-modal.modal-folder-picker").hide()}),jQuery(".shortpixel-modal input.select-folder").click(function(e){if(r=jQuery("UL.jqueryFileTree LI.directory.selected"),0==jQuery(r).length)var r=jQuery("UL.jqueryFileTree LI.selected").parents(".directory");var t=jQuery(r).children("a").attr("rel");if(void 0!==t)if(t=t.trim()){var o=jQuery("#customFolderBase").val()+t;"/"==o.slice(-1)&&(o=o.slice(0,-1)),jQuery("#addCustomFolder").val(o),jQuery("#addCustomFolderView").val(o),jQuery(".sp-folder-picker-shade").fadeOut(100),jQuery(".shortpixel-modal.modal-folder-picker").css("display","none"),jQuery("#saveAdvAddFolder").removeClass("hidden")}else alert("Please select a folder from the list.")})},browseContent:function(e){e.action="shortpixel_browse_content";var r="";return jQuery.ajax({type:"POST",url:ShortPixel.AJAX_URL,data:e,success:function(e){r=e},async:!1}),r},getBackupSize:function(){var e="";return jQuery.ajax({type:"POST",url:ShortPixel.AJAX_URL,data:{action:"shortpixel_get_backup_size"},success:function(r){e=r},async:!1}),e},newApiKey:function(e){if(!jQuery("#tos").is(":checked"))return e.preventDefault(),jQuery("#tos-robo").fadeIn(400,function(){jQuery("#tos-hand").fadeIn()}),void jQuery("#tos").click(function(){jQuery("#tos-robo").css("display","none"),jQuery("#tos-hand").css("display","none")});if(jQuery("#request_key").addClass("disabled"),jQuery("#pluginemail_spinner").addClass("is-active"),ShortPixel.updateSignupEmail(),ShortPixel.isEmailValid(jQuery("#pluginemail").val())){jQuery("#pluginemail-error").css("display","none");var r={action:"shortpixel_new_api_key",email:jQuery("#pluginemail").val()};jQuery.ajax({type:"POST",async:!1,url:ShortPixel.AJAX_URL,data:r,success:function(r){data=JSON.parse(r),"success"==data.Status?(e.preventDefault(),window.location.reload()):"invalid"==data.Status&&(jQuery("#pluginemail-error").html("<b>"+data.Details+"</b>"),jQuery("#pluginemail-error").css("display",""),jQuery("#pluginemail-info").css("display","none"),e.preventDefault())}}),jQuery("#request_key").removeAttr("onclick")}else jQuery("#pluginemail-error").css("display",""),jQuery("#pluginemail-info").css("display","none"),e.preventDefault();jQuery("#request_key").removeClass("disabled"),jQuery("#pluginemail_spinner").removeClass("is-active")},proposeUpgrade:function(){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"),jQuery.ajax({type:"POST",url:ShortPixel.AJAX_URL,data:{action:"shortpixel_propose_upgrade"},success:function(e){jQuery("#shortPixelProposeUpgrade .sp-modal-body").removeClass("sptw-modal-spinner"),jQuery("#shortPixelProposeUpgrade .sp-modal-body").html(e)}})},closeProposeUpgrade:function(){jQuery("#shortPixelProposeUpgradeShade").css("display","none"),jQuery("#shortPixelProposeUpgrade").addClass("shortpixel-hide"),ShortPixel.toRefresh&&ShortPixel.recheckQuota()},includeUnlisted:function(){jQuery("#short-pixel-notice-unlisted").hide(),jQuery("#optimizeUnlisted").prop("checked",!0);var e={action:"shortpixel_dismiss_notice",notice_id:"unlisted",notice_data:"true"};jQuery.get(ShortPixel.AJAX_URL,e,function(r){(e=JSON.parse(r)).Status==ShortPixel.STATUS_SUCCESS&&console.log("dismissed")})},bulkShowLengthyMsg:function(e,r,t){var o=jQuery(".bulk-notice-msg.bulk-lengthy");if(0!=o.length){var s=jQuery("a",o);s.text(r),t?s.attr("href",t):s.attr("href",s.data("href").replace("__ID__",e)),o.css("display","block")}},bulkHideLengthyMsg:function(){jQuery(".bulk-notice-msg.bulk-lengthy").css("display","none")},bulkShowMaintenanceMsg:function(e){var r=jQuery(".bulk-notice-msg.bulk-"+e);0!=r.length&&r.css("display","block")},bulkHideMaintenanceMsg:function(e){jQuery(".bulk-notice-msg.bulk-"+e).css("display","none")},bulkShowError:function(e,r,t,o){var s=jQuery("#bulk-error-template");if(0!=s.length){var i=s.clone();i.attr("id","bulk-error-"+e),-1==e?(jQuery("span.sp-err-title",i).remove(),i.addClass("bulk-error-fatal")):(jQuery("img",i).remove(),jQuery("#bulk-error-".id).remove()),jQuery("span.sp-err-content",i).html(r);var a=jQuery("a.sp-post-link",i);o?a.attr("href",o):a.attr("href",a.attr("href").replace("__ID__",e)),a.text(t),s.after(i),i.css("display","block")}},confirmBulkAction:function(e,r){return!!confirm(_spTr["confirmBulk"+e])||(r.stopPropagation(),r.preventDefault(),!1)},checkRandomAnswer:function(e){var r=jQuery(e.target).val(),t=jQuery('input[name="random_answer"]').val(),o=jQuery('input[name="random_answer"]').data("target");r==t?(jQuery(o).removeClass("disabled").prop("disabled",!1),jQuery(o).removeAttr("aria-disabled")):jQuery(o).addClass("disabled").prop("disabled",!0)},removeBulkMsg:function(e){jQuery(e).parent().parent().remove()},isCustomImageId:function(e){return"C-"==e.substring(0,2)},recheckQuota:function(){var e=window.location.href.split("#");window.location.href=e[0]+(e[0].indexOf("?")>0?"&":"?")+"checkquota=1"+(void 0===e[1]?"":"#"+e[1])},openImageMenu:function(e){e.preventDefault(),this.menuCloseEvent||(jQuery(window).click(function(e){e.target.matches(".sp-dropbtn")||jQuery(".sp-dropdown.sp-show").removeClass("sp-show")}),this.menuCloseEvent=!0);var r=e.target.parentElement.classList.contains("sp-show");jQuery(".sp-dropdown.sp-show").removeClass("sp-show"),r||e.target.parentElement.classList.add("sp-show")},menuCloseEvent:!1,loadComparer:function(e){this.comparerData.origUrl=!1,!1===this.comparerData.cssLoaded&&(jQuery("<link>").appendTo("head").attr({type:"text/css",rel:"stylesheet",href:this.WP_PLUGIN_URL+"/res/css/twentytwenty.min.css"}),this.comparerData.cssLoaded=2),!1===this.comparerData.jsLoaded&&(jQuery.getScript(this.WP_PLUGIN_URL+"/res/js/jquery.twentytwenty.min.js",function(){ShortPixel.comparerData.jsLoaded=2,ShortPixel.comparerData.origUrl.length>0&&ShortPixel.displayComparerPopup(ShortPixel.comparerData.width,ShortPixel.comparerData.height,ShortPixel.comparerData.origUrl,ShortPixel.comparerData.optUrl)}),this.comparerData.jsLoaded=1),!1===this.comparerData.origUrl&&(jQuery.ajax({type:"POST",url:ShortPixel.AJAX_URL,data:{action:"shortpixel_get_comparer_data",id:e},success:function(e){data=JSON.parse(e),jQuery.extend(ShortPixel.comparerData,data),2==ShortPixel.comparerData.jsLoaded&&ShortPixel.displayComparerPopup(ShortPixel.comparerData.width,ShortPixel.comparerData.height,ShortPixel.comparerData.origUrl,ShortPixel.comparerData.optUrl)}}),this.comparerData.origUrl="")},displayComparerPopup:function(e,r,t,o){var s=e,i=r<150||e<350,a=jQuery(i?"#spUploadCompareSideBySide":"#spUploadCompare"),l=jQuery(".sp-modal-shade");i||jQuery("#spCompareSlider").html('<img class="spUploadCompareOriginal"/><img class="spUploadCompareOptimized"/>'),e=Math.max(350,Math.min(800,e<350?2*(e+25):r<150?e+25:e)),r=Math.max(150,i?s>350?2*(r+45):r+45:r*e/s);var n="-"+Math.round(e/2);jQuery(".sp-modal-body",a).css("width",e),jQuery(".shortpixel-slider",a).css("width",e),a.css("width",e),a.css("marginLeft",n+"px"),jQuery(".sp-modal-body",a).css("height",r),a.show(),l.show(),i||jQuery("#spCompareSlider").twentytwenty({slider_move:"mousemove"}),jQuery(".sp-close-button").on("click",ShortPixel.closeComparerPopup),jQuery(document).on("keyup.sp_modal_active",ShortPixel.closeComparerPopup),jQuery(".sp-modal-shade").on("click",ShortPixel.closeComparerPopup);var u=jQuery(".spUploadCompareOptimized",a);jQuery(".spUploadCompareOriginal",a).attr("src",t),setTimeout(function(){jQuery(window).trigger("resize")},1e3),u.load(function(){jQuery(window).trigger("resize")}),u.attr("src",o)},closeComparerPopup:function(e){jQuery("#spUploadCompareSideBySide").hide(),jQuery("#spUploadCompare").hide(),jQuery(".sp-modal-shade").hide(),jQuery(document).unbind("keyup.sp_modal_active"),jQuery(".sp-modal-shade").off("click"),jQuery(".sp-close-button").off("click")},convertPunycode:function(e){var r=document.createElement("a");return r.href=e,e.indexOf(r.protocol+"//"+r.hostname)<0?r.href:e.replace(r.protocol+"//"+r.hostname,r.protocol+"//"+r.hostname.split(".").map(function(e){return sp_punycode.toASCII(e)}).join("."))},checkExifWarning:function(){!jQuery('input[name="removeExif"]').is(":checked")&&jQuery('input[name="png2jpg"]').is(":checked")?jQuery(".exif_warning").fadeIn():jQuery(".exif_warning").fadeOut()},comparerData:{cssLoaded:!1,jsLoaded:!1,origUrl:!1,optUrl:!1,width:0,height:0},toRefresh:!1,resizeSizesAlert:!1,returnedStatusSearching:0}}();"function"!=typeof String.prototype.format&&(String.prototype.format=function(){for(var e=this,r=arguments.length;r--;)e=e.replace(new RegExp("\\{"+r+"\\}","gm"),arguments[r]);return e});
1
+ function showToolBarAlert(e,r,t){var s=jQuery("li.shortpixel-toolbar-processing");switch(e){case ShortPixel.STATUS_QUOTA_EXCEEDED:if(window.location.href.search("wp-short-pixel-bulk")>0&&0==jQuery(".sp-quota-exceeded-alert").length)return void location.reload();s.addClass("shortpixel-alert"),s.addClass("shortpixel-quota-exceeded"),jQuery("a",s).attr("href","options-general.php?page=wp-shortpixel-settings"),jQuery("a div",s).attr("title","ShortPixel quota exceeded. Click for details.");break;case ShortPixel.STATUS_SKIP:case ShortPixel.STATUS_FAIL:s.addClass("shortpixel-alert shortpixel-processing"),jQuery("a div",s).attr("title",r),void 0!==t&&jQuery("a",s).attr("href","post.php?post="+t+"&action=edit");break;case ShortPixel.STATUS_NO_KEY:s.addClass("shortpixel-alert"),s.addClass("shortpixel-quota-exceeded"),jQuery("a",s).attr("href","options-general.php?page=wp-shortpixel-settings"),jQuery("a div",s).attr("title","Get API Key");break;case ShortPixel.STATUS_SUCCESS:case ShortPixel.STATUS_RETRY:s.addClass("shortpixel-processing"),s.removeClass("shortpixel-alert"),jQuery("a",s).removeAttr("target"),jQuery("a",s).attr("href",jQuery("a img",s).attr("success-url"))}s.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(){"undefined"!=typeof shortPixelQuotaExceeded&&(1==shortPixelQuotaExceeded?showToolBarAlert(ShortPixel.STATUS_QUOTA_EXCEEDED):hideQuotaExceededToolBarAlert())}function checkBulkProgress(){var e=function(e){return r?"/":(r=!0,e)},r=!1,t=window.location.href.toLowerCase().replace(/\/\//g,e);r=!1;var s=ShortPixel.WP_ADMIN_URL.toLowerCase().replace(/\/\//g,e);t.search(s)<0&&(t=ShortPixel.convertPunycode(t),s=ShortPixel.convertPunycode(s)),t.search(s+"upload.php")<0&&t.search(s+"edit.php")<0&&t.search(s+"edit-tags.php")<0&&t.search(s+"post-new.php")<0&&t.search(s+"post.php")<0&&t.search("page=nggallery-manage-gallery")<0&&(0==ShortPixel.FRONT_BOOTSTRAP||0==t.search(s))?hideToolBarAlert():(1==ShortPixel.bulkProcessor&&window.location.href.search("wp-short-pixel-bulk")<0&&void 0!==localStorage.bulkPage&&localStorage.bulkPage>0&&(ShortPixel.bulkProcessor=!1),window.location.href.search("wp-short-pixel-bulk")>=0&&(ShortPixel.bulkProcessor=!0,localStorage.bulkTime=Math.floor(Date.now()/1e3),localStorage.bulkPage=1),1==ShortPixel.bulkProcessor||void 0===localStorage.bulkTime||Math.floor(Date.now()/1e3)-localStorage.bulkTime>90?(ShortPixel.bulkProcessor=!0,localStorage.bulkPage=window.location.href.search("wp-short-pixel-bulk")>=0?1:0,localStorage.bulkTime=Math.floor(Date.now()/1e3),console.log(localStorage.bulkTime),checkBulkProcessingCallApi()):setTimeout(checkBulkProgress,5e3))}function checkBulkProcessingCallApi(){jQuery.ajax({type:"POST",url:ShortPixel.AJAX_URL,data:{action:"shortpixel_image_processing"},success:function(e){if(e.length>0){r=null;try{var r=JSON.parse(e)}catch(e){return void ShortPixel.retry(e.message)}ShortPixel.retries=0;var t=r.ImageID,s=jQuery("div.short-pixel-bulk-page").length>0;switch(r.Status&&r.Status!=ShortPixel.STATUS_SEARCHING&&(ShortPixel.returnedStatusSearching>=2&&jQuery(".bulk-notice-msg.bulk-searching").hide(),ShortPixel.returnedStatusSearching=0),r.Status){case ShortPixel.STATUS_NO_KEY:setCellMessage(t,r.Message,"<a class='button button-smaller button-primary' href=\"https://shortpixel.com/wp-apikey"+ShortPixel.AFFILIATE+'" target="_blank">'+_spTr.getApiKey+"</a>"),showToolBarAlert(ShortPixel.STATUS_NO_KEY);break;case ShortPixel.STATUS_QUOTA_EXCEEDED:setCellMessage(t,r.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),0==r.Stop&&setTimeout(checkBulkProgress,5e3),ShortPixel.otherMediaUpdateActions(t,["quota","view"]);break;case ShortPixel.STATUS_FAIL:setCellMessage(t,r.Message,"<a class='button button-smaller button-primary' href=\"javascript:manualOptimization('"+t+"', false)\">"+_spTr.retry+"</a>"),showToolBarAlert(ShortPixel.STATUS_FAIL,r.Message,t),s&&(ShortPixel.bulkShowError(t,r.Message,r.Filename,r.CustomImageLink),r.BulkPercent&&progressUpdate(r.BulkPercent,r.BulkMsg),ShortPixel.otherMediaUpdateActions(t,["retry","view"])),console.log(r.Message),setTimeout(checkBulkProgress,5e3);break;case ShortPixel.STATUS_EMPTY_QUEUE:console.log(r.Message),clearBulkProcessor(),hideToolBarAlert();var o=jQuery("#bulk-progress");s&&o.length&&"2"!=r.BulkStatus&&(progressUpdate(100,"Bulk finished!"),jQuery("a.bulk-cancel").attr("disabled","disabled"),hideSlider(),setTimeout(function(){window.location.reload()},3e3));break;case ShortPixel.STATUS_SUCCESS:s&&(ShortPixel.bulkHideLengthyMsg(),ShortPixel.bulkHideMaintenanceMsg());var i=r.PercentImprovement;showToolBarAlert(ShortPixel.STATUS_SUCCESS,"");var a=ShortPixel.isCustomImageId(t)?"":ShortPixel.successActions(t,r.Type,r.ThumbsCount,r.ThumbsTotal,r.BackupEnabled,r.Filename);setCellMessage(t,ShortPixel.successMsg(t,i,r.Type,r.ThumbsCount,r.RetinasCount),a),jQuery("#post-"+t).length>0&&jQuery("#post-"+t).find(".filename").text(r.Filename),jQuery(".misc-pub-filename strong").length>0&&jQuery(".misc-pub-filename strong").text(r.Filename),ShortPixel.isCustomImageId(t)&&r.TsOptimized&&r.TsOptimized.length>0&&(console.log(t),jQuery(".date-"+t).text(r.TsOptimized));var l=jQuery(["restore","view","redolossy","redoglossy","redolossless"]).not(["redo"+r.Type]).get();ShortPixel.otherMediaUpdateActions(t,l);new PercentageAnimator("#sp-msg-"+t+" span.percent",i).animate(i),s&&void 0!==r.Thumb&&(r.BulkPercent&&progressUpdate(r.BulkPercent,r.BulkMsg),r.Thumb.length>0&&(sliderUpdate(t,r.Thumb,r.BkThumb,r.PercentImprovement,r.Filename),void 0!==r.AverageCompression&&0+r.AverageCompression>0&&(jQuery("#sp-avg-optimization").html('<input type="text" class="dial" value="'+Math.round(r.AverageCompression)+'"/>'),ShortPixel.percentDial("#sp-avg-optimization .dial",60)))),console.log("Server response: "+e),s&&void 0!==r.BulkPercent&&progressUpdate(r.BulkPercent,r.BulkMsg),setTimeout(checkBulkProgress,5e3);break;case ShortPixel.STATUS_SKIP:1!==r.Silent&&ShortPixel.bulkShowError(t,r.Message,r.Filename,r.CustomImageLink);case ShortPixel.STATUS_ERROR:void 0!==r.Message&&(showToolBarAlert(ShortPixel.STATUS_SKIP,r.Message+" Image ID: "+t),setCellMessage(t,r.Message,"")),ShortPixel.otherMediaUpdateActions(t,["retry","view"]);case ShortPixel.STATUS_RETRY:console.log("Server response: "+e),showToolBarAlert(ShortPixel.STATUS_RETRY,""),s&&void 0!==r.BulkPercent&&progressUpdate(r.BulkPercent,r.BulkMsg),s&&r.Count>3&&ShortPixel.bulkShowLengthyMsg(t,r.Filename,r.CustomImageLink),setTimeout(checkBulkProgress,5e3);break;case ShortPixel.STATUS_SEARCHING:console.log("Server response: "+e),ShortPixel.returnedStatusSearching++,ShortPixel.returnedStatusSearching>=2&&jQuery(".bulk-notice-msg.bulk-searching").show(),setTimeout(checkBulkProgress,2500);break;case ShortPixel.STATUS_MAINTENANCE:ShortPixel.bulkShowMaintenanceMsg("maintenance"),setTimeout(checkBulkProgress,6e4);break;case ShortPixel.STATUS_QUEUE_FULL:ShortPixel.bulkShowMaintenanceMsg("queue-full"),setTimeout(checkBulkProgress,6e4);break;default:ShortPixel.retry("Unknown status "+r.Status+". Retrying...")}}},error:function(e){ShortPixel.retry(e.statusText)}})}function clearBulkProcessor(){ShortPixel.bulkProcessor=!1,localStorage.bulkTime=0,window.location.href.search("wp-short-pixel-bulk")>=0&&(localStorage.bulkPage=0)}function setCellMessage(e,r,t){var s=jQuery("#sp-msg-"+e);s.length>0&&(s.html("<div class='sp-column-actions'>"+t+"</div><div class='sp-column-info'>"+r+"</div>"),s.css("color","")),(s=jQuery("#sp-cust-msg-"+e)).length>0&&s.html("<div class='sp-column-info'>"+r+"</div>")}function manualOptimization(e,r){setCellMessage(e,"<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").removeClass("shortpixel-alert"),jQuery("li.shortpixel-toolbar-processing").addClass("shortpixel-processing");var t={action:"shortpixel_manual_optimization",image_id:e,cleanup:r};jQuery.ajax({type:"GET",url:ShortPixel.AJAX_URL,data:t,success:function(r){var t=JSON.parse(r);t.Status==ShortPixel.STATUS_SUCCESS?setTimeout(checkBulkProgress,2e3):setCellMessage(e,void 0!==t.Message?t.Message:_spTr.thisContentNotProcessable,"")},error:function(r){t.action="shortpixel_check_status",jQuery.ajax({type:"GET",url:ShortPixel.AJAX_URL,data:t,success:function(r){var t=JSON.parse(r);t.Status!==ShortPixel.STATUS_SUCCESS&&setCellMessage(e,void 0!==t.Message?t.Message:_spTr.thisContentNotProcessable,"")}})}})}function reoptimize(e,r){setCellMessage(e,"<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 t={action:"shortpixel_redo",attachment_ID:e,type:r};jQuery.get(ShortPixel.AJAX_URL,t,function(r){(t=JSON.parse(r)).Status==ShortPixel.STATUS_SUCCESS?setTimeout(checkBulkProgress,2e3):($msg=void 0!==t.Message?t.Message:_spTr.thisContentNotProcessable,setCellMessage(e,$msg,""),showToolBarAlert(ShortPixel.STATUS_FAIL,$msg))})}function optimizeThumbs(e){setCellMessage(e,"<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 r={action:"shortpixel_optimize_thumbs",attachment_ID:e};jQuery.get(ShortPixel.AJAX_URL,r,function(t){(r=JSON.parse(t)).Status==ShortPixel.STATUS_SUCCESS?setTimeout(checkBulkProgress,2e3):setCellMessage(e,void 0!==r.Message?r.Message:_spTr.thisContentNotProcessable,"")})}function dismissShortPixelNoticeExceed(e){jQuery("#wp-admin-bar-shortpixel_processing").hide();var r={action:"shortpixel_dismiss_notice",notice_id:"exceed"};jQuery.get(ShortPixel.AJAX_URL,r,function(e){(r=JSON.parse(e)).Status==ShortPixel.STATUS_SUCCESS&&console.log("dismissed")}),e.preventDefault()}function dismissShortPixelNotice(e){jQuery("#short-pixel-notice-"+e).hide();var r={action:"shortpixel_dismiss_notice",notice_id:e};jQuery.get(ShortPixel.AJAX_URL,r,function(e){(r=JSON.parse(e)).Status==ShortPixel.STATUS_SUCCESS&&console.log("dismissed")})}function PercentageAnimator(e,r){this.animationSpeed=10,this.increment=2,this.curPercentage=0,this.targetPercentage=r,this.outputSelector=e,this.animate=function(e){this.targetPercentage=e,setTimeout(PercentageTimer.bind(null,this),this.animationSpeed)}}function PercentageTimer(e){e.curPercentage-e.targetPercentage<-e.increment?e.curPercentage+=e.increment:e.curPercentage-e.targetPercentage>e.increment?e.curPercentage-=e.increment:e.curPercentage=e.targetPercentage,jQuery(e.outputSelector).text(e.curPercentage+"%"),e.curPercentage!=e.targetPercentage&&setTimeout(PercentageTimer.bind(null,e),e.animationSpeed)}function progressUpdate(e,r){var t=jQuery("#bulk-progress");t.length&&(jQuery(".progress-left",t).css("width",e+"%"),jQuery(".progress-img",t).css("left",e+"%"),e>24?(jQuery(".progress-img span",t).html(""),jQuery(".progress-left",t).html(e+"%")):(jQuery(".progress-img span",t).html(e+"%"),jQuery(".progress-left",t).html("")),jQuery(".bulk-estimate").html(r))}function sliderUpdate(e,r,t,s,o){var i=jQuery(".bulk-slider div.bulk-slide:first-child");if(0!==i.length){"empty-slide"!=i.attr("id")&&i.hide(),i.css("z-index",1e3),jQuery(".bulk-img-opt",i).attr("src",""),void 0===t&&(t=""),t.length>0&&jQuery(".bulk-img-orig",i).attr("src","");var a=i.clone();a.attr("id","slide-"+e),jQuery(".bulk-img-opt",a).attr("src",r),t.length>0?(jQuery(".img-original",a).css("display","inline-block"),jQuery(".bulk-img-orig",a).attr("src",t)):jQuery(".img-original",a).css("display","none"),jQuery(".bulk-opt-percent",a).html('<input type="text" class="dial" value="'+s+'"/>'),jQuery(".bulk-slider").append(a),ShortPixel.percentDial("#"+a.attr("id")+" .dial",100),jQuery(".bulk-slider-container span.filename").html("&nbsp;&nbsp;"+o),"empty-slide"==i.attr("id")?(i.remove(),jQuery(".bulk-slider-container").css("display","block")):i.animate({left:i.width()+i.position().left},"slow","swing",function(){i.remove(),a.fadeIn("slow")})}}function hideSlider(){jQuery(".bulk-slider-container").css("display","none")}function showStats(){jQuery(".bulk-stats").length}function SPstringFormat(){var e=Array.prototype.slice.call(arguments);if(0!==e.length){var r=e.shift();for(i=0;i<e.length;i++)r=r.replace(new RegExp("\\{"+i+"\\}","gm"),e[i]);return r}}jQuery(document).ready(function(){ShortPixel.init()});var ShortPixel=function(){function e(e){jQuery(e).is(":checked")?jQuery("#width,#height").removeAttr("disabled"):jQuery("#width,#height").attr("disabled","disabled")}function r(){jQuery("#shortpixel-hs-button-blind").remove(),jQuery("#shortpixel-hs-tools").remove(),jQuery("#hs-beacon").remove(),jQuery("#botbutton").remove(),jQuery("#shortpixel-hs-blind").remove()}return jQuery("#key").keypress(function(e){13==e.which&&jQuery("#valid").val("validate")}),{init:function(){void 0===ShortPixel.API_KEY&&(jQuery("table.wp-list-table.media").length>0&&jQuery('select[name^="action"] option:last-child').before('<option value="short-pixel-bulk">'+_spTr.optimizeWithSP+'</option><option value="short-pixel-bulk-lossy"> → '+_spTr.redoLossy+'</option><option value="short-pixel-bulk-glossy"> → '+_spTr.redoGlossy+'</option><option value="short-pixel-bulk-lossless"> → '+_spTr.redoLossless+'</option><option value="short-pixel-bulk-restore"> → '+_spTr.restoreOriginal+"</option>"),ShortPixel.setOptions(ShortPixelConstants[0]),jQuery("#backup-folder-size").length&&jQuery("#backup-folder-size").html(ShortPixel.getBackupSize()),"todo"==ShortPixel.MEDIA_ALERT&&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>'+SPstringFormat(_spTr.changeMLToListMode,'<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(){1==ShortPixel.bulkProcessor&&clearBulkProcessor()}),checkQuotaExceededAlert(),checkBulkProgress())},setOptions:function(e){for(var r in e)ShortPixel[r]=e[r]},isEmailValid:function(e){return/^\w+([\.+-]?\w+)*@\w+([\.-]?\w+)*(\.\w{1,63})+$/.test(e)},updateSignupEmail:function(){var e=jQuery("#pluginemail").val();ShortPixel.isEmailValid(e)&&jQuery("#request_key").removeClass("disabled"),jQuery("#request_key").attr("href",jQuery("#request_key").attr("href").split("?")[0]+"?pluginemail="+e)},enableResize:e,setupGeneralTab:function(){var r=0;void 0!==document.wp_shortpixel_options&&(r=document.wp_shortpixel_options.compressionType);for(var t=0,s=null;t<r.length;t++)r[t].onclick=function(){this!==s&&(s=this),void 0===ShortPixel.setupGeneralTabAlert&&(alert(_spTr.alertOnlyAppliesToNewImages),ShortPixel.setupGeneralTabAlert=1)};ShortPixel.enableResize("#resize"),jQuery("#resize").change(function(){e(this)}),jQuery(".resize-sizes").blur(function(e){var r=jQuery(e.target);if(ShortPixel.resizeSizesAlert!=r.val()){ShortPixel.resizeSizesAlert=r.val();var t=jQuery("#min-"+r.attr("name")).val(),s=jQuery("#min-"+r.attr("name")).data("nicename");r.val()<Math.min(t,1024)?(t>1024?alert(SPstringFormat(_spTr.pleaseDoNotSetLesser1024,s)):alert(SPstringFormat(_spTr.pleaseDoNotSetLesserSize,s,s,t)),e.preventDefault(),r.focus()):this.defaultValue=r.val()}}),jQuery(".shortpixel-confirm").click(function(e){return!!confirm(e.target.getAttribute("data-confirm"))||(e.preventDefault(),!1)}),jQuery('input[name="removeExif"], input[name="png2jpg"]').on("change",function(){ShortPixel.checkExifWarning()}),ShortPixel.checkExifWarning()},apiKeyChanged:function(){jQuery(".wp-shortpixel-options .shortpixel-key-valid").css("display","none"),jQuery(".wp-shortpixel-options button#validate").css("display","inline-block")},setupAdvancedTab:function(){jQuery("input.remove-folder-button").click(function(){var e=jQuery(this).data("value");1==confirm(SPstringFormat(_spTr.areYouSureStopOptimizing,e))&&(jQuery("#removeFolder").val(e),jQuery("#wp_shortpixel_options").submit())}),jQuery("input.recheck-folder-button").click(function(){var e=jQuery(this).data("value");1==confirm(SPstringFormat(_spTr.areYouSureStopOptimizing,e))&&(jQuery("#recheckFolder").val(e),jQuery("#wp_shortpixel_options").submit())})},checkThumbsUpdTotal:function(e){var r=jQuery("#"+(e.checked?"total":"main")+"ToProcess").val();jQuery("div.bulk-play span.total").text(r),jQuery("#displayTotal").text(r)},initSettings:function(){ShortPixel.adjustSettingsTabs(),ShortPixel.setupGeneralTab(),jQuery(window).resize(function(){ShortPixel.adjustSettingsTabs()}),jQuery("article.sp-tabs a.tab-link").click(function(e){var r=jQuery(e.target).data("id");ShortPixel.switchSettingsTab(r)}),jQuery("input[type=radio][name=deliverWebpType]").change(function(){"deliverWebpAltered"==this.value?window.confirm(_spTr.alertDeliverWebPAltered)?0==jQuery("input[type=radio][name=deliverWebpAlteringType]:checked").length&&jQuery("#deliverWebpAlteredWP").prop("checked",!0):jQuery(this).prop("checked",!1):"deliverWebpUnaltered"==this.value&&window.alert(_spTr.alertDeliverWebPUnaltered)})},switchSettingsTab:function(e){var r=e.replace("tab-",""),t="",s=jQuery("section#"+e);jQuery('input[name="display_part"]').val(r);var o=window.location.href.toString();if(o.indexOf("?")>0){var i=o.substring(0,o.indexOf("?"));i+="?"+jQuery.param({page:"wp-shortpixel-settings",part:r}),window.history.replaceState({},document.title,i)}if(s.length>0&&(jQuery("section").removeClass("sel-tab"),jQuery("section .wp-shortpixel-tab-content").fadeOut(50),jQuery(s).addClass("sel-tab"),ShortPixel.adjustSettingsTabs(),jQuery(s).find(".wp-shortpixel-tab-content").fadeIn(50)),void 0!==HS.beacon.suggest){switch(r){case"settings":t=shortpixel_suggestions_settings;break;case"adv-settings":t=shortpixel_suggestions_adv_settings;break;case"cloudflare":case"stats":t=shortpixel_suggestions_cloudflare}HS.beacon.suggest(t)}},adjustSettingsTabs:function(){var e=jQuery("section.sel-tab").height()+90;jQuery(".section-wrapper").css("height",e)},onBulkThumbsCheck:function(e){e.checked?(jQuery("#with-thumbs").css("display","inherit"),jQuery("#without-thumbs").css("display","none")):(jQuery("#without-thumbs").css("display","inherit"),jQuery("#with-thumbs").css("display","none"))},dismissMediaAlert:function(){var e={action:"shortpixel_dismiss_media_alert"};jQuery.get(ShortPixel.AJAX_URL,e,function(r){"success"==(e=JSON.parse(r)).Status&&jQuery("#short-pixel-media-alert").hide()})},closeHelpPane:r,dismissHelpPane:function(){r(),dismissShortPixelNotice("help")},checkQuota:function(){jQuery.get(ShortPixel.AJAX_URL,{action:"shortpixel_check_quota"},function(){console.log("quota refreshed")})},percentDial:function(e,r){jQuery(e).knob({readOnly:!0,width:r,height:r,fgColor:"#1CAECB",format:function(e){return e+"%"}})},successMsg:function(e,r,t,s,o){return(r>0?"<div class='sp-column-info'>"+_spTr.reducedBy+" <strong><span class='percent'>"+r+"%</span></strong> ":"")+(r>0&&r<5?"<br>":"")+(r<5?_spTr.bonusProcessing:"")+(t.length>0?" ("+t+")":"")+(0+s>0?"<br>"+SPstringFormat(_spTr.plusXthumbsOpt,s):"")+(0+o>0?"<br>"+SPstringFormat(_spTr.plusXretinasOpt,o):"")+"</div>"},successActions:function(e,r,t,s,o,i){if(1==o){var a=jQuery(".sp-column-actions-template").clone();if(!a.length)return!1;var l;return l=0==r.length?["lossy","lossless"]:["lossy","glossy","lossless"].filter(function(e){return!(e==r)}),a.html(a.html().replace(/__SP_ID__/g,e)),"pdf"==i.substr(i.lastIndexOf(".")+1).toLowerCase()&&jQuery(".sp-action-compare",a).remove(),0==t&&s>0?a.html(a.html().replace("__SP_THUMBS_TOTAL__",s)):(jQuery(".sp-action-optimize-thumbs",a).remove(),jQuery(".sp-dropbtn",a).removeClass("button-primary")),a.html(a.html().replace(/__SP_FIRST_TYPE__/g,l[0])),a.html(a.html().replace(/__SP_SECOND_TYPE__/g,l[1])),a.html()}return""},otherMediaUpdateActions:function(e,r){if(e=e.substring(2),jQuery(".shortpixel-other-media").length){for(var t=["optimize","retry","restore","redo","quota","view"],s=0,o=t.length;s<o;s++)jQuery("#"+t[s]+"_"+e).css("display","none");for(var s=0,o=r.length;s<o;s++)jQuery("#"+r[s]+"_"+e).css("display","")}},retry:function(e){ShortPixel.retries++,isNaN(ShortPixel.retries)&&(ShortPixel.retries=1),ShortPixel.retries<6?(console.log("Invalid response from server (Error: "+e+"). Retrying pass "+(ShortPixel.retries+1)+"..."),setTimeout(checkBulkProgress,5e3)):(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: "+e+")",""),console.log("Invalid response from server 6 times. Giving up."))},initFolderSelector:function(){jQuery(".select-folder-button").click(function(){jQuery(".sp-folder-picker-shade").fadeIn(100),jQuery(".shortpixel-modal.modal-folder-picker").show();var e=jQuery(".sp-folder-picker");e.parent().css("margin-left",-e.width()/2),e.fileTree({script:ShortPixel.browseContent,multiFolder:!1})}),jQuery(".shortpixel-modal input.select-folder-cancel, .sp-folder-picker-shade").click(function(){jQuery(".sp-folder-picker-shade").fadeOut(100),jQuery(".shortpixel-modal.modal-folder-picker").hide()}),jQuery(".shortpixel-modal input.select-folder").click(function(e){if(r=jQuery("UL.jqueryFileTree LI.directory.selected"),0==jQuery(r).length)var r=jQuery("UL.jqueryFileTree LI.selected").parents(".directory");var t=jQuery(r).children("a").attr("rel");if(void 0!==t)if(t=t.trim()){var s=jQuery("#customFolderBase").val()+t;"/"==s.slice(-1)&&(s=s.slice(0,-1)),jQuery("#addCustomFolder").val(s),jQuery("#addCustomFolderView").val(s),jQuery(".sp-folder-picker-shade").fadeOut(100),jQuery(".shortpixel-modal.modal-folder-picker").css("display","none"),jQuery("#saveAdvAddFolder").removeClass("hidden")}else alert("Please select a folder from the list.")})},browseContent:function(e){e.action="shortpixel_browse_content";var r="";return jQuery.ajax({type:"POST",url:ShortPixel.AJAX_URL,data:e,success:function(e){r=e},async:!1}),r},getBackupSize:function(){var e="";return jQuery.ajax({type:"POST",url:ShortPixel.AJAX_URL,data:{action:"shortpixel_get_backup_size"},success:function(r){e=r},async:!1}),e},newApiKey:function(e){if(!jQuery("#tos").is(":checked"))return e.preventDefault(),jQuery("#tos-robo").fadeIn(400,function(){jQuery("#tos-hand").fadeIn()}),void jQuery("#tos").click(function(){jQuery("#tos-robo").css("display","none"),jQuery("#tos-hand").css("display","none")});if(jQuery("#request_key").addClass("disabled"),jQuery("#pluginemail_spinner").addClass("is-active"),ShortPixel.updateSignupEmail(),ShortPixel.isEmailValid(jQuery("#pluginemail").val())){jQuery("#pluginemail-error").css("display","none");var r={action:"shortpixel_new_api_key",email:jQuery("#pluginemail").val()};jQuery.ajax({type:"POST",async:!1,url:ShortPixel.AJAX_URL,data:r,success:function(r){data=JSON.parse(r),"success"==data.Status?(e.preventDefault(),window.location.reload()):"invalid"==data.Status&&(jQuery("#pluginemail-error").html("<b>"+data.Details+"</b>"),jQuery("#pluginemail-error").css("display",""),jQuery("#pluginemail-info").css("display","none"),e.preventDefault())}}),jQuery("#request_key").removeAttr("onclick")}else jQuery("#pluginemail-error").css("display",""),jQuery("#pluginemail-info").css("display","none"),e.preventDefault();jQuery("#request_key").removeClass("disabled"),jQuery("#pluginemail_spinner").removeClass("is-active")},proposeUpgrade:function(){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"),jQuery.ajax({type:"POST",url:ShortPixel.AJAX_URL,data:{action:"shortpixel_propose_upgrade"},success:function(e){jQuery("#shortPixelProposeUpgrade .sp-modal-body").removeClass("sptw-modal-spinner"),jQuery("#shortPixelProposeUpgrade .sp-modal-body").html(e)}})},closeProposeUpgrade:function(){jQuery("#shortPixelProposeUpgradeShade").css("display","none"),jQuery("#shortPixelProposeUpgrade").addClass("shortpixel-hide"),ShortPixel.toRefresh&&ShortPixel.recheckQuota()},includeUnlisted:function(){jQuery("#short-pixel-notice-unlisted").hide(),jQuery("#optimizeUnlisted").prop("checked",!0);var e={action:"shortpixel_dismiss_notice",notice_id:"unlisted",notice_data:"true"};jQuery.get(ShortPixel.AJAX_URL,e,function(r){(e=JSON.parse(r)).Status==ShortPixel.STATUS_SUCCESS&&console.log("dismissed")})},bulkShowLengthyMsg:function(e,r,t){var s=jQuery(".bulk-notice-msg.bulk-lengthy");if(0!=s.length){var o=jQuery("a",s);o.text(r),t?o.attr("href",t):o.attr("href",o.data("href").replace("__ID__",e)),s.css("display","block")}},bulkHideLengthyMsg:function(){jQuery(".bulk-notice-msg.bulk-lengthy").css("display","none")},bulkShowMaintenanceMsg:function(e){var r=jQuery(".bulk-notice-msg.bulk-"+e);0!=r.length&&r.css("display","block")},bulkHideMaintenanceMsg:function(e){jQuery(".bulk-notice-msg.bulk-"+e).css("display","none")},bulkShowError:function(e,r,t,s){var o=jQuery("#bulk-error-template");if(0!=o.length){var i=o.clone();i.attr("id","bulk-error-"+e),-1==e?(jQuery("span.sp-err-title",i).remove(),i.addClass("bulk-error-fatal")):(jQuery("img",i).remove(),jQuery("#bulk-error-".id).remove()),jQuery("span.sp-err-content",i).html(r);var a=jQuery("a.sp-post-link",i);s?a.attr("href",s):a.attr("href",a.attr("href").replace("__ID__",e)),a.text(t),o.after(i),i.css("display","block")}},confirmBulkAction:function(e,r){return!!confirm(_spTr["confirmBulk"+e])||(r.stopPropagation(),r.preventDefault(),!1)},checkRandomAnswer:function(e){var r=jQuery(e.target).val(),t=jQuery('input[name="random_answer"]').val(),s=jQuery('input[name="random_answer"]').data("target");r==t?(jQuery(s).removeClass("disabled").prop("disabled",!1),jQuery(s).removeAttr("aria-disabled")):jQuery(s).addClass("disabled").prop("disabled",!0)},removeBulkMsg:function(e){jQuery(e).parent().parent().remove()},isCustomImageId:function(e){return"C-"==e.substring(0,2)},recheckQuota:function(){var e=window.location.href.split("#");window.location.href=e[0]+(e[0].indexOf("?")>0?"&":"?")+"checkquota=1"+(void 0===e[1]?"":"#"+e[1])},openImageMenu:function(e){e.preventDefault(),this.menuCloseEvent||(jQuery(window).click(function(e){e.target.matches(".sp-dropbtn")||jQuery(".sp-dropdown.sp-show").removeClass("sp-show")}),this.menuCloseEvent=!0);var r=e.target.parentElement.classList.contains("sp-show");jQuery(".sp-dropdown.sp-show").removeClass("sp-show"),r||e.target.parentElement.classList.add("sp-show")},menuCloseEvent:!1,loadComparer:function(e){this.comparerData.origUrl=!1,!1===this.comparerData.cssLoaded&&(jQuery("<link>").appendTo("head").attr({type:"text/css",rel:"stylesheet",href:this.WP_PLUGIN_URL+"/res/css/twentytwenty.min.css"}),this.comparerData.cssLoaded=2),!1===this.comparerData.jsLoaded&&(jQuery.getScript(this.WP_PLUGIN_URL+"/res/js/jquery.twentytwenty.min.js",function(){ShortPixel.comparerData.jsLoaded=2,ShortPixel.comparerData.origUrl.length>0&&ShortPixel.displayComparerPopup(ShortPixel.comparerData.width,ShortPixel.comparerData.height,ShortPixel.comparerData.origUrl,ShortPixel.comparerData.optUrl)}),this.comparerData.jsLoaded=1),!1===this.comparerData.origUrl&&(jQuery.ajax({type:"POST",url:ShortPixel.AJAX_URL,data:{action:"shortpixel_get_comparer_data",id:e},success:function(e){data=JSON.parse(e),jQuery.extend(ShortPixel.comparerData,data),2==ShortPixel.comparerData.jsLoaded&&ShortPixel.displayComparerPopup(ShortPixel.comparerData.width,ShortPixel.comparerData.height,ShortPixel.comparerData.origUrl,ShortPixel.comparerData.optUrl)}}),this.comparerData.origUrl="")},displayComparerPopup:function(e,r,t,s){var o=e,i=r<150||e<350,a=jQuery(i?"#spUploadCompareSideBySide":"#spUploadCompare"),l=jQuery(".sp-modal-shade");i||jQuery("#spCompareSlider").html('<img class="spUploadCompareOriginal"/><img class="spUploadCompareOptimized"/>'),e=Math.max(350,Math.min(800,e<350?2*(e+25):r<150?e+25:e)),r=Math.max(150,i?o>350?2*(r+45):r+45:r*e/o);var n="-"+Math.round(e/2);jQuery(".sp-modal-body",a).css("width",e),jQuery(".shortpixel-slider",a).css("width",e),a.css("width",e),a.css("marginLeft",n+"px"),jQuery(".sp-modal-body",a).css("height",r),a.show(),l.show(),i||jQuery("#spCompareSlider").twentytwenty({slider_move:"mousemove"}),jQuery(".sp-close-button").on("click",ShortPixel.closeComparerPopup),jQuery(document).on("keyup.sp_modal_active",ShortPixel.closeComparerPopup),jQuery(".sp-modal-shade").on("click",ShortPixel.closeComparerPopup);var u=jQuery(".spUploadCompareOptimized",a);jQuery(".spUploadCompareOriginal",a).attr("src",t),setTimeout(function(){jQuery(window).trigger("resize")},1e3),u.load(function(){jQuery(window).trigger("resize")}),u.attr("src",s)},closeComparerPopup:function(e){jQuery("#spUploadCompareSideBySide").hide(),jQuery("#spUploadCompare").hide(),jQuery(".sp-modal-shade").hide(),jQuery(document).unbind("keyup.sp_modal_active"),jQuery(".sp-modal-shade").off("click"),jQuery(".sp-close-button").off("click")},convertPunycode:function(e){var r=document.createElement("a");return r.href=e,e.indexOf(r.protocol+"//"+r.hostname)<0?r.href:e.replace(r.protocol+"//"+r.hostname,r.protocol+"//"+r.hostname.split(".").map(function(e){return sp_punycode.toASCII(e)}).join("."))},checkExifWarning:function(){!jQuery('input[name="removeExif"]').is(":checked")&&jQuery('input[name="png2jpg"]').is(":checked")?jQuery(".exif_warning").fadeIn():jQuery(".exif_warning").fadeOut()},comparerData:{cssLoaded:!1,jsLoaded:!1,origUrl:!1,optUrl:!1,width:0,height:0},toRefresh:!1,resizeSizesAlert:!1,returnedStatusSearching:0}}();
shortpixel_api.php CHANGED
@@ -134,7 +134,7 @@ class ShortPixelAPI {
134
  }
135
 
136
  //WpShortPixel::log("ShortPixel API Request Settings: " . json_encode($requestParameters));
137
-
138
  $response = wp_remote_post($this->_apiEndPoint, $this->prepareRequest($requestParameters, $Blocking) );
139
 
140
  //WpShortPixel::log('RESPONSE: ' . json_encode($response));
@@ -454,8 +454,8 @@ class ShortPixelAPI {
454
 
455
  /** Tries to create backup
456
  *
457
- * @param $mainPath
458
- * @param $PATHs
459
  * @return Array Array with Status and optional Message */
460
  public static function backupImage($mainPath, $PATHs) {
461
  /**
@@ -487,7 +487,7 @@ class ShortPixelAPI {
487
  //now that we have original files and where we should back them up we attempt to do just that
488
  if(is_writable(SHORTPIXEL_BACKUP_FOLDER))
489
  {
490
- Log::addDebug('Creating backups from source - destination', array('source' => $source, 'destination' => $destination));
491
  foreach ( $destination as $fileID => $filePATH )
492
  {
493
  if ( !file_exists($filePATH) )
@@ -583,7 +583,7 @@ class ShortPixelAPI {
583
  * @return array status/message
584
  */
585
  private function handleSuccess($APIresponse, $PATHs, $itemHandler, $compressionType) {
586
- Log::addDebug('Shortpixel API : Handling Success!');
587
 
588
  $counter = $savedSpace = $originalSpace = $optimizedSpace /* = $averageCompression */ = 0;
589
  $NoBackup = true;
@@ -649,7 +649,6 @@ class ShortPixelAPI {
649
  $mainPath = $itemHandler->getMeta()->getPath();
650
 
651
  //if backup is enabled - we try to save the images
652
- Log::addDebug('Check setting backup', array($this->_settings->backupImages));
653
  if( $this->_settings->backupImages )
654
  {
655
  $backupStatus = self::backupImage($mainPath, $PATHs);
@@ -721,7 +720,7 @@ class ShortPixelAPI {
721
  }
722
  $writeFailed++;
723
  }
724
- @unlink($tempFilePATH);
725
  }
726
 
727
  $tempWebpFilePATH = $tempFile["WebP"];
134
  }
135
 
136
  //WpShortPixel::log("ShortPixel API Request Settings: " . json_encode($requestParameters));
137
+ Log::addDebug('ShortPixel API Request', array($requestParameters));
138
  $response = wp_remote_post($this->_apiEndPoint, $this->prepareRequest($requestParameters, $Blocking) );
139
 
140
  //WpShortPixel::log('RESPONSE: ' . json_encode($response));
454
 
455
  /** Tries to create backup
456
  *
457
+ * @param $mainPath The path of the main image?
458
+ * @param $PATHs MUST be included. If just one image is for backup, add array($mainPath)
459
  * @return Array Array with Status and optional Message */
460
  public static function backupImage($mainPath, $PATHs) {
461
  /**
487
  //now that we have original files and where we should back them up we attempt to do just that
488
  if(is_writable(SHORTPIXEL_BACKUP_FOLDER))
489
  {
490
+
491
  foreach ( $destination as $fileID => $filePATH )
492
  {
493
  if ( !file_exists($filePATH) )
583
  * @return array status/message
584
  */
585
  private function handleSuccess($APIresponse, $PATHs, $itemHandler, $compressionType) {
586
+ Log::addDebug('Shortpixel API : Handling Success!', array($APIresponse));
587
 
588
  $counter = $savedSpace = $originalSpace = $optimizedSpace /* = $averageCompression */ = 0;
589
  $NoBackup = true;
649
  $mainPath = $itemHandler->getMeta()->getPath();
650
 
651
  //if backup is enabled - we try to save the images
 
652
  if( $this->_settings->backupImages )
653
  {
654
  $backupStatus = self::backupImage($mainPath, $PATHs);
720
  }
721
  $writeFailed++;
722
  }
723
+ @unlink($tempFilePATH); // @todo Unlink is risky due to lack of checks.
724
  }
725
 
726
  $tempWebpFilePATH = $tempFile["WebP"];
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-settings" target="_blank">Settings &gt; ShortPixel</a> page on how to start optimizing your image library and make your website load faster.
6
- * Version: 4.14.3
7
  * Author: ShortPixel
8
  * Author URI: https://shortpixel.com
9
  * Text Domain: shortpixel-image-optimiser
@@ -20,7 +20,7 @@ define('SHORTPIXEL_PLUGIN_DIR', __DIR__);
20
 
21
  //define('SHORTPIXEL_AFFILIATE_CODE', '');
22
 
23
- define('SHORTPIXEL_IMAGE_OPTIMISER_VERSION', "4.14.3");
24
  define('SHORTPIXEL_MAX_TIMEOUT', 10);
25
  define('SHORTPIXEL_VALIDATE_MAX_TIMEOUT', 15);
26
  define('SHORTPIXEL_BACKUP', 'ShortpixelBackups');
@@ -65,10 +65,7 @@ else
65
 
66
  define('SHORTPIXEL_MAX_EXECUTION_TIME2', 2 );
67
  define("SHORTPIXEL_MAX_RESULTS_QUERY", 30);
68
-
69
- /** @todo This is a test in progress var */
70
-
71
- //define("SHORTPIXEL_NOFLOCK", true);
72
 
73
  function shortpixelInit() {
74
  global $shortPixelPluginInstance;
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-settings" target="_blank">Settings &gt; ShortPixel</a> page on how to start optimizing your image library and make your website load faster.
6
+ * Version: 4.14.4
7
  * Author: ShortPixel
8
  * Author URI: https://shortpixel.com
9
  * Text Domain: shortpixel-image-optimiser
20
 
21
  //define('SHORTPIXEL_AFFILIATE_CODE', '');
22
 
23
+ define('SHORTPIXEL_IMAGE_OPTIMISER_VERSION', "4.14.4");
24
  define('SHORTPIXEL_MAX_TIMEOUT', 10);
25
  define('SHORTPIXEL_VALIDATE_MAX_TIMEOUT', 15);
26
  define('SHORTPIXEL_BACKUP', 'ShortpixelBackups');
65
 
66
  define('SHORTPIXEL_MAX_EXECUTION_TIME2', 2 );
67
  define("SHORTPIXEL_MAX_RESULTS_QUERY", 30);
68
+ //define("SHORTPIXEL_NOFLOCK", true); // don't use flock queue, can cause instability.
 
 
 
69
 
70
  function shortpixelInit() {
71
  global $shortPixelPluginInstance;