ShortPixel Image Optimizer - Version 4.4.0

Version Description

  • exclude images based on patterns or image sizes, exclude paths based on patterns
  • avoid using basename as a fallback for non-UTF8 filenames but instead use own code (basename strips first character if it's not ASCII-128 - for example ISO/IEC 8859-2)
  • processing spinning indicator in the admin top bar with CSS to display OK on all admin themes.
Download this release

Release Info

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

Code changes from version 4.3.1 to 4.4.0

class/db/shortpixel-custom-meta-dao.php CHANGED
@@ -2,7 +2,7 @@
2
 
3
  class ShortPixelCustomMetaDao {
4
  const META_VERSION = 1;
5
- private $db;
6
 
7
  private static $fields = array(
8
  ShortPixelMeta::TABLE_SUFFIX => array(
@@ -31,8 +31,9 @@ class ShortPixelCustomMetaDao {
31
  )
32
  );
33
 
34
- public function __construct($db) {
35
  $this->db = $db;
 
36
  }
37
 
38
  public static function getCreateFolderTableSQL($tablePrefix, $charsetCollate) {
@@ -127,7 +128,7 @@ class ShortPixelCustomMetaDao {
127
  $rows = $this->db->query($sql);
128
  $folders = array();
129
  foreach($rows as $row) {
130
- $folders[] = new ShortPixelFolder($row);
131
  }
132
  return $folders;
133
  }
@@ -137,7 +138,7 @@ class ShortPixelCustomMetaDao {
137
  $rows = $this->db->query($sql, array($path));
138
  $folders = array();
139
  foreach($rows as $row) {
140
- return new ShortPixelFolder($row);
141
  }
142
  return false;
143
  }
@@ -201,7 +202,7 @@ class ShortPixelCustomMetaDao {
201
  if($this->getFolder($addedFolder)) {
202
  return __('Folder already added.','shortpixel-image-optimiser');
203
  }
204
- $folder = new ShortPixelFolder(array("path" => $addedFolder));
205
  try {
206
  $folder->setFileCount($folder->countFiles());
207
  } catch(SpFileRightsException $ex) {
2
 
3
  class ShortPixelCustomMetaDao {
4
  const META_VERSION = 1;
5
+ private $db, $excludePatterns;
6
 
7
  private static $fields = array(
8
  ShortPixelMeta::TABLE_SUFFIX => array(
31
  )
32
  );
33
 
34
+ public function __construct($db, $excludePatterns = false) {
35
  $this->db = $db;
36
+ $this->excludePatterns = $excludePatterns;
37
  }
38
 
39
  public static function getCreateFolderTableSQL($tablePrefix, $charsetCollate) {
128
  $rows = $this->db->query($sql);
129
  $folders = array();
130
  foreach($rows as $row) {
131
+ $folders[] = new ShortPixelFolder($row, $this->excludePatterns);
132
  }
133
  return $folders;
134
  }
138
  $rows = $this->db->query($sql, array($path));
139
  $folders = array();
140
  foreach($rows as $row) {
141
+ return new ShortPixelFolder($row, $this->excludePatterns);
142
  }
143
  return false;
144
  }
202
  if($this->getFolder($addedFolder)) {
203
  return __('Folder already added.','shortpixel-image-optimiser');
204
  }
205
+ $folder = new ShortPixelFolder(array("path" => $addedFolder), $this->excludePatterns);
206
  try {
207
  $folder->setFileCount($folder->countFiles());
208
  } catch(SpFileRightsException $ex) {
class/db/shortpixel-meta-facade.php CHANGED
@@ -64,7 +64,9 @@ class ShortPixelMetaFacade {
64
  "backup" => !isset($rawMeta['ShortPixel']['NoBackup']),
65
  "status" => (!isset($rawMeta["ShortPixel"]) ? 0
66
  : (isset($rawMeta["ShortPixelImprovement"]) && is_numeric($rawMeta["ShortPixelImprovement"])
67
- && !($rawMeta['ShortPixelImprovement'] == 0 && isset($rawMeta['ShortPixel']['WaitingProcessing'])) ? 2
 
 
68
  : (isset($rawMeta["ShortPixel"]["WaitingProcessing"]) ? 1
69
  : (isset($rawMeta["ShortPixel"]['ErrCode']) ? $rawMeta["ShortPixel"]['ErrCode'] : -500)))),
70
  "retries" =>(isset($rawMeta["ShortPixel"]["Retries"]) ? $rawMeta["ShortPixel"]["Retries"] : 0),
@@ -192,16 +194,15 @@ class ShortPixelMetaFacade {
192
  }
193
  }
194
 
195
- function incrementRetries($count = 1) {
196
  if($this->type == self::CUSTOM_TYPE) {
197
  $this->meta->setRetries($this->meta->getRetries() + $count);
198
- $this->updateMeta();
199
  } else {
200
  if(!isset($this->rawMeta['ShortPixel'])) {$this->rawMeta['ShortPixel'] = array();}
201
  $this->rawMeta['ShortPixel']['Retries'] = isset($this->rawMeta['ShortPixel']['Retries']) ? $this->rawMeta['ShortPixel']['Retries'] + $count : $count;
202
  $this->meta->setRetries($this->rawMeta['ShortPixel']['Retries']);
203
- wp_update_attachment_metadata($this->ID, $this->rawMeta);
204
  }
 
205
  }
206
 
207
  function setWaitingProcessing($status = true) {
@@ -228,7 +229,7 @@ class ShortPixelMetaFacade {
228
  if($errorCode == ShortPixelAPI::ERR_FILE_NOT_FOUND) {
229
  $this->spMetaDao->delete($this->meta);
230
  } else {
231
- $this->spMetaDao->update($this->meta);
232
  }
233
  } else {
234
  $this->rawMeta['ShortPixelImprovement'] = $this->meta->getMessage();
@@ -301,8 +302,8 @@ class ShortPixelMetaFacade {
301
  $sizes = $meta->getThumbs();
302
 
303
  //it is NOT a PDF file and thumbs are processable
304
- if ( strtolower(substr($path,strrpos($path, ".")+1)) != "pdf"
305
- && ($processThumbnails || $onlyThumbs)
306
  && count($sizes))
307
  {
308
  $uploadDir = wp_upload_dir();
64
  "backup" => !isset($rawMeta['ShortPixel']['NoBackup']),
65
  "status" => (!isset($rawMeta["ShortPixel"]) ? 0
66
  : (isset($rawMeta["ShortPixelImprovement"]) && is_numeric($rawMeta["ShortPixelImprovement"])
67
+ && !( $rawMeta['ShortPixelImprovement'] == 0
68
+ && ( isset($rawMeta['ShortPixel']['WaitingProcessing'])
69
+ || isset($rawMeta['ShortPixel']['date']) && $rawMeta['ShortPixel']['date'] == '1970-01-01')) ? 2
70
  : (isset($rawMeta["ShortPixel"]["WaitingProcessing"]) ? 1
71
  : (isset($rawMeta["ShortPixel"]['ErrCode']) ? $rawMeta["ShortPixel"]['ErrCode'] : -500)))),
72
  "retries" =>(isset($rawMeta["ShortPixel"]["Retries"]) ? $rawMeta["ShortPixel"]["Retries"] : 0),
194
  }
195
  }
196
 
197
+ function incrementRetries($count = 1, $errorCode = -999, $errorMessage = '') {
198
  if($this->type == self::CUSTOM_TYPE) {
199
  $this->meta->setRetries($this->meta->getRetries() + $count);
 
200
  } else {
201
  if(!isset($this->rawMeta['ShortPixel'])) {$this->rawMeta['ShortPixel'] = array();}
202
  $this->rawMeta['ShortPixel']['Retries'] = isset($this->rawMeta['ShortPixel']['Retries']) ? $this->rawMeta['ShortPixel']['Retries'] + $count : $count;
203
  $this->meta->setRetries($this->rawMeta['ShortPixel']['Retries']);
 
204
  }
205
+ $this->setError($errorCode, $errorMessage);
206
  }
207
 
208
  function setWaitingProcessing($status = true) {
229
  if($errorCode == ShortPixelAPI::ERR_FILE_NOT_FOUND) {
230
  $this->spMetaDao->delete($this->meta);
231
  } else {
232
+ $this->updateMeta();
233
  }
234
  } else {
235
  $this->rawMeta['ShortPixelImprovement'] = $this->meta->getMessage();
302
  $sizes = $meta->getThumbs();
303
 
304
  //it is NOT a PDF file and thumbs are processable
305
+ if ( /* strtolower(substr($path,strrpos($path, ".")+1)) != "pdf"
306
+ &&*/ ($processThumbnails || $onlyThumbs)
307
  && count($sizes))
308
  {
309
  $uploadDir = wp_upload_dir();
class/db/wp-shortpixel-media-library-adapter.php CHANGED
@@ -12,6 +12,7 @@ class WpShortPixelMediaLbraryAdapter {
12
  $limit = self::getOptimalChunkSize();
13
  $pointer = 0;
14
  $filesWithErrors = array();
 
15
 
16
  //count all the files, main and thumbs
17
  while ( 1 ) {
@@ -46,7 +47,8 @@ class WpShortPixelMediaLbraryAdapter {
46
  $sizesCount = isset($attachment['sizes']) ? WpShortPixelMediaLbraryAdapter::countNonWebpSizes($attachment['sizes']) : 0;
47
  //processable
48
  $isProcessable = false;
49
- if(isset($attachment['file']) && !isset($filesMap[$attachment['file']]) && WPShortPixel::isProcessablePath($attachment['file'])){
 
50
  $isProcessable = true;
51
  if ( isset($attachment['sizes']) ) {
52
  $totalFiles += $sizesCount;
12
  $limit = self::getOptimalChunkSize();
13
  $pointer = 0;
14
  $filesWithErrors = array();
15
+ $excludePatterns = WPShortPixelSettings::getOpt("excludePatterns");
16
 
17
  //count all the files, main and thumbs
18
  while ( 1 ) {
47
  $sizesCount = isset($attachment['sizes']) ? WpShortPixelMediaLbraryAdapter::countNonWebpSizes($attachment['sizes']) : 0;
48
  //processable
49
  $isProcessable = false;
50
+ if( isset($attachment['file']) && !isset($filesMap[$attachment['file']])
51
+ && WPShortPixel::_isProcessablePath($attachment['file'], array(), $excludePatterns)){
52
  $isProcessable = true;
53
  if ( isset($attachment['sizes']) ) {
54
  $totalFiles += $sizesCount;
class/model/shortpixel-folder.php CHANGED
@@ -11,10 +11,13 @@ class ShortPixelFolder extends ShortPixelEntity{
11
  protected $tsCreated;
12
  protected $tsUpdated;
13
 
 
 
14
  const TABLE_SUFFIX = 'folders';
15
 
16
- public function __construct($data) {
17
  parent::__construct($data);
 
18
  }
19
 
20
  public static function checkFolder($folder, $base) {
@@ -81,7 +84,7 @@ class ShortPixelFolder extends ShortPixelEntity{
81
  if(in_array($t, $ignore)) continue;
82
  if (is_dir($tpath)) {
83
  $size += $this->countFiles($tpath);
84
- } elseif(WPShortPixel::isProcessablePath($tpath)) {
85
  $size++;
86
  }
87
  }
@@ -111,7 +114,7 @@ class ShortPixelFolder extends ShortPixelEntity{
111
  $tpath = trailingslashit($path) . $t;
112
  if (is_dir($tpath)) {
113
  self::getFileListRecursive($tpath, $fileHandle, $onlyNewerThan);
114
- } elseif($add && WPShortPixel::isProcessablePath($tpath)) {
115
  fwrite($fileHandle, $tpath . "\n");
116
  }
117
  }
@@ -132,7 +135,7 @@ class ShortPixelFolder extends ShortPixelEntity{
132
  $tpath = trailingslashit($path) . $t;
133
  if (is_dir($tpath)) {
134
  self::checkFolderContentsRecursive($tpath, $callback);
135
- } elseif( WPShortPixel::isProcessablePath($tpath)
136
  && !(in_array($tpath, $reference) && $reference[$tpath]->compressedSize == filesize($tpath))) {
137
  $changed[] = $tpath;
138
  }
11
  protected $tsCreated;
12
  protected $tsUpdated;
13
 
14
+ protected $excludePatterns;
15
+
16
  const TABLE_SUFFIX = 'folders';
17
 
18
+ public function __construct($data, $excludePatterns = false) {
19
  parent::__construct($data);
20
+ $this->excludePatterns = $excludePatterns;
21
  }
22
 
23
  public static function checkFolder($folder, $base) {
84
  if(in_array($t, $ignore)) continue;
85
  if (is_dir($tpath)) {
86
  $size += $this->countFiles($tpath);
87
+ } elseif(WPShortPixel::_isProcessablePath($tpath, array(), $this->excludePatterns)) {
88
  $size++;
89
  }
90
  }
114
  $tpath = trailingslashit($path) . $t;
115
  if (is_dir($tpath)) {
116
  self::getFileListRecursive($tpath, $fileHandle, $onlyNewerThan);
117
+ } elseif($add && WPShortPixel::_isProcessablePath($tpath, array(), WPShortPixelSettings::getOpt('excludePatterns'))) {
118
  fwrite($fileHandle, $tpath . "\n");
119
  }
120
  }
135
  $tpath = trailingslashit($path) . $t;
136
  if (is_dir($tpath)) {
137
  self::checkFolderContentsRecursive($tpath, $callback);
138
+ } elseif( WPShortPixel::_isProcessablePath($tpath, array(), WPShortPixelSettings::getOpt('excludePatterns'))
139
  && !(in_array($tpath, $reference) && $reference[$tpath]->compressedSize == filesize($tpath))) {
140
  $changed[] = $tpath;
141
  }
class/view/shortpixel_view.php CHANGED
@@ -826,6 +826,13 @@ class ShortPixelView {
826
  $autoMediaLibrary = ($settings->autoMediaLibrary ? 'checked' : '');
827
  $optimizeRetina = ($settings->optimizeRetina ? 'checked' : '');
828
  $optimizePdfs = ($settings->optimizePdfs ? 'checked' : '');
 
 
 
 
 
 
 
829
  ?>
830
  <div class="wp-shortpixel-options">
831
  <?php if(!$this->ctrl->getVerifiedKey()) { ?>
@@ -953,6 +960,25 @@ class ShortPixelView {
953
  <input name="optimizePdfs" type="checkbox" id="optimizePdfs" <?php echo( $optimizePdfs );?>> <?php _e('Automatically optimize PDF documents.','shortpixel-image-optimiser');?>
954
  </td>
955
  </tr>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
956
  <tr>
957
  <th scope="row"><label for="authentication"><?php _e('HTTP AUTH credentials','shortpixel-image-optimiser');?></label></th>
958
  <td>
826
  $autoMediaLibrary = ($settings->autoMediaLibrary ? 'checked' : '');
827
  $optimizeRetina = ($settings->optimizeRetina ? 'checked' : '');
828
  $optimizePdfs = ($settings->optimizePdfs ? 'checked' : '');
829
+ $excludePatterns = "";
830
+ if($settings->excludePatterns) {
831
+ foreach($settings->excludePatterns as $item) {
832
+ $excludePatterns .= $item['type'] . ":" . $item['value'] . ", ";
833
+ }
834
+ $excludePatterns = substr($excludePatterns, 0, -2);
835
+ }
836
  ?>
837
  <div class="wp-shortpixel-options">
838
  <?php if(!$this->ctrl->getVerifiedKey()) { ?>
960
  <input name="optimizePdfs" type="checkbox" id="optimizePdfs" <?php echo( $optimizePdfs );?>> <?php _e('Automatically optimize PDF documents.','shortpixel-image-optimiser');?>
961
  </td>
962
  </tr>
963
+ <tr>
964
+ <th scope="row"><label for="excludePatterns"><?php _e('Exclude patterns','shortpixel-image-optimiser');?></label></th>
965
+ <td>
966
+ <input name="excludePatterns" type="text" id="excludePatterns" value="<?php echo( $excludePatterns );?>" class="regular-text" placeholder="<?php
967
+ _e('file:keepbig, path:/ignore_regex/i, size:1000x2000','shortpixel-image-optimiser');?>">
968
+ <?php _e('Exclude certain images from being optimized, based on patterns.','shortpixel-image-optimiser');?>
969
+ <p class="settings-info">
970
+ <?php _e('Add patterns separated by comma. A pattern consist of a <strong>type:value</strong> pair; the accepted types are '
971
+ . '<strong>"file"</strong>, <strong>"path"</strong> and <strong>"size"</strong>. '
972
+ . 'A file will be excluded if it matches any of the patterns. '
973
+ . '<br>For a <strong>"file"</strong> pattern only the filename will be matched but for a <strong>"path"</strong>, '
974
+ . 'all the path will be matched (useful for excluding certain subdirectories altoghether).'
975
+ . 'For these you can also use regular expressions accepted by preg_match, but without "," or ":". '
976
+ . '<br>For the <strong>"size"</strong> type, '
977
+ . 'which applies only to Media Library images, <strong>the main images (not thumbnails)</strong> that have the size in the specified range will be excluded. '
978
+ . 'The format for the "size" exclude is: <strong>minWidth</strong>-<strong>maxWidth</strong>x<strong>minHeight</strong>-<strong>maxHeight</strong>, for example <strong>size:1000-1100x2000-2200</strong>. You can also specify a precise size, as <strong>1000x2000</strong>.','shortpixel-image-optimiser');?>
979
+ </p>
980
+ </td>
981
+ </tr>
982
  <tr>
983
  <th scope="row"><label for="authentication"><?php _e('HTTP AUTH credentials','shortpixel-image-optimiser');?></label></th>
984
  <td>
class/wp-short-pixel.php CHANGED
@@ -29,7 +29,7 @@ class WPShortPixel {
29
  $this->_settings = new WPShortPixelSettings();
30
  $this->_apiInterface = new ShortPixelAPI($this->_settings);
31
  $this->hasNextGen = ShortPixelNextGenAdapter::hasNextGen();
32
- $this->spMetaDao = new ShortPixelCustomMetaDao(new WpShortPixelDb(), $this->_settings->hasCustomFolders);
33
  $this->prioQ = new ShortPixelQueue($this, $this->_settings);
34
  $this->view = new ShortPixelView($this);
35
 
@@ -146,7 +146,7 @@ class WPShortPixel {
146
  WPShortPixelSettings::debugResetOptions();
147
 
148
  $settings = new WPShortPixelSettings();
149
- $spMetaDao = new ShortPixelCustomMetaDao(new WpShortPixelDb(), $settings->hasCustomFolders);
150
  $spMetaDao->dropTables();
151
  }
152
  WPShortPixelSettings::onActivate();
@@ -331,7 +331,8 @@ class WPShortPixel {
331
  $args = array(
332
  'id' => 'shortpixel_processing',
333
  'title' => '<div id="' . $id . '" title="' . $tooltip . '" ><img src="'
334
- . plugins_url( 'res/img/'.$icon, SHORTPIXEL_PLUGIN_FILE ) . '" success-url="' . $successLink . '"><span class="shp-alert">!</span></div>',
 
335
  'href' => $link,
336
  'meta' => array('target'=> $blank, 'class' => 'shortpixel-toolbar-processing' . $extraClasses)
337
  );
@@ -395,13 +396,18 @@ class WPShortPixel {
395
  //else
396
  //self::log("IMG: Auto-analyzing file ID #{$ID}");
397
 
398
- if( self::isProcessable($ID) == false )
 
 
 
 
399
  {//not a file that we can process
400
  $meta['ShortPixelImprovement'] = __('Optimization N/A','shortpixel-image-optimiser');
401
  return $meta;
402
  }
403
  else
404
  {//the kind of file we can process. goody.
 
405
  $this->prioQ->push($ID);
406
  //that's a hack for watermarking plugins, don't send the image right away to processing, only add it in the queue
407
  include_once( ABSPATH . 'wp-admin/includes/plugin.php' );
@@ -443,7 +449,7 @@ class WPShortPixel {
443
  }
444
  if($folderId == -1) { //if not found, create
445
  $galleryPath = dirname($imageFsPath);
446
- $folder = new ShortPixelFolder(array("path" => $galleryPath));
447
  $folderMsg = $this->spMetaDao->saveFolder($folder);
448
  $folderId = $folder->getId();
449
  //self::log("NG Image Upload: created folder from path $galleryPath : Folder info: " . json_encode($folder));
@@ -575,7 +581,7 @@ class WPShortPixel {
575
 
576
  foreach ( $resultsPostMeta as $itemMetaData ) {
577
  $crtStartQueryID = $itemMetaData->post_id;
578
- if(!in_array($crtStartQueryID, $idList) && self::isProcessable($crtStartQueryID, ($this->_settings->optimizePdfs ? array() : array('pdf')))) {
579
  $item = new ShortPixelMetaFacade($crtStartQueryID);
580
  $meta = $item->getMeta();//wp_get_attachment_metadata($crtStartQueryID);
581
 
@@ -738,8 +744,7 @@ class WPShortPixel {
738
  $firstUrlAndPaths = $URLsAndPATHs;
739
  }
740
  } catch(Exception $e) { // Exception("Post metadata is corrupt (No attachment URL)") or Exception("Image files are missing.")
741
- $meta = $crtItemHandler->setError(ShortPixelAPI::ERR_FILE_NOT_FOUND, $e->getMessage());
742
- $crtItemHandler->incrementRetries();
743
  if(! $this->prioQ->remove($crtItemHandler->getQueuedId()) ){
744
  $this->advanceBulk($crtItemHandler->getId());
745
  $res['searching'] = true;
@@ -869,9 +874,10 @@ class WPShortPixel {
869
  }
870
  else {
871
  if(isset($result['Code'])) {
872
- $itemHandler->setError($result['Code'], $result["Message"] );
 
 
873
  }
874
- $itemHandler->incrementRetries();
875
  }
876
  }
877
  elseif ($result["Status"] == ShortPixelAPI::STATUS_SKIP
@@ -1039,7 +1045,7 @@ class WPShortPixel {
1039
 
1040
  //custom hook
1041
  public function optimizeNowHook($imageId, $manual = false) {
1042
- if(self::isProcessable($imageId)) {
1043
  $this->prioQ->push($imageId);
1044
  $itemHandler = new ShortPixelMetaFacade($imageId);
1045
  $path = get_attached_file($imageId);//get the full file PATH
@@ -1047,7 +1053,7 @@ class WPShortPixel {
1047
  $ret = array("Status" => ShortPixelAPI::STATUS_SKIP, "Message" => $imageId);
1048
  } else {
1049
  try {
1050
- $this->sendToProcessing($itemHandler);
1051
  $ret = array("Status" => ShortPixelAPI::STATUS_SUCCESS, "Message" => "");
1052
  } catch(Exception $e) { // Exception("Post metadata is corrupt (No attachment URL)")
1053
  $itemHandler->getMeta();
@@ -1343,7 +1349,7 @@ class WPShortPixel {
1343
  $file = get_attached_file($ID);
1344
  $meta = wp_get_attachment_metadata($ID);
1345
 
1346
- if(self::isProcessable($ID) != false)
1347
  {
1348
  try {
1349
  $SubDir = ShortPixelMetaFacade::returnSubDir($file, ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE);
@@ -1616,18 +1622,6 @@ class WPShortPixel {
1616
  ));
1617
 
1618
 
1619
- //parse all images and set the right flag that the image has no backup
1620
- /* this is obsolete as the backup exists decision is taken on verfication of the actual backup files
1621
- foreach($attachments as $attachment)
1622
- {
1623
- if(self::isProcessable($attachment->ID) == false) continue;
1624
-
1625
- $meta = wp_get_attachment_metadata($attachment->ID);
1626
- $meta['ShortPixel']['NoBackup'] = true;
1627
- wp_update_attachment_metadata($attachment->ID, $meta);
1628
- }
1629
- */
1630
-
1631
  //delete the actual files on disk
1632
  $this->deleteDir(SP_BACKUP_FOLDER);//call a recursive function to empty files and sub-dirs in backup dir
1633
  }
@@ -1879,6 +1873,21 @@ class WPShortPixel {
1879
  $this->_settings->createWebp = (isset($_POST['createWebp']) ? 1: 0);
1880
  $this->_settings->optimizeRetina = (isset($_POST['optimizeRetina']) ? 1: 0);
1881
  $this->_settings->optimizePdfs = (isset($_POST['optimizePdfs']) ? 1: 0);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1882
  $this->_settings->frontBootstrap = (isset($_POST['frontBootstrap']) ? 1: 0);
1883
  $this->_settings->autoMediaLibrary = (isset($_POST['autoMediaLibrary']) ? 1: 0);
1884
 
@@ -2123,13 +2132,13 @@ class WPShortPixel {
2123
  public function generateCustomColumn( $column_name, $id, $extended = false ) {
2124
  if( 'wp-shortPixel' == $column_name ) {
2125
 
2126
- $file = get_attached_file($id);
2127
- if(!self::isProcessablePath($file)) {
2128
  $renderData['status'] = 'n/a';
2129
  $this->view->renderCustomColumn($id, $renderData, $extended);
2130
  return;
2131
  }
2132
-
 
2133
  $data = wp_get_attachment_metadata($id);
2134
  $fileExtension = strtolower(pathinfo($file, PATHINFO_EXTENSION));
2135
  $invalidKey = !$this->_settings->verifiedKey;
@@ -2167,7 +2176,7 @@ class WPShortPixel {
2167
  $renderData['status'] = $fileExtension == "pdf" ? 'pdfOptimized' : 'imgOptimized';
2168
  $renderData['percent'] = $data['ShortPixelImprovement'];
2169
  $renderData['bonus'] = ($data['ShortPixelImprovement'] < 5);
2170
- $renderData['backup'] = $this->getBackupFolderAny(get_attached_file($id), $sizesCount? $data['sizes'] : array());
2171
  $renderData['type'] = isset($data['ShortPixel']['type']) ? $data['ShortPixel']['type'] : '';
2172
  $renderData['invType'] = ShortPixelAPI::getCompressionTypeName($this->getOtherCompressionType(ShortPixelAPI::getCompressionTypeCode($renderData['type'])));
2173
  $renderData['thumbsTotal'] = $sizesCount;
@@ -2194,9 +2203,9 @@ class WPShortPixel {
2194
  }
2195
  $renderData['webpCount'] = $webP;
2196
  }
2197
- elseif($data['ShortPixelImprovement'] == __('Optimization N/A','shortpixel-image-optimiser')) { //We don't optimize this
2198
  $renderData['status'] = 'n/a';
2199
- }
2200
  elseif(isset($meta['ShortPixel']['BulkProcessing'])) { //Scheduled to bulk.
2201
  $renderData['status'] = $quotaExceeded ? 'quotaExceeded' : 'optimizeNow';
2202
  $renderData['message'] = 'Waiting for bulk processing.';
@@ -2220,7 +2229,9 @@ class WPShortPixel {
2220
  elseif(isset($data['ShortPixel']['WaitingProcessing'])) {
2221
  $renderData['status'] = $quotaExceeded ? 'quotaExceeded' : 'retry';
2222
  $renderData['message'] = "<img src=\"" . plugins_url( 'res/img/loading.gif', SHORTPIXEL_PLUGIN_FILE ) . "\" class='sp-loading-small'>&nbsp;" . __("Image waiting to be processed.",'shortpixel-image-optimiser');
2223
- if($id > $this->prioQ->getFlagBulkId() || !$this->prioQ->bulkRunning()) $this->prioQ->push($id); //should be there but just to make sure
 
 
2224
  }
2225
  else { //finally
2226
  $renderData['status'] = $quotaExceeded ? 'quotaExceeded' : 'optimizeNow';
@@ -2340,20 +2351,69 @@ class WPShortPixel {
2340
  return round($bytes, $precision) . ' ' . $units[$pow];
2341
  }
2342
 
2343
- static public function isProcessable($ID, $exclude = array()) {
 
 
 
 
 
 
 
 
 
 
2344
  $path = get_attached_file($ID);//get the full file PATH
2345
- return $path ? self::isProcessablePath($path, $exclude) : false;
 
 
 
 
 
 
 
 
 
 
 
 
2346
  }
2347
 
2348
- static public function isProcessablePath($path, $exclude = array()) {
2349
  $pathParts = pathinfo($path);
2350
  $ext = $pathParts['extension'];
2351
- if( isset($ext) && in_array(strtolower($ext), array_diff(self::$PROCESSABLE_EXTENSIONS, $exclude))) {
 
 
 
 
 
 
 
 
 
 
 
 
 
2352
  return true;
2353
  } else {
2354
  return false;
2355
  }
2356
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2357
 
2358
 
2359
  //return an array with URL(s) and PATH(s) for this file
29
  $this->_settings = new WPShortPixelSettings();
30
  $this->_apiInterface = new ShortPixelAPI($this->_settings);
31
  $this->hasNextGen = ShortPixelNextGenAdapter::hasNextGen();
32
+ $this->spMetaDao = new ShortPixelCustomMetaDao(new WpShortPixelDb(), $this->_settings->excludePatterns);
33
  $this->prioQ = new ShortPixelQueue($this, $this->_settings);
34
  $this->view = new ShortPixelView($this);
35
 
146
  WPShortPixelSettings::debugResetOptions();
147
 
148
  $settings = new WPShortPixelSettings();
149
+ $spMetaDao = new ShortPixelCustomMetaDao(new WpShortPixelDb(), $settings->excludePatterns);
150
  $spMetaDao->dropTables();
151
  }
152
  WPShortPixelSettings::onActivate();
331
  $args = array(
332
  'id' => 'shortpixel_processing',
333
  'title' => '<div id="' . $id . '" title="' . $tooltip . '" ><img src="'
334
+ . plugins_url( 'res/img/'.$icon, SHORTPIXEL_PLUGIN_FILE ) . '" success-url="' . $successLink . '"><span class="shp-alert">!</span>'
335
+ .'<div class="cssload-container"><div class="cssload-speeding-wheel"></div></div></div>',
336
  'href' => $link,
337
  'meta' => array('target'=> $blank, 'class' => 'shortpixel-toolbar-processing' . $extraClasses)
338
  );
396
  //else
397
  //self::log("IMG: Auto-analyzing file ID #{$ID}");
398
 
399
+ if(!$this->_settings->optimizePdfs && 'pdf' === pathinfo(get_attached_file($ID), PATHINFO_EXTENSION)) {
400
+ //pdf is not optimized automatically as per the option, but can be optimized by button. Nothing to do.
401
+ return $meta;
402
+ }
403
+ elseif( self::_isProcessable($ID, array(), $this->_settings->excludePatterns, $meta) == false )
404
  {//not a file that we can process
405
  $meta['ShortPixelImprovement'] = __('Optimization N/A','shortpixel-image-optimiser');
406
  return $meta;
407
  }
408
  else
409
  {//the kind of file we can process. goody.
410
+
411
  $this->prioQ->push($ID);
412
  //that's a hack for watermarking plugins, don't send the image right away to processing, only add it in the queue
413
  include_once( ABSPATH . 'wp-admin/includes/plugin.php' );
449
  }
450
  if($folderId == -1) { //if not found, create
451
  $galleryPath = dirname($imageFsPath);
452
+ $folder = new ShortPixelFolder(array("path" => $galleryPath), $this->_settings->excludePatterns);
453
  $folderMsg = $this->spMetaDao->saveFolder($folder);
454
  $folderId = $folder->getId();
455
  //self::log("NG Image Upload: created folder from path $galleryPath : Folder info: " . json_encode($folder));
581
 
582
  foreach ( $resultsPostMeta as $itemMetaData ) {
583
  $crtStartQueryID = $itemMetaData->post_id;
584
+ if(!in_array($crtStartQueryID, $idList) && $this->isProcessable($crtStartQueryID, ($this->_settings->optimizePdfs ? array() : array('pdf')))) {
585
  $item = new ShortPixelMetaFacade($crtStartQueryID);
586
  $meta = $item->getMeta();//wp_get_attachment_metadata($crtStartQueryID);
587
 
744
  $firstUrlAndPaths = $URLsAndPATHs;
745
  }
746
  } catch(Exception $e) { // Exception("Post metadata is corrupt (No attachment URL)") or Exception("Image files are missing.")
747
+ $crtItemHandler->incrementRetries(1, ShortPixelAPI::ERR_FILE_NOT_FOUND, $e->getMessage());
 
748
  if(! $this->prioQ->remove($crtItemHandler->getQueuedId()) ){
749
  $this->advanceBulk($crtItemHandler->getId());
750
  $res['searching'] = true;
874
  }
875
  else {
876
  if(isset($result['Code'])) {
877
+ $itemHandler->incrementRetries(1, $result['Code'], $result["Message"]);
878
+ } else {
879
+ $itemHandler->incrementRetries(1, -999, "Connection error (" . $result["Message"] . ")" );
880
  }
 
881
  }
882
  }
883
  elseif ($result["Status"] == ShortPixelAPI::STATUS_SKIP
1045
 
1046
  //custom hook
1047
  public function optimizeNowHook($imageId, $manual = false) {
1048
+ if($this->isProcessable($imageId)) {
1049
  $this->prioQ->push($imageId);
1050
  $itemHandler = new ShortPixelMetaFacade($imageId);
1051
  $path = get_attached_file($imageId);//get the full file PATH
1053
  $ret = array("Status" => ShortPixelAPI::STATUS_SKIP, "Message" => $imageId);
1054
  } else {
1055
  try {
1056
+ $this->sendToProcessing($itemHandler, false, $itemHandler->getMeta()->getThumbsTodo());
1057
  $ret = array("Status" => ShortPixelAPI::STATUS_SUCCESS, "Message" => "");
1058
  } catch(Exception $e) { // Exception("Post metadata is corrupt (No attachment URL)")
1059
  $itemHandler->getMeta();
1349
  $file = get_attached_file($ID);
1350
  $meta = wp_get_attachment_metadata($ID);
1351
 
1352
+ if(self::_isProcessable($ID) != false) //we use the static isProcessable to bypass the exclude patterns
1353
  {
1354
  try {
1355
  $SubDir = ShortPixelMetaFacade::returnSubDir($file, ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE);
1622
  ));
1623
 
1624
 
 
 
 
 
 
 
 
 
 
 
 
 
1625
  //delete the actual files on disk
1626
  $this->deleteDir(SP_BACKUP_FOLDER);//call a recursive function to empty files and sub-dirs in backup dir
1627
  }
1873
  $this->_settings->createWebp = (isset($_POST['createWebp']) ? 1: 0);
1874
  $this->_settings->optimizeRetina = (isset($_POST['optimizeRetina']) ? 1: 0);
1875
  $this->_settings->optimizePdfs = (isset($_POST['optimizePdfs']) ? 1: 0);
1876
+ if(isset($_POST['excludePatterns']) && strlen($_POST['excludePatterns'])) {
1877
+ $patterns = array();
1878
+ $items = explode(',', $_POST['excludePatterns']);
1879
+ foreach($items as $pat) {
1880
+ $parts = explode(':', $pat);
1881
+ if(count($parts) == 1) {
1882
+ $patterns[] = array("type" =>"name", "value" => trim($pat));
1883
+ } else {
1884
+ $patterns[] = array("type" =>trim($parts[0]), "value" => trim($parts[1]));
1885
+ }
1886
+ }
1887
+ $this->_settings->excludePatterns = $patterns;
1888
+ } else {
1889
+ $this->_settings->excludePatterns = array();
1890
+ }
1891
  $this->_settings->frontBootstrap = (isset($_POST['frontBootstrap']) ? 1: 0);
1892
  $this->_settings->autoMediaLibrary = (isset($_POST['autoMediaLibrary']) ? 1: 0);
1893
 
2132
  public function generateCustomColumn( $column_name, $id, $extended = false ) {
2133
  if( 'wp-shortPixel' == $column_name ) {
2134
 
2135
+ if(!$this->isProcessable($id)) {
 
2136
  $renderData['status'] = 'n/a';
2137
  $this->view->renderCustomColumn($id, $renderData, $extended);
2138
  return;
2139
  }
2140
+
2141
+ $file = get_attached_file($id);
2142
  $data = wp_get_attachment_metadata($id);
2143
  $fileExtension = strtolower(pathinfo($file, PATHINFO_EXTENSION));
2144
  $invalidKey = !$this->_settings->verifiedKey;
2176
  $renderData['status'] = $fileExtension == "pdf" ? 'pdfOptimized' : 'imgOptimized';
2177
  $renderData['percent'] = $data['ShortPixelImprovement'];
2178
  $renderData['bonus'] = ($data['ShortPixelImprovement'] < 5);
2179
+ $renderData['backup'] = $this->getBackupFolderAny($file, $sizesCount? $data['sizes'] : array());
2180
  $renderData['type'] = isset($data['ShortPixel']['type']) ? $data['ShortPixel']['type'] : '';
2181
  $renderData['invType'] = ShortPixelAPI::getCompressionTypeName($this->getOtherCompressionType(ShortPixelAPI::getCompressionTypeCode($renderData['type'])));
2182
  $renderData['thumbsTotal'] = $sizesCount;
2203
  }
2204
  $renderData['webpCount'] = $webP;
2205
  }
2206
+ /* elseif($data['ShortPixelImprovement'] == __('Optimization N/A','shortpixel-image-optimiser')) { //We don't optimize this
2207
  $renderData['status'] = 'n/a';
2208
+ }*/
2209
  elseif(isset($meta['ShortPixel']['BulkProcessing'])) { //Scheduled to bulk.
2210
  $renderData['status'] = $quotaExceeded ? 'quotaExceeded' : 'optimizeNow';
2211
  $renderData['message'] = 'Waiting for bulk processing.';
2229
  elseif(isset($data['ShortPixel']['WaitingProcessing'])) {
2230
  $renderData['status'] = $quotaExceeded ? 'quotaExceeded' : 'retry';
2231
  $renderData['message'] = "<img src=\"" . plugins_url( 'res/img/loading.gif', SHORTPIXEL_PLUGIN_FILE ) . "\" class='sp-loading-small'>&nbsp;" . __("Image waiting to be processed.",'shortpixel-image-optimiser');
2232
+ if(!$quotaExceeded && ($id > $this->prioQ->getFlagBulkId() || !$this->prioQ->bulkRunning())) {
2233
+ $this->prioQ->push($id); //should be there but just to make sure
2234
+ }
2235
  }
2236
  else { //finally
2237
  $renderData['status'] = $quotaExceeded ? 'quotaExceeded' : 'optimizeNow';
2351
  return round($bytes, $precision) . ' ' . $units[$pow];
2352
  }
2353
 
2354
+ public function isProcessable($ID, $excludeExtensions = array()) {
2355
+ $excludePatterns = $this->_settings->excludePatterns;
2356
+ return self::_isProcessable($ID, $excludeExtensions, $excludePatterns);
2357
+ }
2358
+
2359
+ public function isProcessablePath($path, $excludeExtensions = array()) {
2360
+ $excludePatterns = $this->_settings->excludePatterns;
2361
+ return self::_isProcessablePath($path, $excludeExtensions, $excludePatterns);
2362
+ }
2363
+
2364
+ static public function _isProcessable($ID, $excludeExtensions = array(), $excludePatterns = array(), $meta = false) {
2365
  $path = get_attached_file($ID);//get the full file PATH
2366
+ if(isset($excludePatterns) && is_array($excludePatterns)) {
2367
+ foreach($excludePatterns as $excludePattern) {
2368
+ $type = $excludePattern["type"];
2369
+ if($type == "size") {
2370
+ $meta = $meta? $meta : wp_get_attachment_metadata($ID);
2371
+ if( isset($meta["width"]) && isset($meta["height"])
2372
+ && self::isProcessableSize($meta["width"], $meta["height"], $excludePattern["value"]) === false){
2373
+ return false;
2374
+ }
2375
+ }
2376
+ }
2377
+ }
2378
+ return $path ? self::_isProcessablePath($path, $excludeExtensions, $excludePatterns) : false;
2379
  }
2380
 
2381
+ static public function _isProcessablePath($path, $excludeExtensions = array(), $excludePatterns = array()) {
2382
  $pathParts = pathinfo($path);
2383
  $ext = $pathParts['extension'];
2384
+ if( isset($ext) && in_array(strtolower($ext), array_diff(self::$PROCESSABLE_EXTENSIONS, $excludeExtensions))) {
2385
+ //apply patterns defined by user to exclude some file names or paths
2386
+ if(!$excludePatterns || !is_array($excludePatterns)) { return true; }
2387
+ foreach($excludePatterns as $item) {
2388
+ $type = trim($item["type"]);
2389
+ if(in_array($type, array("name", "path"))) {
2390
+ $pattern = trim($item["value"]);
2391
+ $target = $type == "name" ? ShortPixelAPI::MB_basename($path) : $path;
2392
+ if( $pattern[0] == '/' && preg_match($pattern, $target) //search as regex pattern if starts with a /
2393
+ || $pattern[0] != '/' && strpos($target, $pattern) !== false) { //search as a substring if not
2394
+ return false;
2395
+ }
2396
+ }
2397
+ }
2398
  return true;
2399
  } else {
2400
  return false;
2401
  }
2402
  }
2403
+
2404
+ static public function isProcessableSize($width, $height, $excludePattern) {
2405
+ $ranges = preg_split("/(x|×)/",$excludePattern);
2406
+ $widthBounds = explode("-", $ranges[0]);
2407
+ $heightBounds = isset($ranges[1]) ? explode("-", $ranges[1]) : false;
2408
+ if( $width >= 0 + $widthBounds[0]
2409
+ && (!isset($widthBounds[1]) || isset($widthBounds[1]) && $width <= 0 + $widthBounds[1])
2410
+ && ( $heightBounds === false
2411
+ || ($height >= 0 + $heightBounds[0]
2412
+ && (!isset($heightBounds[1]) || isset($heightBounds[1]) && $height <= 0 + $heightBounds[1])))) {
2413
+ return false;
2414
+ }
2415
+ return true;
2416
+ }
2417
 
2418
 
2419
  //return an array with URL(s) and PATH(s) for this file
class/wp-shortpixel-settings.php CHANGED
@@ -15,76 +15,77 @@ class WPShortPixelSettings {
15
 
16
  private static $_optionsMap = array(
17
  //This one is accessed also directly via get_option
18
- 'frontBootstrap' => 'wp-short-pixel-front-bootstrap', //set to 1 when need the plugin active for logged in user in the front-end
19
- 'lastBackAction' => 'wp-short-pixel-last-back-action', //when less than 10 min. passed from this timestamp, the front-bootstrap is ineffective.
20
 
21
  //optimization options
22
- 'apiKey' => 'wp-short-pixel-apiKey',
23
- 'verifiedKey' => 'wp-short-pixel-verifiedKey',
24
- 'compressionType' => 'wp-short-pixel-compression',
25
- 'processThumbnails' => 'wp-short-process_thumbnails',
26
- 'keepExif' => 'wp-short-pixel-keep-exif',
27
- 'CMYKtoRGBconversion' => 'wp-short-pixel_cmyk2rgb',
28
- 'createWebp' => 'wp-short-create-webp',
29
- 'optimizeRetina' => 'wp-short-pixel-optimize-retina',
30
- 'backupImages' => 'wp-short-backup_images',
31
- 'resizeImages' => 'wp-short-pixel-resize-images',
32
- 'resizeType' => 'wp-short-pixel-resize-type',
33
- 'resizeWidth' => 'wp-short-pixel-resize-width',
34
- 'resizeHeight' => 'wp-short-pixel-resize-height',
35
- 'siteAuthUser' => 'wp-short-pixel-site-auth-user',
36
- 'siteAuthPass' => 'wp-short-pixel-site-auth-pass',
37
- 'autoMediaLibrary' => 'wp-short-pixel-auto-media-library',
38
- 'optimizePdfs' => 'wp-short-pixel-optimize-pdfs',
 
39
 
40
  //optimize other images than the ones in Media Library
41
- 'includeNextGen' => 'wp-short-pixel-include-next-gen',
42
- 'hasCustomFolders' => 'wp-short-pixel-has-custom-folders',
43
- 'customBulkPaused' => 'wp-short-pixel-custom-bulk-paused',
44
 
45
  //stats, notices, etc.
46
- 'currentTotalFiles' => 'wp-short-pixel-current-total-files',
47
- 'fileCount' => 'wp-short-pixel-fileCount',
48
- 'thumbsCount' => 'wp-short-pixel-thumbnail-count',
49
- 'under5Percent' => 'wp-short-pixel-files-under-5-percent',
50
- 'savedSpace' => 'wp-short-pixel-savedSpace',
51
- 'averageCompression' => 'wp-short-pixel-averageCompression',
52
- 'apiRetries' => 'wp-short-pixel-api-retries',
53
- 'totalOptimized' => 'wp-short-pixel-total-optimized',
54
- 'totalOriginal' => 'wp-short-pixel-total-original',
55
- 'quotaExceeded' => 'wp-short-pixel-quota-exceeded',
56
- 'httpProto' => 'wp-short-pixel-protocol',
57
- 'downloadProto' => 'wp-short-pixel-download-protocol',
58
- 'mediaAlert' => 'wp-short-pixel-media-alert',
59
- 'dismissedNotices' => 'wp-short-pixel-dismissed-notices',
60
- 'activationDate' => 'wp-short-pixel-activation-date',
61
- 'activationNotice' => 'wp-short-pixel-activation-notice',
62
- 'mediaLibraryViewMode' => 'wp-short-pixel-view-mode',
63
- 'redirectedSettings' => 'wp-short-pixel-redirected-settings',
64
 
65
  //bulk state machine
66
- 'bulkType' => 'wp-short-pixel-bulk-type',
67
- 'bulkLastStatus' => 'wp-short-pixel-bulk-last-status',
68
- 'startBulkId' => 'wp-short-pixel-query-id-start',
69
- 'stopBulkId' => 'wp-short-pixel-query-id-stop',
70
- 'bulkCount' => 'wp-short-pixel-bulk-count',
71
- 'bulkPreviousPercent' => 'wp-short-pixel-bulk-previous-percent',
72
- 'bulkCurrentlyProcessed' => 'wp-short-pixel-bulk-processed-items',
73
- 'bulkAlreadyDoneCount' => 'wp-short-pixel-bulk-done-count',
74
- 'lastBulkStartTime' => 'wp-short-pixel-last-bulk-start-time',
75
- 'lastBulkSuccessTime' => 'wp-short-pixel-last-bulk-success-time',
76
- 'bulkRunningTime' => 'wp-short-pixel-bulk-running-time',
77
- 'cancelPointer' => 'wp-short-pixel-cancel-pointer',
78
- 'skipToCustom' => 'wp-short-pixel-skip-to-custom',
79
- 'bulkEverRan' => 'wp-short-pixel-bulk-ever-ran',
80
- 'flagId' => 'wp-short-pixel-flag-id',
81
- 'failedImages' => 'wp-short-pixel-failed-imgs',
82
- 'bulkProcessingStatus' => 'bulkProcessingStatus',
83
 
84
- 'priorityQueue' => 'wp-short-pixel-priorityQueue',
85
- 'prioritySkip' => 'wp-short-pixel-prioritySkip',
86
 
87
- '' => '',
88
  );
89
 
90
  public function __construct() {
@@ -99,28 +100,19 @@ class WPShortPixelSettings {
99
  $this->_processThumbnails = self::getOpt('wp-short-process_thumbnails', $this->_processThumbnails);
100
  $this->_CMYKtoRGBconversion = self::getOpt('wp-short-pixel_cmyk2rgb', $this->_CMYKtoRGBconversion);
101
  $this->_backupImages = self::getOpt('wp-short-backup_images', $this->_backupImages);
102
- // the following lines practically set defaults for options if they're not set
103
- self::getOpt('wp-short-pixel-auto-media-library', 1);
104
- self::getOpt('wp-short-pixel-optimize-retina', 1);
105
- self::getOpt('wp-short-pixel-optimize-pdfs', 1);
106
- self::getOpt( 'wp-short-pixel-fileCount', 0);
107
- self::getOpt( 'wp-short-pixel-thumbnail-count', 0);//amount of optimized thumbnails
108
- self::getOpt( 'wp-short-pixel-files-under-5-percent', 0);//amount of optimized thumbnails
109
- self::getOpt( 'wp-short-pixel-savedSpace', 0);
110
- self::getOpt( 'wp-short-pixel-api-retries', 0);//sometimes we need to retry processing/downloading a file multiple times
111
- self::getOpt( 'wp-short-pixel-quota-exceeded', 0);
112
- self::getOpt( 'wp-short-pixel-total-original', 0);//amount of original data
113
- self::getOpt( 'wp-short-pixel-total-optimized', 0);//amount of optimized
114
- self::getOpt( 'wp-short-pixel-protocol', 'https');
115
-
116
  $this->_resizeImages = self::getOpt( 'wp-short-pixel-resize-images', 0);
117
  $this->_resizeWidth = self::getOpt( 'wp-short-pixel-resize-width', 0);
118
  $this->_resizeHeight = self::getOpt( 'wp-short-pixel-resize-height', 0);
 
 
 
 
 
119
  }
120
 
121
  public static function debugResetOptions() {
122
  foreach(self::$_optionsMap as $key => $val) {
123
- delete_option($val);
124
  }
125
  if(isset($_SESSION["wp-short-pixel-priorityQueue"])) {
126
  unset($_SESSION["wp-short-pixel-priorityQueue"]);
@@ -150,7 +142,7 @@ class WPShortPixelSettings {
150
  public function __get($name)
151
  {
152
  if (array_key_exists($name, self::$_optionsMap)) {
153
- return $this->getOpt(self::$_optionsMap[$name]);
154
  }
155
  $trace = debug_backtrace();
156
  trigger_error(
@@ -164,14 +156,17 @@ class WPShortPixelSettings {
164
  public function __set($name, $value) {
165
  if (array_key_exists($name, self::$_optionsMap)) {
166
  if($value !== null) {
167
- $this->setOpt(self::$_optionsMap[$name], $value);
168
  } else {
169
- delete_option(self::$_optionsMap[$name]);
170
  }
171
  }
172
  }
173
 
174
  public static function getOpt($key, $default = null) {
 
 
 
175
  if(get_option($key) === false) {
176
  add_option( $key, $default, '', 'yes' );
177
  }
15
 
16
  private static $_optionsMap = array(
17
  //This one is accessed also directly via get_option
18
+ 'frontBootstrap' => array('key' => 'wp-short-pixel-front-bootstrap', 'default' => null), //set to 1 when need the plugin active for logged in user in the front-end
19
+ 'lastBackAction' => array('key' => 'wp-short-pixel-last-back-action', 'default' => null), //when less than 10 min. passed from this timestamp, the front-bootstrap is ineffective.
20
 
21
  //optimization options
22
+ 'apiKey' => array('key' => 'wp-short-pixel-apiKey', 'default' => ''),
23
+ 'verifiedKey' => array('key' => 'wp-short-pixel-verifiedKey', 'default' => false),
24
+ 'compressionType' => array('key' => 'wp-short-pixel-compression', 'default' => 1),
25
+ 'processThumbnails' => array('key' => 'wp-short-process_thumbnails', 'default' => null),
26
+ 'keepExif' => array('key' => 'wp-short-pixel-keep-exif', 'default' => 0),
27
+ 'CMYKtoRGBconversion' => array('key' => 'wp-short-pixel_cmyk2rgb', 'default' => 1),
28
+ 'createWebp' => array('key' => 'wp-short-create-webp', 'default' => null),
29
+ 'optimizeRetina' => array('key' => 'wp-short-pixel-optimize-retina', 'default' => 1),
30
+ 'backupImages' => array('key' => 'wp-short-backup_images', 'default' => 1),
31
+ 'resizeImages' => array('key' => 'wp-short-pixel-resize-images', 'default' => false),
32
+ 'resizeType' => array('key' => 'wp-short-pixel-resize-type', 'default' => null),
33
+ 'resizeWidth' => array('key' => 'wp-short-pixel-resize-width', 'default' => 0),
34
+ 'resizeHeight' => array('key' => 'wp-short-pixel-resize-height', 'default' => 0),
35
+ 'siteAuthUser' => array('key' => 'wp-short-pixel-site-auth-user', 'default' => null),
36
+ 'siteAuthPass' => array('key' => 'wp-short-pixel-site-auth-pass', 'default' => null),
37
+ 'autoMediaLibrary' => array('key' => 'wp-short-pixel-auto-media-library', 'default' => 1),
38
+ 'optimizePdfs' => array('key' => 'wp-short-pixel-optimize-pdfs', 'default' => 1),
39
+ 'excludePatterns' => array('key' => 'wp-short-pixel-exclude-patterns', 'default' => array()),
40
 
41
  //optimize other images than the ones in Media Library
42
+ 'includeNextGen' => array('key' => 'wp-short-pixel-include-next-gen', 'default' => null),
43
+ 'hasCustomFolders' => array('key' => 'wp-short-pixel-has-custom-folders', 'default' => false),
44
+ 'customBulkPaused' => array('key' => 'wp-short-pixel-custom-bulk-paused', 'default' => false),
45
 
46
  //stats, notices, etc.
47
+ 'currentTotalFiles' => array('key' => 'wp-short-pixel-current-total-files', 'default' => null),
48
+ 'fileCount' => array('key' => 'wp-short-pixel-fileCount', 'default' => 0),
49
+ 'thumbsCount' => array('key' => 'wp-short-pixel-thumbnail-count', 'default' => 0),
50
+ 'under5Percent' => array('key' => 'wp-short-pixel-files-under-5-percent', 'default' => 0),
51
+ 'savedSpace' => array('key' => 'wp-short-pixel-savedSpace', 'default' => 0),
52
+ 'averageCompression' => array('key' => 'wp-short-pixel-averageCompression', 'default' => null),
53
+ 'apiRetries' => array('key' => 'wp-short-pixel-api-retries', 'default' => 0),
54
+ 'totalOptimized' => array('key' => 'wp-short-pixel-total-optimized', 'default' => 0),
55
+ 'totalOriginal' => array('key' => 'wp-short-pixel-total-original', 'default' => 0),
56
+ 'quotaExceeded' => array('key' => 'wp-short-pixel-quota-exceeded', 'default' => 0),
57
+ 'httpProto' => array('key' => 'wp-short-pixel-protocol', 'default' => 'https'),
58
+ 'downloadProto' => array('key' => 'wp-short-pixel-download-protocol', 'default' => null),
59
+ 'mediaAlert' => array('key' => 'wp-short-pixel-media-alert', 'default' => null),
60
+ 'dismissedNotices' => array('key' => 'wp-short-pixel-dismissed-notices', 'default' => null),
61
+ 'activationDate' => array('key' => 'wp-short-pixel-activation-date', 'default' => null),
62
+ 'activationNotice' => array('key' => 'wp-short-pixel-activation-notice', 'default' => null),
63
+ 'mediaLibraryViewMode' => array('key' => 'wp-short-pixel-view-mode', 'default' => null),
64
+ 'redirectedSettings' => array('key' => 'wp-short-pixel-redirected-settings', 'default' => null),
65
 
66
  //bulk state machine
67
+ 'bulkType' => array('key' => 'wp-short-pixel-bulk-type', 'default' => null),
68
+ 'bulkLastStatus' => array('key' => 'wp-short-pixel-bulk-last-status', 'default' => null),
69
+ 'startBulkId' => array('key' => 'wp-short-pixel-query-id-start', 'default' => 0),
70
+ 'stopBulkId' => array('key' => 'wp-short-pixel-query-id-stop', 'default' => 0),
71
+ 'bulkCount' => array('key' => 'wp-short-pixel-bulk-count', 'default' => 0),
72
+ 'bulkPreviousPercent' => array('key' => 'wp-short-pixel-bulk-previous-percent', 'default' => 0),
73
+ 'bulkCurrentlyProcessed' => array('key' => 'wp-short-pixel-bulk-processed-items', 'default' => 0),
74
+ 'bulkAlreadyDoneCount' => array('key' => 'wp-short-pixel-bulk-done-count', 'default' => 0),
75
+ 'lastBulkStartTime' => array('key' => 'wp-short-pixel-last-bulk-start-time', 'default' => 0),
76
+ 'lastBulkSuccessTime' => array('key' => 'wp-short-pixel-last-bulk-success-time', 'default' => 0),
77
+ 'bulkRunningTime' => array('key' => 'wp-short-pixel-bulk-running-time', 'default' => 0),
78
+ 'cancelPointer' => array('key' => 'wp-short-pixel-cancel-pointer', 'default' => 0),
79
+ 'skipToCustom' => array('key' => 'wp-short-pixel-skip-to-custom', 'default' => null),
80
+ 'bulkEverRan' => array('key' => 'wp-short-pixel-bulk-ever-ran', 'default' => false),
81
+ 'flagId' => array('key' => 'wp-short-pixel-flag-id', 'default' => 0),
82
+ 'failedImages' => array('key' => 'wp-short-pixel-failed-imgs', 'default' => 0),
83
+ 'bulkProcessingStatus' => array('key' => 'bulkProcessingStatus', 'default' => null),
84
 
85
+ 'priorityQueue' => array('key' => 'wp-short-pixel-priorityQueue', 'default' => null),
86
+ 'prioritySkip' => array('key' => 'wp-short-pixel-prioritySkip', 'default' => null),
87
 
88
+ //'' => array('key' => 'wp-short-pixel-', 'default' => null),
89
  );
90
 
91
  public function __construct() {
100
  $this->_processThumbnails = self::getOpt('wp-short-process_thumbnails', $this->_processThumbnails);
101
  $this->_CMYKtoRGBconversion = self::getOpt('wp-short-pixel_cmyk2rgb', $this->_CMYKtoRGBconversion);
102
  $this->_backupImages = self::getOpt('wp-short-backup_images', $this->_backupImages);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
103
  $this->_resizeImages = self::getOpt( 'wp-short-pixel-resize-images', 0);
104
  $this->_resizeWidth = self::getOpt( 'wp-short-pixel-resize-width', 0);
105
  $this->_resizeHeight = self::getOpt( 'wp-short-pixel-resize-height', 0);
106
+
107
+ // the following lines practically set defaults for options if they're not set
108
+ foreach(self::$_optionsMap as $opt) {
109
+ self::getOpt($opt['key'], $opt['default']);
110
+ }
111
  }
112
 
113
  public static function debugResetOptions() {
114
  foreach(self::$_optionsMap as $key => $val) {
115
+ delete_option($val['key']);
116
  }
117
  if(isset($_SESSION["wp-short-pixel-priorityQueue"])) {
118
  unset($_SESSION["wp-short-pixel-priorityQueue"]);
142
  public function __get($name)
143
  {
144
  if (array_key_exists($name, self::$_optionsMap)) {
145
+ return $this->getOpt(self::$_optionsMap[$name]['key']);
146
  }
147
  $trace = debug_backtrace();
148
  trigger_error(
156
  public function __set($name, $value) {
157
  if (array_key_exists($name, self::$_optionsMap)) {
158
  if($value !== null) {
159
+ $this->setOpt(self::$_optionsMap[$name]['key'], $value);
160
  } else {
161
+ delete_option(self::$_optionsMap[$name]['key']);
162
  }
163
  }
164
  }
165
 
166
  public static function getOpt($key, $default = null) {
167
+ if(isset(self::$_optionsMap[$key]['key'])) { //first try our name
168
+ $key = self::$_optionsMap[$key]['key'];
169
+ }
170
  if(get_option($key) === false) {
171
  add_option( $key, $default, '', 'yes' );
172
  }
readme.txt CHANGED
@@ -6,7 +6,7 @@ Tags: compress, image, compression, optimize, image optimizer, image compression
6
 
7
  Requires at least: 3.2.0
8
  Tested up to: 4.7
9
- Stable tag: 4.3.1
10
  License: GPLv2 or later
11
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
12
 
@@ -221,6 +221,12 @@ The ShortPixel team is here to help. <a href="https://shortpixel.com/contact">Co
221
 
222
  == Changelog ==
223
 
 
 
 
 
 
 
224
  = 4.3.1 =
225
 
226
  * hide API Key on single sites option ( define SHORTPIXEL_HIDE_API_KEY true in wp-config.php)
6
 
7
  Requires at least: 3.2.0
8
  Tested up to: 4.7
9
+ Stable tag: 4.4.0
10
  License: GPLv2 or later
11
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
12
 
221
 
222
  == Changelog ==
223
 
224
+ = 4.4.0 =
225
+
226
+ * exclude images based on patterns or image sizes, exclude paths based on patterns
227
+ * avoid using basename as a fallback for non-UTF8 filenames but instead use own code (basename strips first character if it's not ASCII-128 - for example ISO/IEC 8859-2)
228
+ * processing spinning indicator in the admin top bar with CSS to display OK on all admin themes.
229
+
230
  = 4.3.1 =
231
 
232
  * hide API Key on single sites option ( define SHORTPIXEL_HIDE_API_KEY true in wp-config.php)
res/css/short-pixel.css CHANGED
@@ -176,10 +176,10 @@ div.shortpixel-rate-us > a:focus {
176
 
177
  li.shortpixel-toolbar-processing > a.ab-item > div,
178
  #wpadminbar li.shortpixel-toolbar-processing > a.ab-item > div{
179
- background-image: url("../img/loading-dark-big.gif");
180
  background-position: center center;
181
  background-repeat: no-repeat;
182
- height: 33px;
183
  margin-top: -1px;
184
  padding: 0 3px;
185
  }
@@ -602,3 +602,50 @@ section#tab-resources p {
602
  .sp-tabs h2:before{
603
  content:none;
604
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
176
 
177
  li.shortpixel-toolbar-processing > a.ab-item > div,
178
  #wpadminbar li.shortpixel-toolbar-processing > a.ab-item > div{
179
+ /* background-image: url("../img/loading-dark-big.gif");
180
  background-position: center center;
181
  background-repeat: no-repeat;
182
+ */ height: 33px;
183
  margin-top: -1px;
184
  padding: 0 3px;
185
  }
602
  .sp-tabs h2:before{
603
  content:none;
604
  }
605
+
606
+ #wpadminbar .shortpixel-toolbar-processing .cssload-container {
607
+ width: 100%;
608
+ height: 24px;
609
+ text-align: center;
610
+ position: absolute;
611
+ top: 0px;
612
+ left: -1px;
613
+ }
614
+ #wpadminbar .shortpixel-toolbar-processing.shortpixel-quota-exceeded .cssload-container{
615
+ display: none;
616
+ }
617
+
618
+ #wpadminbar .shortpixel-toolbar-processing .cssload-speeding-wheel {
619
+ width: 24px;
620
+ height: 24px;
621
+ opacity: 0.7;
622
+ margin: 0 auto;
623
+ border: 4px solid rgb(28,191,203);
624
+ border-radius: 50%;
625
+ border-left-color: transparent;
626
+ animation: cssload-spin 2000ms infinite linear;
627
+ -o-animation: cssload-spin 2000ms infinite linear;
628
+ -ms-animation: cssload-spin 2000ms infinite linear;
629
+ -webkit-animation: cssload-spin 2000ms infinite linear;
630
+ -moz-animation: cssload-spin 2000ms infinite linear;
631
+ }
632
+
633
+ @keyframes cssload-spin {
634
+ 100%{ transform: rotate(360deg); transform: rotate(360deg); }
635
+ }
636
+
637
+ @-o-keyframes cssload-spin {
638
+ 100%{ -o-transform: rotate(360deg); transform: rotate(360deg); }
639
+ }
640
+
641
+ @-ms-keyframes cssload-spin {
642
+ 100%{ -ms-transform: rotate(360deg); transform: rotate(360deg); }
643
+ }
644
+
645
+ @-webkit-keyframes cssload-spin {
646
+ 100%{ -webkit-transform: rotate(360deg); transform: rotate(360deg); }
647
+ }
648
+
649
+ @-moz-keyframes cssload-spin {
650
+ 100%{ -moz-transform: rotate(360deg); transform: rotate(360deg); }
651
+ }
res/js/short-pixel.js CHANGED
@@ -529,21 +529,21 @@ function checkBulkProcessingCallApi(){
529
  ShortPixel.retry(e.message);
530
  return;
531
  }
 
 
532
  var id = data["ImageID"];
533
 
534
  var isBulkPage = (jQuery("div.short-pixel-bulk-page").length > 0);
535
 
536
  switch (data["Status"]) {
537
  case ShortPixel.STATUS_NO_KEY:
538
- setCellMessage(id, "<a class='button button-smaller button-primary' href=\"https://shortpixel.com/wp-apikey\" target=\"_blank\">" + _spTr.getApiKey + "</a>",
539
- data["Message"]);
540
  showToolBarAlert(ShortPixel.STATUS_NO_KEY);
541
  break;
542
  case ShortPixel.STATUS_QUOTA_EXCEEDED:
543
- setCellMessage(id, "<a class='button button-smaller button-primary' href=\"https://shortpixel.com/login/"
544
  + ShortPixel.API_KEY + "\" target=\"_blank\">" + _spTr.extendQuota + "</a>"
545
- + "<a class='button button-smaller' href='admin.php?action=shortpixel_check_quota'>" + _spTr.check__Quota + "</a>",
546
- data["Message"]);
547
  showToolBarAlert(ShortPixel.STATUS_QUOTA_EXCEEDED);
548
  if(data['Stop'] == false) { //there are other items in the priority list, maybe processed, try those
549
  setTimeout(checkBulkProgress, 5000);
529
  ShortPixel.retry(e.message);
530
  return;
531
  }
532
+ ShortPixel.retries = 0;
533
+
534
  var id = data["ImageID"];
535
 
536
  var isBulkPage = (jQuery("div.short-pixel-bulk-page").length > 0);
537
 
538
  switch (data["Status"]) {
539
  case ShortPixel.STATUS_NO_KEY:
540
+ setCellMessage(id, data["Message"], "<a class='button button-smaller button-primary' href=\"https://shortpixel.com/wp-apikey\" target=\"_blank\">" + _spTr.getApiKey + "</a>");
 
541
  showToolBarAlert(ShortPixel.STATUS_NO_KEY);
542
  break;
543
  case ShortPixel.STATUS_QUOTA_EXCEEDED:
544
+ setCellMessage(id, data["Message"], "<a class='button button-smaller button-primary' href=\"https://shortpixel.com/login/"
545
  + ShortPixel.API_KEY + "\" target=\"_blank\">" + _spTr.extendQuota + "</a>"
546
+ + "<a class='button button-smaller' href='admin.php?action=shortpixel_check_quota'>" + _spTr.check__Quota + "</a>");
 
547
  showToolBarAlert(ShortPixel.STATUS_QUOTA_EXCEEDED);
548
  if(data['Stop'] == false) { //there are other items in the priority list, maybe processed, try those
549
  setTimeout(checkBulkProgress, 5000);
shortpixel_api.php CHANGED
@@ -23,6 +23,7 @@ class ShortPixelAPI {
23
  const ERR_SAVE_BKP = -5;
24
  const ERR_INCORRECT_FILE_SIZE = -6;
25
  const ERR_DOWNLOAD = -7;
 
26
 
27
  private $_settings;
28
  private $_maxAttempts = 10;
@@ -103,8 +104,7 @@ class ShortPixelAPI {
103
 
104
  if ( isset($errorMessage) )
105
  {//set details inside file so user can know what happened
106
- $itemHandler->setError($errorCode, $errorMessage);
107
- $itemHandler->incrementRetries();
108
  return array("response" => array("code" => $errorCode, "message" => $errorMessage ));
109
  }
110
 
@@ -171,8 +171,7 @@ class ShortPixelAPI {
171
  {//keeps track of time
172
  if ( $apiRetries > MAX_API_RETRIES )//we tried to process this time too many times, giving up...
173
  {
174
- $itemHandler->setError(self::ERR_TIMEOUT, __('Timed out while processing.','shortpixel-image-optimiser'));
175
- $itemHandler->incrementRetries();
176
  $this->_settings->apiRetries = 0; //fai added to solve a bug?
177
  return array("Status" => self::STATUS_SKIP,
178
  "Message" => ($itemHandler->getType() == ShortPixelMetaFacade::CUSTOM_TYPE ? __('Image ID','shortpixel-image-optimiser') : __('Media ID','shortpixel-image-optimiser'))
@@ -219,22 +218,24 @@ class ShortPixelAPI {
219
  return $this->handleSuccess($APIresponse, $PATHs, $itemHandler, $compressionType);
220
  default:
221
  //handle error
 
222
  if ( !file_exists($PATHs[0]) ) {
223
- $itemHandler->incrementRetries(2);
224
  $err = array("Status" => self::STATUS_NOT_FOUND, "Message" => "File not found on disk. "
225
  . ($itemHandler->getType() == ShortPixelMetaFacade::CUSTOM_TYPE ? "Image" : "Media")
226
- . " ID: " . $itemHandler->getId());
 
227
  }
228
  elseif ( isset($APIresponse[0]->Status->Message) ) {
229
  //return array("Status" => self::STATUS_FAIL, "Message" => "There was an error and your request was not processed (" . $APIresponse[0]->Status->Message . "). REQ: " . json_encode($URLs));
230
- $err = array("Status" => self::STATUS_FAIL, "Code" => (isset($APIresponse[0]->Status->Code) ? $APIresponse[0]->Status->Code : ""),
231
  "Message" => __('There was an error and your request was not processed.','shortpixel-image-optimiser')
232
  . " (" . $APIresponse[0]->Status->Message . ")");
233
  } else {
234
- $err = array("Status" => self::STATUS_FAIL, "Message" => __('There was an error and your request was not processed.','shortpixel-image-optimiser'));
 
235
  }
236
 
237
- $itemHandler->incrementRetries();
238
  $meta = $itemHandler->getMeta();
239
  if($meta->getRetries() >= MAX_FAIL_RETRIES) {
240
  $meta->setStatus($APIresponse[0]->Status->Code);
@@ -447,8 +448,7 @@ class ShortPixelAPI {
447
  if ( !@copy($source[$fileID], $filePATH) )
448
  {//file couldn't be saved in backup folder
449
  $msg = sprintf(__('Cannot save file <i>%s</i> in backup directory','shortpixel-image-optimiser'),self::MB_basename($source[$fileID]));
450
- $itemHandler->setError(self::ERR_SAVE_BKP, $msg);
451
- $itemHandler->incrementRetries();
452
  return array("Status" => self::STATUS_FAIL, "Message" => $msg);
453
  }
454
  }
@@ -456,8 +456,7 @@ class ShortPixelAPI {
456
  $NoBackup = true;
457
  } else {//cannot write to the backup dir, return with an error
458
  $msg = __('Cannot save file in backup directory','shortpixel-image-optimiser');
459
- $itemHandler->setError(self::ERR_SAVE_BKP, $msg);
460
- $itemHandler->incrementRetries();
461
  return array("Status" => self::STATUS_FAIL, "Message" => $msg);
462
  }
463
 
@@ -535,8 +534,7 @@ class ShortPixelAPI {
535
  {
536
  $msg = sprintf(__('Optimized version of %s file(s) couldn\'t be updated.','shortpixel-image-optimiser'),$writeFailed);
537
  //#ShortPixelAPI::SaveMessageinMetadata($ID, 'Error: optimized version of ' . $writeFailed . ' file(s) couldn\'t be updated.');
538
- $itemHandler->setError(self::ERR_SAVE, $msg);
539
- $itemHandler->incrementRetries();
540
  update_option('bulkProcessingStatus', "error");
541
  return array("Status" => self::STATUS_FAIL, "Code" =>"write-fail", "Message" => $msg);
542
  }
@@ -596,10 +594,19 @@ class ShortPixelAPI {
596
  */
597
  static public function MB_basename($Path, $suffix = false){
598
  $Separator = " qq ";
599
- $Path = preg_replace("/[^ ]/u", $Separator."\$0".$Separator, $Path);
600
- $Base = basename($Path, $suffix);
 
 
 
 
 
 
 
 
 
601
  $Base = str_replace($Separator, "", $Base);
602
- return $Base;
603
  }
604
 
605
  /**
23
  const ERR_SAVE_BKP = -5;
24
  const ERR_INCORRECT_FILE_SIZE = -6;
25
  const ERR_DOWNLOAD = -7;
26
+ const ERR_UNKNOWN = -999;
27
 
28
  private $_settings;
29
  private $_maxAttempts = 10;
104
 
105
  if ( isset($errorMessage) )
106
  {//set details inside file so user can know what happened
107
+ $itemHandler->incrementRetries(1, $errorCode, $errorMessage);
 
108
  return array("response" => array("code" => $errorCode, "message" => $errorMessage ));
109
  }
110
 
171
  {//keeps track of time
172
  if ( $apiRetries > MAX_API_RETRIES )//we tried to process this time too many times, giving up...
173
  {
174
+ $itemHandler->incrementRetries(1, self::ERR_TIMEOUT, __('Timed out while processing.','shortpixel-image-optimiser'));
 
175
  $this->_settings->apiRetries = 0; //fai added to solve a bug?
176
  return array("Status" => self::STATUS_SKIP,
177
  "Message" => ($itemHandler->getType() == ShortPixelMetaFacade::CUSTOM_TYPE ? __('Image ID','shortpixel-image-optimiser') : __('Media ID','shortpixel-image-optimiser'))
218
  return $this->handleSuccess($APIresponse, $PATHs, $itemHandler, $compressionType);
219
  default:
220
  //handle error
221
+ $incR = 1;
222
  if ( !file_exists($PATHs[0]) ) {
 
223
  $err = array("Status" => self::STATUS_NOT_FOUND, "Message" => "File not found on disk. "
224
  . ($itemHandler->getType() == ShortPixelMetaFacade::CUSTOM_TYPE ? "Image" : "Media")
225
+ . " ID: " . $itemHandler->getId(), "Code" => self::ERR_FILE_NOT_FOUND);
226
+ $incR = 3;
227
  }
228
  elseif ( isset($APIresponse[0]->Status->Message) ) {
229
  //return array("Status" => self::STATUS_FAIL, "Message" => "There was an error and your request was not processed (" . $APIresponse[0]->Status->Message . "). REQ: " . json_encode($URLs));
230
+ $err = array("Status" => self::STATUS_FAIL, "Code" => (isset($APIresponse[0]->Status->Code) ? $APIresponse[0]->Status->Code : self::ERR_UNKNOWN),
231
  "Message" => __('There was an error and your request was not processed.','shortpixel-image-optimiser')
232
  . " (" . $APIresponse[0]->Status->Message . ")");
233
  } else {
234
+ $err = array("Status" => self::STATUS_FAIL, "Message" => __('There was an error and your request was not processed.','shortpixel-image-optimiser'),
235
+ "Code" => (isset($APIresponse[0]->Status->Code) ? $APIresponse[0]->Status->Code : self::ERR_UNKNOWN));
236
  }
237
 
238
+ $itemHandler->incrementRetries($incR, $err["Code"], $err["Message"]);
239
  $meta = $itemHandler->getMeta();
240
  if($meta->getRetries() >= MAX_FAIL_RETRIES) {
241
  $meta->setStatus($APIresponse[0]->Status->Code);
448
  if ( !@copy($source[$fileID], $filePATH) )
449
  {//file couldn't be saved in backup folder
450
  $msg = sprintf(__('Cannot save file <i>%s</i> in backup directory','shortpixel-image-optimiser'),self::MB_basename($source[$fileID]));
451
+ $itemHandler->incrementRetries(1, self::ERR_SAVE_BKP, $msg);
 
452
  return array("Status" => self::STATUS_FAIL, "Message" => $msg);
453
  }
454
  }
456
  $NoBackup = true;
457
  } else {//cannot write to the backup dir, return with an error
458
  $msg = __('Cannot save file in backup directory','shortpixel-image-optimiser');
459
+ $itemHandler->incrementRetries(1, self::ERR_SAVE_BKP, $msg);
 
460
  return array("Status" => self::STATUS_FAIL, "Message" => $msg);
461
  }
462
 
534
  {
535
  $msg = sprintf(__('Optimized version of %s file(s) couldn\'t be updated.','shortpixel-image-optimiser'),$writeFailed);
536
  //#ShortPixelAPI::SaveMessageinMetadata($ID, 'Error: optimized version of ' . $writeFailed . ' file(s) couldn\'t be updated.');
537
+ $itemHandler->incrementRetries(1, self::ERR_SAVE, $msg);
 
538
  update_option('bulkProcessingStatus', "error");
539
  return array("Status" => self::STATUS_FAIL, "Code" =>"write-fail", "Message" => $msg);
540
  }
594
  */
595
  static public function MB_basename($Path, $suffix = false){
596
  $Separator = " qq ";
597
+ $qqPath = preg_replace("/[^ ]/u", $Separator."\$0".$Separator, $Path);
598
+ if(!$qqPath) { //this is not an UTF8 string!! Don't rely on basename either, since if filename starts with a non-ASCII character it strips it off
599
+ $fileName = end(explode(DIRECTORY_SEPARATOR, $Path));
600
+ $pos = strpos($fileName, $suffix);
601
+ if($pos !== false) {
602
+ return substr($fileName, 0, $pos);
603
+ }
604
+ return $fileName;
605
+ }
606
+ $suffix = preg_replace("/[^ ]/u", $Separator."\$0".$Separator, $suffix);
607
+ $Base = basename($qqPath, $suffix);
608
  $Base = str_replace($Separator, "", $Base);
609
+ return $Base;
610
  }
611
 
612
  /**
wp-shortpixel.php CHANGED
@@ -3,7 +3,7 @@
3
  * Plugin Name: ShortPixel Image Optimizer
4
  * Plugin URI: https://shortpixel.com/
5
  * Description: ShortPixel optimizes images automatically, while guarding the quality of your images. Check your <a href="options-general.php?page=wp-shortpixel" target="_blank">Settings &gt; ShortPixel</a> page on how to start optimizing your image library and make your website load faster.
6
- * Version: 4.3.1
7
  * Author: ShortPixel
8
  * Author URI: https://shortpixel.com
9
  * Text Domain: shortpixel-image-optimiser
@@ -17,7 +17,7 @@ define('SHORTPIXEL_PLUGIN_FILE', __FILE__);
17
 
18
  define('SP_AFFILIATE_CODE', '');
19
 
20
- define('PLUGIN_VERSION', "4.3.1");
21
  define('SP_MAX_TIMEOUT', 10);
22
  define('SP_VALIDATE_MAX_TIMEOUT', 15);
23
  define('SP_BACKUP', 'ShortpixelBackups');
@@ -104,6 +104,5 @@ if ( !function_exists( 'vc_action' ) || vc_action() !== 'vc_inline' ) { //handle
104
 
105
  register_activation_hook( __FILE__, 'shortPixelActivatePlugin' );
106
  register_deactivation_hook( __FILE__, 'shortPixelDeactivatePlugin' );
107
-
108
  }
109
  ?>
3
  * Plugin Name: ShortPixel Image Optimizer
4
  * Plugin URI: https://shortpixel.com/
5
  * Description: ShortPixel optimizes images automatically, while guarding the quality of your images. Check your <a href="options-general.php?page=wp-shortpixel" target="_blank">Settings &gt; ShortPixel</a> page on how to start optimizing your image library and make your website load faster.
6
+ * Version: 4.4.0
7
  * Author: ShortPixel
8
  * Author URI: https://shortpixel.com
9
  * Text Domain: shortpixel-image-optimiser
17
 
18
  define('SP_AFFILIATE_CODE', '');
19
 
20
+ define('PLUGIN_VERSION', "4.4.0");
21
  define('SP_MAX_TIMEOUT', 10);
22
  define('SP_VALIDATE_MAX_TIMEOUT', 15);
23
  define('SP_BACKUP', 'ShortpixelBackups');
104
 
105
  register_activation_hook( __FILE__, 'shortPixelActivatePlugin' );
106
  register_deactivation_hook( __FILE__, 'shortPixelDeactivatePlugin' );
 
107
  }
108
  ?>