ShortPixel Image Optimizer - Version 4.17.0

Version Description

Release date: 2nd April 2020 * Complete rewrite of the Other Media part of the plugin. It now looks closer to the standard Media Library, having thumbnails and actions like Compare, Re-optimize and Restore from backup for all images when you have Backups activated; * Added notification to activate the integration with NextGen Gallery, when the plugin is active and the integration is not activated; * Improved the way Other Media folders are added and it should not crash anymore for folders with a very large number of images; * Fix for the extra information (i) next to each Other Media folder in the Advanced Settings; * Fixes for multiple issues reagrding the NextGen Gallery plugin integration; * Fix for notififcations showing up when they're not supposed to show up; * Fix for multiple notifications when backup files are not found. These are now merged together; * Fix for notifications that were crashing outside ShortPixel screens; * Fix for the report that was wrongly stating 40 days, when actually the report is only for 30 days; * Fix for the exclude regex section that was returning true even if no matches were found; * Removed from the plugin the files that are not used anymore; * Language 15 new strings added, 0 updated, 0 fuzzied, and 8 obsoleted.

Download this release

Release Info

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

Code changes from version 4.16.4 to 4.17.0

Files changed (60) hide show
  1. build/shortpixel/log/src/ShortPixelLogger.php +6 -0
  2. build/shortpixel/notices/composer.json +1 -1
  3. build/shortpixel/notices/src/NoticeController.php +11 -3
  4. build/shortpixel/notices/src/NoticeModel.php +31 -1
  5. build/shortpixel/notices/src/css/notices.min.css +0 -1
  6. class/controller/adminnotices_controller.php +12 -2
  7. class/controller/bulk-restore-all.php +6 -5
  8. class/controller/cache_controller.php +8 -3
  9. class/controller/controller.php +19 -5
  10. class/controller/debug.php +0 -266
  11. class/controller/edit_media_controller.php +4 -13
  12. class/controller/filesystem_controller.php +8 -1
  13. class/controller/notice.php +0 -134
  14. class/controller/othermedia_controller.php +192 -0
  15. class/controller/settings.php +52 -38
  16. class/controller/views/othermedia_view_controller.php +695 -0
  17. class/db/shortpixel-custom-meta-dao.php +169 -117
  18. class/db/shortpixel-meta-facade.php +3 -2
  19. class/db/shortpixel-nextgen-adapter.php +0 -40
  20. class/db/wp-shortpixel-db.php +20 -4
  21. class/external/cloudflare.php +2 -0
  22. class/external/nextgen.php +97 -24
  23. class/model/apikey_model.php +4 -0
  24. class/model/cache_model.php +3 -5
  25. class/model/directory_model.php +4 -4
  26. class/model/directory_othermedia_model.php +354 -0
  27. class/model/notice_model.php +0 -87
  28. class/model/shortpixel-debug.php +0 -140
  29. class/model/shortpixel-folder.php +8 -4
  30. class/model/shortpixel-image.php +0 -32
  31. class/model/shortpixel-meta.php +5 -1
  32. class/model/sp-file-rights-exception.php +0 -6
  33. class/shortpixel_queue.php +3 -2
  34. class/view/settings/part-advanced.php +49 -39
  35. class/view/settings/part-statistics.php +1 -1
  36. class/view/shortpixel-list-table.php +2 -24
  37. class/view/shortpixel_view.php +2 -2
  38. class/view/view-debug-box.php +0 -44
  39. class/view/view-other-media.php +139 -0
  40. class/view/view-restore-all.php +3 -0
  41. class/wp-short-pixel.php +79 -319
  42. class/wp-shortpixel-cloudflare-api.php +0 -161
  43. readme.txt +23 -7
  44. res/css/short-pixel.css +1 -6
  45. res/css/short-pixel.min.css +1 -1
  46. res/css/shortpixel-admin.css +23 -3
  47. res/css/shortpixel-admin.min.css +0 -1
  48. res/css/shortpixel-notices.css +2 -0
  49. res/css/shortpixel-othermedia.css +102 -0
  50. res/js/shortpixel.js +23 -7
  51. res/js/shortpixel.min.js +1 -1
  52. res/scss/shortpixel-notices.scss +6 -0
  53. res/scss/shortpixel-othermedia.scss +185 -0
  54. res/scss/utils/_notices.scss +0 -39
  55. res/scss/view/_settings-advanced.scss +28 -1
  56. shortpixel-debug.php +0 -47
  57. shortpixel-plugin.php +38 -10
  58. shortpixel_api.php +21 -2
  59. wp-shortpixel-req.php +1 -1
  60. wp-shortpixel.php +12 -8
build/shortpixel/log/src/ShortPixelLogger.php CHANGED
@@ -250,6 +250,12 @@ namespace ShortPixel\ShortPixelLogger;
250
  $log->addLog($message, $level, $args);
251
  }
252
 
 
 
 
 
 
 
253
  public static function logLevel($level)
254
  {
255
  $log = self::getInstance();
250
  $log->addLog($message, $level, $args);
251
  }
252
 
253
+ /** These should be removed every release. They are temporary only for d'bugging the current release */
254
+ public static function addTemp($message, $args = array())
255
+ {
256
+ self::addDebug($message, $args);
257
+ }
258
+
259
  public static function logLevel($level)
260
  {
261
  $log = self::getInstance();
build/shortpixel/notices/composer.json CHANGED
@@ -1,7 +1,7 @@
1
  {
2
  "name": "shortpixel/notices",
3
  "description": "ShortPixel WordPress Notice System",
4
- "version": "1.3",
5
  "type": "library",
6
  "license": "MIT",
7
  "authors": [
1
  {
2
  "name": "shortpixel/notices",
3
  "description": "ShortPixel WordPress Notice System",
4
+ "version": "1.4",
5
  "type": "library",
6
  "license": "MIT",
7
  "authors": [
build/shortpixel/notices/src/NoticeController.php CHANGED
@@ -65,8 +65,6 @@ class NoticeController //extends ShortPixelController
65
  {
66
  $notices = get_option($this->notice_option, false);
67
  $cnotice = (is_array($notices)) ? count($notices) : 0;
68
- if ($cnotice > 0)
69
- Log::addDebug('Notice Control - #num notices' . $cnotice);
70
 
71
  if ($notices !== false && is_array($notices))
72
  {
@@ -90,7 +88,7 @@ class NoticeController //extends ShortPixelController
90
  foreach(self::$notices as $nitem)
91
  {
92
  if ($nitem->message == $notice->message && $nitem->code == $notice->code) // same message.
93
- return $notice; // return the notice with the same message.
94
  }
95
  }
96
  self::$notices[] = $notice;
@@ -266,6 +264,16 @@ class NoticeController //extends ShortPixelController
266
 
267
  }
268
 
 
 
 
 
 
 
 
 
 
 
269
  public static function makePersistent($notice, $key, $suppress = -1)
270
  {
271
  $noticeController = self::getInstance();
65
  {
66
  $notices = get_option($this->notice_option, false);
67
  $cnotice = (is_array($notices)) ? count($notices) : 0;
 
 
68
 
69
  if ($notices !== false && is_array($notices))
70
  {
88
  foreach(self::$notices as $nitem)
89
  {
90
  if ($nitem->message == $notice->message && $nitem->code == $notice->code) // same message.
91
+ return $nitem; // return the notice with the same message.
92
  }
93
  }
94
  self::$notices[] = $notice;
264
 
265
  }
266
 
267
+ public static function addDetail($notice, $detail)
268
+ {
269
+ $noticeController = self::getInstance();
270
+ $notice->addDetail($detail);
271
+
272
+ // $notice_id = spl_object_id($notice);
273
+
274
+ $noticeController->update();
275
+ }
276
+
277
  public static function makePersistent($notice, $key, $suppress = -1)
278
  {
279
  $noticeController = self::getInstance();
build/shortpixel/notices/src/NoticeModel.php CHANGED
@@ -4,6 +4,7 @@ namespace ShortPixel\Notices;
4
  class NoticeModel //extends ShortPixelModel
5
  {
6
  public $message; // The message we want to convey.
 
7
  public $code;
8
 
9
  private $id = null; // used for persistent messages.
@@ -82,6 +83,18 @@ class NoticeModel //extends ShortPixelModel
82
  $this->suppress_until = $timestamp;
83
  }
84
 
 
 
 
 
 
 
 
 
 
 
 
 
85
 
86
  /** Set a notice persistent. Meaning it shows every page load until dismissed.
87
  * @param $key Unique Key of this message. Required
@@ -160,7 +173,11 @@ class NoticeModel //extends ShortPixelModel
160
 
161
  $id = ! is_null($this->id) ? 'id="' . $this->id . '"' : '';
162
 
163
- $output = "<div $id class='$class'><span class='icon'> " . $icon . "</span> <span class='content'>" . $this->message . "</span></div>";
 
 
 
 
164
  if ($this->is_persistent && $this->is_removable)
165
  {
166
  $output .= "<script type='text/javascript'>\n" . $this->getDismissJS() . "\n</script>";
@@ -169,6 +186,19 @@ class NoticeModel //extends ShortPixelModel
169
 
170
  }
171
 
 
 
 
 
 
 
 
 
 
 
 
 
 
172
  private function getDismissJS()
173
  {
174
  $url = wp_json_encode(admin_url('admin-ajax.php'));
4
  class NoticeModel //extends ShortPixelModel
5
  {
6
  public $message; // The message we want to convey.
7
+ public $details = array(); // extra details, like the files involved. Something could be hideable in the future.
8
  public $code;
9
 
10
  private $id = null; // used for persistent messages.
83
  $this->suppress_until = $timestamp;
84
  }
85
 
86
+ /** Support for extra information beyond the message.
87
+ * Can help to not overwhelm users w/ the same message but different file /circumstances.
88
+ */
89
+ public function addDetail($detail, $clean = false)
90
+ {
91
+ if (! $clean)
92
+ $this->details[] = $detail;
93
+ else
94
+ $this->details = array($detail);
95
+ }
96
+
97
+
98
 
99
  /** Set a notice persistent. Meaning it shows every page load until dismissed.
100
  * @param $key Unique Key of this message. Required
173
 
174
  $id = ! is_null($this->id) ? 'id="' . $this->id . '"' : '';
175
 
176
+ $output = "<div $id class='$class'><span class='icon'> " . $icon . "</span> <span class='content'>" . $this->message;
177
+ if ($this->hasDetails())
178
+ $output .= "<p class='details'>" . $this->parseDetails() . "</p>";
179
+ $output .= "</span></div>";
180
+
181
  if ($this->is_persistent && $this->is_removable)
182
  {
183
  $output .= "<script type='text/javascript'>\n" . $this->getDismissJS() . "\n</script>";
186
 
187
  }
188
 
189
+ protected function hasDetails()
190
+ {
191
+ if (is_array($this->details) && count($this->details) > 0)
192
+ return true;
193
+ else
194
+ return false;
195
+ }
196
+
197
+ protected function parseDetails()
198
+ {
199
+ return implode('<BR>', $this->details);
200
+ }
201
+
202
  private function getDismissJS()
203
  {
204
  $url = wp_json_encode(admin_url('admin-ajax.php'));
build/shortpixel/notices/src/css/notices.min.css DELETED
@@ -1 +0,0 @@
1
- .shortpixel.notice{padding:8px}.shortpixel.notice img{display:inline-block;margin:0 25px 0 0;max-height:50px}.shortpixel.notice .notice-dismiss{margin-top:10px}.view-notice{box-shadow:0 1px 1px 0 rgba(0,0,0,0.1);border:4px solid #fff;padding:1px 12px}.view-notice p{margin:1em 0 !important}.view-notice.warning{border-left-color:#ffb900}.view-notice-row{display:none}
 
class/controller/adminnotices_controller.php CHANGED
@@ -85,13 +85,18 @@ class adminNoticesController extends ShortPixelController
85
  $this->doUnlistedNotices();
86
  $this->doQuotaNotices();
87
 
88
- //$this->doIntegrationNotices();
 
89
  }
90
 
91
 
92
  protected function doIntegrationNotices()
93
  {
94
  $settings= \wpSPIO()->settings();
 
 
 
 
95
 
96
  if (\wpSPIO()->env()->has_nextgen && ! $settings->includeNextGen )
97
  {
@@ -229,6 +234,7 @@ class adminNoticesController extends ShortPixelController
229
  $shortpixel->getQuotaInformation();
230
  }
231
 
 
232
  /** Comment for historical reasons, this seems strange in the original, excluding.
233
  * isset($this->_settings->currentStats['optimizePdfs'])
234
  * && $this->_settings->currentStats['optimizePdfs'] == $this->_settings->optimizePdfs )
@@ -272,6 +278,9 @@ class adminNoticesController extends ShortPixelController
272
  $message = $this->getQuotaExceededMessage($quotaData);
273
  $notice = Notices::addError($message);
274
  Notices::makePersistent($notice, self::MSG_QUOTA_REACHED, WEEK_IN_SECONDS);
 
 
 
275
  }
276
 
277
  }
@@ -342,7 +351,6 @@ class adminNoticesController extends ShortPixelController
342
  protected function getQuotaExceededMessage($quotaData)
343
  {
344
  $averageCompression = \wpSPIO()->getShortPixel()->getAverageCompression();
345
- $recheck = isset($_GET['checkquota']) ? true : false;
346
  \wpSPIO()->loadModel('apikey');
347
 
348
  $keyModel = new apiKeyModel();
@@ -381,6 +389,8 @@ class adminNoticesController extends ShortPixelController
381
 
382
  $message .= '<h3>' . __('Quota Exceeded','shortpixel-image-optimiser') . '</h3>';
383
 
 
 
384
  if($recheck) {
385
  $message .= '<p style="color: red">' . __('You have no available image credits. If you just bought a package, please note that sometimes it takes a few minutes for the payment confirmation to be sent to us by the payment processor.','shortpixel-image-optimiser') . '</p>';
386
  }
85
  $this->doUnlistedNotices();
86
  $this->doQuotaNotices();
87
 
88
+
89
+ $this->doIntegrationNotices();
90
  }
91
 
92
 
93
  protected function doIntegrationNotices()
94
  {
95
  $settings= \wpSPIO()->settings();
96
+ if (! \wpSPIO()->settings()->verifiedKey)
97
+ {
98
+ return; // no key, no integrations.
99
+ }
100
 
101
  if (\wpSPIO()->env()->has_nextgen && ! $settings->includeNextGen )
102
  {
234
  $shortpixel->getQuotaInformation();
235
  }
236
 
237
+
238
  /** Comment for historical reasons, this seems strange in the original, excluding.
239
  * isset($this->_settings->currentStats['optimizePdfs'])
240
  * && $this->_settings->currentStats['optimizePdfs'] == $this->_settings->optimizePdfs )
278
  $message = $this->getQuotaExceededMessage($quotaData);
279
  $notice = Notices::addError($message);
280
  Notices::makePersistent($notice, self::MSG_QUOTA_REACHED, WEEK_IN_SECONDS);
281
+
282
+ Notices::removeNoticeByID(self::MSG_UPGRADE_MONTH); // get rid of doubles. reset
283
+ Notices::removeNoticeByID(self::MSG_UPGRADE_BULK);
284
  }
285
 
286
  }
351
  protected function getQuotaExceededMessage($quotaData)
352
  {
353
  $averageCompression = \wpSPIO()->getShortPixel()->getAverageCompression();
 
354
  \wpSPIO()->loadModel('apikey');
355
 
356
  $keyModel = new apiKeyModel();
389
 
390
  $message .= '<h3>' . __('Quota Exceeded','shortpixel-image-optimiser') . '</h3>';
391
 
392
+ $recheck = isset($_GET['checkquota']) ? true : false;
393
+
394
  if($recheck) {
395
  $message .= '<p style="color: red">' . __('You have no available image credits. If you just bought a package, please note that sometimes it takes a few minutes for the payment confirmation to be sent to us by the payment processor.','shortpixel-image-optimiser') . '</p>';
396
  }
class/controller/bulk-restore-all.php CHANGED
@@ -5,6 +5,7 @@ class BulkRestoreAll extends ShortPixelController
5
  {
6
  protected static $slug = 'bulk-restore-all';
7
  protected $template = 'view-restore-all';
 
8
 
9
  protected $selected_folders = array();
10
 
@@ -37,10 +38,11 @@ class BulkRestoreAll extends ShortPixelController
37
  public function getCustomFolders()
38
  {
39
  //wpshortPixel::refreshCustomFolders();
40
- $spMetaDao = $this->shortPixel->getSpMetaDao();
41
- $customFolders = $spMetaDao->getFolders();
 
42
 
43
- return $customFolders;
44
 
45
  }
46
 
@@ -49,7 +51,6 @@ class BulkRestoreAll extends ShortPixelController
49
  if (isset($post['selected_folders']))
50
  {
51
  $folders = array_filter($post['selected_folders'], 'intval');
52
- // var_dump($post['selected_folders']);
53
  if (count($folders) > 0)
54
  {
55
  $this->selected_folders = $folders;
@@ -68,7 +69,7 @@ class BulkRestoreAll extends ShortPixelController
68
  // handle the custom folders if there are any.
69
  if (count($this->selected_folders) > 0)
70
  {
71
- $spMetaDao = $this->shortPixel->getSpMetaDao();
72
 
73
  foreach($this->selected_folders as $folder_id)
74
  {
5
  {
6
  protected static $slug = 'bulk-restore-all';
7
  protected $template = 'view-restore-all';
8
+ protected $form_action = 'bulk-restore-all';
9
 
10
  protected $selected_folders = array();
11
 
38
  public function getCustomFolders()
39
  {
40
  //wpshortPixel::refreshCustomFolders();
41
+ //$spMetaDao = $this->shortPixel->getSpMetaDao();
42
+ //$customFolders = $spMetaDao->getFolders();
43
+ $otherMedia = new OtherMediaController();
44
 
45
+ return $otherMedia->getAllFolders();
46
 
47
  }
48
 
51
  if (isset($post['selected_folders']))
52
  {
53
  $folders = array_filter($post['selected_folders'], 'intval');
 
54
  if (count($folders) > 0)
55
  {
56
  $this->selected_folders = $folders;
69
  // handle the custom folders if there are any.
70
  if (count($this->selected_folders) > 0)
71
  {
72
+ $spMetaDao = \wpSPIO()->getShortPixel()->getSpMetaDao();
73
 
74
  foreach($this->selected_folders as $folder_id)
75
  {
class/controller/cache_controller.php CHANGED
@@ -21,6 +21,7 @@ class CacheController extends ShortPixelController
21
  $cache = $this->getItem($name);
22
  $cache->setValue($value);
23
  $cache->setExpires($expires);
 
24
  $cache->save();
25
  $cache = apply_filters('shortpixel/cache/save', $cache, $name);
26
  self::$cached_items[$name] = $cache;
@@ -34,8 +35,9 @@ class CacheController extends ShortPixelController
34
  */
35
  public function storeItemObject(CacheModel $cache)
36
  {
37
- self::$cached_items[$cache->getName()] = $cache;
38
- $cache->save();
 
39
  }
40
 
41
  public function getItem($name)
@@ -58,8 +60,11 @@ class CacheController extends ShortPixelController
58
  {
59
  $cache->delete();
60
  }
 
61
 
62
-
 
 
63
  }
64
 
65
  }
21
  $cache = $this->getItem($name);
22
  $cache->setValue($value);
23
  $cache->setExpires($expires);
24
+
25
  $cache->save();
26
  $cache = apply_filters('shortpixel/cache/save', $cache, $name);
27
  self::$cached_items[$name] = $cache;
35
  */
36
  public function storeItemObject(CacheModel $cache)
37
  {
38
+ self::$cached_items[$cache->getName()] = $cache;
39
+ $cache->save();
40
+
41
  }
42
 
43
  public function getItem($name)
60
  {
61
  $cache->delete();
62
  }
63
+ }
64
 
65
+ public function deleteItemObject(CacheModel $cache)
66
+ {
67
+ $cache->delete();
68
  }
69
 
70
  }
class/controller/controller.php CHANGED
@@ -8,16 +8,20 @@ class ShortPixelController
8
 
9
  protected $shortPixel;
10
 
11
- protected $model;
12
  protected $template = null; // template name to include when loading.
 
13
  protected $data = array(); // data array for usage with databases data and such
14
  protected $postData = array(); // data coming from form posts.
 
15
  protected $mapper; // Mapper is array of View Name => Model Name. Convert between the two
16
- protected $is_form_submit = false;
 
17
  protected $view; // object to use in the view.
18
  protected $url; // if controller is home to a page, sets the URL here. For redirects and what not.
19
 
20
  protected $form_action = 'sp-action';
 
21
 
22
  public static function init()
23
  {
@@ -52,6 +56,7 @@ class ShortPixelController
52
  $this->view->notices = null; // Notices of class notice, for everything noticable
53
  $this->view->data = null; // Data(base), to separate from regular view data
54
 
 
55
 
56
  }
57
 
@@ -65,7 +70,7 @@ class ShortPixelController
65
 
66
  if (! isset($_POST['sp-nonce']) || ! wp_verify_nonce( $_POST['sp-nonce'], $this->form_action))
67
  {
68
- Log::addInfo('Check Post fails nonce check' . $this->form_action, array($_POST) );
69
  return false;
70
  }
71
  else if (isset($_POST) && count($_POST) > 0)
@@ -90,7 +95,7 @@ class ShortPixelController
90
 
91
  /** Loads a view
92
  *
93
- *
94
  */
95
  public function loadView($template = null)
96
  {
@@ -125,7 +130,7 @@ class ShortPixelController
125
  * @param string $name Name of the model
126
  */
127
  protected function loadModel($name){
128
- return wpSPIO()->loadModel($name);
129
  }
130
 
131
 
@@ -166,9 +171,18 @@ class ShortPixelController
166
 
167
  }
168
 
 
169
  public function setControllerURL($url)
170
  {
171
  $this->url = $url;
172
  }
173
 
 
 
 
 
 
 
 
 
174
  } // controller
8
 
9
  protected $shortPixel;
10
 
11
+ protected $model; // connected model to load.
12
  protected $template = null; // template name to include when loading.
13
+
14
  protected $data = array(); // data array for usage with databases data and such
15
  protected $postData = array(); // data coming from form posts.
16
+
17
  protected $mapper; // Mapper is array of View Name => Model Name. Convert between the two
18
+ protected $is_form_submit = false; // Was the form submitted?
19
+
20
  protected $view; // object to use in the view.
21
  protected $url; // if controller is home to a page, sets the URL here. For redirects and what not.
22
 
23
  protected $form_action = 'sp-action';
24
+ protected $userIsAllowed = false;
25
 
26
  public static function init()
27
  {
56
  $this->view->notices = null; // Notices of class notice, for everything noticable
57
  $this->view->data = null; // Data(base), to separate from regular view data
58
 
59
+ $this->userisAllowed = $this->checkUserPrivileges();
60
 
61
  }
62
 
70
 
71
  if (! isset($_POST['sp-nonce']) || ! wp_verify_nonce( $_POST['sp-nonce'], $this->form_action))
72
  {
73
+ Log::addInfo('Check Post fails nonce check, action : ' . $this->form_action, array($_POST) );
74
  return false;
75
  }
76
  else if (isset($_POST) && count($_POST) > 0)
95
 
96
  /** Loads a view
97
  *
98
+ * @param String View Template in view directory to load. When empty will search for class attribute
99
  */
100
  public function loadView($template = null)
101
  {
130
  * @param string $name Name of the model
131
  */
132
  protected function loadModel($name){
133
+ return \wpSPIO()->loadModel($name);
134
  }
135
 
136
 
171
 
172
  }
173
 
174
+ /** Sets the URL of the admin page */
175
  public function setControllerURL($url)
176
  {
177
  $this->url = $url;
178
  }
179
 
180
+ protected function checkUserPrivileges()
181
+ {
182
+ if ((current_user_can( 'manage_options' ) || current_user_can( 'upload_files' ) || current_user_can( 'edit_posts' )))
183
+ return true;
184
+
185
+ return false;
186
+ }
187
+
188
  } // controller
class/controller/debug.php DELETED
@@ -1,266 +0,0 @@
1
- <?php
2
- namespace ShortPixel;
3
-
4
- /*** Logger class
5
- *
6
- * Class uses the debug data model for keeping log entries.
7
- */
8
- class ShortPixelLogger extends shortPixelController
9
- {
10
- static protected $instance = null;
11
- protected $start_time;
12
-
13
- protected $is_active = false;
14
- protected $is_manual_request = false;
15
- protected $show_debug_view = false;
16
-
17
- protected $items = array();
18
- protected $logPath = false;
19
- protected $logMode = FILE_APPEND;
20
-
21
- protected $logLevel;
22
- protected $format = "[ %%time%% ] %%color%% %%level%% %%color_end%% \t %%message%% \t %%caller%% ( %%time_passed%% )";
23
- protected $format_data = "\t %%data%% ";
24
-
25
- /* protected $hooks = array(
26
- 'shortpixel_image_exists' => array('numargs' => 3),
27
- 'shortpixel_webp_image_base' => array('numargs' => 2),
28
- 'shortpixel_image_urls' => array('numargs' => 2),
29
- ); // @todo monitor hooks, but this should be more dynamic. Do when moving to module via config.
30
- */
31
- protected $hooks = array();
32
-
33
- protected $template = 'view-debug-box';
34
-
35
- /** Debugger constructor
36
- * Two ways to activate the debugger. 1) Define SHORTPIXEL_DEBUG in wp-config.php. Either must be true or a number corresponding to required LogLevel
37
- * 2) Put SHORTPIXEL_DEBUG in the request. Either true or number.
38
- */
39
- public function __construct()
40
- {
41
- $this->start_time = microtime(true);
42
- $this->logLevel = DebugItem::LEVEL_WARN;
43
-
44
- if (isset($_REQUEST['SHORTPIXEL_DEBUG'])) // manual takes precedence over constants
45
- {
46
- $this->is_manual_request = true;
47
- $this->is_active = true;
48
-
49
- if ($_REQUEST['SHORTPIXEL_DEBUG'] === 'true')
50
- {
51
- $this->logLevel = DebugItem::LEVEL_INFO;
52
- }
53
- else {
54
- $this->logLevel = intval($_REQUEST['SHORTPIXEL_DEBUG']);
55
- }
56
-
57
- }
58
- else if ( (defined('SHORTPIXEL_DEBUG') && SHORTPIXEL_DEBUG > 0) )
59
- {
60
- $this->is_active = true;
61
- if (SHORTPIXEL_DEBUG === true)
62
- $this->logLevel = DebugItem::LEVEL_INFO;
63
- else {
64
- $this->logLevel = intval(SHORTPIXEL_DEBUG);
65
- }
66
- }
67
-
68
- if (defined('SHORTPIXEL_DEBUG_TARGET') && SHORTPIXEL_DEBUG_TARGET || $this->is_manual_request)
69
- {
70
- $this->logPath = SHORTPIXEL_BACKUP_FOLDER . "/shortpixel_log";
71
- //$this->logMode = defined('SHORTPIXEL_LOG_OVERWRITE') ? 0 : FILE_APPEND;
72
- if (defined('SHORTPIXEL_LOG_OVERWRITE')) // if overwrite, do this on init once.
73
- file_put_contents($this->logPath,'-- Log Reset -- ' .PHP_EOL);
74
-
75
- }
76
-
77
- $user_is_administrator = (current_user_can('manage_options')) ? true : false;
78
-
79
- if ($this->is_active && $this->is_manual_request && $user_is_administrator )
80
- {
81
- $this->layout = new \stdClass;
82
- $this->layout->logLink = SHORTPIXEL_BACKUP_URL . "/shortpixel_log";
83
-
84
- add_action('admin_footer', array($this, 'loadView'));
85
- }
86
-
87
- if ($this->is_active && count($this->hooks) > 0)
88
- $this->monitorHooks();
89
- }
90
-
91
- public static function getInstance()
92
- {
93
- if ( self::$instance === null)
94
- {
95
- self::$instance = new ShortPixelLogger();
96
- }
97
- return self::$instance;
98
- }
99
-
100
- protected static function addLog($message, $level, $data = array())
101
- {
102
- $log = self::getInstance();
103
-
104
- // don't log anything too low.
105
- if ($log->logLevel < $level)
106
- {
107
- return;
108
- }
109
-
110
- $arg = array();
111
- $args['level'] = $level;
112
- $args['data'] = $data;
113
-
114
- $newItem = new \ShortPixel\DebugItem($message, $args);
115
- $log->items[] = $newItem;
116
-
117
- if ($log->is_active)
118
- {
119
- $log->write($newItem);
120
- }
121
- }
122
-
123
- /** Writes to log File. */
124
- protected function write($debugItem, $mode = 'file')
125
- {
126
- $items = $debugItem->getForFormat();
127
- $items['time_passed'] = round ( ($items['time'] - $this->start_time), 5);
128
- $items['time'] = date('Y-m-d H:i:s', $items['time'] );
129
-
130
- if ( ($items['caller']) && is_array($items['caller']) && count($items['caller']) > 0)
131
- {
132
- $caller = $items['caller'];
133
- $items['caller'] = $caller['file'] . ' in ' . $caller['function'] . '(' . $caller['line'] . ')';
134
- }
135
-
136
- $line = $this->formatLine($items);
137
-
138
- if ($this->logPath)
139
- {
140
- file_put_contents($this->logPath,$line, FILE_APPEND);
141
- }
142
- else {
143
- error_log($line);
144
- }
145
- }
146
-
147
- protected function formatLine($args = array() )
148
- {
149
- $line= $this->format;
150
- foreach($args as $key => $value)
151
- {
152
- if (! is_array($value) && ! is_object($value))
153
- $line = str_replace('%%' . $key . '%%', $value, $line);
154
- }
155
-
156
- $line .= PHP_EOL;
157
-
158
- if (isset($args['data']))
159
- {
160
- $data = array_filter($args['data']);
161
- if (count($data) > 0)
162
- {
163
- foreach($data as $item)
164
- {
165
- $line .= $item . PHP_EOL;
166
- }
167
- }
168
- }
169
-
170
- return $line;
171
- }
172
-
173
- protected function setLogLevel($level)
174
- {
175
- $this->logLevel = $level;
176
- }
177
-
178
- protected function getEnv($name)
179
- {
180
- if (isset($this->{$name}))
181
- {
182
- return $this->{$name};
183
- }
184
- else {
185
- return false;
186
- }
187
- }
188
-
189
- public static function addError($message, $args = array())
190
- {
191
- $level = DebugItem::LEVEL_ERROR;
192
- static::addLog($message, $level, $args);
193
- }
194
- public static function addWarn($message, $args = array())
195
- {
196
- $level = DebugItem::LEVEL_WARN;
197
- static::addLog($message, $level, $args);
198
- }
199
- public static function addInfo($message, $args = array())
200
- {
201
- $level = DebugItem::LEVEL_INFO;
202
- static::addLog($message, $level, $args);
203
- }
204
- public static function addDebug($message, $args = array())
205
- {
206
- $level = DebugItem::LEVEL_DEBUG;
207
- static::addLog($message, $level, $args);
208
- }
209
-
210
- public static function logLevel($level)
211
- {
212
- $log = self::getInstance();
213
- static::addInfo('Changing Log level' . $level);
214
- $log->setLogLevel($level);
215
- }
216
-
217
- public static function getLogLevel()
218
- {
219
- $log = self::getInstance();
220
- return $log->getEnv('logLevel');
221
- }
222
-
223
- public static function isManualDebug()
224
- {
225
- $log = self::getInstance();
226
- return $log->getEnv('is_manual_request');
227
- }
228
-
229
- public static function getLogPath()
230
- {
231
- $log = self::getInstance();
232
- return $log->getEnv('logPath');
233
- }
234
-
235
- /** Function to test if the debugger is active
236
- * @return boolean true when active.
237
- */
238
- public static function debugIsActive()
239
- {
240
- $log = self::getInstance();
241
- return $log->getEnv('is_active');
242
- }
243
-
244
- protected function monitorHooks()
245
- {
246
-
247
- foreach($this->hooks as $hook => $data)
248
- {
249
- $numargs = isset($data['numargs']) ? $data['numargs'] : 1;
250
- $prio = isset($data['priority']) ? $data['priority'] : 10;
251
-
252
- add_filter($hook, function($value) use ($hook) {
253
- $args = func_get_args();
254
- return $this->logHook($hook, $value, $args); }, $prio, $numargs);
255
- }
256
- }
257
-
258
- public function logHook($hook, $value, $args)
259
- {
260
- array_shift($args);
261
- self::addInfo('[Hook] - ' . $hook . ' with ' . var_export($value,true), $args);
262
- return $value;
263
- }
264
-
265
-
266
- } // class debugController
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
class/controller/edit_media_controller.php CHANGED
@@ -10,7 +10,7 @@ class editMediaController extends ShortPixelController
10
  protected $model = 'image';
11
 
12
  private $post_id;
13
- private $actions_allowed;
14
 
15
  private $legacyViewObj;
16
 
@@ -39,7 +39,7 @@ class editMediaController extends ShortPixelController
39
  $this->view->id = $post_id;
40
  $this->view->status_message = null;
41
 
42
- $this->actions_allowed = $this->checkUserPrivileges();
43
 
44
  $this->view->status_message = $this->getStatusMessage();
45
  $this->view->actions = $this->getActions();
@@ -85,7 +85,7 @@ class editMediaController extends ShortPixelController
85
  protected function getActions()
86
  {
87
  $actions = array();
88
- if (! $this->actions_allowed)
89
  return $actions;
90
 
91
  switch($this->data['status'])
@@ -257,7 +257,7 @@ class editMediaController extends ShortPixelController
257
  $debugInfo[] = array('', __('Thumbnails were not generated', 'shortpixel-image-optimiser'));
258
  }
259
  else
260
- {
261
  foreach($meta['sizes'] as $size => $data)
262
  {
263
  $display_size = ucfirst(str_replace("_", " ", $size));
@@ -271,7 +271,6 @@ class editMediaController extends ShortPixelController
271
 
272
  protected function renderLegacyCell()
273
  {
274
-
275
  $data = $this->data;
276
 
277
  if ( $data['status'] != 'pdfOptimized' && $data['status'] != 'imgOptimized')
@@ -281,12 +280,4 @@ class editMediaController extends ShortPixelController
281
  $data['backup'], $data['type'], $data['invType'], '');
282
  }
283
 
284
- private function checkUserPrivileges()
285
- {
286
- if ((current_user_can( 'manage_options' ) || current_user_can( 'upload_files' ) || current_user_can( 'edit_posts' )))
287
- return true;
288
-
289
- return false;
290
- }
291
-
292
  } // controller .
10
  protected $model = 'image';
11
 
12
  private $post_id;
13
+ // private $actions_allowed;
14
 
15
  private $legacyViewObj;
16
 
39
  $this->view->id = $post_id;
40
  $this->view->status_message = null;
41
 
42
+ // $this->actions_allowed = $this->checkUserPrivileges();
43
 
44
  $this->view->status_message = $this->getStatusMessage();
45
  $this->view->actions = $this->getActions();
85
  protected function getActions()
86
  {
87
  $actions = array();
88
+ if (! $this->userIsAllowed)
89
  return $actions;
90
 
91
  switch($this->data['status'])
257
  $debugInfo[] = array('', __('Thumbnails were not generated', 'shortpixel-image-optimiser'));
258
  }
259
  else
260
+ {
261
  foreach($meta['sizes'] as $size => $data)
262
  {
263
  $display_size = ucfirst(str_replace("_", " ", $size));
271
 
272
  protected function renderLegacyCell()
273
  {
 
274
  $data = $this->data;
275
 
276
  if ( $data['status'] != 'pdfOptimized' && $data['status'] != 'imgOptimized')
280
  $data['backup'], $data['type'], $data['invType'], '');
281
  }
282
 
 
 
 
 
 
 
 
 
283
  } // controller .
class/controller/filesystem_controller.php CHANGED
@@ -103,7 +103,6 @@ Class FileSystemController extends ShortPixelController
103
  {
104
  if(\wpSPIO()->env()->is_mainsite) {
105
  $path = get_home_path();
106
-
107
  } else {
108
  $up = wp_upload_dir();
109
  $path = realpath($up['basedir']);
@@ -116,6 +115,14 @@ Class FileSystemController extends ShortPixelController
116
 
117
  }
118
 
 
 
 
 
 
 
 
 
119
  /** Not in use yet, do not use. Future replacement. */
120
  public function createBackUpFolder($folder = SHORTPIXEL_BACKUP_FOLDER)
121
  {
103
  {
104
  if(\wpSPIO()->env()->is_mainsite) {
105
  $path = get_home_path();
 
106
  } else {
107
  $up = wp_upload_dir();
108
  $path = realpath($up['basedir']);
115
 
116
  }
117
 
118
+ public function getWPUploadBase()
119
+ {
120
+ $upload_dir = wp_upload_dir(null, false);
121
+
122
+ return $this->getDirectory($upload_dir['basedir']);
123
+
124
+ }
125
+
126
  /** Not in use yet, do not use. Future replacement. */
127
  public function createBackUpFolder($folder = SHORTPIXEL_BACKUP_FOLDER)
128
  {
class/controller/notice.php DELETED
@@ -1,134 +0,0 @@
1
- <?php
2
- namespace ShortPixel;
3
- use ShortPixel\ShortPixelLogger as Log;
4
-
5
- class NoticeController extends ShortPixelController
6
- {
7
- protected static $notices;
8
- protected static $instance = null;
9
- public $notice_count = 0;
10
-
11
- protected $has_stored = false;
12
-
13
- public function __construct()
14
- {
15
- $this->loadModel('notice');
16
- $this->loadNotices();
17
- }
18
-
19
-
20
- protected function loadNotices()
21
- {
22
- $notices = get_option('shortpixel-notices', false);
23
- $cnotice = (is_array($notices)) ? count($notices) : 0;
24
- Log::addDebug('Notice Control - #num notices' . $cnotice);
25
- if ($notices !== false)
26
- {
27
- self::$notices = $notices;
28
- $this->has_stored = true;
29
- }
30
- else {
31
- self::$notices = array();
32
- $this->has_stored = false;
33
- }
34
- $this->countNotices();
35
- }
36
-
37
- public function addNotice($message, $code)
38
- {
39
- $notice = new NoticeModel($message, $code);
40
- self::$notices[] = $notice;
41
- $this->countNotices();
42
- Log::addDebug('Adding notice - ', $notice);
43
- $this->update();
44
- return $notice;
45
- }
46
-
47
- /** Update the notices to store, check what to remove, returns count. */
48
- public function update()
49
- {
50
- if (! is_array(self::$notices) || count(self::$notices) == 0)
51
- {
52
- if ($this->has_stored)
53
- delete_option('shortpixel-notices');
54
-
55
- return 0;
56
- }
57
-
58
- $new_notices = array();
59
- foreach(self::$notices as $item)
60
- {
61
- if (! $item->isDone() )
62
- {
63
- $new_notices[] = $item;
64
- }
65
- }
66
-
67
- update_option('shortpixel-notices', $new_notices);
68
- self::$notices = $new_notices;
69
-
70
- return $this->countNotices();
71
- }
72
-
73
- public function countNotices()
74
- {
75
- $this->notice_count = count(self::$notices);
76
- return $this->notice_count;
77
- }
78
-
79
-
80
- public function getNotices()
81
- {
82
- return self::$notices;
83
- }
84
-
85
- public static function getInstance()
86
- {
87
- if ( self::$instance === null)
88
- {
89
- self::$instance = new NoticeController();
90
- }
91
-
92
- return self::$instance;
93
- }
94
-
95
- /** Adds a notice, quick and fast method
96
- * @param String $message The Message you want to notify
97
- * @param int $code A value of messageType as defined in model
98
- * @returm Object Instance of noticeModel
99
- */
100
-
101
- public static function addNormal($message)
102
- {
103
- $noticeController = self::getInstance();
104
- $notice = $noticeController->addNotice($message, NoticeModel::NOTICE_NORMAL);
105
- return $notice;
106
-
107
- }
108
-
109
- public static function addError($message)
110
- {
111
- $noticeController = self::getInstance();
112
- $notice = $noticeController->addNotice($message, NoticeModel::NOTICE_ERROR);
113
- return $notice;
114
-
115
- }
116
-
117
- public static function addWarning($message)
118
- {
119
- $noticeController = self::getInstance();
120
- $notice = $noticeController->addNotice($message, NoticeModel::NOTICE_WARNING);
121
- return $notice;
122
-
123
- }
124
-
125
- public static function addSuccess($message)
126
- {
127
- $noticeController = self::getInstance();
128
- $notice = $noticeController->addNotice($message, NoticeModel::NOTICE_SUCCESS);
129
- return $notice;
130
-
131
- }
132
-
133
-
134
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
class/controller/othermedia_controller.php ADDED
@@ -0,0 +1,192 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace ShortPixel;
4
+ use ShortPixel\ShortpixelLogger\ShortPixelLogger as Log;
5
+ use ShortPixel\Notices\NoticeController as Notices;
6
+
7
+ // Future contoller for the edit media metabox view.
8
+ class OtherMediaController extends ShortPixelController
9
+ {
10
+
11
+ // protected $dataProvider; // spmetadao
12
+
13
+ public function __construct()
14
+ {
15
+ parent::__construct();
16
+ // $this->dataProvider = \wpSPIO()->getShortPixel()->getSpMetaDao();
17
+
18
+ $this->loadModel('directory');
19
+ $this->loadModel('directory_othermedia');
20
+
21
+ }
22
+
23
+ // Get CustomFolder for usage.
24
+ public function getAllFolders()
25
+ {
26
+ $folders = DirectoryOtherMediaModel::get();
27
+ return $folders;
28
+ }
29
+
30
+ public function getActiveFolders()
31
+ {
32
+ $folders = DirectoryOtherMediaModel::get(array('remove_hidden' => true));
33
+ return $folders;
34
+
35
+ }
36
+
37
+ public function getFolderByID($id)
38
+ {
39
+ $folders = DirectoryOtherMediaModel::get(array('id' => $id));
40
+
41
+ if (count($folders) > 0)
42
+ return $folders[0];
43
+
44
+ return false;
45
+ }
46
+
47
+ public function getFolderByPath($path)
48
+ {
49
+ $folder = new DirectoryOtherMediaModel($path);
50
+ return $folder;
51
+ }
52
+
53
+
54
+ public function addDirectory($path)
55
+ {
56
+ $fs = \wpSPIO()->filesystem();
57
+ $directory = new DirectoryOtherMediaModel($path);
58
+ $rootDir = $fs->getWPFileBase();
59
+ $backupDir = $fs->getDirectory(SHORTPIXEL_BACKUP_FOLDER);
60
+
61
+ /* if(ShortPixelMetaFacade::isMediaSubfolder($folder->getPath())) {
62
+ return
63
+ } */
64
+
65
+ if (! $directory->exists())
66
+ {
67
+ Notices::addError(__('Could not be added, directory not found: ' . $path ,'shortpixel-image-optimiser'));
68
+ return false;
69
+ }
70
+ elseif (! $directory->isSubFolderOf($rootDir) && $directory->getPath() != $rootDir->getPath() )
71
+ {
72
+ Notices::addError( sprintf(__('The %s folder cannot be processed as it\'s not inside the root path of your website (%s).','shortpixel-image-optimiser'),$addedFolder, $rootDir->getPath()));
73
+ return false;
74
+ }
75
+ elseif($directory->isSubFolderOf($backupDir) || $directory->getPath() == $backupDir->getPath() )
76
+ {
77
+ Notices::addError( __('This folder contains the ShortPixel Backups. Please select a different folder.','shortpixel-image-optimiser'));
78
+ return false;
79
+ }
80
+ elseif( $this->checkIfMediaLibrary($directory) )
81
+ { // ShortPixelMetaFacade::isMediaSubfolder
82
+ Notices::addError(__('This folder contains Media Library images. To optimize Media Library images please go to <a href="upload.php?mode=list">Media Library list view</a> or to <a href="upload.php?page=wp-short-pixel-bulk">ShortPixel Bulk page</a>.','shortpixel-image-optimiser'));
83
+ return false;
84
+ }
85
+ elseif (! $directory->is_writable())
86
+ {
87
+ Notices::addError( sprintf(__('Folder %s is not writeable. Please check permissions and try again.','shortpixel-image-optimiser'),$directory->getPath()) );
88
+ return false;
89
+ }
90
+
91
+
92
+ if (! $directory->hasDBEntry())
93
+ {
94
+ Log::addDebug('Has no DB entry, on addDirectory', $directory);
95
+ if ($directory->save())
96
+ {
97
+ $directory->updateFileContentChange();
98
+ $directory->refreshFolder(0);
99
+ }
100
+ }
101
+ else // if directory is already added, fail silently, but still refresh it.
102
+ {
103
+ if ($directory->isRemoved())
104
+ {
105
+ $directory->setStatus(DirectoryOtherMediaModel::DIRECTORY_STATUS_NORMAL);
106
+ $directory->updateFileContentChange(); // does a save. Dunno if that's wise.
107
+ $directory->refreshFolder(0);
108
+ }
109
+ else
110
+ $directory->refreshFolder();
111
+ }
112
+
113
+ if ($directory->exists() && $directory->getID() > 0)
114
+ return $directory;
115
+ else
116
+ return false;
117
+ }
118
+
119
+ public function refreshFolder(DirectoryOtherMediaModel $directory, $force = false)
120
+ {
121
+ $updated = $directory->updateFileContentChange();
122
+ $update_time = $directory->getUpdated();
123
+ if ($updated || $force)
124
+ {
125
+
126
+ // when forcing, set to never updated.
127
+ if ($force)
128
+ {
129
+ $update_time = 0; // force from begin of times.
130
+ }
131
+
132
+ if ($directory->exists() )
133
+ {
134
+ $directory->refreshFolder($update_time);
135
+ }
136
+ else {
137
+ Log::addWarn('Custom folder does not exist: ', $directory);
138
+ return false;
139
+ }
140
+ }
141
+
142
+ }
143
+
144
+ /** Check directory structure for new files */
145
+ public function refreshFolders($force = false, $expires = 5 * MINUTE_IN_SECONDS)
146
+ {
147
+ $customFolders = $this->getActiveFolders();
148
+
149
+ $cache = new CacheController();
150
+ $refreshDelay = $cache->getItem('othermedia_refresh_folder_delay');
151
+
152
+ if ($refreshDelay->exists() && ! $force)
153
+ {
154
+ return true;
155
+ }
156
+
157
+ $refreshDelay->setExpires($expires);
158
+ $refreshDelay->save();
159
+
160
+
161
+ foreach($customFolders as $directory) {
162
+ if ($force)
163
+ {
164
+ $cache->deleteItemObject($refreshDelay);
165
+ }
166
+
167
+ $this->refreshFolder($directory, $force);
168
+
169
+ } // folders
170
+
171
+ return true;
172
+ }
173
+
174
+ /* Check if this directory is part of the MediaLibrary */
175
+ protected function checkifMediaLibrary(DirectoryModel $directory)
176
+ {
177
+ $fs = \wpSPIO()->filesystem();
178
+ $uploadDir = $fs->getWPUploadBase();
179
+
180
+ // if it's the uploads base dir, the media library would be included, so don't allow.
181
+ if ($directory->getPath() == $uploadDir->getPath() )
182
+ return true;
183
+ elseif (! $directory->isSubFolderOf($uploadDir))// The easy check. No subdir, no problem.
184
+ return false;
185
+ elseif (is_numeric($directory->getName() )) // upload subdirs come in variation of year or month, both numeric.
186
+ return true;
187
+
188
+
189
+ }
190
+
191
+
192
+ }
class/controller/settings.php CHANGED
@@ -95,6 +95,26 @@ class SettingsController extends shortPixelController
95
  $this->doRedirect();
96
  }
97
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
98
  public function action_debug_medialibrary()
99
  {
100
  $this->loadEnv();
@@ -107,9 +127,7 @@ class SettingsController extends shortPixelController
107
 
108
  public function processSave()
109
  {
110
- Log::addDebug('after process postData', $this->postData);
111
  // Split this in the several screens. I.e. settings, advanced, Key Request IF etc.
112
-
113
  if ($this->postData['includeNextGen'] == 1)
114
  {
115
  $nextgen = new NextGen();
@@ -255,37 +273,36 @@ class SettingsController extends shortPixelController
255
 
256
  protected function loadCustomFolders()
257
  {
258
- $notice = null;
259
- $customFolders = $this->shortPixel->refreshCustomFolders();
260
 
261
- if (! is_null($notice))
262
- {
263
- $message = $notice['msg'];
264
- if ($notice['status'] == 'error')
265
- Notice::addError($message);
266
- else
267
- Notice::addNormal($message);
268
 
269
- }
 
270
 
271
  if ($this->has_nextgen)
272
  {
273
- // $ngg = array_map(array('ShortPixelNextGenAdapter','pathToAbsolute'), \ShortPixelNextGenAdapter::getGalleries());
274
  $ng = NextGen::getInstance();
275
- $folders = $ng->getGalleries();
276
  $foldersArray = array();
277
- foreach($folders as $dirObj)
 
278
  {
279
- $foldersArray[] = $dirObj->getPath();
 
280
  }
281
 
282
- foreach($customFolders as $id => $folder)
283
  {
284
  if(in_array($folder->getPath(), $foldersArray )) {
285
- $folder->setType("nextgen");
286
  }
287
  }
288
  }
 
289
  return $customFolders;
290
  }
291
 
@@ -330,32 +347,29 @@ class SettingsController extends shortPixelController
330
  unset($post['validate']);
331
  }
332
 
 
333
  if (isset($post['addCustomFolder']) && strlen($post['addCustomFolder']) > 0)
334
  {
335
- $folder = sanitize_text_field(stripslashes($post['addCustomFolder']));
336
- $uploadPath = realpath(SHORTPIXEL_UPLOADS_BASE);
337
-
338
- $metaDao = $this->shortPixel->getSpMetaDao();
339
- $folderMsg = $metaDao->newFolderFromPath($folder, $uploadPath, \WPShortPixel::getCustomFolderBase());
340
- $is_warning = true;
341
- if(!$folderMsg) {
342
- //$notice = array("status" => "success", "msg" => __('Folder added successfully.','shortpixel-image-optimiser'));
343
- $folderMsg = __('Folder added successfully.','shortpixel-image-optimiser');
344
- $is_warning = false;
345
- }
346
- if ($is_warning)
347
- Notice::addWarning($folderMsg);
348
- else
349
- Notice::addNormal($folderMsg);
350
 
351
- $this->model->hasCustomFolders = time();
 
 
 
 
 
352
  }
353
  unset($post['addCustomFolder']);
354
 
355
- if(isset($post['removeFolder']) && strlen( trim($post['removeFolder'])) > 0) {
356
- $metaDao = $this->shortPixel->getSpMetaDao();
357
- Log::addDebug('Removing folder ' . $post['removeFolder']);
358
- $metaDao->removeFolder( sanitize_text_field($post['removeFolder']) );
 
 
 
 
 
359
 
360
  }
361
  unset($post['removeFolder']);
95
  $this->doRedirect();
96
  }
97
 
98
+ /* Custom Media, refresh a single Folder */
99
+ public function action_refreshfolder()
100
+ {
101
+ $folder_id = isset($_REQUEST['folder_id']) ? intval($_REQUEST['folder_id']) : false;
102
+
103
+ if ($folder_id)
104
+ {
105
+ $otherMediaController = new OtherMediaController();
106
+ $folder = $otherMediaController->getFolderByID($folder_id);
107
+
108
+ if ($folder)
109
+ {
110
+ $otherMediaController->refreshFolder($folder, true);
111
+ }
112
+
113
+ }
114
+
115
+ $this->load();
116
+ }
117
+
118
  public function action_debug_medialibrary()
119
  {
120
  $this->loadEnv();
127
 
128
  public function processSave()
129
  {
 
130
  // Split this in the several screens. I.e. settings, advanced, Key Request IF etc.
 
131
  if ($this->postData['includeNextGen'] == 1)
132
  {
133
  $nextgen = new NextGen();
273
 
274
  protected function loadCustomFolders()
275
  {
276
+
277
+ $otherMedia = new OtherMediaController();
278
 
279
+ $otherMedia->refreshFolders();
280
+ $customFolders = $otherMedia->getActiveFolders();
281
+ $fs = \wpSPIO()->filesystem();
 
 
 
 
282
 
283
+ $customFolderBase = $fs->getWPFileBase();
284
+ $this->view->customFolderBase = $customFolderBase->getPath();
285
 
286
  if ($this->has_nextgen)
287
  {
 
288
  $ng = NextGen::getInstance();
289
+ $NGfolders = $ng->getGalleries();
290
  $foldersArray = array();
291
+
292
+ foreach($NGfolders as $folder)
293
  {
294
+ $fsFolder = $fs->getDirectory($folder->getPath());
295
+ $foldersArray[] = $fsFolder->getPath();
296
  }
297
 
298
+ foreach($customFolders as $index => $folder)
299
  {
300
  if(in_array($folder->getPath(), $foldersArray )) {
301
+ $folder->setNextGen(true);
302
  }
303
  }
304
  }
305
+
306
  return $customFolders;
307
  }
308
 
347
  unset($post['validate']);
348
  }
349
 
350
+ // when adding a new custom folder
351
  if (isset($post['addCustomFolder']) && strlen($post['addCustomFolder']) > 0)
352
  {
353
+ $folderpath = sanitize_text_field(stripslashes($post['addCustomFolder']));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
354
 
355
+ $otherMedia = new OtherMediaController();
356
+ $result = $otherMedia->addDirectory($folderpath);
357
+ if ($result)
358
+ {
359
+ Notice::addSuccess(__('Folder added successfully.','shortpixel-image-optimiser'));
360
+ }
361
  }
362
  unset($post['addCustomFolder']);
363
 
364
+ if(isset($post['removeFolder']) && intval($post['removeFolder']) > 0) {
365
+ //$metaDao = $this->shortPixel->getSpMetaDao();
366
+ $folder_id = intval($post['removeFolder']);
367
+ $otherMedia = new OtherMediaController();
368
+ $folder = $otherMedia->getFolderByID($folder_id);
369
+
370
+ // Log::addDebug('Removing folder ' . $post['removeFolder']);
371
+ $folder->delete();
372
+ //$metaDao->removeFolder( sanitize_text_field($post['removeFolder']) );
373
 
374
  }
375
  unset($post['removeFolder']);
class/controller/views/othermedia_view_controller.php ADDED
@@ -0,0 +1,695 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace ShortPixel;
3
+ use ShortPixel\ShortpixelLogger\ShortPixelLogger as Log;
4
+ use ShortPixel\Notices\NoticeController as Notices;
5
+
6
+
7
+ // Future contoller for the edit media metabox view.
8
+ class OtherMediaViewController extends ShortPixelController
9
+ {
10
+ //$this->model = new
11
+ protected $template = 'view-other-media';
12
+ protected $model = 'image';
13
+
14
+ // Pagination .
15
+ protected $items_per_page = 20;
16
+ protected $currentPage = 1;
17
+ protected $total_items = 0;
18
+ protected $order;
19
+ protected $orderby;
20
+ protected $search;
21
+
22
+ protected $actions = array();
23
+
24
+ public function __construct()
25
+ {
26
+ $this->loadModel($this->model);
27
+ // $this->loadModel('image');
28
+ parent::__construct();
29
+ $this->setActions(); // possible actions.
30
+
31
+ $this->currentPage = isset($_GET['paged']) ? intval($_GET['paged']) : 1;
32
+ $this->total_items = intval($this->record_count());
33
+ $this->orderby = ( ! empty( $_GET['orderby'] ) ) ? $this->filterAllowedOrderBy(sanitize_text_field($_GET['orderby'])) : 'id';
34
+ $this->order = ( ! empty($_GET['order'] ) ) ? sanitize_text_field($_GET['order']) : 'desc'; // If no order, default to asc
35
+ $this->search = (isset($_GET["s"]) && strlen($_GET["s"])) ? sanitize_text_field($_GET['s']) : false;
36
+
37
+ }
38
+
39
+ /** Controller default action - overview */
40
+ public function load()
41
+ {
42
+ $this->process_actions();
43
+
44
+ $this->view->items = $this->getItems();
45
+ $this->view->folders = $this->getItemFolders($this->view->items);
46
+ $this->view->headings = $this->getHeadings();
47
+ $this->view->pagination = $this->getPagination();
48
+ $this->view->filter = $this->getFilter();
49
+
50
+ $this->checkQueue();
51
+ $this->loadView();
52
+ }
53
+
54
+ public function renderNewActions($item_id)
55
+ {
56
+ $item = new \stdClass; // mock class to mimick the records used in the controller
57
+ $item->id = $item_id;
58
+
59
+ $spMetaDao = \wpSPIO()->getShortPixel()->getSpMetaDao();
60
+ $metaModel = $spMetaDao->getMeta($item_id); // returns shortpixelMeta object
61
+ if (is_null($metaModel))
62
+ return '';
63
+
64
+ $item->status = $metaModel->getStatus();
65
+ $item->compression_type = $metaModel->getCompressionType();
66
+
67
+ $fs = \wpSPIO()->filesystem();
68
+ $file = $fs->getFile($metaModel->getPath());
69
+
70
+ $actions = $this->getDisplayActions($this->getActions($item, $file));
71
+
72
+ return $actions;
73
+ }
74
+
75
+ //push to the processing list the pending ones, just in cas
76
+ protected function checkQueue()
77
+ {
78
+ $sp = \wpSPIO()->getShortPixel();
79
+ foreach ($this->view->items as $item) {
80
+ if($item->status == \ShortPixelMeta::FILE_STATUS_PENDING ){
81
+ Log::addDebug('Adding pending files to processing - ' . $item->id);
82
+ $sp->getPrioQ()->push(\ShortPixelMetaFacade::queuedId(\ShortPixelMetaFacade::CUSTOM_TYPE, $item->id));
83
+ }
84
+ }
85
+ }
86
+
87
+
88
+ protected function setActions()
89
+ {
90
+ $nonce = wp_create_nonce( 'sp_custom_action' );
91
+ $actions = array(
92
+ 'optimize' => array('action' => 'optimize', '_wpnonce' => $nonce , 'text' => __('Optimize now','shortpixel-image-optimiser')),
93
+
94
+ 'retry' => array('action' => 'optimize', '_wpnonce' => $nonce, 'text' => __('Retry','shortpixel-image-optimiser')),
95
+
96
+ 'redolossless' => array('action' => 'redo', '_wpnonce' => $nonce, 'type' => 'lossless', 'text' => __('Re-optimize lossless','shortpixel-image-optimiser')),
97
+
98
+ 'redolossy' => array('action' => 'redo', '_wpnonce' => $nonce, 'type' => 'lossy', 'text' => __('Re-optimize lossy','shortpixel-image-optimiser')),
99
+
100
+ 'redoglossy' => array('action' => 'redo', '_wpnonce' => $nonce, 'type' => 'glossy', 'text' => __('Re-optimize glossy','shortpixel-image-optimiser')),
101
+
102
+ 'quota' => array('action' => 'quota', '_wpnonce' => $nonce, 'text' =>__('Check quota','shortpixel-image-optimiser')),
103
+
104
+ 'restore' => array('action' => 'restore', '_wpnonce' => $nonce, 'text' => __('Restore Backup','shortpixel-image-optimiser')),
105
+
106
+ 'compare' => array('link' => '<a href="javascript:ShortPixel.loadComparer(\'C-%%item_id%%\');">%%text%%</a>',
107
+ 'text' => __('Compare', 'shortpixel-image-optimiser')),
108
+ 'view' => array('link' => '<a href="%%item_url%%" target="_blank">%%text%%</a>', 'text' => __('View','shortpixel-image-optimiser')),
109
+ );
110
+ $this->actions = $actions;
111
+ }
112
+
113
+ protected function getHeadings()
114
+ {
115
+ $headings = array(
116
+ 'thumbnails' => array('title' => __('Thumbnails', 'shortpixel-image-optimiser'),
117
+ 'sortable' => false,
118
+ 'orderby' => 'id', // placeholder to allow sort on this.
119
+ ),
120
+ 'name' => array('title' => __('Name', 'shortpixel-image-optimiser'),
121
+ 'sortable' => true,
122
+ 'orderby' => 'name',
123
+ ),
124
+ 'folder' => array('title' => __('Folder', 'shortpixel-image-optimiser'),
125
+ 'sortable' => true,
126
+ 'orderby' => 'path',
127
+ ),
128
+ 'type' => array('title' => __('Type', 'shortpixel-image-optimiser'),
129
+ 'sortable' => false,
130
+ ),
131
+ 'date' => array('title' => __('Date', 'shortpixel-image-optimiser'),
132
+ 'sortable' => true,
133
+ 'orderby' => 'ts_optimized',
134
+ ),
135
+ 'status' => array('title' => __('Status', 'shortpixel-image-optimiser'),
136
+ 'sortable' => true,
137
+ 'orderby' => 'status',
138
+ ),
139
+ 'actions' => array('title' => __('Actions', 'shortpixel-image-optimiser'),
140
+ 'sortable' => false,
141
+ ),
142
+ );
143
+
144
+ return $headings;
145
+ }
146
+
147
+ protected function getItems()
148
+ {
149
+ $spMetaDao = \wpSPIO()->getShortPixel()->getSpMetaDao();
150
+ $fs = \wpSPIO()->filesystem();
151
+ //$total_items =
152
+
153
+ // [BS] Moving this from ts_added since often images get added at the same time, resulting in unpredictable sorting
154
+ $items = $spMetaDao->getPaginatedMetas(\wpSPIO()->env()->has_nextgen, $this->getFilter(), $this->items_per_page, $this->currentPage, $this->orderby, $this->order);
155
+
156
+ $removed = array();
157
+ foreach($items as $index => $item)
158
+ {
159
+ $fsFile = $fs->getFile($item->path);
160
+ if (! $fsFile->exists()) // remove image if it doesn't exist.
161
+ {
162
+ $meta = new \ShortPixelMeta($item);
163
+ $spMetaDao->delete($meta);
164
+ $removed[] = $item->path;
165
+ unset($items[$index]);
166
+ }
167
+ }
168
+
169
+ if (count($removed) > 0)
170
+ {
171
+ Notices::addWarning(sprintf(__('Some images were missing. They have been removed from the Custom Media overview : %s %s'),
172
+ '<BR>', implode('<BR>', $removed)));
173
+ }
174
+
175
+ return $items;
176
+ }
177
+
178
+ protected function getItemFolders($items)
179
+ {
180
+ $folderArray = array();
181
+ $otherMedia = new OtherMediaController();
182
+
183
+ foreach ($items as $item)
184
+ {
185
+ $folder_id = $item->folder_id;
186
+ if (! isset($folderArray[$folder_id]))
187
+ {
188
+ $folderArray[$folder_id] = $otherMedia->getFolderByID($folder_id);
189
+ }
190
+ }
191
+
192
+ return $folderArray;
193
+ }
194
+
195
+ /* Check which folders are in result, and load them. */
196
+ protected function loadFolders($items)
197
+ {
198
+ $folderArray = array();
199
+ $otherMedia = new OtherMediaController();
200
+
201
+ foreach($items as $item)
202
+ {
203
+ $folder_id = $item->folder_id;
204
+ if (! isset($folderArray[$folder_id]))
205
+ {
206
+ $folderArray[$folder_id] = $otherMedia->getFolderByID($folder_id);
207
+ }
208
+ }
209
+
210
+ return $folderArray;
211
+
212
+ }
213
+
214
+ protected function getFilter() {
215
+ $filter = array();
216
+ if(isset($_GET["s"]) && strlen($_GET["s"])) {
217
+ $filter['path'] = (object)array("operator" => "like", "value" =>"'%" . esc_sql($_GET["s"]) . "%'");
218
+ }
219
+ return $filter;
220
+ }
221
+
222
+ protected function record_count() {
223
+ $spMetaDao = \wpSPIO()->getShortPixel()->getSpMetaDao();
224
+ return $spMetaDao->getCustomMetaCount($this->getFilter());
225
+ }
226
+
227
+ protected function process_actions()
228
+ {
229
+
230
+ $nonce = isset($_REQUEST['_wpnonce']) ? esc_attr($_REQUEST['_wpnonce']) : false;
231
+ $redirect_url = esc_url_raw(remove_query_arg(array('action', 'image', '_wpnonce')));
232
+ $action = isset($_REQUEST['action']) ? sanitize_text_field($_REQUEST['action']) : false;
233
+ $item_id = isset($_REQUEST['item_id']) ? intval($_REQUEST['item_id']) : false;
234
+ $this->view->rewriteHREF = '';
235
+
236
+ $otherMediaController = new OtherMediaController();
237
+
238
+ if (! $action)
239
+ return; // no action this view.
240
+
241
+ if (!wp_verify_nonce($nonce, 'sp_custom_action'))
242
+ {
243
+ die('Error. Nonce not verified. Do not call this function directly');
244
+ }
245
+
246
+ if ( $item_id === false && $action && $action != 'refresh')
247
+ {
248
+ exit('Error. No Item_id given');
249
+ }
250
+
251
+ switch ($action)
252
+ {
253
+ case 'optimize':
254
+ $this->shortPixel->optimizeCustomImage($item_id);
255
+ $this->rewriteHREF();
256
+
257
+ break;
258
+ case 'restore':
259
+ if($this->shortPixel->doCustomRestore($item_id))
260
+ {
261
+ Notices::addSuccess(__('File Successfully restored', 'shortpixel-image-optimiser'));
262
+ }
263
+ $this->rewriteHREF();
264
+ break;
265
+ case 'redo':
266
+ $this->shortPixel->redo('C-' . $item_id, sanitize_text_field($_GET['type']));
267
+ $this->rewriteHREF();
268
+
269
+ break;
270
+ case 'refresh':
271
+ $result = $otherMediaController->refreshFolders(true);
272
+ if ($result)
273
+ {
274
+ Notices::addSuccess(__('Other media folders fully refreshed and updated', 'shortpixel-image-optimiser'));
275
+ $this->rewriteHREF();
276
+ }
277
+ break;
278
+ case 'bulk-optimize': // bulk action checkboxes
279
+ $optimize_ids = esc_sql($_POST['bulk-optimize']);
280
+ foreach ($optimize_ids as $id) {
281
+ $this->shortPixel->optimizeCustomImage($id);
282
+ }
283
+ $this->rewriteHREF();
284
+ break;
285
+ }
286
+ }
287
+
288
+ /** This is a workaround for doing wp_redirect when doing an action, which doesn't work due to the route. Long-term fix would be using Ajax for the actions */
289
+ protected function rewriteHREF()
290
+ {
291
+ $rewrite = $this->url; //isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] :
292
+ $this->view->rewriteHREF = '<script language="javascript"> history.pushState(null,null, "' . $rewrite . '"); </script>';
293
+ }
294
+
295
+
296
+ protected function getPageURL($args = array())
297
+ {
298
+ $defaults = array(
299
+ 'orderby' => $this->orderby,
300
+ 'order' => $this->order,
301
+ 's' => $this->search,
302
+ 'paged' => $this->currentPage
303
+ );
304
+
305
+ // Try with controller URL, if not present, try with upload URL and page param.
306
+ $admin_url = admin_url('upload.php');
307
+ $url = (is_null($this->url)) ? add_query_arg('page','wp-short-pixel-custom', $admin_url) : $this->url;
308
+
309
+ $page_args = array_filter(wp_parse_args($args, $defaults));
310
+ return add_query_arg($page_args, $url);
311
+
312
+ }
313
+
314
+ protected function filterAllowedOrderBy($orderby)
315
+ {
316
+ $headings = $this->getHeadings() ;
317
+ $filters = array();
318
+ foreach ($headings as $heading)
319
+ {
320
+ if (isset($heading['orderby']))
321
+ {
322
+ $filters[]= $heading['orderby'];
323
+ }
324
+ }
325
+
326
+ if (! in_array($orderby, $filters))
327
+ return '';
328
+
329
+ return $orderby;
330
+ }
331
+
332
+ protected function getPagination()
333
+ {
334
+ $parray = array();
335
+
336
+ $current = $this->currentPage;
337
+ $total = $this->total_items;
338
+ $per_page = $this->items_per_page;
339
+
340
+ $pages = round($total / $per_page);
341
+
342
+ if ($pages <= 1)
343
+ return ''; // no pages.
344
+
345
+ $disable_first = $disable_last = $disable_prev = $disable_next = false;
346
+ $page_links = array();
347
+
348
+ if ( $current == 1 ) {
349
+ $disable_first = true;
350
+ $disable_prev = true;
351
+ }
352
+ if ( $current == 2 ) {
353
+ $disable_first = true;
354
+ }
355
+ if ( $current == $pages ) {
356
+ $disable_last = true;
357
+ $disable_next = true;
358
+ }
359
+ if ( $current == $pages - 1 ) {
360
+ $disable_last = true;
361
+ }
362
+
363
+ $total_pages_before = '<span class="paging-input">';
364
+ $total_pages_after = '</span></span>';
365
+
366
+ $current_url = remove_query_arg( 'paged', $this->getPageURL());
367
+
368
+ $output = '<form method="GET" action="'. $current_url . '">'; //'<span class="pagination-links">';
369
+ $output .= '<span class="displaying-num">'. sprintf(__('%d Items', 'shortpixel-image-optimiser'), $this->total_items) . '</span>';
370
+
371
+ if ( $disable_first ) {
372
+ $page_links[] = '<span class="tablenav-pages-navspan button disabled" aria-hidden="true">&laquo;</span>';
373
+ } else {
374
+ $page_links[] = sprintf(
375
+ "<a class='first-page button' href='%s'><span class='screen-reader-text'>%s</span><span aria-hidden='true'>%s</span></a>",
376
+ esc_url( $current_url ),
377
+ __( 'First page' ),
378
+ '&laquo;'
379
+ );
380
+ }
381
+
382
+ if ( $disable_prev ) {
383
+ $page_links[] = '<span class="tablenav-pages-navspan button disabled" aria-hidden="true">&lsaquo;</span>';
384
+ } else {
385
+ $page_links[] = sprintf(
386
+ "<a class='prev-page button' href='%s'><span class='screen-reader-text'>%s</span><span aria-hidden='true'>%s</span></a>",
387
+ esc_url( add_query_arg( 'paged', max( 1, $current - 1 ), $current_url ) ),
388
+ __( 'Previous page' ),
389
+ '&lsaquo;'
390
+ );
391
+ }
392
+
393
+ $html_current_page = sprintf(
394
+ "%s<input class='current-page' id='current-page-selector' type='text' name='paged' value='%s' size='%d' aria-describedby='table-paging' /><span class='tablenav-paging-text'>",
395
+ '<label for="current-page-selector" class="screen-reader-text">' . __( 'Current Page' ) . '</label>',
396
+ $current,
397
+ strlen( $pages )
398
+ );
399
+
400
+ $html_total_pages = sprintf( "<span class='total-pages'>%s</span>", number_format_i18n( $pages ) );
401
+ $page_links[] = $total_pages_before . sprintf(
402
+ /* translators: 1: Current page, 2: Total pages. */
403
+ _x( '%1$s of %2$s', 'paging' ),
404
+ $html_current_page,
405
+ $html_total_pages
406
+ ) . $total_pages_after;
407
+
408
+ if ( $disable_next ) {
409
+ $page_links[] = '<span class="tablenav-pages-navspan button disabled" aria-hidden="true">&rsaquo;</span>';
410
+ } else {
411
+ $page_links[] = sprintf(
412
+ "<a class='next-page button' href='%s'><span class='screen-reader-text'>%s</span><span aria-hidden='true'>%s</span></a>",
413
+ esc_url( add_query_arg( 'paged', min( $pages, $current + 1 ), $current_url ) ),
414
+ __( 'Next page' ),
415
+ '&rsaquo;'
416
+ );
417
+ }
418
+
419
+ if ( $disable_last ) {
420
+ $page_links[] = '<span class="tablenav-pages-navspan button disabled" aria-hidden="true">&raquo;</span>';
421
+ } else {
422
+ $page_links[] = sprintf(
423
+ "<a class='last-page button' href='%s'><span class='screen-reader-text'>%s</span><span aria-hidden='true'>%s</span></a>",
424
+ esc_url( add_query_arg( 'paged', $pages, $current_url ) ),
425
+ __( 'Last page' ),
426
+ '&raquo;'
427
+ );
428
+ }
429
+
430
+ $output .= "\n<span class='pagination-links'>" . join( "\n", $page_links ) . '</span>';
431
+ $output .= "</form>";
432
+
433
+
434
+ return $output;
435
+ }
436
+
437
+ /** Actions to list under the Image row */
438
+ protected function getRowActions($item, $file)
439
+ {
440
+ $thisActions = array();
441
+ $thisActions[] = $this->actions['view']; // always .
442
+ $settings = \wpSPIO()->settings();
443
+
444
+ if ($settings->quotaExceeded)
445
+ {
446
+ return $this->renderActions($thisActions, $item, $file); // nothing more.
447
+ }
448
+
449
+ if ($item->status < \ShortPixelMeta::FILE_STATUS_UNPROCESSED)
450
+ {
451
+ $thisActions[] = $this->actions['retry'];
452
+ }
453
+ elseif ($item->status == \ShortPixelMeta::FILE_STATUS_UNPROCESSED || $item->status == \ShortPixelMeta::FILE_STATUS_RESTORED)
454
+ {
455
+ $thisActions[] = $this->actions['optimize'];
456
+ }
457
+
458
+ return $this->renderActions($thisActions, $item, $file);
459
+ }
460
+
461
+ /* Actions to list in the action menu */
462
+ protected function getActions($item, $file)
463
+ {
464
+ $thisActions = array();
465
+ $settings = \wpSPIO()->settings();
466
+
467
+ if ($settings->quotaExceeded)
468
+ {
469
+ $thisActions[] = $this->actions['quota'];
470
+ }
471
+ elseif ($item->status < \ShortPixelMeta::FILE_STATUS_UNPROCESSED)
472
+ {
473
+ $thisActions[] = $this->actions['retry'];
474
+ }
475
+ elseif ($item->status == \ShortPixelMeta::FILE_STATUS_UNPROCESSED || $item->status == \ShortPixelMeta::FILE_STATUS_RESTORED)
476
+ {
477
+ $thisActions[] = $this->actions['optimize'];
478
+ }
479
+ elseif ( intval($item->status) == \ShortPixelMeta::FILE_STATUS_SUCCESS)
480
+ {
481
+ $thisActions[] = $this->actions['compare'];
482
+
483
+ if ($file->hasBackup())
484
+ {
485
+ switch($item->compression_type) {
486
+ case 2:
487
+ $actionsEnabled['redolossy'] = $actionsEnabled['redolossless'] = true;
488
+ $thisActions[] = $this->actions['redolossy'];
489
+ $thisActions[] = $this->actions['redolossless'];
490
+ break;
491
+ case 1:
492
+ $actionsEnabled['redoglossy'] = $actionsEnabled['redolossless'] = true;
493
+ $thisActions[] = $this->actions['redoglossy'];
494
+ $thisActions[] = $this->actions['redolossless'];
495
+ break;
496
+ default:
497
+ $thisActions[] = $this->actions['redolossy'];
498
+ $thisActions[] = $this->actions['redoglossy'];
499
+ break;
500
+ }
501
+ $thisActions[] = $this->actions['restore'];
502
+ }
503
+ }
504
+
505
+ return $this->renderActions($thisActions, $item, $file);
506
+ }
507
+
508
+ protected function renderActions($actions, $item, $file)
509
+ {
510
+
511
+ foreach($actions as $index => $action)
512
+ {
513
+ $text = $action['text'];
514
+
515
+ if (isset($action['link']))
516
+ {
517
+ $fs = \wpSPIO()->filesystem();
518
+ $item_url = $fs->pathToUrl($file);
519
+
520
+ $link = $action['link'];
521
+ $link = str_replace('%%item_id%%', $item->id, $link);
522
+ $link = str_replace('%%text%%', $text, $link);
523
+ $link = str_replace('%%item_url%%', $item_url, $link);
524
+ }
525
+ else
526
+ {
527
+ $action_arg = $action['action']; //
528
+ $nonce = $action['_wpnonce'];
529
+ $url = $this->getPageURL(array('action' => $action_arg, '_wpnonce' => $nonce, 'item_id' => $item->id));
530
+ if (isset($action['type']))
531
+ $url = add_query_arg('type', $action['type'], $url);
532
+
533
+ $link = '<a href="' . $url . '" class="action-' . $action_arg . '">' . $text . '</a>';
534
+ }
535
+
536
+ $actions[$index] = $link;
537
+ }
538
+
539
+ return $actions;
540
+ }
541
+
542
+ protected function renderLegacyCell()
543
+ {
544
+
545
+ $data = $this->data;
546
+
547
+ if ( $data['status'] != 'pdfOptimized' && $data['status'] != 'imgOptimized')
548
+ return null;
549
+
550
+ $this->legacyViewObj->renderListCell($this->post_id, $data['status'], $data['showActions'], $data['thumbsToOptimize'],
551
+ $data['backup'], $data['type'], $data['invType'], '');
552
+ }
553
+
554
+ protected function getDisplayStatus($item)
555
+ {
556
+ switch($item->status) {
557
+ case \ShortPixelMeta::FILE_STATUS_RESTORED:
558
+ $msg = __('Restored','shortpixel-image-optimiser');
559
+ break;
560
+ case \ShortPixelMeta::FILE_STATUS_TORESTORE:
561
+ $msg = __('Restore Pending','shortpixel-image-optimiser');
562
+ break;
563
+ case \ShortPixelMeta::FILE_STATUS_SUCCESS:
564
+ $msg = $this->getSuccessMessage($item);
565
+ break;
566
+ case 1: $msg = "<img src=\"" . wpSPIO()->plugin_url('res/img/loading.gif') . "\" class='sp-loading-small'>&nbsp;"
567
+ . __('Pending','shortpixel-image-optimiser');
568
+ break;
569
+ case 0: $msg = __('Image not processed.','shortpixel-image-optimiser');
570
+ break;
571
+ default:
572
+ if($item->status < 0) {
573
+ $msg = $item->message . "(" . __('code','shortpixel-image-optimiser') . ": " . $item->status . ")";
574
+ } else {
575
+ $msg = "<span style='display:none;'>" . $item->status . "</span>";
576
+ }
577
+ }
578
+ return $msg;
579
+
580
+ }
581
+
582
+ protected function getSuccessMessage($item)
583
+ {
584
+ $msg = '';
585
+
586
+ $amount = intval($item->message);
587
+ if (0 + $amount == 0 || 0 + $amount < 5)
588
+ $msg .= __('Bonus processing','shortpixel-image-optimiser') . ' ';
589
+ else
590
+ $msg .= __('Reduced by','shortpixel-image-optimiser') . " <strong>" . $item->message . "%</strong> ";
591
+
592
+ switch($item->compression_type)
593
+ {
594
+ case \ShortPixelMeta::COMPRESSION_LOSSY:
595
+ $msg .= '(' . __('Lossy', 'shortpixel-image-optimiser') . ')';
596
+ break;
597
+ case \ShortPixelMeta::COMPRESSION_GLOSSY:
598
+ $msg .= '(' . __('Glossy', 'shortpixel-image-optimiser') . ')';
599
+ break;
600
+ case \ShortPixelMeta::COMPRESSION_LOSSLESSS:
601
+ $msg .= '(' . __('Lossless', 'shortpixel-image-optimiser') . ')';
602
+ break;
603
+ }
604
+
605
+ if ($item->resize)
606
+ {
607
+ $msg .= '<br>' . sprintf(__('Resized to %s x %s', 'shortpixel-image-optimiser'), $item->resize_width, $item->resize_height);
608
+ }
609
+ return $msg;
610
+
611
+ }
612
+
613
+ protected function getDisplayHeading($heading)
614
+ {
615
+ $output = '';
616
+ $defaults = array('title' => '', 'sortable' => false);
617
+
618
+ $heading = wp_parse_args($heading, $defaults);
619
+ $title = $heading['title'];
620
+
621
+ if ($heading['sortable'])
622
+ {
623
+ //$current_order = isset($_GET['order']) ? $current_order : false;
624
+ //$current_orderby = isset($_GET['orderby']) ? $current_orderby : false;
625
+
626
+ $sorturl = add_query_arg('orderby', $heading['orderby'] );
627
+ $sorted = '';
628
+
629
+ if ($this->orderby == $heading['orderby'])
630
+ {
631
+ if ($this->order == 'desc')
632
+ {
633
+ $sorturl = add_query_arg('order', 'asc', $sorturl);
634
+ $sorted = 'sorted desc';
635
+ }
636
+ else
637
+ {
638
+ $sorturl = add_query_arg('order', 'desc', $sorturl);
639
+ $sorted = 'sorted asc';
640
+ }
641
+ }
642
+ else
643
+ {
644
+ $sorturl = add_query_arg('order', 'asc', $sorturl);
645
+ }
646
+ $output = '<a href="' . $sorturl . '"><span>' . $title . '</span><span class="sorting-indicator '. $sorted . '">&nbsp;</span></a>';
647
+ }
648
+ else
649
+ {
650
+ $output = $title;
651
+ }
652
+
653
+ return $output;
654
+ }
655
+
656
+ protected function getDisplayDate($item)
657
+ {
658
+ if ($item->ts_optimized > 0)
659
+ $date_string = $item->ts_optimized;
660
+ else
661
+ $date_string = $item->ts_added;
662
+
663
+ $date = new \DateTime($date_string);
664
+
665
+ $display_date = \ShortPixelTools::format_nice_date($date);
666
+
667
+ return $display_date;
668
+ }
669
+
670
+ protected function getDisplayActions($actions)
671
+ {
672
+ if (count($actions) == 0)
673
+ {
674
+ return '';
675
+ }
676
+ elseif (count($actions) == 1)
677
+ {
678
+ return "<div class='single-action button-primary'>" . $actions[0] . "</div>";
679
+ }
680
+ else{
681
+
682
+ $output = "<div class='sp-dropdown'>
683
+ <button onclick='ShortPixel.openImageMenu(event);' class='sp-dropbtn button dashicons dashicons-menu' title='" . __('ShortPixel Actions', 'shortpixel-image-optimiser') . "'></button>
684
+ <div class='sp-dropdown-content'>";
685
+ foreach($actions as $action)
686
+ {
687
+ $output .= $action;
688
+ }
689
+ $output .= "</div></div> <!-- sp-dropdown -->";
690
+ return $output;
691
+ }
692
+ }
693
+
694
+
695
+ }
class/db/shortpixel-custom-meta-dao.php CHANGED
@@ -122,31 +122,53 @@ class ShortPixelCustomMetaDao {
122
  ));
123
  // Set up indexes, not handled well by WP DBDelta
124
  $this->addIfMissing("UNIQUE INDEX", $this->db->getPrefix()."shortpixel_folders", "spf_path_md5", "path_md5");
 
 
125
  $this->addIfMissing("UNIQUE INDEX", $this->db->getPrefix()."shortpixel_meta", "sp_path_md5", "path_md5");
 
126
  $this->addIfMissing("FOREIGN KEY", $this->db->getPrefix()."shortpixel_meta", "fk_shortpixel_meta_folder", "folder_id",
127
  $this->db->getPrefix()."shortpixel_folders", "id");
 
 
128
  }
129
 
130
- public function getFolders($deleted = false) {
131
- $sql = "SELECT * FROM {$this->db->getPrefix()}shortpixel_folders" . ($deleted ? "" : " WHERE status <> -1");
132
  $rows = $this->db->query($sql);
133
  $folders = array();
134
  foreach($rows as $row) {
135
- $folders[$row->id] = new ShortPixelFolder($row, $this->excludePatterns);
136
  }
137
  return $folders;
138
  }
139
 
140
- public function getFolder($path, $deleted = false) {
141
- $sql = "SELECT * FROM {$this->db->getPrefix()}shortpixel_folders" . ($deleted ? "WHERE path = %s " : " WHERE path = %s AND status <> -1");
142
  $rows = $this->db->query($sql, array($path));
143
  $folders = array();
144
  foreach($rows as $row) {
145
- return new ShortPixelFolder($row, $this->excludePatterns);
 
 
146
  }
147
  return false;
148
  }
149
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
150
  public function hasFoldersTable() {
151
  global $wpdb;
152
  $foldersTable = $wpdb->get_results("SELECT COUNT(1) hasFoldersTable FROM information_schema.tables WHERE table_schema='{$wpdb->dbname}' AND table_name='{$wpdb->prefix}shortpixel_folders'");
@@ -161,10 +183,10 @@ class ShortPixelCustomMetaDao {
161
  $path = $folder->getPath();
162
  $tsUpdated = date("Y-m-d H:i:s", $folder->getTsUpdated());
163
 
164
-
165
  return $this->db->insert($this->db->getPrefix().'shortpixel_folders',
166
  array("path" => $path, "path_md5" => md5($path), "file_count" => $fileCount, "ts_updated" => $tsUpdated, "ts_created" => date("Y-m-d H:i:s")),
167
  array("path" => "%s", "path_md5" => "%s", "file_count" => "%d", "ts_updated" => "%s"));
 
168
  }
169
 
170
  public function updateFolder($folder, $newPath, $status = 0, $fileCount = 0) {
@@ -178,12 +200,12 @@ class ShortPixelCustomMetaDao {
178
  else return -1;
179
  }
180
 
181
- public function removeFolder($folderPath) {
182
- $sql = "SELECT id FROM {$this->db->getPrefix()}shortpixel_folders WHERE path = %s";
183
- $row = $this->db->query($sql, array(stripslashes($folderPath)));
184
 
185
- if(!isset($row[0]->id)) return false;
186
- $id = $row[0]->id;
187
  $sql = "UPDATE {$this->db->getPrefix()}shortpixel_folders SET status = -1 WHERE id = %d";
188
  $this->db->query($sql, array($id));
189
 
@@ -192,115 +214,29 @@ class ShortPixelCustomMetaDao {
192
  $sql = "DELETE FROM {$this->db->getPrefix()}shortpixel_meta WHERE folder_id = %d AND status <> %d AND status <> %d";
193
  $this->db->query($sql, array($id, ShortPixelMeta::FILE_STATUS_PENDING, ShortPixelMeta::FILE_STATUS_SUCCESS));
194
 
195
- $sql = "SELECT FROM {$this->db->getPrefix()}shortpixel_meta WHERE folder_id = %d ";
196
  $still_has_images = $this->db->query($sql, array($id));
197
 
198
  // if there are no images left, remove the folder. Otherwise keep it at -1.
199
  if (count($still_has_images) == 0)
200
  {
201
- $sql = "DELETE FROM {$this->db->getPrefix()}shortpixel_folders WHERE path = %s";
202
- $this->db->query($sql, array($folderPath));
203
  }
204
 
205
  //$this->db->restoreErrors();
206
  }
207
 
208
- public function newFolderFromPath($path, $uploadPath, $rootPath) {
209
- WpShortPixelDb::checkCustomTables(); // check if custom tables are created, if not, create them
210
-
211
- $fs = \wpSPIO()->filesystem();
212
-
213
- //$addedFolder = ShortPixelFolder::checkFolder($path, $uploadPath);
214
- $newfolder = $fs->getDirectory($path);
215
- $rootPath = $fs->getWPFileBase();
216
-
217
- if(! $newfolder->exists() ) {
218
- return __('Folder could not be found: ' . $uploadPath . $path ,'shortpixel-image-optimiser');
219
- }
220
-
221
- if (! $newfolder->isSubFolderOf($rootPath))
222
- {
223
- return( sprintf(__('The %s folder cannot be processed as it\'s not inside the root path of your website (%s).','shortpixel-image-optimiser'),$addedFolder, $rootPath));
224
- }
225
-
226
- if($this->getFolder($newfolder->getPath())) {
227
- return __('Folder already added.','shortpixel-image-optimiser');
228
- }
229
-
230
- $folder = new ShortPixelFolder(array("path" => $newfolder->getPath()), $this->excludePatterns);
231
- /* try {
232
- $folder->setFileCount($folder->countFiles());
233
- } catch(ShortPixelFileRightsException $ex) {
234
- return $ex->getMessage();
235
- } */
236
-
237
- if(ShortPixelMetaFacade::isMediaSubfolder($folder->getPath())) {
238
- return __('This folder contains Media Library images. To optimize Media Library images please go to <a href="upload.php?mode=list">Media Library list view</a> or to <a href="upload.php?page=wp-short-pixel-bulk">SortPixel Bulk page</a>.','shortpixel-image-optimiser');
239
- }
240
-
241
- // Set this to 0 on new, not null since mysql will auto-complete that to current TS.
242
- $folder->setTSUpdated(0);
243
- $folder->setFileCount(0);
244
-
245
- $folderMsg = $this->saveFolder($folder);
246
- if(!$folder->getId()) {
247
- //try again creating the tables first.
248
- $this->createUpdateShortPixelTables();
249
- $folderMsg = $this->saveFolder($folder);
250
- //still no luck - complain... :)
251
- if(!$folder->getId()) {
252
- return __('The folder could not be saved to the database. Please check that the plugin can create its database tables.', 'shortpixel-image-optimiser') . $folderMsg;
253
- }
254
- }
255
-
256
- if(!$folderMsg) {
257
- //$fileList = $folder->getFileList();
258
- $this->refreshFolder($newfolder);
259
- }
260
- return $folderMsg;
261
 
262
- }
263
 
264
- /** Check files and add what's needed */
 
265
  public function refreshFolder(ShortPixel\DirectoryModel $folder)
266
  {
267
 
268
- $folderObj = $this->getFolder($folder->getPath());
269
-
270
- if ($folderObj === false)
271
- {
272
- Log::addWarn('FolderObj from database is not there, while folder seems ok ' . $folder->getPath() );
273
- return false;
274
- }
275
-
276
- Log::addDebug('Doing Refresh Folder for (DirectoryModel / ShortpixelFolder) ', array($folder->getPath(), $folderObj->getPath()) );
277
-
278
- $fs = \wpSPIO()->fileSystem();
279
-
280
- if (! $folder->exists())
281
- {
282
- Notice::addError( sprintf(__('Folder %s does not exist! ', 'shortpixel-image-optimiser'), $folder->getPath()) );
283
- return false;
284
- }
285
- if (! $folder->is_writable())
286
- {
287
- Notice::addWarning( sprintf(__('Folder %s is not writeable. Please check permissions and try again.','shortpixel-image-optimiser'),$folder->getPath()) );
288
- }
289
-
290
- $filter = array('date_newer' => strtotime($folderObj->getTsUpdated()));
291
- $files = $fs->getFilesRecursive($folder, $filter);
292
 
293
- $shortpixel = \wpSPIO()->getShortPixel();
294
- // check processable by invoking filter, for now processablepath takes only paths, not objects.
295
- $files = array_filter($files, function($file) use($shortpixel) { return $shortpixel->isProcessablePath($file->getFullPath()); });
296
-
297
- Log::addDebug('Found Files for custom media ' . count($files));
298
- $folderObj->setTsUpdated(date("Y-m-d H:i:s", $folderObj->getFolderContentsChangeDate()) );
299
- $folderObj->setFileCount($folderObj->countFiles() );
300
- $this->update($folderObj);
301
-
302
- $this->batchInsertImages($files, $folderObj->getId());
303
  }
 
304
 
305
  /**
306
  *
@@ -362,7 +298,10 @@ class ShortPixelCustomMetaDao {
362
  return $id;
363
  }
364
 
365
- private function batchInsertImages($files, $folderId) {
 
 
 
366
  //facem un delete pe cele care nu au shortpixel_folder, pentru curatenie - am mai intalnit situatii in care stergerea s-a agatat (stop monitoring)
367
  global $wpdb;
368
 
@@ -420,26 +359,37 @@ class ShortPixelCustomMetaDao {
420
 
421
  public function getPaginatedMetas($hasNextGen, $filters, $count, $page, $orderby = false, $order = false) {
422
  // [BS] Remove exclusion for sm.status <> 3. Status 3 is 'restored, perform no action'
423
- $sql = "SELECT sm.id, sm.name, sm.path folder, "
424
- . ($hasNextGen ? "CASE WHEN ng.gid IS NOT NULL THEN 'NextGen' ELSE 'Custom' END media_type, " : "'Custom' media_type, ")
425
- . "sm.status, sm.compression_type, sm.keep_exif, sm.cmyk2rgb, sm.resize, sm.resize_width, sm.resize_height, sm.message, sm.ts_added, sm.ts_optimized "
 
 
 
426
  . "FROM {$this->db->getPrefix()}shortpixel_meta sm "
427
  . "INNER JOIN {$this->db->getPrefix()}shortpixel_folders sf on sm.folder_id = sf.id "
428
- . ($hasNextGen ? "LEFT JOIN {$this->db->getPrefix()}ngg_gallery ng on sf.path = ng.path " : " ")
429
  . "WHERE sf.status <> -1"; // AND sm.status <> 3
 
 
 
 
 
 
430
  foreach($filters as $field => $value) {
431
  $sql .= " AND sm.$field " . $value->operator . " ". $value->value . " ";
432
  }
433
- $sql .= ($orderby ? " ORDER BY $orderby $order " : "")
434
  . " LIMIT $count OFFSET " . ($page - 1) * $count;
435
- return $this->db->query($sql);
 
 
436
  }
437
 
438
  public function getPendingMetas($count) {
439
- return $this->db->query("SELECT sm.id from {$this->db->getPrefix()}shortpixel_meta sm "
440
- . "INNER JOIN {$this->db->getPrefix()}shortpixel_folders sf on sm.folder_id = sf.id "
441
- . "WHERE sf.status <> -1 AND sm.status <> 3 AND ( sm.status = 0 OR sm.status = 1 OR (sm.status < 0 AND sm.retries < 3)) "
442
- . "ORDER BY sm.id DESC LIMIT $count");
 
443
  }
444
 
445
  public function getFolderOptimizationStatus($folderId) {
@@ -492,7 +442,7 @@ class ShortPixelCustomMetaDao {
492
  }
493
 
494
  $res = $this->db->query($sql);
495
- return isset($res[0]->recCount) ? $res[0]->recCount : 0;
496
  }
497
 
498
  public function getMeta($id, $deleted = false) {
@@ -556,6 +506,7 @@ class ShortPixelCustomMetaDao {
556
  foreach(self::$fields[$tableSuffix] as $field => $type) {
557
  $getter = "get" . ShortPixelTools::snakeToCamel($field);
558
  $val = $meta->$getter();
 
559
  if($meta->$getter() !== null) {
560
  $sql .= " {$field} = %{$type},";
561
  $params[] = $val;
@@ -569,10 +520,111 @@ class ShortPixelCustomMetaDao {
569
  $sql = rtrim($sql, ",");
570
  $sql .= " WHERE id = %d";
571
  $params[] = $meta->getId();
572
- Log::addDebug('Update Custom Meta' . $sql, $params);
573
  $this->db->query($sql, $params);
574
  }
575
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
576
  public function delete($meta) {
577
  $metaClass = get_class($meta);
578
  $tableSuffix = $metaClass::TABLE_SUFFIX;
122
  ));
123
  // Set up indexes, not handled well by WP DBDelta
124
  $this->addIfMissing("UNIQUE INDEX", $this->db->getPrefix()."shortpixel_folders", "spf_path_md5", "path_md5");
125
+ $this->addIfMissing("UNIQUE INDEX", $this->db->getPrefix()."shortpixel_folders", "spf_path", "path");
126
+
127
  $this->addIfMissing("UNIQUE INDEX", $this->db->getPrefix()."shortpixel_meta", "sp_path_md5", "path_md5");
128
+ $this->addIfMissing("UNIQUE INDEX", $this->db->getPrefix()."shortpixel_meta", "sp_path", "path");
129
  $this->addIfMissing("FOREIGN KEY", $this->db->getPrefix()."shortpixel_meta", "fk_shortpixel_meta_folder", "folder_id",
130
  $this->db->getPrefix()."shortpixel_folders", "id");
131
+
132
+
133
  }
134
 
135
+ public function getFolders() {
136
+ $sql = "SELECT * FROM {$this->db->getPrefix()}shortpixel_folders order by path";
137
  $rows = $this->db->query($sql);
138
  $folders = array();
139
  foreach($rows as $row) {
140
+ $folders[$row->id] = $row; //new ShortPixelFolder($row, $this->excludePatterns);
141
  }
142
  return $folders;
143
  }
144
 
145
+ public function getFolder($path) {
146
+ $sql = "SELECT * FROM {$this->db->getPrefix()}shortpixel_folders WHERE path = %s ";
147
  $rows = $this->db->query($sql, array($path));
148
  $folders = array();
149
  foreach($rows as $row) {
150
+ // return new ShortPixelFolder($row, $this->excludePatterns);
151
+ $folders[$row->id] = $row;
152
+ return $folders;
153
  }
154
  return false;
155
  }
156
 
157
+ public function getFolderByID($id)
158
+ {
159
+ $sql = "SELECT * FROM {$this->db->getPrefix()}shortpixel_folders WHERE id = %d ";
160
+ $rows = $this->db->query($sql, array($id));
161
+ $folders = array();
162
+
163
+ foreach($rows as $row) {
164
+ // return new ShortPixelFolder($row, $this->excludePatterns);
165
+ $folders[$row->id] = $row;
166
+ return $folders;
167
+ }
168
+ return false;
169
+
170
+ }
171
+
172
  public function hasFoldersTable() {
173
  global $wpdb;
174
  $foldersTable = $wpdb->get_results("SELECT COUNT(1) hasFoldersTable FROM information_schema.tables WHERE table_schema='{$wpdb->dbname}' AND table_name='{$wpdb->prefix}shortpixel_folders'");
183
  $path = $folder->getPath();
184
  $tsUpdated = date("Y-m-d H:i:s", $folder->getTsUpdated());
185
 
 
186
  return $this->db->insert($this->db->getPrefix().'shortpixel_folders',
187
  array("path" => $path, "path_md5" => md5($path), "file_count" => $fileCount, "ts_updated" => $tsUpdated, "ts_created" => date("Y-m-d H:i:s")),
188
  array("path" => "%s", "path_md5" => "%s", "file_count" => "%d", "ts_updated" => "%s"));
189
+
190
  }
191
 
192
  public function updateFolder($folder, $newPath, $status = 0, $fileCount = 0) {
200
  else return -1;
201
  }
202
 
203
+ public function removeFolder($id) {
204
+ //$sql = "SELECT id FROM {$this->db->getPrefix()}shortpixel_folders WHERE path = %s";
205
+ //$row = $this->db->query($sql, array(stripslashes($folderPath)));
206
 
207
+ //if(!isset($row[0]->id)) return false;
208
+ //$id = $row[0]->id;
209
  $sql = "UPDATE {$this->db->getPrefix()}shortpixel_folders SET status = -1 WHERE id = %d";
210
  $this->db->query($sql, array($id));
211
 
214
  $sql = "DELETE FROM {$this->db->getPrefix()}shortpixel_meta WHERE folder_id = %d AND status <> %d AND status <> %d";
215
  $this->db->query($sql, array($id, ShortPixelMeta::FILE_STATUS_PENDING, ShortPixelMeta::FILE_STATUS_SUCCESS));
216
 
217
+ $sql = "SELECT * FROM {$this->db->getPrefix()}shortpixel_meta WHERE folder_id = %d ";
218
  $still_has_images = $this->db->query($sql, array($id));
219
 
220
  // if there are no images left, remove the folder. Otherwise keep it at -1.
221
  if (count($still_has_images) == 0)
222
  {
223
+ $sql = "DELETE FROM {$this->db->getPrefix()}shortpixel_folders WHERE id = %d";
224
+ $this->db->query($sql, array($id));
225
  }
226
 
227
  //$this->db->restoreErrors();
228
  }
229
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
230
 
 
231
 
232
+ /* Check files and add what's needed
233
+ * Moved for directory Other Media Model
234
  public function refreshFolder(ShortPixel\DirectoryModel $folder)
235
  {
236
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
237
 
 
 
 
 
 
 
 
 
 
 
238
  }
239
+ */
240
 
241
  /**
242
  *
298
  return $id;
299
  }
300
 
301
+ /** This function is called by OtherMediaController / RefreshFolders. Other scripts should not call it
302
+ * @private
303
+ */
304
+ public function batchInsertImages($files, $folderId) {
305
  //facem un delete pe cele care nu au shortpixel_folder, pentru curatenie - am mai intalnit situatii in care stergerea s-a agatat (stop monitoring)
306
  global $wpdb;
307
 
359
 
360
  public function getPaginatedMetas($hasNextGen, $filters, $count, $page, $orderby = false, $order = false) {
361
  // [BS] Remove exclusion for sm.status <> 3. Status 3 is 'restored, perform no action'
362
+ if ($page <= 0)
363
+ $page = 1; // first page on invalid input
364
+
365
+ // Not sure why the NGgallery is joined on this. */
366
+ $sql = "SELECT sm.id, sm.name, sm.path, "
367
+ . "sm.status, sm.folder_id, sm.compression_type, sm.keep_exif, sm.cmyk2rgb, sm.resize, sm.resize_width, sm.resize_height, sm.message, sm.ts_added, sm.ts_optimized "
368
  . "FROM {$this->db->getPrefix()}shortpixel_meta sm "
369
  . "INNER JOIN {$this->db->getPrefix()}shortpixel_folders sf on sm.folder_id = sf.id "
 
370
  . "WHERE sf.status <> -1"; // AND sm.status <> 3
371
+
372
+ /* $sql = 'SELECT sm.* FROM ' . $this->db->getPrefix() . 'shortpixel_meta sm
373
+ INNER JOIN ' . $this->db->getPrefix() . 'shortpixel_folders sf on sm.folder_id = sf.id
374
+ where sf.status <> -1 '; */
375
+
376
+
377
  foreach($filters as $field => $value) {
378
  $sql .= " AND sm.$field " . $value->operator . " ". $value->value . " ";
379
  }
380
+ $sql .= ($orderby ? " ORDER BY sm.$orderby $order " : "")
381
  . " LIMIT $count OFFSET " . ($page - 1) * $count;
382
+ $result = $this->db->query($sql);
383
+
384
+ return $result;
385
  }
386
 
387
  public function getPendingMetas($count) {
388
+ $sql = "SELECT sm.id from {$this->db->getPrefix()}shortpixel_meta sm "
389
+ . "INNER JOIN {$this->db->getPrefix()}shortpixel_folders sf on sm.folder_id = sf.id "
390
+ . "WHERE sf.status <> -1 AND sm.status <> 3 AND ( sm.status = 1 OR (sm.status < 0 AND sm.retries < 3)) "
391
+ . "ORDER BY sm.id DESC LIMIT $count";
392
+ return $this->db->query($sql);
393
  }
394
 
395
  public function getFolderOptimizationStatus($folderId) {
442
  }
443
 
444
  $res = $this->db->query($sql);
445
+ return isset($res[0]->recCount) ? intval($res[0]->recCount) : 0;
446
  }
447
 
448
  public function getMeta($id, $deleted = false) {
506
  foreach(self::$fields[$tableSuffix] as $field => $type) {
507
  $getter = "get" . ShortPixelTools::snakeToCamel($field);
508
  $val = $meta->$getter();
509
+
510
  if($meta->$getter() !== null) {
511
  $sql .= " {$field} = %{$type},";
512
  $params[] = $val;
520
  $sql = rtrim($sql, ",");
521
  $sql .= " WHERE id = %d";
522
  $params[] = $meta->getId();
523
+
524
  $this->db->query($sql, $params);
525
  }
526
 
527
+ /** Replacement function for using with MVC structure.
528
+ * - This should be the only save function for folder (add or update).
529
+ * - The DB class should be only worrying about the database part.
530
+ */
531
+ public function saveDirectory($fields)
532
+ {
533
+ $result = false;
534
+ $folder_id = -1;
535
+
536
+ if (isset($fields['id']))
537
+ {
538
+ $folder_id = $fields['id'];
539
+ unset($fields['id']);
540
+ }
541
+
542
+ if ($folder_id > 0 && $folder_id !== false)
543
+ {
544
+ $result = $this->updateDirectory($folder_id, $fields);
545
+ }
546
+ else
547
+ {
548
+ if (isset($fields['ts_updated']))
549
+ unset($fields['ts_updated']);
550
+
551
+ $result = $this->addDirectory($fields);
552
+ }
553
+
554
+ return $result;
555
+ }
556
+
557
+ private function addDirectory($fields)
558
+ {
559
+ $prefix = $this->db->getPrefix();
560
+
561
+ $defaults = array(
562
+ 'status' => 0,
563
+ 'file_count' => 0,
564
+ 'ts_created' => date("Y-m-d H:i:s"),
565
+ );
566
+ $fields = wp_parse_args($fields, $defaults);
567
+
568
+
569
+ $prepared_fields = $this->prepareFields($fields);
570
+
571
+ $result = $this->db->insert($prefix .'shortpixel_folders',
572
+ $fields,
573
+ array_values($prepared_fields['fields'])
574
+ );
575
+
576
+ return $result;
577
+ }
578
+
579
+ private function updateDirectory($id, $fields)
580
+ {
581
+ $prefix = $this->db->getPrefix();
582
+
583
+ $sql = 'UPDATE ' . $prefix . 'shortpixel_folders SET ';
584
+
585
+ $setline = array();
586
+ $prepared_fields = $this->prepareFields($fields);
587
+
588
+ $fields = $prepared_fields["fields"];
589
+ $prepared = $prepared_fields['prepared'];
590
+
591
+ foreach($fields as $name => $mask)
592
+ {
593
+ $setline[] = $name . ' = ' . $mask . ' ';
594
+ }
595
+
596
+ $sql .= implode(',', $setline);
597
+ $sql .= ' WHERE id = %d';
598
+ $prepared[] = $id;
599
+
600
+ $sql = $this->db->prepare($sql, $prepared);
601
+ $this->db->query($sql);
602
+
603
+ }
604
+
605
+ /* prepare fields for update or insert. Replaces values with a proper mask for preparing
606
+ * @param Array Array of fields
607
+ * @return Array Assoc array of fields replaced with masked and an array with prepared values
608
+ */
609
+ private function prepareFields($fields)
610
+ {
611
+ $result = array();
612
+ $masks = array('status' => '%d', 'file_count' => '%d', 'ts_updated' => '%s', 'ts_created' => "%s" );
613
+
614
+ foreach($fields as $name => $value)
615
+ {
616
+ $mask = isset($masks[$name]) ? $masks[$name] : '%s';
617
+ $fields[$name] = $mask;
618
+ $prepared[] = $value;
619
+ }
620
+
621
+ $result['fields'] = $fields;
622
+ $result['prepared'] = $prepared;
623
+ return $result;
624
+ }
625
+
626
+
627
+
628
  public function delete($meta) {
629
  $metaClass = get_class($meta);
630
  $tableSuffix = $metaClass::TABLE_SUFFIX;
class/db/shortpixel-meta-facade.php CHANGED
@@ -115,8 +115,9 @@ class ShortPixelMetaFacade {
115
  if($this->type == self::CUSTOM_TYPE) {
116
  $this->spMetaDao->update($this->meta);
117
  if($this->meta->getExtMetaId()) {
118
- $ng = \ShortPixel\NextGen::getInstance();
119
- $ng->updateImageSize($this->meta->getExtMetaId(), $this->meta->getPath());
 
120
  }
121
  }
122
  elseif($this->type == ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE) {
115
  if($this->type == self::CUSTOM_TYPE) {
116
  $this->spMetaDao->update($this->meta);
117
  if($this->meta->getExtMetaId()) {
118
+ $ng = \ShortPixel\NextGen::getInstance(); // @todo This needs reversing. Nextgen should listen to a filter to be implemented here.
119
+ if ($ng->has_nextGen()) // prevent fatal error when Nextgen is not activated
120
+ $ng->updateImageSize($this->meta->getExtMetaId(), $this->meta->getPath());
121
  }
122
  }
123
  elseif($this->type == ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE) {
class/db/shortpixel-nextgen-adapter.php DELETED
@@ -1,40 +0,0 @@
1
- <?php
2
-
3
- class ShortPixelNextGenAdapter {
4
- public static function getGalleries () {
5
- global $wpdb;
6
- return array_map(array('ShortPixelNextGenAdapter','path'), $wpdb->get_results("SELECT path FROM {$wpdb->prefix}ngg_gallery"));
7
- }
8
-
9
- public static function hasNextGen() {
10
- global $wpdb;
11
- $nggTable = $wpdb->get_results("SELECT COUNT(1) hasNggTable FROM information_schema.tables WHERE table_schema='{$wpdb->dbname}' AND table_name='{$wpdb->prefix}ngg_gallery'");
12
- if(isset($nggTable[0]->hasNggTable) && $nggTable[0]->hasNggTable > 0) {
13
- return true;
14
- }
15
- return false;
16
- }
17
-
18
- public static function getImageAbspath($image) {
19
- $storage = C_Gallery_Storage::get_instance();
20
- return $storage->get_image_abspath($image);
21
- }
22
-
23
- public static function updateImageSize($nggId, $path) {
24
- $mapper = C_Image_Mapper::get_instance();
25
- $image = $mapper->find($nggId);
26
- $dimensions = getimagesize(self::getImageAbspath($image));
27
- $size_meta = array('width' => $dimensions[0], 'height' => $dimensions[1]);
28
- $image->meta_data = array_merge($image->meta_data, $size_meta);
29
- $image->meta_data['full'] = $size_meta;
30
- $mapper->save($image);
31
- }
32
-
33
- public static function pathToAbsolute($item) {
34
- return str_replace('//', '/', get_home_path() . $item);
35
- }
36
-
37
- public static function path($item) {
38
- return $item->path;
39
- }
40
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
class/db/wp-shortpixel-db.php CHANGED
@@ -11,6 +11,7 @@ class WpShortPixelDb implements ShortPixelDb {
11
  const QTYPE_INSERT = 1;
12
  const QTYPE_DELETE = 2;
13
  const QTYPE_UPDATE = 3;
 
14
 
15
  public function __construct($prefix = null) {
16
  $this->prefix = $prefix;
@@ -64,7 +65,14 @@ class WpShortPixelDb implements ShortPixelDb {
64
  if($params) {
65
  $sql = $wpdb->prepare($sql, $params);
66
  }
67
- return $wpdb->get_results($sql);
 
 
 
 
 
 
 
68
  }
69
 
70
  public function insert($table, $params, $format = null) {
@@ -72,7 +80,10 @@ class WpShortPixelDb implements ShortPixelDb {
72
 
73
  $num_inserted = $wpdb->insert($table, $params, $format);
74
  if ($num_inserted === false)
75
- $this->handleError(self::QTYPE_INSERT);
 
 
 
76
 
77
  return $wpdb->insert_id;
78
  }
@@ -92,9 +103,14 @@ class WpShortPixelDb implements ShortPixelDb {
92
 
93
  public function handleError($error_type)
94
  {
95
- Log::addError('WP Database error: ' . $wpdb->last_error);
96
-
97
  global $wpdb;
 
 
 
 
 
 
 
98
  switch($error_type)
99
  {
100
  case self::QTYPE_INSERT:
11
  const QTYPE_INSERT = 1;
12
  const QTYPE_DELETE = 2;
13
  const QTYPE_UPDATE = 3;
14
+ const QTYPE_QUERY = 4;
15
 
16
  public function __construct($prefix = null) {
17
  $this->prefix = $prefix;
65
  if($params) {
66
  $sql = $wpdb->prepare($sql, $params);
67
  }
68
+ $result = $wpdb->get_results($sql);
69
+
70
+ if (count($result) == 0 && strlen($wpdb->last_error) > 0)
71
+ {
72
+ $this->handleError(self::QTYPE_QUERY);
73
+ }
74
+
75
+ return $result;
76
  }
77
 
78
  public function insert($table, $params, $format = null) {
80
 
81
  $num_inserted = $wpdb->insert($table, $params, $format);
82
  if ($num_inserted === false)
83
+ {
84
+ $this->handleError(self::QTYPE_INSERT);
85
+ return false;
86
+ }
87
 
88
  return $wpdb->insert_id;
89
  }
103
 
104
  public function handleError($error_type)
105
  {
 
 
106
  global $wpdb;
107
+
108
+ Log::addError('WP Database error: ' . $wpdb->last_error, $wpdb->last_query );
109
+ self::checkCustomTables(); // on error, test if tables are fine.
110
+
111
+ if (strlen($wpdb->last_error) > 0)
112
+ { $wpdb->last_error = ''; }
113
+
114
  switch($error_type)
115
  {
116
  case self::QTYPE_INSERT:
class/external/cloudflare.php CHANGED
@@ -181,6 +181,8 @@ class CloudFlareAPI {
181
  curl_setopt( $curl_connection, CURLOPT_POSTFIELDS, $postfields);
182
  curl_setopt( $curl_connection, CURLOPT_RETURNTRANSFER, true );
183
  curl_setopt( $curl_connection, CURLOPT_HTTPHEADER, $headers );
 
 
184
  curl_setopt( $curl_connection, CURLOPT_USERAGENT, '"User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.87 Safari/537.36"' );
185
 
186
  $request_response = curl_exec( $curl_connection );
181
  curl_setopt( $curl_connection, CURLOPT_POSTFIELDS, $postfields);
182
  curl_setopt( $curl_connection, CURLOPT_RETURNTRANSFER, true );
183
  curl_setopt( $curl_connection, CURLOPT_HTTPHEADER, $headers );
184
+ curl_setopt( $curl_connection, CURLOPT_CONNECTTIMEOUT, 5); // in seconds!
185
+ curl_setopt( $curl_connection, CURLOPT_TIMEOUT, 10); // in seconds!
186
  curl_setopt( $curl_connection, CURLOPT_USERAGENT, '"User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.87 Safari/537.36"' );
187
 
188
  $request_response = curl_exec( $curl_connection );
class/external/nextgen.php CHANGED
@@ -1,6 +1,8 @@
1
  <?php
2
  namespace ShortPixel;
3
  use ShortPixel\Notices\NoticeController as Notice;
 
 
4
 
5
  class NextGen
6
  {
@@ -8,22 +10,27 @@ class NextGen
8
  protected $view;
9
 
10
  // ngg_created_new_gallery
11
-
12
  public function __construct()
13
  {
14
  add_filter('shortpixel/init/optimize_on_screens', array($this, 'add_screen_loads'));
15
  $this->view = new nextGenView();
16
 
17
-
18
  add_action('plugins_loaded', array($this, 'hooks'));
 
19
  }
20
 
21
  public function hooks()
22
  {
23
  if ($this->optimizeNextGen()) // if optimization is on, hook.
24
  {
25
- add_action('ngg_update_addgallery_page', array( &$this, 'addNextGenGalleriesToCustom'));
26
  add_action('ngg_added_new_image', array($this,'handleImageUpload'));
 
 
 
 
 
 
27
  }
28
 
29
  }
@@ -37,7 +44,7 @@ class NextGen
37
  return self::$instance;
38
  }
39
 
40
- public function has_nextgen()
41
  {
42
  if (defined('NGG_PLUGIN'))
43
  return true;
@@ -61,6 +68,7 @@ class NextGen
61
  $use_screens[] = 'gallery_page_ngg_addgallery'; // add gallery
62
  $use_screens[] = 'nggallery-manage-gallery'; // manage gallery
63
  $use_screens[] = 'gallery_page_nggallery-manage-album'; // manage album
 
64
 
65
  return $use_screens;
66
  }
@@ -69,10 +77,32 @@ class NextGen
69
  */
70
  public function nextGenEnabled($silent)
71
  {
72
- \WpShortPixelDb::checkCustomTables(); // check if custom tables are created, if not, create them
73
 
 
74
  $this->addNextGenGalleriesToCustom($silent);
 
75
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
76
  }
77
 
78
  /* @return DirectoryModel */
@@ -105,18 +135,22 @@ class NextGen
105
  $homepath = $fs->getWPFileBase();
106
  $folderMsg = "";
107
  //add the NextGen galleries to custom folders
108
- $ngGalleries = $this->getGalleries();
109
 
 
110
 
111
  $meta = $shortPixel->getSpMetaDao();
 
112
  foreach($ngGalleries as $gallery) {
113
- $msg = $meta->newFolderFromPath($gallery, $homepath->getPath(), \WPShortPixel::getCustomFolderBase());
114
- // if($msg) { //try again with ABSPATH as maybe WP is in a subdir
115
- // $msg = $meta->newFolderFromPath($gallery, ABSPATH, \WPShortPixel::getCustomFolderBase());
116
- // }
117
- if ($msg)
118
- $folderMsg .= $msg . '(' . $gallery . ') <br>';
119
- //$this->_settings->hasCustomFolders = time();
 
 
120
  }
121
 
122
  if (count($ngGalleries) > 0)
@@ -124,7 +158,6 @@ class NextGen
124
  // put timestamp to this setting.
125
  $settings = \wpSPIO()->settings();
126
  $settings->hasCustomFolders = time();
127
-
128
  }
129
  if (! $silent && (strlen(trim($folderMsg)) > 0 && $folderMsg !== false))
130
  {
@@ -137,10 +170,11 @@ class NextGen
137
  {
138
  $shortPixel = \wpSPIO()->getShortPixel();
139
  $metadao = $shortPixel->getSpMetaDao();
 
140
 
141
- if (\wpSPIO()->settings()->includeNextGen == 1) {
142
  $imageFsPath = $this->getImageAbspath($image);
143
- $customFolders = $metadao->getFolders();
144
 
145
  $folderId = -1;
146
  foreach ($customFolders as $folder) {
@@ -151,9 +185,12 @@ class NextGen
151
  }
152
  if ($folderId == -1) { //if not found, create
153
  $galleryPath = dirname($imageFsPath);
154
- $folder = new \ShortPixelFolder(array("path" => $galleryPath), $this->_settings->excludePatterns);
155
- $folderMsg = $metadao->saveFolder($folder);
156
- $folderId = $folder->getId();
 
 
 
157
  //self::log("NG Image Upload: created folder from path $galleryPath : Folder info: " . json_encode($folder));
158
  }
159
 
@@ -161,25 +198,55 @@ class NextGen
161
  }
162
  }
163
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
164
  public function updateImageSize($nggId, $path) {
165
 
166
- $mapper = \C_Image_Mapper::get_instance();
167
- $image = $mapper->find($nggId);
168
 
169
  $dimensions = getimagesize($this->getImageAbspath($image));
170
  $size_meta = array('width' => $dimensions[0], 'height' => $dimensions[1]);
171
  $image->meta_data = array_merge($image->meta_data, $size_meta);
172
  $image->meta_data['full'] = $size_meta;
173
- $mapper->save($image);
174
  }
175
 
176
- public function getImageAbspath($image) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
177
  $storage = \C_Gallery_Storage::get_instance();
178
  return $storage->get_image_abspath($image);
179
  }
180
 
181
- } // class .
182
 
 
183
  class nextGenView
184
  {
185
  protected $nggColumnIndex = 0;
@@ -220,7 +287,13 @@ class nextGenView
220
  $view = new \ShortPixelView($shortPixel);
221
 
222
  $meta = $metadao->getMetaForPath($picture->imagePath);
 
223
  if($meta) {
 
 
 
 
 
224
  switch($meta->getStatus()) {
225
  case "0": echo("<div id='sp-msg-C-{$meta->getId()}' class='column-wp-shortPixel' style='color: #000'>Waiting</div>"); break;
226
  case "1": echo("<div id='sp-msg-C-{$meta->getId()}' class='column-wp-shortPixel' style='color: #000'>Pending</div>"); break;
1
  <?php
2
  namespace ShortPixel;
3
  use ShortPixel\Notices\NoticeController as Notice;
4
+ use ShortPixel\ShortpixelLogger\ShortPixelLogger as Log;
5
+
6
 
7
  class NextGen
8
  {
10
  protected $view;
11
 
12
  // ngg_created_new_gallery
 
13
  public function __construct()
14
  {
15
  add_filter('shortpixel/init/optimize_on_screens', array($this, 'add_screen_loads'));
16
  $this->view = new nextGenView();
17
 
 
18
  add_action('plugins_loaded', array($this, 'hooks'));
19
+ add_action('deactivate_nextgen-gallery/nggallery.php', array($this, 'resetNotification'));
20
  }
21
 
22
  public function hooks()
23
  {
24
  if ($this->optimizeNextGen()) // if optimization is on, hook.
25
  {
26
+ add_action('ngg_update_addgallery_page', array( $this, 'addNextGenGalleriesToCustom'));
27
  add_action('ngg_added_new_image', array($this,'handleImageUpload'));
28
+ add_action('ngg_delete_image', array($this, 'OnDeleteImage'),10, 2); // this works only on single images!
29
+ }
30
+
31
+ if ($this->has_nextgen())
32
+ {
33
+ add_action('shortpixel/othermedia/folder/load', array($this, 'loadFolder'), 10, 2);
34
  }
35
 
36
  }
44
  return self::$instance;
45
  }
46
 
47
+ public function has_nextgen()
48
  {
49
  if (defined('NGG_PLUGIN'))
50
  return true;
68
  $use_screens[] = 'gallery_page_ngg_addgallery'; // add gallery
69
  $use_screens[] = 'nggallery-manage-gallery'; // manage gallery
70
  $use_screens[] = 'gallery_page_nggallery-manage-album'; // manage album
71
+ $use_screens[] = 'nggallery-manage-images'; // images in gallery overview
72
 
73
  return $use_screens;
74
  }
77
  */
78
  public function nextGenEnabled($silent)
79
  {
 
80
 
81
+ \WpShortPixelDb::checkCustomTables(); // check if custom tables are created, if not, create them
82
  $this->addNextGenGalleriesToCustom($silent);
83
+ }
84
 
85
+ /** Tries to find a nextgen gallery for a shortpixel folder.
86
+ * Purpose is to test if this folder is a nextgen gallery
87
+ * Problem is that NG stores folders in a short format, not from root while SPIO stores whole path
88
+ * Assumption: The last two directory names should lead to an unique gallery and if so, it's nextgen
89
+ * @param $id int Folder ID
90
+ * @param $directory DirectoryOtherMediaModel Directory Object
91
+ */
92
+ public function loadFolder($id, $directory)
93
+ {
94
+ $path = $directory->getPath();
95
+ $path_split = array_filter(explode('/', $path));
96
+
97
+ $searchPath = trailingslashit(implode('/', array_slice($path_split, -2, 2)));
98
+
99
+ global $wpdb;
100
+ $sql = "SELECT gid FROM {$wpdb->prefix}ngg_gallery WHERE path LIKE %s";
101
+ $sql = $wpdb->prepare($sql, '%' . $searchPath . '');
102
+ $gid = $wpdb->get_var($sql);
103
+
104
+ if (! is_null($gid) && is_numeric($gid))
105
+ $directory->setNextGen(true);
106
  }
107
 
108
  /* @return DirectoryModel */
135
  $homepath = $fs->getWPFileBase();
136
  $folderMsg = "";
137
  //add the NextGen galleries to custom folders
138
+ $ngGalleries = $this->getGalleries(); // DirectoryModel return.
139
 
140
+ $otherMedia = new otherMediaController();
141
 
142
  $meta = $shortPixel->getSpMetaDao();
143
+
144
  foreach($ngGalleries as $gallery) {
145
+ $folder = $otherMedia->getFolderByPath($gallery->getPath());
146
+ if ($folder->hasDBEntry())
147
+ {
148
+ continue;
149
+ }
150
+
151
+ $result = $otherMedia->addDirectory($gallery->getPath());
152
+ if (! $result)
153
+ Log::addWarn('Could not add this directory' . $gallery->getPath() );
154
  }
155
 
156
  if (count($ngGalleries) > 0)
158
  // put timestamp to this setting.
159
  $settings = \wpSPIO()->settings();
160
  $settings->hasCustomFolders = time();
 
161
  }
162
  if (! $silent && (strlen(trim($folderMsg)) > 0 && $folderMsg !== false))
163
  {
170
  {
171
  $shortPixel = \wpSPIO()->getShortPixel();
172
  $metadao = $shortPixel->getSpMetaDao();
173
+ $otherMedia = new OtherMediaController();
174
 
175
+ if (\wpSPIO()->settings()->includeNextGen == 1) {
176
  $imageFsPath = $this->getImageAbspath($image);
177
+ $customFolders = $otherMedia->getAllFolders();
178
 
179
  $folderId = -1;
180
  foreach ($customFolders as $folder) {
185
  }
186
  if ($folderId == -1) { //if not found, create
187
  $galleryPath = dirname($imageFsPath);
188
+ $folder = $otherMedia->addDirectory($galleryPath);
189
+
190
+ // $folder = new \ShortPixelFolder(array("path" => $galleryPath), $this->_settings->excludePatterns);
191
+ // $folderMsg = $metadao->saveFolder($folder);
192
+ if ($folder)
193
+ $folderId = $folder->getId();
194
  //self::log("NG Image Upload: created folder from path $galleryPath : Folder info: " . json_encode($folder));
195
  }
196
 
198
  }
199
  }
200
 
201
+ public function resetNotification()
202
+ {
203
+ Notice::removeNoticeByID(adminNoticesController::MSG_INTEGRATION_NGGALLERY);
204
+ }
205
+
206
+ public function onDeleteImage($nggId, $size)
207
+ {
208
+
209
+ $image = $this->getNGImageByID($nggId);
210
+ $path = $this->getImageAbspath($image);
211
+
212
+ $meta = \wpSPIO()->getShortPixel()->getSpMetaDao()->getMetaForPath($path);
213
+ \wpSPIO()->getShortPixel()->getSpMetaDao()->delete($meta);
214
+
215
+ }
216
+
217
  public function updateImageSize($nggId, $path) {
218
 
219
+ $image = $this->getNGImageByID($nggId);
 
220
 
221
  $dimensions = getimagesize($this->getImageAbspath($image));
222
  $size_meta = array('width' => $dimensions[0], 'height' => $dimensions[1]);
223
  $image->meta_data = array_merge($image->meta_data, $size_meta);
224
  $image->meta_data['full'] = $size_meta;
225
+ $this->saveToNextGen($image);
226
  }
227
 
228
+ protected function getNGImageByID($nggId)
229
+ {
230
+ $mapper = \C_Image_Mapper::get_instance();
231
+ $image = $mapper->find($nggId);
232
+ return $image;
233
+ }
234
+
235
+ /* @param NextGen Image */
236
+ protected function saveToNextGen($image)
237
+ {
238
+ $mapper = \C_Image_Mapper::get_instance();
239
+ $mapper->save($image);
240
+ }
241
+
242
+ protected function getImageAbspath($image, $size = 'full') {
243
  $storage = \C_Gallery_Storage::get_instance();
244
  return $storage->get_image_abspath($image);
245
  }
246
 
247
+ } // class.
248
 
249
+ /* Class for View integration in the Nextgen gallery */
250
  class nextGenView
251
  {
252
  protected $nggColumnIndex = 0;
287
  $view = new \ShortPixelView($shortPixel);
288
 
289
  $meta = $metadao->getMetaForPath($picture->imagePath);
290
+
291
  if($meta) {
292
+ // optimize if status is pending.
293
+ if($meta->getStatus() == \ShortPixelMeta::FILE_STATUS_PENDING ){
294
+ Log::addDebug('Adding pending files to processing - ' . $meta->getID() );
295
+ $shortPixel->getPrioQ()->push(\ShortPixelMetaFacade::queuedId(\ShortPixelMetaFacade::CUSTOM_TYPE, $meta->getID() ));
296
+ }
297
  switch($meta->getStatus()) {
298
  case "0": echo("<div id='sp-msg-C-{$meta->getId()}' class='column-wp-shortPixel' style='color: #000'>Waiting</div>"); break;
299
  case "1": echo("<div id='sp-msg-C-{$meta->getId()}' class='column-wp-shortPixel' style='color: #000'>Pending</div>"); break;
class/model/apikey_model.php CHANGED
@@ -186,6 +186,10 @@ class ApiKeyModel extends ShortPixelModel
186
  $this->key_is_verified = false;
187
  Log::addDebug('Clearing API Key');
188
 
 
 
 
 
189
  $this->update();
190
 
191
  }
186
  $this->key_is_verified = false;
187
  Log::addDebug('Clearing API Key');
188
 
189
+ adminNoticesController::resetAPINotices();
190
+ adminNoticesController::resetQuotaNotices();
191
+ adminNoticesController::resetIntegrationNotices();
192
+
193
  $this->update();
194
 
195
  }
class/model/cache_model.php CHANGED
@@ -12,15 +12,14 @@ class CacheModel
12
 
13
  protected $name;
14
  protected $value;
15
- protected $expires = HOUR_IN_SECONDS;
16
-
17
  protected $exists = false;
18
 
19
 
20
  public function __construct($name)
21
  {
22
  $this->name = $name;
23
- $this->load($name);
24
  }
25
 
26
  /** Set the expiration of this item. In seconds
@@ -65,8 +64,7 @@ class CacheModel
65
  protected function load()
66
  {
67
  $item = get_transient($this->name);
68
-
69
- if ($item)
70
  {
71
  $this->value = $item;
72
  $this->exists = true;
12
 
13
  protected $name;
14
  protected $value;
15
+ protected $expires = HOUR_IN_SECONDS; // This is the expires, when saved without SetExpires! This value is not a representation of any expire time when loading something cache!
 
16
  protected $exists = false;
17
 
18
 
19
  public function __construct($name)
20
  {
21
  $this->name = $name;
22
+ $this->load();
23
  }
24
 
25
  /** Set the expiration of this item. In seconds
64
  protected function load()
65
  {
66
  $item = get_transient($this->name);
67
+ if ($item !== false)
 
68
  {
69
  $this->value = $item;
70
  $this->exists = true;
class/model/directory_model.php CHANGED
@@ -20,6 +20,8 @@ class DirectoryModel extends ShortPixelModel
20
  protected $is_writable = false;
21
  protected $is_readable = false;
22
 
 
 
23
  protected $new_directory_permission = 0755;
24
 
25
  /** Creates a directory model object. DirectoryModel directories don't need to exist on FileSystem
@@ -29,8 +31,6 @@ class DirectoryModel extends ShortPixelModel
29
  */
30
  public function __construct($path)
31
  {
32
-
33
-
34
  $path = wp_normalize_path($path);
35
  if (! is_dir($path)) // path is wrong, *or* simply doesn't exist.
36
  {
@@ -294,8 +294,8 @@ class DirectoryModel extends ShortPixelModel
294
  $dirIt = new \DirectoryIterator($this->path);
295
  $dirArray = array();
296
  foreach($dirIt as $fileInfo)
297
- {
298
- if ($fileInfo->isDir() && $fileInfo->isReadable() && ! $fileInfo->isDot() )
299
  {
300
  $dir = new DirectoryModel($fileInfo->getRealPath());
301
  if ($dir->exists())
20
  protected $is_writable = false;
21
  protected $is_readable = false;
22
 
23
+ protected $fields = array();
24
+
25
  protected $new_directory_permission = 0755;
26
 
27
  /** Creates a directory model object. DirectoryModel directories don't need to exist on FileSystem
31
  */
32
  public function __construct($path)
33
  {
 
 
34
  $path = wp_normalize_path($path);
35
  if (! is_dir($path)) // path is wrong, *or* simply doesn't exist.
36
  {
294
  $dirIt = new \DirectoryIterator($this->path);
295
  $dirArray = array();
296
  foreach($dirIt as $fileInfo)
297
+ { // IsDot must go first here, or there is possiblity to run into openbasedir restrictions.
298
+ if (! $fileInfo->isDot() && $fileInfo->isDir() && $fileInfo->isReadable() )
299
  {
300
  $dir = new DirectoryModel($fileInfo->getRealPath());
301
  if ($dir->exists())
class/model/directory_othermedia_model.php ADDED
@@ -0,0 +1,354 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace ShortPixel;
3
+ use ShortPixel\ShortpixelLogger\ShortPixelLogger as Log;
4
+ use ShortPixel\Notices\NoticeController as Notice;
5
+
6
+ // extends DirectoryModel. Handles Shortpixel_meta database table
7
+ // Replacing main parts of shortpixel-folder
8
+ class DirectoryOtherMediaModel extends DirectoryModel
9
+ {
10
+
11
+ protected $id = -1; // if -1, this might not exist yet in Dbase. Null is not used, because that messes with isset
12
+
13
+ protected $name;
14
+ protected $status = 0;
15
+ protected $fileCount = 0; // inherent onreliable statistic in dbase. When insert / batch insert the folder count could not be updated, only on refreshFolder which is a relative heavy function to use on every file upload. Totals are better gotten from a stat-query, on request.
16
+ protected $updated = 0;
17
+ protected $created = 0;
18
+
19
+ protected $is_nextgen;
20
+ protected $in_db = false;
21
+ protected $is_removed = false;
22
+
23
+ protected $stats;
24
+
25
+ const DIRECTORY_STATUS_REMOVED = -1;
26
+ const DIRECTORY_STATUS_NORMAL = 0;
27
+ const DIRECTORY_STATUS_NEXTGEN = 1;
28
+
29
+ /** Path or Folder Object, from SpMetaDao
30
+ *
31
+ */
32
+ public function __construct($path)
33
+ {
34
+
35
+ if (is_object($path))
36
+ {
37
+ $folder = $path;
38
+ $path = $folder->path;
39
+
40
+ parent::__construct($path);
41
+ $this->loadFolder($folder);
42
+ }
43
+ else
44
+ {
45
+ parent::__construct($path);
46
+ $this->loadFolderbyPath($path);
47
+ }
48
+ }
49
+
50
+
51
+ private function loadFolderByPath($path)
52
+ {
53
+ $folders = self::get(array('path' => $path)); //s\wpSPIO()->getShortPixel()->getSpMetaDao()->getFolder($path);
54
+ $folder = false;
55
+
56
+ if ($folders && count($folders) > 0)
57
+ $folder = $folders[0];
58
+
59
+ return $this->loadFolder($folder);
60
+
61
+ }
62
+
63
+ /** Loads from database into model, the extra data of this model. */
64
+ private function loadFolder($folder)
65
+ {
66
+
67
+ if (is_object($folder))
68
+ {
69
+ // suboptimally, this function needs to work both with database record output and instances of itself
70
+ $class = get_class($folder);
71
+
72
+ $this->id = $folder->id;
73
+
74
+ if ($this->id > 0)
75
+ $this->in_db = true;
76
+
77
+ if ($class == 'ShortPixel\DirectoryOtherMediaModel')
78
+ {
79
+ $this->updated = $folder->updated;
80
+ $this->create = $folder->created;
81
+ $this->fileCount = $folder->fileCount;
82
+ }
83
+ else
84
+ {
85
+ $this->updated = $this->DBtoTimestamp($folder->ts_updated);
86
+ $this->created = $this->DBtoTimestamp($folder->ts_created);
87
+ $this->fileCount = $folder->file_count;
88
+ }
89
+ if (strlen($folder->name) == 0)
90
+ $this->name = basename($folder->path);
91
+ else
92
+ $this->name = $folder->name;
93
+
94
+ $this->status = $folder->status;
95
+
96
+ if ($this->status == -1)
97
+ $this->is_removed = true;
98
+
99
+ do_action('shortpixel/othermedia/folder/load', $this->id, $this);
100
+
101
+ }
102
+ }
103
+
104
+ public function getStatus()
105
+ {
106
+ return $this->status;
107
+ }
108
+
109
+ public function setStatus($status)
110
+ {
111
+ $this->status = $status;
112
+ }
113
+
114
+ public function getFileCount()
115
+ {
116
+ return $this->fileCount;
117
+ }
118
+
119
+ public function getId()
120
+ {
121
+ return $this->id;
122
+ }
123
+
124
+ public function getUpdated()
125
+ {
126
+ return $this->updated;
127
+ }
128
+
129
+ public function setUpdated($time)
130
+ {
131
+ $this->updated = $time;
132
+ }
133
+
134
+ public function setNextGen($bool = true)
135
+ {
136
+ $this->is_nextgen = $bool;
137
+ }
138
+
139
+ public function isNextGen()
140
+ {
141
+ return $this->is_nextgen;
142
+ }
143
+
144
+ public function hasDBEntry()
145
+ {
146
+ return $this->in_db;
147
+ }
148
+
149
+ public function isRemoved()
150
+ {
151
+ return $this->is_removed;
152
+ }
153
+
154
+ public function getStats()
155
+ {
156
+ if (is_null($this->stats))
157
+ {
158
+ $this->stats = \wpSPIO()->getShortPixel()->getSpMetaDao()->getFolderOptimizationStatus($this->id);
159
+ }
160
+
161
+ return $this->stats;
162
+ }
163
+
164
+ public function save()
165
+ {
166
+ // Simple Update
167
+ $args = array(
168
+ 'id' => $this->id,
169
+ 'status' => $this->status,
170
+ 'file_count' => $this->fileCount,
171
+ 'ts_updated' => $this->timestampToDB($this->updated),
172
+ 'name' => $this->name,
173
+ 'path' => $this->getPath(),
174
+ );
175
+ $result = \wpSPIO()->getShortPixel()->getSpMetaDao()->saveDirectory($args);
176
+ if ($result) // reloading because action can create a new DB-entry, which will not be reflected (in id )
177
+ $this->loadFolderByPath($this->getPath());
178
+
179
+ return $result;
180
+ }
181
+
182
+ public function delete()
183
+ {
184
+ $id = $this->id;
185
+ if (! $in_db)
186
+ {
187
+ Log::addError('Trying to remove Folder without ID ' . $id, $this->getPath());
188
+ }
189
+
190
+ return \wpSPIO()->getShortPixel()->getSpMetaDao()->removeFolder($id);
191
+
192
+ }
193
+
194
+ /** Updates the updated variable on folder to indicating when the last file change was made
195
+ * @return boolean True if file were changed since last update, false if not
196
+ */
197
+ public function updateFileContentChange()
198
+ {
199
+ if (! $this->exists() )
200
+ return false;
201
+
202
+ $old_time = $this->updated;
203
+
204
+ $time = $this->recurseLastChangeFile();
205
+ $this->updated = $time;
206
+ $this->save();
207
+
208
+ if ($old_time !== $time)
209
+ return true;
210
+ else
211
+ return false;
212
+ }
213
+
214
+
215
+ private function recurseLastChangeFile($mtime = 0)
216
+ {
217
+ $ignore = array('.','..');
218
+ $path = $this->getPath();
219
+
220
+ $files = scandir($path);
221
+ $files = array_diff($files, $ignore);
222
+
223
+ $mtime = max($mtime, filemtime($path));
224
+
225
+ foreach($files as $file) {
226
+
227
+ $filepath = $path . $file;
228
+
229
+ if (is_dir($filepath)) {
230
+ $mtime = max($mtime, filemtime($filepath));
231
+ $subDirObj = new DirectoryOtherMediaModel($filepath);
232
+ $subdirtime = $subDirObj->recurseLastChangeFile($mtime);
233
+ if ($subdirtime > $mtime)
234
+ $mtime = $subdirtime;
235
+ }
236
+ }
237
+ return $mtime;
238
+ }
239
+
240
+ private function timestampToDB($timestamp)
241
+ {
242
+ return date("Y-m-d H:i:s", $timestamp);
243
+ }
244
+
245
+ private function DBtoTimestamp($date)
246
+ {
247
+ return strtotime($date);
248
+ }
249
+
250
+
251
+
252
+ /** Crawls the folder and check for files that are newer than param time, or folder updated
253
+ * Note - last update timestamp is not updated here, needs to be done separately.
254
+ */
255
+ public function refreshFolder($time = false)
256
+ {
257
+ if ($time === false)
258
+ $time = $this->updated;
259
+
260
+ if ($this->id <= 0)
261
+ {
262
+ Log::addWarn('FolderObj from database is not there, while folder seems ok ' . $this->getPath() );
263
+ return false;
264
+ }
265
+ elseif (! $this->exists())
266
+ {
267
+ Notice::addError( sprintf(__('Folder %s does not exist! ', 'shortpixel-image-optimiser'), $this->getPath()) );
268
+ return false;
269
+ }
270
+ elseif (! $this->is_writable())
271
+ {
272
+ Notice::addWarning( sprintf(__('Folder %s is not writeable. Please check permissions and try again.','shortpixel-image-optimiser'),$this->getPath()) );
273
+ return false;
274
+ }
275
+
276
+ $fs = \wpSPIO()->filesystem();
277
+
278
+ $filter = ($time > 0) ? array('date_newer' => $time) : array();
279
+ $files = $fs->getFilesRecursive($this, $filter);
280
+
281
+ $shortpixel = \wpSPIO()->getShortPixel();
282
+ // check processable by invoking filter, for now processablepath takes only paths, not objects.
283
+ $files = array_filter($files, function($file) use($shortpixel) { return $shortpixel->isProcessablePath($file->getFullPath()); });
284
+
285
+ Log::addDebug('Refreshing from ' . $time . ', found Files for custom media ID ' . $this-> id . ' -> ' . count($files));
286
+
287
+ // $folderObj->setFileCount( count($files) );
288
+
289
+ \wpSPIO()->getShortPixel()->getSpMetaDao()->batchInsertImages($files, $this->id);
290
+
291
+ $stats = $this->getStats();
292
+ $this->fileCount = $stats->Total;
293
+ $this->save();
294
+
295
+ }
296
+
297
+
298
+ /* Get the custom Folders from DB, put them in model
299
+ @return Array Array of directoryOtherMediaModel
300
+ */
301
+ public static function get($args = array())
302
+ {
303
+ $defaults = array(
304
+ 'id' => false, // Get folder by Id
305
+ 'remove_hidden' => false,
306
+ 'path' => false,
307
+ );
308
+
309
+ $args = wp_parse_args($args, $defaults);
310
+
311
+ $fs = \wpSPIO()->fileSystem();
312
+ $cache = new \ShortPixel\CacheController();
313
+
314
+ $spMetaDao = \wpSPIO()->getShortPixel()->getSpMetaDao();
315
+
316
+ if ($args['id'] !== false && $args['id'] > 0)
317
+ {
318
+ $folders = $spMetaDao->getFolderByID($args['id']);
319
+ }
320
+ elseif($args['path'] !== false && strlen($args['path']) > 0)
321
+ {
322
+ $folders = $spMetaDao->getFolder($args['path']);
323
+ }
324
+ else
325
+ {
326
+ $folders = $spMetaDao->getFolders();
327
+ }
328
+
329
+ if ($folders === false) // no folders.
330
+ return $folders;
331
+
332
+ $i = 0;
333
+ $newfolders = array();
334
+ foreach($folders as $index => $folder)
335
+ {
336
+
337
+ $dirObj = new DirectoryOtherMediaModel($folder);
338
+
339
+ if ($args['remove_hidden'])
340
+ {
341
+ if ($dirObj->is_removed)
342
+ continue;
343
+ }
344
+ $newfolders[$i] = $dirObj; // $index is dbase id, we just want an array
345
+ $i++;
346
+ }
347
+
348
+ return $newfolders;
349
+ }
350
+
351
+
352
+
353
+
354
+ }
class/model/notice_model.php DELETED
@@ -1,87 +0,0 @@
1
- <?php
2
-
3
- namespace ShortPixel;
4
-
5
- class NoticeModel extends ShortPixelModel
6
- {
7
- protected $message;
8
- public $code;
9
-
10
- protected $viewed = false;
11
- public $is_persistent = false; // This is a fatal issue, display until something was fixed.
12
- public $is_removable = true; // if removable, display a notice dialog with red X or so.
13
- public $messageType = self::NOTICE_NORMAL;
14
-
15
- const NOTICE_NORMAL = 1;
16
- const NOTICE_ERROR = 2;
17
- const NOTICE_SUCCESS = 3;
18
- const NOTICE_WARNING = 4;
19
-
20
-
21
- public function __construct($message, $messageType = self::NOTICE_NORMAL)
22
- {
23
- $this->message = $message;
24
- $this->messageType = $messageType;
25
-
26
- }
27
-
28
- public function isDone()
29
- {
30
- if ($this->viewed && ! $this->is_persistent)
31
- return true;
32
- else
33
- return false;
34
-
35
- }
36
-
37
- public function getForDisplay()
38
- {
39
- $this->viewed = true;
40
- $class = 'shortpixel notice ';
41
-
42
- $icon = 'slider';
43
-
44
- switch($this->messageType)
45
- {
46
- case self::NOTICE_ERROR:
47
- $class .= 'notice-error ';
48
- $icon = 'scared';
49
- break;
50
- case self::NOTICE_SUCCESS:
51
- $class .= 'notice-success ';
52
- break;
53
- case self::NOTICE_WARNING:
54
- $class .= 'notice-warning ';
55
- break;
56
- case self::NOTICE_NORMAL:
57
- default:
58
- $class .= 'notice-info ';
59
- break;
60
- }
61
-
62
- $image = '<img src="' . plugins_url('/shortpixel-image-optimiser/res/img/robo-' . $icon . '.png') . '"
63
- srcset="' . plugins_url( 'shortpixel-image-optimiser/res/img/robo-' . $icon . '.png' ) . ' 1x, ' . plugins_url( 'shortpixel-image-optimiser/res/img/robo-' . $icon . '@2x.png') . ' 2x" class="short-pixel-notice-icon">';
64
-
65
-
66
- if ($this->is_removable)
67
- {
68
- $class .= 'is-dismissible ';
69
- }
70
-
71
- if ($this->is_persistent)
72
- {
73
- $class .= '';
74
- }
75
-
76
- return "<div class='$class'>" . $image . "<p>" . $this->message . "</p></div>";
77
-
78
- }
79
-
80
-
81
-
82
- // @todo Transient save, since that is used in some parts.
83
- // save
84
- // load
85
-
86
-
87
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
class/model/shortpixel-debug.php DELETED
@@ -1,140 +0,0 @@
1
- <?php
2
- // The data models.
3
- namespace ShortPixel;
4
-
5
-
6
- class DebugItem // extends ShortPixelModel Too early init for this.
7
- {
8
- protected $time;
9
- protected $level;
10
- protected $message;
11
- protected $data = array();
12
- protected $caller = false; // array when filled
13
-
14
- protected $model;
15
-
16
- const LEVEL_ERROR = 1;
17
- const LEVEL_WARN = 2;
18
- const LEVEL_INFO = 3;
19
- const LEVEL_DEBUG = 4;
20
-
21
- public function __construct($message, $args)
22
- {
23
- $this->level = $args['level'];
24
- $data = $args['data'];
25
-
26
- $this->message = $message;
27
- $this->time = microtime(true);
28
-
29
- $this->setCaller();
30
-
31
- // Add message to data if it seems to be some debug variable.
32
- if (is_object($this->message) || is_array($this->message))
33
- {
34
- $data[] = $this->message;
35
- $this->message = __('[Data]');
36
- }
37
- if (is_array($data) && count($data) > 0)
38
- {
39
- $dataType = $this->getDataType($data);
40
- if ($dataType == 1) // singular
41
- {
42
- $this->data[] = print_r($data, true);
43
- }
44
- if ($dataType == 2) //array
45
- {
46
- foreach($data as $index => $item)
47
- {
48
- if (is_object($item) || is_array($item))
49
- {
50
- $this->data[] = print_r($item, true);
51
- }
52
- }
53
- }
54
- } // if
55
- elseif (! is_array($data)) // this leaves out empty default arrays
56
- {
57
- $this->data[] = print_r($data, true);
58
- }
59
- }
60
-
61
- public function getData()
62
- {
63
- return array('time' => $this->time, 'level' => $this->level, 'message' => $this->message, 'data' => $this->data, 'caller' => $this->caller);
64
- }
65
-
66
- /** Test Data Array for possible values
67
- *
68
- * Data can be a collection of several debug vars, a single var, or just an normal array. Test if array has single types,
69
- * which is a sign the array is not a collection.
70
- */
71
- protected function getDataType($data)
72
- {
73
- $single_type = array('integer', 'boolean', 'string');
74
- if (in_array(gettype(reset($data)), $single_type))
75
- {
76
- return 1;
77
- }
78
- else
79
- {
80
- return 2;
81
- }
82
- }
83
-
84
- public function getForFormat()
85
- {
86
- $data = $this->getData();
87
- switch($this->level)
88
- {
89
- case self::LEVEL_ERROR:
90
- $level = 'ERR';
91
- $color = "\033[31m";
92
- break;
93
- case self::LEVEL_WARN:
94
- $level = 'WRN';
95
- $color = "\033[33m";
96
- break;
97
- case self::LEVEL_INFO:
98
- $level = 'INF';
99
- $color = "\033[37m";
100
- break;
101
- case self::LEVEL_DEBUG:
102
- $level = 'DBG';
103
- $color = "\033[37m";
104
- break;
105
-
106
- }
107
- $color_end = "\033[0m";
108
-
109
- $data['color'] = $color;
110
- $data['color_end'] = $color_end;
111
- $data['level'] = $level;
112
-
113
- return $data;
114
-
115
- //return array('time' => $this->time, 'level' => $level, 'message' => $this->message, 'data' => $this->data, 'color' => $color, 'color_end' => $color_end, 'caller' => $this->caller);
116
-
117
- }
118
-
119
- protected function setCaller()
120
- {
121
- if(PHP_VERSION_ID < 50400) {
122
- $debug=debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
123
- } else {
124
- $debug=debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS,5);
125
- }
126
- $i = 4;
127
- if (isset($debug[$i]))
128
- {
129
- $info = $debug[$i];
130
- $line = isset($info['line']) ? $info['line'] : 'Line unknown';
131
- $file = isset($info['file']) ? basename($info['file']) : 'File not set';
132
-
133
- $this->caller = array('line' => $line, 'file' => $file, 'function' => $info['function']);
134
- }
135
-
136
-
137
- }
138
-
139
-
140
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
class/model/shortpixel-folder.php CHANGED
@@ -127,7 +127,9 @@ class ShortPixelFolder extends ShortPixelEntity{
127
  return false;
128
  }
129
 
 
130
  public function countFiles($path = null) {
 
131
  $size = 0;
132
  $path = $path ? $path : $this->getPath();
133
  if($path == null) {
@@ -148,7 +150,7 @@ class ShortPixelFolder extends ShortPixelEntity{
148
  }
149
  }
150
  return $size;
151
- }
152
 
153
  public function getFileList($onlyNewerThan = 0) {
154
  $fileListPath = tempnam(SHORTPIXEL_UPLOADS_BASE . '/', 'sp_');
@@ -200,10 +202,12 @@ class ShortPixelFolder extends ShortPixelEntity{
200
  }
201
  }
202
 
 
203
  public function getFolderContentsChangeDate() {
204
  return self::getFolderContentsChangeDateRecursive($this->getPath(), 0, strtotime($this->getTsUpdated()));
205
  }
206
-
 
207
  protected static function getFolderContentsChangeDateRecursive($path, $mtime, $refMtime) {
208
  $ignore = array('.','..');
209
  if(!is_writable($path)) {
@@ -220,7 +224,7 @@ class ShortPixelFolder extends ShortPixelEntity{
220
  }
221
  }
222
  return $mtime;
223
- }
224
 
225
  function getId() {
226
  return $this->id;
@@ -243,7 +247,7 @@ class ShortPixelFolder extends ShortPixelEntity{
243
  }
244
 
245
  function setPath($path) {
246
- $this->path = $path;
247
  }
248
 
249
  function getType() {
127
  return false;
128
  }
129
 
130
+ /*
131
  public function countFiles($path = null) {
132
+
133
  $size = 0;
134
  $path = $path ? $path : $this->getPath();
135
  if($path == null) {
150
  }
151
  }
152
  return $size;
153
+ } */
154
 
155
  public function getFileList($onlyNewerThan = 0) {
156
  $fileListPath = tempnam(SHORTPIXEL_UPLOADS_BASE . '/', 'sp_');
202
  }
203
  }
204
 
205
+ /*
206
  public function getFolderContentsChangeDate() {
207
  return self::getFolderContentsChangeDateRecursive($this->getPath(), 0, strtotime($this->getTsUpdated()));
208
  }
209
+ */
210
+ /*
211
  protected static function getFolderContentsChangeDateRecursive($path, $mtime, $refMtime) {
212
  $ignore = array('.','..');
213
  if(!is_writable($path)) {
224
  }
225
  }
226
  return $mtime;
227
+ } */
228
 
229
  function getId() {
230
  return $this->id;
247
  }
248
 
249
  function setPath($path) {
250
+ $this->path = trailingslashit($path);
251
  }
252
 
253
  function getType() {
class/model/shortpixel-image.php DELETED
@@ -1,32 +0,0 @@
1
- <?php
2
- // NOT FOR COMMIT
3
- namespace shortPixel;
4
-
5
- /* Image class.
6
- *
7
- *
8
- * - Represents a -single- image.
9
- * - Can handle any type
10
- * - Usually controllers would use a collection of images
11
- * -
12
- *
13
- */
14
- class shortPixelImage
15
- {
16
-
17
- protected $meta; // MetaFacade
18
-
19
- public function __construct($path)
20
- {
21
-
22
- }
23
-
24
-
25
- }
26
-
27
- /*
28
- // do this before putting the meta down, since maybeDump check for last timestamp
29
- $URLsAndPATHs = $itemHandler->getURLsAndPATHs(false);
30
- $this->maybeDumpFromProcessedOnServer($itemHandler, $URLsAndPATHs);
31
-
32
- */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
class/model/shortpixel-meta.php CHANGED
@@ -26,7 +26,7 @@ class ShortPixelMeta extends ShortPixelEntity{
26
  protected $actualWidth;
27
  protected $actualHeight;
28
  protected $backup;
29
- protected $status; //0 waiting, 1 pending, 2 success, -x errors
30
  protected $retries;
31
  protected $message;
32
  protected $tsAdded;
@@ -45,6 +45,10 @@ class ShortPixelMeta extends ShortPixelEntity{
45
  const FILE_STATUS_RESTORED = 3;
46
  const FILE_STATUS_TORESTORE = 4; // Used for Bulk Restore
47
 
 
 
 
 
48
  public function __construct($data = array()) {
49
  parent::__construct($data);
50
  }
26
  protected $actualWidth;
27
  protected $actualHeight;
28
  protected $backup;
29
+ protected $status; //0 not-optimized, 1 pending, 2 success, -x errors
30
  protected $retries;
31
  protected $message;
32
  protected $tsAdded;
45
  const FILE_STATUS_RESTORED = 3;
46
  const FILE_STATUS_TORESTORE = 4; // Used for Bulk Restore
47
 
48
+ const COMPRESSION_LOSSLESSS = 0;
49
+ const COMPRESSION_LOSSY = 1;
50
+ const COMPRESSION_GLOSSY = 2;
51
+
52
  public function __construct($data = array()) {
53
  parent::__construct($data);
54
  }
class/model/sp-file-rights-exception.php DELETED
@@ -1,6 +0,0 @@
1
- <?php
2
-
3
- class ShortPixelFileRightsException extends Exception {
4
-
5
- }
6
-
 
 
 
 
 
 
class/shortpixel_queue.php CHANGED
@@ -134,10 +134,11 @@ class ShortPixelQueue {
134
  }
135
 
136
  protected function pushCallback($priorityQueue, $ID) {
137
- WPShortPixel::log("PUSH: Push ID $ID into queue " . json_encode($priorityQueue));
 
138
  array_push($priorityQueue, $ID);
139
  $prioQ = array_unique($priorityQueue);
140
- WPShortPixel::log("PUSH: Updated: " . json_encode($prioQ));//get_option("wp-short-pixel-priorityQueue")));
141
  return $prioQ;
142
  }
143
 
134
  }
135
 
136
  protected function pushCallback($priorityQueue, $ID) {
137
+ Log::addDebug("PUSH: Push ID $ID into queue " . json_encode($priorityQueue));
138
+
139
  array_push($priorityQueue, $ID);
140
  $prioQ = array_unique($priorityQueue);
141
+
142
  return $prioQ;
143
  }
144
 
class/view/settings/part-advanced.php CHANGED
@@ -51,66 +51,76 @@ namespace ShortPixel;
51
  <td>
52
  <span style="display:none;">Current PHP version: <?php echo(phpversion()) ?></span>
53
  <?php if($view->customFolders) { ?>
54
- <table class="shortpixel-folders-list">
55
- <tr style="font-weight: bold;">
56
- <th><?php _e('Folder name','shortpixel-image-optimiser');?></th>
57
- <th><?php _e('Type &amp; Status','shortpixel-image-optimiser');?></th>
58
- <th><?php _e('Files','shortpixel-image-optimiser');?></th>
59
- <th><?php _e('Last change','shortpixel-image-optimiser');?></th>
60
- <td>&nbsp;</td>
61
- </tr>
62
- <?php foreach($view->customFolders as $folder_id => $folder) {
63
- $folder_type = $folder->getType();
64
 
65
- $type_display = ($folder_type) ? ucfirst($folder_type) . "<br>" : "";
66
- $stat = $this->shortPixel->getSpMetaDao()->getFolderOptimizationStatus($folder->getId());
67
- $cnt = $folder->getFileCount();
 
 
 
 
 
 
68
 
 
 
 
 
 
 
 
 
 
 
 
69
  $st = ($cnt == 0
70
  ? __("Empty",'shortpixel-image-optimiser')
71
  : ($stat->Total == $stat->Optimized
72
  ? __("Optimized",'shortpixel-image-optimiser')
73
  : ($stat->Optimized + $stat->Pending > 0 ? __("Pending",'shortpixel-image-optimiser') : __("Waiting",'shortpixel-image-optimiser'))));
74
 
75
- $err = $stat->Failed > 0 && !$st == __("Empty",'shortpixel-image-optimiser') ? " ({$stat->Failed} failed)" : "";
 
 
76
 
77
  $action = ($st == __("Optimized",'shortpixel-image-optimiser') || $st == __("Empty",'shortpixel-image-optimiser') ? __("Stop monitoring",'shortpixel-image-optimiser') : __("Stop optimizing",'shortpixel-image-optimiser'));
78
 
79
- if ($folder_type == 'nextgen' && $view->data->includeNextGen == 1)
80
  $action = false;
81
 
82
  $fullStat = $st == __("Empty",'shortpixel-image-optimiser') ? "" : __("Optimized",'shortpixel-image-optimiser') . ": " . $stat->Optimized . ", "
83
  . __("Pending",'shortpixel-image-optimiser') . ": " . $stat->Pending . ", " . __("Waiting",'shortpixel-image-optimiser') . ": " . $stat->Waiting . ", "
84
  . __("Failed",'shortpixel-image-optimiser') . ": " . $stat->Failed;
 
 
85
  ?>
86
- <tr>
87
- <td class='folder folder-<?php echo $folder_id ?>'>
88
- <?php echo($folder->getPath()); ?>
89
- </td>
90
- <td>
91
  <?php if(!($st == "Empty")) { ?>
92
- <a href="javascript:none();" title="<?php echo $fullStat; ?>" style="text-decoration: none;">
93
- <img alt='Info icon' src='<?php echo( wpSPIO()->plugin_url('res/img/info-icon.png' ));?>' style="margin-bottom: -2px;"/>
94
- </a>&nbsp;<?php } echo($type_display.$st.$err); ?>
95
-
96
- </td>
97
- <td>
 
98
  <?php echo($cnt); ?> files
99
- </td>
100
- <td>
101
- <?php echo($folder->getTsUpdated()); ?>
102
- </td>
103
- <td>
 
 
 
104
  <?php if ($action): ?>
105
- <input type="button" class="button remove-folder-button" data-value="<?php echo($folder->getPath()); ?>" title="<?php echo($action . " " . $folder->getPath()); ?>" value="<?php echo $action;?>">
106
  <?php endif; ?>
107
- <input type="button" style="display:none;" class="button button-alert recheck-folder-button" data-value="<?php echo($folder->getPath()); ?>"
108
- title="<?php _e('Full folder refresh, check each file of the folder if it changed since it was optimized. Might take up to 1 min. for big folders.','shortpixel-image-optimiser');?>"
109
- value="<?php _e('Refresh','shortpixel-image-optimiser');?>">
110
- </td>
111
- </tr>
112
  <?php }?>
113
- </table>
114
  <?php } ?>
115
 
116
  <div class='addCustomFolder'>
@@ -119,7 +129,7 @@ namespace ShortPixel;
119
  <p class='add-folder-text'><strong><?php _e('Add a custom folder', 'shortpixel-image-optimiser'); ?></strong></p>
120
  <input type="text" name="addCustomFolderView" id="addCustomFolderView" class="regular-text" value="" disabled style="">&nbsp;
121
  <input type="hidden" name="addCustomFolder" id="addCustomFolder" value=""/>
122
- <input type="hidden" id="customFolderBase" value="<?php echo $this->shortPixel->getCustomFolderBase(); ?>">
123
 
124
  <a class="button select-folder-button" title="<?php _e('Select the images folder on your server.','shortpixel-image-optimiser');?>" href="javascript:void(0);">
125
  <?php _e('Select ...','shortpixel-image-optimiser');?>
51
  <td>
52
  <span style="display:none;">Current PHP version: <?php echo(phpversion()) ?></span>
53
  <?php if($view->customFolders) { ?>
 
 
 
 
 
 
 
 
 
 
54
 
55
+ <div class="shortpixel-folders-list">
56
+ <div class='heading'>
57
+ <span><?php _e('Folder name','shortpixel-image-optimiser');?></span>
58
+ <span><?php _e('Type &amp; Status','shortpixel-image-optimiser');?></span>
59
+ <span><?php _e('Files','shortpixel-image-optimiser');?></span>
60
+ <span><?php _e('Last change','shortpixel-image-optimiser');?></span>
61
+ <span>&nbsp;</span>
62
+ <span class='action'>&nbsp;</span>
63
+ </div>
64
 
65
+ <?php
66
+ foreach($view->customFolders as $index => $dirObj) {
67
+ $folder_id = $dirObj->getID();
68
+
69
+
70
+ $type_display = ($dirObj->isNextGen() ) ? __('Nextgen', 'shortpixel-image-optimiser') . "<br>" : "";
71
+ // $stat = $this->shortPixel->getSpMetaDao()->getFolderOptimizationStatus($folder->getId());
72
+ $stat = $dirObj->getStats();
73
+
74
+ $cnt = $stat->Total;
75
+
76
  $st = ($cnt == 0
77
  ? __("Empty",'shortpixel-image-optimiser')
78
  : ($stat->Total == $stat->Optimized
79
  ? __("Optimized",'shortpixel-image-optimiser')
80
  : ($stat->Optimized + $stat->Pending > 0 ? __("Pending",'shortpixel-image-optimiser') : __("Waiting",'shortpixel-image-optimiser'))));
81
 
82
+ $err = $stat->Failed > 0 && !$st == __("Empty",'shortpixel-image-optimiser') ? " ({$stat->Failed} failed)" : false;
83
+ if (! $dirObj->exists() && ! $err)
84
+ $err = __('Directory does not exist', 'shortpixel-image-optimiser');
85
 
86
  $action = ($st == __("Optimized",'shortpixel-image-optimiser') || $st == __("Empty",'shortpixel-image-optimiser') ? __("Stop monitoring",'shortpixel-image-optimiser') : __("Stop optimizing",'shortpixel-image-optimiser'));
87
 
88
+ if ($dirObj->isNextGen() && $view->data->includeNextGen == 1)
89
  $action = false;
90
 
91
  $fullStat = $st == __("Empty",'shortpixel-image-optimiser') ? "" : __("Optimized",'shortpixel-image-optimiser') . ": " . $stat->Optimized . ", "
92
  . __("Pending",'shortpixel-image-optimiser') . ": " . $stat->Pending . ", " . __("Waiting",'shortpixel-image-optimiser') . ": " . $stat->Waiting . ", "
93
  . __("Failed",'shortpixel-image-optimiser') . ": " . $stat->Failed;
94
+
95
+ $refreshUrl = add_query_arg(array('sp-action' => 'action_refreshfolder', 'folder_id' => $folder_id, 'part' => 'adv-settings'), $this->url);
96
  ?>
97
+ <div>
98
+ <span class='folder folder-<?php echo $dirObj->getId() ?>'><?php echo($dirObj->getPath()); ?></span>
99
+ <span>
 
 
100
  <?php if(!($st == "Empty")) { ?>
101
+ <span title="<?php echo $fullStat; ?>" class='info-icon'>
102
+ <img alt='<?php _e('Info Icon', 'shortpixel-image-optimiser') ?>' src='<?php echo( wpSPIO()->plugin_url('res/img/info-icon.png' ));?>' style="margin-bottom: -2px;"/>
103
+ </span>&nbsp;<?php }
104
+ echo($type_display. ' ' . $st . '<br>' . $err);
105
+ ?>
106
+ </span>
107
+ <span>
108
  <?php echo($cnt); ?> files
109
+ </span>
110
+ <span>
111
+ <?php echo( date_i18n( get_option('date_format') . ' H:i', $dirObj->getUpdated() )); ?>
112
+ </span>
113
+ <span>
114
+ <a href='<?php echo $refreshUrl ?>' title="<?php _e('Recheck for new images', 'shortpixel-image-optimiser'); ?>" class='refresh-folder'><i class='dashicons dashicons-update'>&nbsp;</i></a>
115
+ </span>
116
+ <span class='action'>
117
  <?php if ($action): ?>
118
+ <input type="button" class="button remove-folder-button" data-value="<?php echo($dirObj->getID()); ?>" data-name="<?php echo $dirObj->getPath() ?>" title="<?php echo($action . " " . $dirObj->getPath()); ?>" value="<?php echo $action;?>">
119
  <?php endif; ?>
120
+ </span>
121
+ </div>
 
 
 
122
  <?php }?>
123
+ </div> <!-- shortpixel-folders-list -->
124
  <?php } ?>
125
 
126
  <div class='addCustomFolder'>
129
  <p class='add-folder-text'><strong><?php _e('Add a custom folder', 'shortpixel-image-optimiser'); ?></strong></p>
130
  <input type="text" name="addCustomFolderView" id="addCustomFolderView" class="regular-text" value="" disabled style="">&nbsp;
131
  <input type="hidden" name="addCustomFolder" id="addCustomFolder" value=""/>
132
+ <input type="hidden" id="customFolderBase" value="<?php echo $this->view->customFolderBase; ?>">
133
 
134
  <a class="button select-folder-button" title="<?php _e('Select the images folder on your server.','shortpixel-image-optimiser');?>" href="javascript:void(0);">
135
  <?php _e('Select ...','shortpixel-image-optimiser');?>
class/view/settings/part-statistics.php CHANGED
@@ -122,7 +122,7 @@ $quotaData = $this->quotaData;
122
  }
123
  ?>
124
  <th><a href="<?php echo $link ?>" target="_blank">
125
- <?php _e('See report (last 40 days)','shortpixel-image-optimiser');?>
126
  </a></th>
127
  <td>&nbsp;</td>
128
  </tr>
122
  }
123
  ?>
124
  <th><a href="<?php echo $link ?>" target="_blank">
125
+ <?php _e('See report (last 30 days)','shortpixel-image-optimiser');?>
126
  </a></th>
127
  <td>&nbsp;</td>
128
  </tr>
class/view/shortpixel-list-table.php CHANGED
@@ -1,4 +1,5 @@
1
  <?php
 
2
  use ShortPixel\Notices\NoticeController as Notices;
3
 
4
 
@@ -86,29 +87,6 @@ class ShortPixelListTable extends WP_List_Table {
86
  );
87
 
88
 
89
- /*'optimize' => sprintf( '<a href="?page=%s&action=%s&image=%s&_wpnonce=%s&noheader=true">%s</a>',
90
- esc_attr( $_REQUEST['page'] ), 'optimize', absint( $item->id ), wp_create_nonce( 'sp_optimize_image' ),
91
- __('Optimize','shortpixel-image-optimiser')), */
92
- /*'retry' => sprintf( '<a href="?page=%s&action=%s&image=%s&_wpnonce=%s&noheader=true">%s</a>',
93
- esc_attr( $_REQUEST['page'] ), 'optimize', absint( $item->id ), wp_create_nonce( 'sp_optimize_image' ),
94
- __('Retry','shortpixel-image-optimiser')), */
95
-
96
- /* 'redolossless' => sprintf( '<a href="?page=%s&action=%s&type=%s&image=%s&_wpnonce=%s&noheader=true">%s</a>',
97
- esc_attr( $_REQUEST['page'] ), 'redo', 'lossless', absint( $item->id ), wp_create_nonce( 'sp_redo_image' ),
98
- __('Re-optimize lossless','shortpixel-image-optimiser')), */
99
- /* 'redolossy' => sprintf( '<a href="?page=%s&action=%s&type=%s&image=%s&_wpnonce=%s&noheader=true">%s</a>',
100
- esc_attr( $_REQUEST['page'] ), 'redo', 'lossy', absint( $item->id ), wp_create_nonce( 'sp_redo_image' ),
101
- __('Re-optimize lossy','shortpixel-image-optimiser')), */
102
- /*'redoglossy' => sprintf( '<a href="?page=%s&action=%s&type=%s&image=%s&_wpnonce=%s&noheader=true">%s</a>',
103
- esc_attr( $_REQUEST['page'] ), 'redo', 'glossy', absint( $item->id ), wp_create_nonce( 'sp_redo_image' ),
104
- __('Re-optimize glossy','shortpixel-image-optimiser')), */
105
- /*'quota' => sprintf( '<a href="?page=%s&action=%s&image=%s&_wpnonce=%s&noheader=true">%s</a>',
106
- esc_attr( $_REQUEST['page'] ), 'quota', absint( $item->id ), wp_create_nonce( 'sp_check_quota' ),
107
- __('Check quota','shortpixel-image-optimiser')), */
108
- /*'restore' => sprintf( '<a href="?page=%s&action=%s&image=%s&_wpnonce=%s&noheader=true">%s</a>',
109
- esc_attr( $_REQUEST['page'] ), 'restore', absint( $item->id ), wp_create_nonce( 'sp_restore_image' ),
110
- __('Restore','shortpixel-image-optimiser')), */
111
-
112
  $has_backup = $this->ctrl->getBackupFolderAny($item->folder, array());
113
 
114
  $settings = $this->ctrl->getSettings();
@@ -134,7 +112,7 @@ class ShortPixelListTable extends WP_List_Table {
134
  }
135
  //$actionsEnabled['redo'.($item->compression_type == 1 ? "lossless" : "lossy")] = true;
136
  } elseif($item->status == ShortPixelMeta::FILE_STATUS_RESTORED || $item->status < ShortPixelMeta::FILE_STATUS_UNPROCESSED) {
137
- $actionsEnabled['retry'] = true;
138
  }
139
  $actionsEnabled['view'] = true;
140
  $title = $title . $this->row_actions($actions, false, $item->id, $actionsEnabled );
1
  <?php
2
+ return; // not in use
3
  use ShortPixel\Notices\NoticeController as Notices;
4
 
5
 
87
  );
88
 
89
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
  $has_backup = $this->ctrl->getBackupFolderAny($item->folder, array());
91
 
92
  $settings = $this->ctrl->getSettings();
112
  }
113
  //$actionsEnabled['redo'.($item->compression_type == 1 ? "lossless" : "lossy")] = true;
114
  } elseif($item->status == ShortPixelMeta::FILE_STATUS_RESTORED || $item->status < ShortPixelMeta::FILE_STATUS_UNPROCESSED) {
115
+ $actionsEnabled['retry'] = true; // This one can never hit on Status restored
116
  }
117
  $actionsEnabled['view'] = true;
118
  $title = $title . $this->row_actions($actions, false, $item->id, $actionsEnabled );
class/view/shortpixel_view.php CHANGED
@@ -446,7 +446,7 @@ class ShortPixelView {
446
  </div>
447
  <p><?php printf(__('Go to the ShortPixel <a href="%soptions-general.php?page=wp-shortpixel-settings&part=stats">Stats</a>
448
  and see all your websites\' optimized stats. Download your detailed <a href="https://%s/v2/report.php?key=%s">Optimization Report</a>
449
- to check your image optimization statistics for the last 40 days.','shortpixel-image-optimiser'),
450
  get_admin_url(), SHORTPIXEL_API, (defined("SHORTPIXEL_HIDE_API_KEY") ? '' : $this->ctrl->getApiKey()) );?></p>
451
  <?php
452
  $failed = $this->ctrl->getPrioQ()->getFailed();
@@ -1659,7 +1659,7 @@ class ShortPixelView {
1659
  </tr>
1660
  <tr>
1661
  <th><a href="https://<?php echo(SHORTPIXEL_API);?>/v2/report.php?key=<?php echo(defined("SHORTPIXEL_HIDE_API_KEY") ? '' : $this->ctrl->getApiKey());?>" target="_blank">
1662
- <?php _e('See report (last 40 days)','shortpixel-image-optimiser');?>
1663
  </a></th>
1664
  <td>&nbsp;</td>
1665
  </tr>
446
  </div>
447
  <p><?php printf(__('Go to the ShortPixel <a href="%soptions-general.php?page=wp-shortpixel-settings&part=stats">Stats</a>
448
  and see all your websites\' optimized stats. Download your detailed <a href="https://%s/v2/report.php?key=%s">Optimization Report</a>
449
+ to check your image optimization statistics for the last 30 days.','shortpixel-image-optimiser'),
450
  get_admin_url(), SHORTPIXEL_API, (defined("SHORTPIXEL_HIDE_API_KEY") ? '' : $this->ctrl->getApiKey()) );?></p>
451
  <?php
452
  $failed = $this->ctrl->getPrioQ()->getFailed();
1659
  </tr>
1660
  <tr>
1661
  <th><a href="https://<?php echo(SHORTPIXEL_API);?>/v2/report.php?key=<?php echo(defined("SHORTPIXEL_HIDE_API_KEY") ? '' : $this->ctrl->getApiKey());?>" target="_blank">
1662
+ <?php _e('See report (last 30 days)','shortpixel-image-optimiser');?>
1663
  </a></th>
1664
  <td>&nbsp;</td>
1665
  </tr>
class/view/view-debug-box.php DELETED
@@ -1,44 +0,0 @@
1
- <?php
2
- // Debug Box to load Log File
3
- namespace ShortPixel;
4
- wp_enqueue_script( 'jquery-ui-draggable' );
5
- ?>
6
-
7
- <style>
8
- .sp_debug_box
9
- {
10
- position: absolute;
11
- right: 0px;
12
- top: 50px;
13
- background-color: #fff;
14
- width: 100px;
15
- z-index: 1000000;
16
- border: 1px solid #000;
17
- }
18
- .sp_debug_box .header
19
- {
20
- min-height: 10px;
21
- background: #000;
22
- color: #fff;
23
- }
24
- .sp_debug_box .content_box
25
- {
26
- background: #ccc;
27
- }
28
- </style>
29
-
30
- <script language='javascript'>
31
- jQuery(document).ready(function($)
32
- {
33
- $( ".sp_debug_box" ).draggable();
34
-
35
- });
36
- </script>
37
-
38
- <div class='sp_debug_box'>
39
- <div class='header'>Debug Box </div>
40
- <a target="_blank" href='<?php echo $this->layout->logLink ?>'>Logfile</a>
41
- <div class='content_box'>
42
-
43
- </div>
44
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
class/view/view-other-media.php ADDED
@@ -0,0 +1,139 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace ShortPixel;
3
+ use ShortPixel\ShortpixelLogger\ShortPixelLogger as Log;
4
+ use ShortPixel\Notices\NoticeController as Notices;
5
+
6
+ $fs = \wpSPIO()->filesystem();
7
+
8
+ if ( isset($_GET['noheader']) ) {
9
+ require_once(ABSPATH . 'wp-admin/admin-header.php');
10
+ }
11
+ //$this->outputHSBeacon();
12
+ \ShortPixel\HelpScout::outputBeacon(\wpSPIO()->getShortPixel()->getApiKey());
13
+
14
+ echo $this->view->rewriteHREF;
15
+
16
+ ?>
17
+ <div class="wrap shortpixel-other-media">
18
+ <h2>
19
+ <?php _e('Other Media optimized by ShortPixel','shortpixel-image-optimiser');?>
20
+ </h2>
21
+
22
+ <div class='toolbar'>
23
+
24
+ <div>
25
+ <?php
26
+ $nonce = wp_create_nonce( 'sp_custom_action' );
27
+ ?>
28
+ <a href="upload.php?page=wp-short-pixel-custom&action=refresh&_wpnonce=<?php echo $nonce ?>" id="refresh" class="button button-primary" title="<?php _e('Refresh custom folders content','shortpixel-image-optimiser');?>">
29
+ <?php _e('Refresh folders','shortpixel-image-optimiser');?>
30
+ </a>
31
+ </div>
32
+
33
+
34
+ <div class="searchbox">
35
+ <form method="get">
36
+ <input type="hidden" name="page" value="wp-short-pixel-custom" />
37
+ <input type='hidden' name='order' value="<?php echo $this->order ?>" />
38
+ <input type="hidden" name="orderby" value="<?php echo $this->orderby ?>" />
39
+
40
+ <p class="search-form">
41
+ <label><?php _e('Search', 'shortpixel-image-optimiser'); ?></label>
42
+ <input type="text" name="s" value="<?php echo $this->search ?>" />
43
+
44
+ </p>
45
+ <?php //$customMediaListTable->search_box("Search", "sp_search_file");
46
+ ?>
47
+ </form>
48
+ </div>
49
+ </div>
50
+
51
+ <div class='pagination tablenav'>
52
+ <div class='tablenav-pages'>
53
+ <?php echo $this->view->pagination; ?>
54
+ </div>
55
+ </div>
56
+
57
+ <div class='list-overview'>
58
+ <div class='heading'>
59
+ <?php foreach($this->view->headings as $hname => $heading):
60
+ $isSortable = $heading['sortable'];
61
+ ?>
62
+ <span class='heading <?php echo $hname ?>'>
63
+ <?php echo $this->getDisplayHeading($heading); ?>
64
+ </span>
65
+
66
+ <?php endforeach; ?>
67
+ </div>
68
+
69
+ <?php if (count($this->view->items) == 0) : ?>
70
+ <div class='no-items'> <p>
71
+ <?php
72
+ if ($this->search === false):
73
+ echo(__('No images available. Go to <a href="options-general.php?page=wp-shortpixel-settings&part=adv-settings">Advanced Settings</a> to configure additional folders to be optimized.','shortpixel-image-optimiser'));
74
+ else:
75
+ echo __('Your search query didn\'t result in any images. ', 'shortpixel-image-optimiser');
76
+ endif; ?>
77
+ </p>
78
+ </div>
79
+
80
+ <?php endif; ?>
81
+
82
+ <?php
83
+ $folders = $this->view->folders;
84
+
85
+ foreach($this->view->items as $item): ?>
86
+ <div class='item item-C-<?php echo $item->id ?>'>
87
+ <?php
88
+ $itemFile = $fs->getFile($item->path);
89
+ $filesize = $itemFile->getFileSize();
90
+ $display_date = $this->getDisplayDate($item);
91
+ $folder_id = $item->folder_id;
92
+
93
+ $rowActions = $this->getRowActions($item, $itemFile);
94
+ $actions = $this->getActions($item, $itemFile);
95
+
96
+ $folder = isset($folders[$folder_id]) ? $folders[$folder_id] : false;
97
+ $media_type = ($folder && $folder->isNextGen()) ? __('Nextgen', 'shortpixel-image-optimiser') : __('Custom', 'shortpixel_image_optimiser');
98
+
99
+ ?>
100
+ <span><div class='thumb'>
101
+ <?php if ($filesize <= 500000 && $filesize > 0):
102
+ $img_url = $fs->pathToUrl($itemFile); ?>
103
+ <img src="<?php echo $img_url ?>" />
104
+ <?php endif; ?>
105
+
106
+ </div></span>
107
+ <span class='filename'><?php echo $itemFile->getFileName() ?>
108
+ <div class="row-actions"><?php
109
+ $numberActions = count($rowActions);
110
+ for ($i = 0; $i < $numberActions; $i++)
111
+ {
112
+ echo $rowActions[$i];
113
+ if ($i < ($numberActions-1) )
114
+ echo '|';
115
+ }
116
+ ?></div>
117
+ </span>
118
+ <span class='folderpath'><?php echo (string) $itemFile->getFileDir(); ?></span>
119
+ <span class='mediatype'><?php echo $media_type ?></span>
120
+ <span class="date"><?php echo $display_date ?></span>
121
+ <span id='sp-cust-msg-C-<?php echo $item->id ?>'>
122
+ <span class='sp-column-info'><?php echo $this->getDisplayStatus($item); ?></span>
123
+ </span>
124
+ <span class='actions'>
125
+ <?php echo $this->getDisplayActions($this->getActions($item, $itemFile))
126
+ ?></span>
127
+ </div>
128
+ <?php endforeach; ?>
129
+ </div>
130
+
131
+
132
+ <div class='pagination tablenav bottom'>
133
+ <div class='tablenav-pages'>
134
+ <?php echo $this->view->pagination; ?>
135
+ </div>
136
+ </div>
137
+
138
+
139
+ </div> <!-- wrap -->
class/view/view-restore-all.php CHANGED
@@ -1,6 +1,7 @@
1
 
2
  <div class="wrap short-pixel-bulk-page bulk-restore-all">
3
  <form action='<?php echo remove_query_arg('part'); ?>' method='POST' >
 
4
  <h1><?php _e('Bulk Image Optimization by ShortPixel','shortpixel-image-optimiser');?></h1>
5
 
6
  <div class="sp-notice sp-notice-info sp-floating-block sp-full-width">
@@ -17,7 +18,9 @@
17
  <h4><?php _e('Select which Custom Media Folders to restore', 'shortpixel-image-optimiser'); ?></h4>
18
 
19
  <?php $folders = $controller->getCustomFolders();
 
20
  foreach($folders as $folder):
 
21
  $path = $folder->getPath();
22
  $fileCount = $folder->getFileCount();
23
  $folder_id = $folder->getId();
1
 
2
  <div class="wrap short-pixel-bulk-page bulk-restore-all">
3
  <form action='<?php echo remove_query_arg('part'); ?>' method='POST' >
4
+ <?php wp_nonce_field('bulk-restore-all', 'sp-nonce'); ?>
5
  <h1><?php _e('Bulk Image Optimization by ShortPixel','shortpixel-image-optimiser');?></h1>
6
 
7
  <div class="sp-notice sp-notice-info sp-floating-block sp-full-width">
18
  <h4><?php _e('Select which Custom Media Folders to restore', 'shortpixel-image-optimiser'); ?></h4>
19
 
20
  <?php $folders = $controller->getCustomFolders();
21
+ // echo get_class($controller);
22
  foreach($folders as $folder):
23
+
24
  $path = $folder->getPath();
25
  $fileCount = $folder->getFileCount();
26
  $folder_id = $folder->getId();
class/wp-short-pixel.php CHANGED
@@ -116,7 +116,7 @@ class WPShortPixel {
116
  if($isAdminUser) {
117
  //add settings page
118
  //add_action( 'admin_menu', array( &$this, 'registerSettingsPage' ) );//display SP in Settings menu
119
- add_action( 'admin_menu', array( &$this, 'registerAdminPage' ) );
120
 
121
  add_action('wp_ajax_shortpixel_browse_content', array(&$this, 'browseContent'));
122
  add_action('wp_ajax_shortpixel_get_backup_size', array(&$this, 'getBackupSize'));
@@ -180,15 +180,16 @@ class WPShortPixel {
180
 
181
  // @hook admin menu
182
  // @todo move to plugin class
 
183
  function registerAdminPage( ) {
184
  return;
185
  if($this->spMetaDao->hasFoldersTable() && count($this->spMetaDao->getFolders())) {
186
- /*translators: title and menu name for the Other media page*/
187
  add_media_page( __('Other Media Optimized by ShortPixel','shortpixel-image-optimiser'), __('Other Media','shortpixel-image-optimiser'), 'edit_others_posts', 'wp-short-pixel-custom', array( &$this, 'listCustomMedia' ) );
188
  }
189
- /*translators: title and menu name for the Bulk Processing page*/
190
  add_media_page( __('ShortPixel Bulk Process','shortpixel-image-optimiser'), __('Bulk ShortPixel','shortpixel-image-optimiser'), 'edit_others_posts', 'wp-short-pixel-bulk', array( &$this, 'bulkProcess' ) );
191
- }
192
 
193
  /*public static function shortPixelActivatePlugin()//reset some params to avoid trouble for plugins that were activated/deactivated/activated
194
  {
@@ -357,11 +358,7 @@ class WPShortPixel {
357
  /** @todo Plugin init class. Try to get rid of inline JS. Also still loads on all WP pages, prevent that. */
358
  function shortPixelJS() {
359
 
360
- if (! \wpSPIO()->env()->is_screen_to_use )
361
- {
362
- if (! wpSPIO()->env()->is_front) // exeception if this is called to load from your frontie.
363
- return; // not ours, don't load JS and such.
364
- }
365
 
366
  $is_front = (wpSPIO()->env()->is_front) ? true : false;
367
 
@@ -389,7 +386,7 @@ class WPShortPixel {
389
  // }
390
 
391
 
392
- wp_register_script('shortpixel' . $this->jsSuffix, plugins_url('/res/js/shortpixel' . $this->jsSuffix,SHORTPIXEL_PLUGIN_FILE), array('jquery'), SHORTPIXEL_IMAGE_OPTIMISER_VERSION, true);
393
 
394
 
395
  // Using an Array within another Array to protect the primitive values from being cast to strings
@@ -456,13 +453,22 @@ class WPShortPixel {
456
  'loading' => __('Loading...', 'shortpixel-image-optimiser' ),
457
  //'' => __('', 'shortpixel-image-optimiser' ),
458
  );
459
- wp_localize_script( 'shortpixel' . $this->jsSuffix, '_spTr', $jsTranslation );
460
- wp_localize_script( 'shortpixel' . $this->jsSuffix, 'ShortPixelConstants', $ShortPixelConstants );
461
- wp_enqueue_script('shortpixel' . $this->jsSuffix);
 
 
 
462
 
463
- wp_enqueue_script('jquery.knob.min.js', plugins_url('/res/js/jquery.knob.min.js',SHORTPIXEL_PLUGIN_FILE) );
464
- wp_enqueue_script('jquery.tooltip.min.js', plugins_url('/res/js/jquery.tooltip.min.js',SHORTPIXEL_PLUGIN_FILE) );
 
 
 
465
 
 
 
 
466
 
467
  wp_enqueue_script('punycode.min.js', plugins_url('/res/js/punycode.min.js',SHORTPIXEL_PLUGIN_FILE) );
468
  }
@@ -687,8 +693,7 @@ class WPShortPixel {
687
  return $meta;
688
  }
689
 
690
- self::log("Handle Media Library Image Upload #{$ID}");
691
- //self::log("STACK: " . json_encode(debug_backtrace()));
692
 
693
  if(!$this->_settings->optimizePdfs && 'pdf' === $currentFile->getExtension() ) {
694
  //pdf is not optimized automatically as per the option, but can be optimized by button. Nothing to do.
@@ -724,6 +729,7 @@ class WPShortPixel {
724
  //send a processing request right after a file was uploaded, do NOT wait for response
725
  $this->_apiInterface->doRequests($URLsAndPATHs['URLs'], false, $itemHandler, false, $refresh);
726
  } catch(Exception $e) {
 
727
  $meta['ShortPixelImprovement'] = $e->getMessage();
728
  return $meta;
729
  }
@@ -796,52 +802,8 @@ class WPShortPixel {
796
  return $converter->checkConvertMediaPng2Jpg($itemHandler);
797
  }
798
 
799
- // moved to external.
800
- /* public function handleGravityFormsImageField($value) {
801
- if(!($folder = $this->spMetaDao->getFolder(SHORTPIXEL_UPLOADS_BASE . '/gravity_forms'))) {
802
- return;
803
- }
804
- if(strpos($value , '|:|')) {
805
- $cleanup = explode('|:|', $value);
806
- $value = $cleanup[0];
807
- }
808
- //ShortPixel is monitoring the gravity forms folder, add the image to queue
809
- $uploadDir = wp_upload_dir();
810
- $localPath = str_replace($uploadDir['baseurl'], SHORTPIXEL_UPLOADS_BASE, $value);
811
-
812
- return $this->addPathToCustomFolder($localPath, $folder->getId(), 0);
813
- } */
814
-
815
- /**
816
- * this is hooked onto the NextGen upload
817
- * @param type $image
818
- */
819
- /* public function handleNextGenImageUpload($image)
820
- {
821
- if ($this->_settings->includeNextGen == 1) {
822
- $imageFsPath = ShortPixelNextGenAdapter::getImageAbspath($image);
823
-
824
- $customFolders = $this->spMetaDao->getFolders();
825
-
826
- $folderId = -1;
827
- foreach ($customFolders as $folder) {
828
- if (strpos($imageFsPath, $folder->getPath()) === 0) {
829
- $folderId = $folder->getId();
830
- break;
831
- }
832
- }
833
- if ($folderId == -1) { //if not found, create
834
- $galleryPath = dirname($imageFsPath);
835
- $folder = new ShortPixelFolder(array("path" => $galleryPath), $this->_settings->excludePatterns);
836
- $folderMsg = $this->spMetaDao->saveFolder($folder);
837
- $folderId = $folder->getId();
838
- //self::log("NG Image Upload: created folder from path $galleryPath : Folder info: " . json_encode($folder));
839
- }
840
-
841
- return $this->addPathToCustomFolder($imageFsPath, $folderId, $image->pid);
842
- }
843
- } */
844
 
 
845
  public function addPathToCustomFolder($imageFsPath, $folderId, $pid) {
846
  //prevent adding it multiple times if the action is called repeatedly (Gravity Forms does that)
847
  $existing = $this->spMetaDao->getMetaForPath($imageFsPath);
@@ -863,7 +825,10 @@ class WPShortPixel {
863
  $meta->setResizeHeight($this->_settings->resizeHeight);
864
  $ID = $this->spMetaDao->addImage($meta);
865
  $meta->setId($ID);
866
- $this->prioQ->push('C-' . $ID);
 
 
 
867
  //add the thumb image if exists
868
  $pathParts[] = "thumbs_" . $pathParts[count($pathParts) - 1];
869
  $pathParts[count($pathParts) - 2] = "thumbs";
@@ -881,7 +846,9 @@ class WPShortPixel {
881
  $metaThumb->setResizeHeight($this->_settings->resizeHeight);
882
  $ID = $this->spMetaDao->addImage($metaThumb);
883
  $metaThumb->setId($ID);
884
- $this->prioQ->push('C-' . $ID);
 
 
885
  }
886
  return $meta;
887
  }
@@ -897,7 +864,6 @@ class WPShortPixel {
897
  }
898
  if($meta->getStatus() != ShortPixelMeta::FILE_STATUS_SUCCESS) {
899
 
900
-
901
  $meta->setStatus(ShortPixelMeta::FILE_STATUS_PENDING);
902
  $meta->setRetries(0);
903
  /* [BS] This is being set because meta in other states does not keep previous values. The value 0 is problematic
@@ -1256,15 +1222,18 @@ class WPShortPixel {
1256
 
1257
  //self::log("HIP: 0 Bulk ran: " . $this->prioQ->bulkRan());
1258
  $customIds = false;
 
1259
  if(count($ids) < SHORTPIXEL_PRESEND_ITEMS && $this->prioQ->bulkRan() && $this->_settings->hasCustomFolders
1260
  && (!$this->_settings->cancelPointer || $this->_settings->skipToCustom)
1261
  && !$this->_settings->customBulkPaused)
1262
  { //take from custom images if any left to optimize - only if bulk was ever started
1263
- //but first refresh if it wasn't refreshed in the last hour
1264
- if(time() - $this->_settings->hasCustomFolders > 3600) {
 
 
1265
  $notice = null; $this->refreshCustomFolders();
1266
  $this->_settings->hasCustomFolders = time();
1267
- }
1268
 
1269
  $customIds = $this->spMetaDao->getPendingMetas( SHORTPIXEL_PRESEND_ITEMS - count($ids));
1270
 
@@ -1273,6 +1242,9 @@ class WPShortPixel {
1273
  }
1274
  }
1275
 
 
 
 
1276
  if(count($ids)) {$idl='';foreach($ids as $i){$idl.=$i->getId().' ';}
1277
  Log::addInfo("HIP: 1 Selected IDs: $idl");}
1278
 
@@ -1519,6 +1491,14 @@ class WPShortPixel {
1519
  $this->_settings->bulkLastStatus = $result;
1520
  }
1521
 
 
 
 
 
 
 
 
 
1522
  $ret = json_encode($result);
1523
  self::log("HIP RET " . $ret);
1524
  die($ret);
@@ -2052,7 +2032,6 @@ class WPShortPixel {
2052
  $imageObj->setbyPostID($attachmentID);
2053
 
2054
  $fsFile = $imageObj->getFile();
2055
- //$fsFile = $fs->getAttachedFile($attachmentID);
2056
  $filePath = (string) $fsFile->getFileDir();
2057
 
2058
  $itemHandler = $imageObj->getFacade(); //new ShortPixelMetaFacade($attachmentID);
@@ -2174,8 +2153,11 @@ class WPShortPixel {
2174
  }
2175
  }
2176
  if(!$bkCount) {
2177
- $this->throwNotice('generic-err', __("No backup files found. Restore not performed.",'shortpixel-image-optimiser'));
2178
- Log::addError('No Backup Files Found. ', array($bkFile));
 
 
 
2179
  return false;
2180
  }
2181
 
@@ -2351,6 +2333,7 @@ class WPShortPixel {
2351
  */
2352
  public function throwNotice($when = 'activate', $extra = '') {
2353
  // set_transient("shortpixel_thrown_notice", array('when' => $when, 'extra' => $extra), 120);
 
2354
  Notices::addError($extra); // whatever error is in the extra. Seems that normal messages don't pass here.
2355
  }
2356
 
@@ -2402,19 +2385,20 @@ class WPShortPixel {
2402
  if($backupFile === false)
2403
  {
2404
  Log::addWarn("Custom File $ID - $file does not have a backup");
2405
- Notices::addWarning(sprintf(__('Not able to restore file %s. Could not find backup', 'shortpixel-image-optimiser'), $file));
 
 
2406
  return false;
2407
  }
2408
-
2409
- if ($backupFile->copy($fileObj))
2410
- {
2411
  $backupFile->delete();
2412
- }
2413
- else {
2414
- Log::addError('Could not restore back to source' . $backupFile->getFullPath() );
2415
- Notices::addError('The file could not be restored from backup. Plugin could not copy backup back to original location. Check file permissions. ', 'shortpixel-image-optimiser');
2416
- return false;
2417
- }
2418
 
2419
  /* [BS] Reset all generated image meta. Bring back to start state.
2420
  * Since Wpdb->prepare doesn't support 'null', zero values in this table should not be trusted */
@@ -2477,8 +2461,9 @@ class WPShortPixel {
2477
  $folder_id = $meta->getFolderId();
2478
  $this->doCustomRestore($ID);
2479
 
2480
- $this->spMetaDao->delete($meta);
2481
- $meta = $this->addPathToCustomFolder($path, $folder_id, NULL);
 
2482
 
2483
  if($meta) {
2484
  $meta->setCompressionType(ShortPixelAPI::getCompressionTypeCode($compressionType));
@@ -2757,6 +2742,7 @@ class WPShortPixel {
2757
  * @todo Move this to own view.
2758
  */
2759
  /* Gone! @todo Must go when new ListCMedia is done */
 
2760
  public function listCustomMedia() {
2761
  if( ! class_exists( 'ShortPixelListTable' ) ) {
2762
  require_once('view/shortpixel-list-table.php');
@@ -2814,7 +2800,7 @@ class WPShortPixel {
2814
  <br class="clear">
2815
  </div>
2816
  </div> <?php
2817
- }
2818
 
2819
 
2820
  /** Front End function that controls bulk processes.
@@ -2884,7 +2870,6 @@ class WPShortPixel {
2884
  Log::addInfo('Bulk Process - Bulk Restore');
2885
 
2886
  $bulkRestore = new \ShortPixel\BulkRestoreAll(); // controller
2887
- $bulkRestore->setShortPixel($this);
2888
  $bulkRestore->setupBulk();
2889
 
2890
  $this->prioQ->startBulk(ShortPixelQueue::BULK_TYPE_RESTORE);
@@ -2930,6 +2915,7 @@ class WPShortPixel {
2930
  Log::addInfo('Bulk Process - Pending Meta Count ' . $pendingMeta);
2931
  Log::addInfo('Bulk Process - File left ' . $filesLeft[0]->FilesLeftToBeProcessed );
2932
 
 
2933
  if ( ($filesLeft[0]->FilesLeftToBeProcessed > 0 && $this->prioQ->bulkRunning())
2934
  || (0 + $pendingMeta > 0 && !$this->_settings->customBulkPaused && $this->prioQ->bulkRan())//bulk processing was started
2935
  && (!$this->prioQ->bulkPaused() || $this->_settings->skipToCustom)) //bulk not paused or if paused, user pressed Process Custom button
@@ -3074,6 +3060,7 @@ class WPShortPixel {
3074
 
3075
  $dirpath = $dir->getPath();
3076
  $dirname = $dir->getName();
 
3077
  if($dirname == 'ShortpixelBackups' || ShortPixelMetaFacade::isMediaSubfolder($dirname, false)) continue;
3078
 
3079
  $htmlRel = str_replace("'", "&apos;", $returnDir . $dirname);
@@ -3258,64 +3245,6 @@ class WPShortPixel {
3258
  } */
3259
 
3260
 
3261
- // @todo - Should be part of folder model
3262
- // @param force boolean Force a recheck.
3263
- public function refreshCustomFolders($force = false) {
3264
- $customFolders = array();
3265
- $fs = \wpSPIO()->fileSystem();
3266
-
3267
- if($this->_settings->hasCustomFolders) {
3268
- $customFolders = $this->spMetaDao->getFolders();
3269
- foreach($customFolders as $folder) {
3270
-
3271
- try {
3272
- $mt = $folder->getFolderContentsChangeDate();
3273
- }
3274
- catch(ShortPixelFileRightsException $ex) {
3275
- Notices::addWarning($ex->getMessage());
3276
- }
3277
-
3278
- if($mt > strtotime($folder->getTsUpdated()) || $force) {
3279
- // when forcing, set to never updated.
3280
- if ($force)
3281
- {
3282
- $folder->setTsUpdated(date("Y-m-d H:i:s", 0) ); //
3283
- $this->spMetaDao->update($folder);
3284
- }
3285
-
3286
- $fsFolder = $fs->getDirectory($folder->getPath());
3287
- if ($fsFolder->exists())
3288
- $this->spMetaDao->refreshFolder($fsFolder);
3289
- else {
3290
- Log::addWarn('Custom folder does not exist: ' . $fsFolder->getPath() );
3291
- }
3292
-
3293
- }
3294
- /* if($folder->getPath() === $ignore) continue;
3295
- try {
3296
-
3297
- $mt = $folder->getFolderContentsChangeDate();
3298
- if($mt > strtotime($folder->getTsUpdated())) {
3299
- $fileList = $folder->getFileList(strtotime($folder->getTsUpdated()));
3300
- $this->spMetaDao->batchInsertImages($fileList, $folder->getId());
3301
- $folder->setTsUpdated(date("Y-m-d H:i:s", $mt));
3302
- $folder->setFileCount($folder->countFiles());
3303
- $this->spMetaDao->update($folder);
3304
- }
3305
- } catch(ShortPixelFileRightsException $ex) {
3306
- if(is_array($notice)) {
3307
- if($notice['status'] == 'error') {
3308
- $notice['msg'] .= " " . $ex->getMessage();
3309
- }
3310
- } else {
3311
- $notice = array("status" => "error", "msg" => $ex->getMessage());
3312
- }
3313
- }*/
3314
- } // folders
3315
- }
3316
- return $customFolders;
3317
- }
3318
-
3319
  /** Updates HTAccess files for Webp
3320
  * @param boolean $clear Clear removes all statements from htaccess. For disabling webp.
3321
  */
@@ -3582,11 +3511,11 @@ class WPShortPixel {
3582
  public function resetQuotaExceeded() {
3583
  if( $this->_settings->quotaExceeded == 1) {
3584
  $dismissed = $this->_settings->dismissedNotices ? $this->_settings->dismissedNotices : array();
3585
- ShortPixel\adminNoticesController::resetAPINotices();
3586
- ShortPixel\adminNoticesController::resetQuotaNotices();
3587
- unset($dismissed['exceed']);
3588
  $this->_settings->prioritySkip = array();
3589
  $this->_settings->dismissedNotices = $dismissed;
 
 
3590
  }
3591
  $this->_settings->quotaExceeded = 0;
3592
  }
@@ -4062,8 +3991,10 @@ class WPShortPixel {
4062
  if (@preg_match($pattern, false) !== false)
4063
  {
4064
  $m = preg_match($pattern, $target);
4065
- if ($m !== false)
 
4066
  return true;
 
4067
  }
4068
  }
4069
  else
@@ -4250,157 +4181,6 @@ class WPShortPixel {
4250
  return array_values(array_diff(array(0, 1, 2), array(0 + $compressionType)));
4251
  }
4252
 
4253
- function outputHSBeacon() {
4254
- Log::addWarn('OutputHSBeacon called on old function');
4255
- ?>
4256
- <style>
4257
- .shortpixel-hs-blind {
4258
- position: fixed;
4259
- bottom: 18px;
4260
- right: 0;
4261
- z-index: 20003;
4262
- background-color: white;
4263
- width: 87px;
4264
- height: 174px;
4265
- border-radius: 20px 0 0 20px;
4266
- text-align: right;
4267
- padding-right: 15px;
4268
- }
4269
- .shortpixel-hs-blind a {
4270
- color: lightgray;
4271
- text-decoration: none;
4272
- }
4273
- .shortpixel-hs-blind .dashicons-minus {
4274
- border: 3px solid;
4275
- border-radius: 12px;
4276
- font-size: 12px;
4277
- font-weight: bold;
4278
- line-height: 15px;
4279
- height: 13px;
4280
- width: 13px;
4281
- display:none;
4282
- }
4283
- .shortpixel-hs-blind .dashicons-dismiss {
4284
- font-size: 23px;
4285
- line-height: 19px;
4286
- display: none;
4287
- }
4288
- .shortpixel-hs-blind:hover .dashicons-minus,
4289
- .shortpixel-hs-blind:hover .dashicons-dismiss {
4290
- display: inline-block;
4291
- }
4292
- .shortpixel-hs-button-blind {
4293
- display:none;
4294
- position: fixed;
4295
- bottom: 115px;right: 0;
4296
- z-index: 20003;
4297
- background-color: white;
4298
- width: 237px;
4299
- height: 54px;
4300
- }
4301
- .shortpixel-hs-tools {
4302
- position: fixed;
4303
- bottom: 116px;
4304
- right: 0px;
4305
- z-index: 20003;
4306
- background-color: #ecf9fc;
4307
- padding: 8px 18px 3px 12px;
4308
- border-radius: 26px 0 0 26px;
4309
- -webkit-box-shadow: 1px 1px 5px 0px rgba(6,109,117,1);
4310
- -moz-box-shadow: 1px 1px 5px 0px rgba(6,109,117,1);
4311
- box-shadow: 1px 1px 10px 0px rgb(172, 173, 173);
4312
- }
4313
- @media (max-width: 767px) {
4314
- .shortpixel-hs-blind {
4315
- bottom: 8px;
4316
- height: 194px;
4317
- }
4318
- .shortpixel-hs-button-blind {
4319
- bottom: 100px;
4320
- }
4321
- }
4322
- </style>
4323
- <div id="shortpixel-hs-blind" class="shortpixel-hs-blind">
4324
- <a href="javascript:ShortPixel.closeHelpPane();">
4325
- <i class="dashicons dashicons-minus" title="<?php _e('Dismiss for now', 'shortpixel-image-optimiser'); ?> "></i>
4326
- </a>
4327
- <a href="javascript:ShortPixel.dismissHelpPane();">
4328
- <i class="dashicons dashicons-dismiss" title="<?php _e('Never display again', 'shortpixel-image-optimiser'); ?>"></i>
4329
- </a>
4330
- </div>
4331
- <div id="shortpixel-hs-button-blind" class="shortpixel-hs-button-blind"></div>
4332
- <div id="shortpixel-hs-tools" class="shortpixel-hs-tools">
4333
- <a href="javascript:shortpixelToggleHS();" class="shortpixel-hs-tools-docs" title="<?php _e('Search through our online documentation.', 'shortpixel-image-optimiser'); ?>">
4334
- <img src="<?php echo(wpSPIO()->plugin_url('res/img/notes-sp.png'));?>" style="margin-bottom: 2px;width: 36px;">
4335
- </a>
4336
- </div>
4337
- <script>
4338
- window.shortpixelHSOpen = -1;
4339
- function shortpixelToggleHS() {
4340
- if(window.shortpixelHSOpen == -1) {
4341
- HS.beacon.init();
4342
- }
4343
- if(window.shortpixelHSOpen == 1) {
4344
- HS.beacon.close();
4345
- jQuery("#shortpixel-hs-button-blind").css('display', 'none');
4346
- window.shortpixelHSOpen = 0;
4347
- } else {
4348
- HS.beacon.open();
4349
- jQuery("#shortpixel-hs-button-blind").css('display', 'block');
4350
- window.shortpixelHSOpen = 1;
4351
- }
4352
- }
4353
- </script>
4354
- <script type="text/javascript" src="https://quriobot.com/qb/widget/KoPqxmzqzjbg5eNl/V895xbyndnmeqZYd" async defer></script>
4355
- <script>
4356
- <?php
4357
- $screen = get_current_screen();
4358
- if($screen) {
4359
- switch($screen->id) {
4360
- case 'media_page_wp-short-pixel-bulk':
4361
- echo("var shortpixel_suggestions = [ '5a5de2782c7d3a19436843af', '5a5de6902c7d3a19436843e9', '5a5de5c42c7d3a19436843d0', '5a9945e42c7d3a75495145d0', '5a5de1c2042863193801047c', '5a5de66f2c7d3a19436843e0', '5a9946e62c7d3a75495145d8', '5a5de4f02c7d3a19436843c8', '5a5de65f042863193801049f', '5a5de2df0428631938010485' ]; ");
4362
- $suggestions = "shortpixel_suggestions";
4363
- break;
4364
- case 'settings_page_wp-shortpixel':
4365
- echo("var shortpixel_suggestions_settings = [ '5a5de1de2c7d3a19436843a8', '5a6612032c7d3a39e6263a1d', '5a5de1c2042863193801047c', '5a5de2782c7d3a19436843af', '5a6610c62c7d3a39e6263a02', '5a9945e42c7d3a75495145d0', '5a5de66f2c7d3a19436843e0', '5a6597e80428632faf620487', '5a5de5c42c7d3a19436843d0', '5a5de5642c7d3a19436843cc' ]; ");
4366
- echo("var shortpixel_suggestions_adv_settings = [ '5a5de4f02c7d3a19436843c8', '5a8431f00428634376d01dc4', '5a5de58b0428631938010497', '5a5de65f042863193801049f', '5a9945e42c7d3a75495145d0', '5a9946e62c7d3a75495145d8', '5a5de57c0428631938010495', '5a5de2d22c7d3a19436843b1', '5a5de5c42c7d3a19436843d0', '5a5de5642c7d3a19436843cc' ]; ");
4367
- echo("var shortpixel_suggestions_cloudflare = [ '5a5de1f62c7d3a19436843a9', '5a5de58b0428631938010497', '5a5de66f2c7d3a19436843e0', '5a5de5c42c7d3a19436843d0', '5a5de6902c7d3a19436843e9', '5a5de51a2c7d3a19436843c9', '5a9946e62c7d3a75495145d8', '5a5de46c2c7d3a19436843c1', '5a5de1de2c7d3a19436843a8', '5a6597e80428632faf620487' ]; ");
4368
- $suggestions = "shortpixel_suggestions_settings";
4369
- break;
4370
- case 'media_page_wp-short-pixel-custom':
4371
- echo("var shortpixel_suggestions = [ '5a9946e62c7d3a75495145d8', '5a5de1c2042863193801047c', '5a5de2782c7d3a19436843af', '5a5de6902c7d3a19436843e9', '5a5de4f02c7d3a19436843c8', '5a6610c62c7d3a39e6263a02', '5a9945e42c7d3a75495145d0', '5a5de46c2c7d3a19436843c1', '5a5de1de2c7d3a19436843a8', '5a5de25c2c7d3a19436843ad' ]; ");
4372
- $suggestions = "shortpixel_suggestions";
4373
- break;
4374
- }
4375
- }
4376
- ?>
4377
- !function(e,o,n){ window.HSCW=o,window.HS=n,n.beacon=n.beacon||{};var t=n.beacon;t.userConfig={
4378
- color: "#1CBECB",
4379
- icon: "question",
4380
- instructions: "Send ShortPixel a message",
4381
- topArticles: true,
4382
- poweredBy: false,
4383
- showContactFields: true,
4384
- showName: false,
4385
- showSubject: true,
4386
- translation: {
4387
- searchLabel: "What can ShortPixel help you with?",
4388
- contactSuccessDescription: "Thanks for reaching out! Someone from our team will get back to you in 24h max."
4389
- }
4390
-
4391
- },t.readyQueue=[],t.config=function(e){this.userConfig=e},t.ready=function(e){this.readyQueue.push(e)},o.config={docs:{enabled:!0,baseUrl:"//shortpixel.helpscoutdocs.com/"},contact:{enabled:!0,formId:"278a7825-fce0-11e7-b466-0ec85169275a"}};var r=e.getElementsByTagName("script")[0],c=e.createElement("script");
4392
- c.type="text/javascript",c.async=!0,c.src="https://djtflbt20bdde.cloudfront.net/",r.parentNode.insertBefore(c,r);
4393
- }(document,window.HSCW||{},window.HS||{});
4394
-
4395
- window.HS.beacon.ready(function(){
4396
- HS.beacon.identify({
4397
- email: "<?php $u = wp_get_current_user(); echo($u->user_email); ?>",
4398
- apiKey: "<?php echo($this->getApiKey());?>"
4399
- });
4400
- HS.beacon.suggest( <?php echo( $suggestions ) ?> );
4401
- });
4402
- </script><?php
4403
- }
4404
 
4405
  public function validateFeedback($params) {
4406
  if(isset($params['keep-settings'])) {
@@ -4410,26 +4190,6 @@ class WPShortPixel {
4410
  }
4411
 
4412
 
4413
- /* public function getEncryptedData() {
4414
- return base64_encode(self::encrypt($this->getApiKey() . "|" . get_site_url(), "sh0r+Pix3l8im1N3r"));
4415
- }
4416
- */
4417
-
4418
- /**
4419
- * Returns an encrypted & utf8-encoded
4420
- */
4421
- /* public static function encrypt($pure_string, $encryption_key)
4422
- {
4423
- if(!function_exists("mcrypt_get_iv_size") || !function_exists('utf8_encode')) {
4424
- return "";
4425
- }
4426
- $iv_size = \mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB);
4427
- $iv = \mcrypt_create_iv($iv_size, MCRYPT_RAND);
4428
- $encrypted_string = \mcrypt_encrypt(MCRYPT_BLOWFISH, $encryption_key, utf8_encode($pure_string), MCRYPT_MODE_ECB, $iv);
4429
- return $encrypted_string;
4430
- }
4431
- */
4432
-
4433
  public function getApiKey() {
4434
  return $this->_settings->apiKey;
4435
  }
@@ -4514,4 +4274,4 @@ class WPShortPixel {
4514
  return $this->_settings->cloudflareZoneID;
4515
  }
4516
 
4517
- }
116
  if($isAdminUser) {
117
  //add settings page
118
  //add_action( 'admin_menu', array( &$this, 'registerSettingsPage' ) );//display SP in Settings menu
119
+ // add_action( 'admin_menu', array( &$this, 'registerAdminPage' ) ); // removed
120
 
121
  add_action('wp_ajax_shortpixel_browse_content', array(&$this, 'browseContent'));
122
  add_action('wp_ajax_shortpixel_get_backup_size', array(&$this, 'getBackupSize'));
180
 
181
  // @hook admin menu
182
  // @todo move to plugin class
183
+ /* Gone. Both pages moved elsewhere ( plugin class )
184
  function registerAdminPage( ) {
185
  return;
186
  if($this->spMetaDao->hasFoldersTable() && count($this->spMetaDao->getFolders())) {
187
+
188
  add_media_page( __('Other Media Optimized by ShortPixel','shortpixel-image-optimiser'), __('Other Media','shortpixel-image-optimiser'), 'edit_others_posts', 'wp-short-pixel-custom', array( &$this, 'listCustomMedia' ) );
189
  }
190
+
191
  add_media_page( __('ShortPixel Bulk Process','shortpixel-image-optimiser'), __('Bulk ShortPixel','shortpixel-image-optimiser'), 'edit_others_posts', 'wp-short-pixel-bulk', array( &$this, 'bulkProcess' ) );
192
+ } */
193
 
194
  /*public static function shortPixelActivatePlugin()//reset some params to avoid trouble for plugins that were activated/deactivated/activated
195
  {
358
  /** @todo Plugin init class. Try to get rid of inline JS. Also still loads on all WP pages, prevent that. */
359
  function shortPixelJS() {
360
 
361
+
 
 
 
 
362
 
363
  $is_front = (wpSPIO()->env()->is_front) ? true : false;
364
 
386
  // }
387
 
388
 
389
+ wp_register_script('shortpixel', plugins_url('/res/js/shortpixel' . $this->jsSuffix,SHORTPIXEL_PLUGIN_FILE), array('jquery', 'jquery.knob.min.js'), SHORTPIXEL_IMAGE_OPTIMISER_VERSION, true);
390
 
391
 
392
  // Using an Array within another Array to protect the primitive values from being cast to strings
453
  'loading' => __('Loading...', 'shortpixel-image-optimiser' ),
454
  //'' => __('', 'shortpixel-image-optimiser' ),
455
  );
456
+ wp_localize_script( 'shortpixel', '_spTr', $jsTranslation );
457
+ wp_localize_script( 'shortpixel', 'ShortPixelConstants', $ShortPixelConstants );
458
+
459
+ wp_register_script('jquery.knob.min.js', plugins_url('/res/js/jquery.knob.min.js',SHORTPIXEL_PLUGIN_FILE) );
460
+ wp_register_script('jquery.tooltip.min.js', plugins_url('/res/js/jquery.tooltip.min.js',SHORTPIXEL_PLUGIN_FILE) );
461
+
462
 
463
+ if (! \wpSPIO()->env()->is_screen_to_use )
464
+ {
465
+ if (! wpSPIO()->env()->is_front) // exeception if this is called to load from your frontie.
466
+ return; // not ours, don't load JS and such.
467
+ }
468
 
469
+ wp_enqueue_script('shortpixel');
470
+ wp_enqueue_script('jquery.knob.min.js');
471
+ wp_enqueue_script('jquery.tooltip.min.js');
472
 
473
  wp_enqueue_script('punycode.min.js', plugins_url('/res/js/punycode.min.js',SHORTPIXEL_PLUGIN_FILE) );
474
  }
693
  return $meta;
694
  }
695
 
696
+ Log::addDebug("Handle Media Library Image Upload #{$ID}", $currentFile->exists());
 
697
 
698
  if(!$this->_settings->optimizePdfs && 'pdf' === $currentFile->getExtension() ) {
699
  //pdf is not optimized automatically as per the option, but can be optimized by button. Nothing to do.
729
  //send a processing request right after a file was uploaded, do NOT wait for response
730
  $this->_apiInterface->doRequests($URLsAndPATHs['URLs'], false, $itemHandler, false, $refresh);
731
  } catch(Exception $e) {
732
+ Log::addWarning('Handle Media Library Image Exceptions', $e);
733
  $meta['ShortPixelImprovement'] = $e->getMessage();
734
  return $meta;
735
  }
802
  return $converter->checkConvertMediaPng2Jpg($itemHandler);
803
  }
804
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
805
 
806
+ // needs moving. Used by Nextgen ( and others )
807
  public function addPathToCustomFolder($imageFsPath, $folderId, $pid) {
808
  //prevent adding it multiple times if the action is called repeatedly (Gravity Forms does that)
809
  $existing = $this->spMetaDao->getMetaForPath($imageFsPath);
825
  $meta->setResizeHeight($this->_settings->resizeHeight);
826
  $ID = $this->spMetaDao->addImage($meta);
827
  $meta->setId($ID);
828
+
829
+ if ($this->_settings->autoMediaLibrary)
830
+ $this->prioQ->push('C-' . $ID); // should not blindly push to optimize!
831
+
832
  //add the thumb image if exists
833
  $pathParts[] = "thumbs_" . $pathParts[count($pathParts) - 1];
834
  $pathParts[count($pathParts) - 2] = "thumbs";
846
  $metaThumb->setResizeHeight($this->_settings->resizeHeight);
847
  $ID = $this->spMetaDao->addImage($metaThumb);
848
  $metaThumb->setId($ID);
849
+
850
+ if ($this->_settings->autoMediaLibrary)
851
+ $this->prioQ->push('C-' . $ID);
852
  }
853
  return $meta;
854
  }
864
  }
865
  if($meta->getStatus() != ShortPixelMeta::FILE_STATUS_SUCCESS) {
866
 
 
867
  $meta->setStatus(ShortPixelMeta::FILE_STATUS_PENDING);
868
  $meta->setRetries(0);
869
  /* [BS] This is being set because meta in other states does not keep previous values. The value 0 is problematic
1222
 
1223
  //self::log("HIP: 0 Bulk ran: " . $this->prioQ->bulkRan());
1224
  $customIds = false;
1225
+ //@todo Unreadable statement. This will never run outside of bulk.
1226
  if(count($ids) < SHORTPIXEL_PRESEND_ITEMS && $this->prioQ->bulkRan() && $this->_settings->hasCustomFolders
1227
  && (!$this->_settings->cancelPointer || $this->_settings->skipToCustom)
1228
  && !$this->_settings->customBulkPaused)
1229
  { //take from custom images if any left to optimize - only if bulk was ever started
1230
+ //but first refresh. Refresh interval is handled by controller.
1231
+ $otherMedia = new \ShortPixel\OtherMediaController();
1232
+ $otherMedia->refreshFolders();
1233
+ /*if(time() - $this->_settings->hasCustomFolders > 3600) {
1234
  $notice = null; $this->refreshCustomFolders();
1235
  $this->_settings->hasCustomFolders = time();
1236
+ } */
1237
 
1238
  $customIds = $this->spMetaDao->getPendingMetas( SHORTPIXEL_PRESEND_ITEMS - count($ids));
1239
 
1242
  }
1243
  }
1244
 
1245
+
1246
+
1247
+
1248
  if(count($ids)) {$idl='';foreach($ids as $i){$idl.=$i->getId().' ';}
1249
  Log::addInfo("HIP: 1 Selected IDs: $idl");}
1250
 
1491
  $this->_settings->bulkLastStatus = $result;
1492
  }
1493
 
1494
+ // Generate new actions after doing something for custom type (for now)
1495
+ if($itemHandler->getType() == ShortPixelMetaFacade::CUSTOM_TYPE)
1496
+ {
1497
+ $othermediaView = new \ShortPixel\OtherMediaViewController();
1498
+ $othermediaView->setShortPixel($this);
1499
+ $result['actions'] = $othermediaView->renderNewActions(substr($itemId, 2));
1500
+ }
1501
+
1502
  $ret = json_encode($result);
1503
  self::log("HIP RET " . $ret);
1504
  die($ret);
2032
  $imageObj->setbyPostID($attachmentID);
2033
 
2034
  $fsFile = $imageObj->getFile();
 
2035
  $filePath = (string) $fsFile->getFileDir();
2036
 
2037
  $itemHandler = $imageObj->getFacade(); //new ShortPixelMetaFacade($attachmentID);
2153
  }
2154
  }
2155
  if(!$bkCount) {
2156
+ //$this->throwNotice('generic-err', __("No backup files found. Restore not performed.",'shortpixel-image-optimiser'));
2157
+ $notice = Notices::addWarning(__("Not all backup files found. Restore not performed on these files ",'shortpixel-image-optimiser'), true);
2158
+ Notices::addDetail($notice, (string) $bkFile);
2159
+
2160
+ Log::addError('No Backup Files Found: ' . $bkFile);
2161
  return false;
2162
  }
2163
 
2333
  */
2334
  public function throwNotice($when = 'activate', $extra = '') {
2335
  // set_transient("shortpixel_thrown_notice", array('when' => $when, 'extra' => $extra), 120);
2336
+
2337
  Notices::addError($extra); // whatever error is in the extra. Seems that normal messages don't pass here.
2338
  }
2339
 
2385
  if($backupFile === false)
2386
  {
2387
  Log::addWarn("Custom File $ID - $file does not have a backup");
2388
+ $notice = Notices::addWarning(__('Not able to restore file. Could not find backup', 'shortpixel-image-optimiser'), true);
2389
+ Notices::addDetail($notice, (string) $file);
2390
+
2391
  return false;
2392
  }
2393
+ elseif ($backupFile->copy($fileObj))
2394
+ {
 
2395
  $backupFile->delete();
2396
+ }
2397
+ else {
2398
+ Log::addError('Could not restore back to source' . $backupFile->getFullPath() );
2399
+ Notices::addError('The file could not be restored from backup. Plugin could not copy backup back to original location. Check file permissions. ', 'shortpixel-image-optimiser');
2400
+ return false;
2401
+ }
2402
 
2403
  /* [BS] Reset all generated image meta. Bring back to start state.
2404
  * Since Wpdb->prepare doesn't support 'null', zero values in this table should not be trusted */
2461
  $folder_id = $meta->getFolderId();
2462
  $this->doCustomRestore($ID);
2463
 
2464
+ // Commented, this is creating weird issues. Seems unneeded as well.
2465
+ //$this->spMetaDao->delete($meta);
2466
+ // $meta = $this->addPathToCustomFolder($path, $folder_id, NULL);
2467
 
2468
  if($meta) {
2469
  $meta->setCompressionType(ShortPixelAPI::getCompressionTypeCode($compressionType));
2742
  * @todo Move this to own view.
2743
  */
2744
  /* Gone! @todo Must go when new ListCMedia is done */
2745
+ /*
2746
  public function listCustomMedia() {
2747
  if( ! class_exists( 'ShortPixelListTable' ) ) {
2748
  require_once('view/shortpixel-list-table.php');
2800
  <br class="clear">
2801
  </div>
2802
  </div> <?php
2803
+ } */
2804
 
2805
 
2806
  /** Front End function that controls bulk processes.
2870
  Log::addInfo('Bulk Process - Bulk Restore');
2871
 
2872
  $bulkRestore = new \ShortPixel\BulkRestoreAll(); // controller
 
2873
  $bulkRestore->setupBulk();
2874
 
2875
  $this->prioQ->startBulk(ShortPixelQueue::BULK_TYPE_RESTORE);
2915
  Log::addInfo('Bulk Process - Pending Meta Count ' . $pendingMeta);
2916
  Log::addInfo('Bulk Process - File left ' . $filesLeft[0]->FilesLeftToBeProcessed );
2917
 
2918
+
2919
  if ( ($filesLeft[0]->FilesLeftToBeProcessed > 0 && $this->prioQ->bulkRunning())
2920
  || (0 + $pendingMeta > 0 && !$this->_settings->customBulkPaused && $this->prioQ->bulkRan())//bulk processing was started
2921
  && (!$this->prioQ->bulkPaused() || $this->_settings->skipToCustom)) //bulk not paused or if paused, user pressed Process Custom button
3060
 
3061
  $dirpath = $dir->getPath();
3062
  $dirname = $dir->getName();
3063
+ // @todo Should in time be moved to othermedia_controller / check if media library
3064
  if($dirname == 'ShortpixelBackups' || ShortPixelMetaFacade::isMediaSubfolder($dirname, false)) continue;
3065
 
3066
  $htmlRel = str_replace("'", "&apos;", $returnDir . $dirname);
3245
  } */
3246
 
3247
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3248
  /** Updates HTAccess files for Webp
3249
  * @param boolean $clear Clear removes all statements from htaccess. For disabling webp.
3250
  */
3511
  public function resetQuotaExceeded() {
3512
  if( $this->_settings->quotaExceeded == 1) {
3513
  $dismissed = $this->_settings->dismissedNotices ? $this->_settings->dismissedNotices : array();
3514
+ //unset($dismissed['exceed']);
 
 
3515
  $this->_settings->prioritySkip = array();
3516
  $this->_settings->dismissedNotices = $dismissed;
3517
+ \ShortPixel\adminNoticesController::resetAPINotices();
3518
+ \ShortPixel\adminNoticesController::resetQuotaNotices();
3519
  }
3520
  $this->_settings->quotaExceeded = 0;
3521
  }
3991
  if (@preg_match($pattern, false) !== false)
3992
  {
3993
  $m = preg_match($pattern, $target);
3994
+ if ($m !== false && $m > 0) // valid regex, more hits than zero
3995
+ {
3996
  return true;
3997
+ }
3998
  }
3999
  }
4000
  else
4181
  return array_values(array_diff(array(0, 1, 2), array(0 + $compressionType)));
4182
  }
4183
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4184
 
4185
  public function validateFeedback($params) {
4186
  if(isset($params['keep-settings'])) {
4190
  }
4191
 
4192
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4193
  public function getApiKey() {
4194
  return $this->_settings->apiKey;
4195
  }
4274
  return $this->_settings->cloudflareZoneID;
4275
  }
4276
 
4277
+ } // class
class/wp-shortpixel-cloudflare-api.php DELETED
@@ -1,161 +0,0 @@
1
- <?php
2
-
3
- class ShortPixelCloudFlareApi {
4
- private $_cloudflareEmail = ''; // $_cloudflareEmail
5
- private $_cloudflareAuthKey = ''; // $_cloudflareAuthKey
6
- private $_cloudflareZoneID = ''; // $_cloudflareZoneID
7
-
8
- public function __construct($cloudflareEmail, $cloudflareAuthKey, $cloudflareZoneID) {
9
- $this->set_up($cloudflareEmail, $cloudflareAuthKey, $cloudflareZoneID);
10
- $this->set_up_required_hooks();
11
- }
12
-
13
- public function set_up($cloudflareEmail, $cloudflareAuthKey, $cloudflareZoneID) {
14
- $this->_cloudflareEmail = $cloudflareEmail;
15
- $this->_cloudflareAuthKey = $cloudflareAuthKey;
16
- $this->_cloudflareZoneID = $cloudflareZoneID;
17
- }
18
-
19
- /**
20
- * @desc A list of hooks needed for actions towards CloudFlare
21
- */
22
- private function set_up_required_hooks() {
23
- // After the image is optimized we apply the code that will purge cached URL(img) from CloudFlare
24
- add_action( 'shortpixel_image_optimised', array( $this, 'start_cloudflare_cache_purge_process' ) );
25
- }
26
-
27
- /**
28
- * Method taken from @class WPShortPixelSettings
29
- *
30
- * @param string $key
31
- * @param string|array $val
32
- */
33
- public function save_to_wp_options( $key = '', $val = '' ) {
34
- $ret = update_option( $key, $val, 'no' );
35
-
36
- //hack for the situation when the option would just not update....
37
- if ( $ret === false && ! is_array( $val ) && $val != get_option( $key ) ) {
38
- delete_option( $key );
39
- $alloptions = wp_load_alloptions();
40
- if ( isset( $alloptions[ $key ] ) ) {
41
- wp_cache_delete( 'alloptions', 'options' );
42
- } else {
43
- wp_cache_delete( $key, 'options' );
44
- }
45
- add_option( $key, $val, '', 'no' );
46
-
47
- // still not? try the DB way...
48
- if ( $ret === false && $val != get_option( $key ) ) {
49
- global $wpdb;
50
- $sql = "SELECT * FROM {$wpdb->prefix}options WHERE option_name = '" . $key . "'";
51
- $rows = $wpdb->get_results( $sql );
52
- if ( count( $rows ) === 0 ) {
53
- $wpdb->insert( $wpdb->prefix . 'options',
54
- array( "option_name" => $key, "option_value" => ( is_array( $val ) ? serialize( $val ) : $val ), "autoload" => "no" ),
55
- array( "option_name" => "%s", "option_value" => ( is_numeric( $val ) ? "%d" : "%s" ) ) );
56
- } else { //update
57
- $sql = "update {$wpdb->prefix}options SET option_value=" .
58
- ( is_array( $val )
59
- ? "'" . serialize( $val ) . "'"
60
- : ( is_numeric( $val ) ? $val : "'" . $val . "'" ) ) . " WHERE option_name = '" . $key . "'";
61
- $rows = $wpdb->get_results( $sql );
62
- }
63
-
64
- if ( $val != get_option( $key ) ) {
65
- //tough luck, gonna use the bomb...
66
- wp_cache_flush();
67
- add_option( $key, $val, '', 'no' );
68
- }
69
- }
70
- }
71
- }
72
-
73
- /**
74
- * @desc Start the process of purging all cache for image URL (includes all the image sizes/thumbnails)f1
75
- *
76
- * @param $image_id - WordPress image media ID
77
- */
78
- function start_cloudflare_cache_purge_process( $image_id ) {
79
-
80
- // Fetch CloudFlare API credentials
81
- $cloudflare_auth_email = $this->_cloudflareEmail;
82
- $cloudflare_auth_key = $this->_cloudflareAuthKey;
83
- $cloudflare_zone_id = $this->_cloudflareZoneID;
84
-
85
- if ( ! empty( $cloudflare_auth_email ) && ! empty( $cloudflare_auth_key ) && ! empty( $cloudflare_zone_id ) ) {
86
-
87
- // Fetch all WordPress install possible thumbnail sizes ( this will not return the full size option )
88
- $fetch_images_sizes = get_intermediate_image_sizes();
89
- $image_url_for_purge = array();
90
- $prepare_request_info = array();
91
-
92
- // if full image size tag is missing, we need to add it
93
- if ( ! in_array( 'full', $fetch_images_sizes ) ) {
94
- $fetch_images_sizes[] = 'full';
95
- }
96
-
97
- // Fetch the URL for each image size
98
- foreach ( $fetch_images_sizes as $size ) {
99
- // 0 - url; 1 - width; 2 - height
100
- $image_attributes = wp_get_attachment_image_src( $image_id, $size );
101
- // Append to the list
102
- array_push( $image_url_for_purge, $image_attributes[0] );
103
- }
104
-
105
- if ( ! empty( $image_url_for_purge ) ) {
106
- $prepare_request_info['files'] = $image_url_for_purge;
107
- // Encode the data into JSON before send
108
- $dispatch_purge_info = function_exists('wp_json_encode') ? wp_json_encode( $prepare_request_info ) : json_encode( $prepare_request_info );
109
- // Set headers for remote API to authenticate for the request
110
- $dispatch_header = array(
111
- 'X-Auth-Email: ' . $cloudflare_auth_email,
112
- 'X-Auth-Key: ' . $cloudflare_auth_key,
113
- 'Content-Type: application/json'
114
- );
115
-
116
- // Start the process of cache purge
117
- $request_response = $this->delete_url_cache_request_action( "https://api.cloudflare.com/client/v4/zones/" . $cloudflare_zone_id . "/purge_cache", $dispatch_purge_info, $dispatch_header );
118
-
119
- if ( ! is_array( $request_response ) ) {
120
- WPShortPixel::log( 'Shortpixel - CloudFlare: The CloudFlare API is not responding correctly' );
121
- } elseif ( isset( $request_response['success'] ) && isset( $request_response['errors'] ) && false === (bool) $request_response['success'] ) {
122
- WPShortPixel::log( 'Shortpixel - CloudFlare, Error messages: '
123
- . (isset($request_response['errors']['message']) ? $request_response['errors']['message'] : json_encode($request_response['errors'])) );
124
- } else {
125
- WPShortPixel::log('Shortpixel - CloudFlare successfully requested clear cache for: ' . json_encode($image_url_for_purge));
126
- }
127
- } else {
128
- // No use in running the process
129
- }
130
- } else {
131
- // CloudFlare credentials do not exist
132
- }
133
- }
134
-
135
- /**
136
- * @desc Send a delete cache request to CloudFlare for specified URL(s)
137
- *
138
- * @param string $request_url - The url to which we need to send the DELETE request
139
- * @param string $parameters_as_json - This JSON will contain the required parameters for DELETE request
140
- * @param array $request_headers - Authentication information and type of request
141
- *
142
- * @return array|mixed|object - Request response as decoded JSON
143
- */
144
- private function delete_url_cache_request_action( $request_url = '', $parameters_as_json = '', $request_headers = array() ) {
145
- if(!function_exists('curl_init')) return false;
146
-
147
- $curl_connection = curl_init();
148
- curl_setopt( $curl_connection, CURLOPT_URL, $request_url );
149
- curl_setopt( $curl_connection, CURLOPT_CUSTOMREQUEST, "DELETE" );
150
- curl_setopt( $curl_connection, CURLOPT_POSTFIELDS, $parameters_as_json );
151
- curl_setopt( $curl_connection, CURLOPT_RETURNTRANSFER, true );
152
- curl_setopt( $curl_connection, CURLOPT_HTTPHEADER, $request_headers );
153
- curl_setopt( $curl_connection, CURLOPT_USERAGENT, '"User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.87 Safari/537.36"' );
154
-
155
- $request_response = curl_exec( $curl_connection );
156
- $result = json_decode( $request_response, true );
157
- curl_close( $curl_connection );
158
-
159
- return $result;
160
- }
161
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
readme.txt CHANGED
@@ -2,9 +2,9 @@
2
  Contributors: ShortPixel
3
  Tags: compressor, image, compression, optimize, image optimizer, image optimiser, image compression, resize, compress pdf, compress jpg, compress png, image compression
4
  Requires at least: 3.2.0
5
- Tested up to: 5.3
6
  Requires PHP: 5.3
7
- Stable tag: 4.16.4
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
@@ -58,7 +58,7 @@ Make an instant <a href="http://shortpixel.com/image-compression-test" target="_
58
  * option to deactivate auto-optimizing images on upload
59
  * images that are optimized less that 5% are bonus
60
  * WooCommerce, WP offload S3 and WP Stateless compatible
61
- * 40 days optimization report with all image details and overall statistics
62
  * We are GDPR compliant! <a href="https://shortpixel.com/privacy#gdpr" target="_blank">Read more.</a>
63
  * **free optimization credits for non-profits**, <a href="https://shortpixel.com/contact" target="_blank">contact us</a> for details
64
 
@@ -281,6 +281,22 @@ Hide the Cloudflare settings by defining these constants in wp-config.php:
281
 
282
  == Changelog ==
283
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
284
  = 4.16.4 =
285
 
286
  Release date: 26th March 2020
@@ -381,7 +397,7 @@ Release date: 27th November 2019
381
  * Fixed: check for DOING_AJAX on redirect to settings.
382
  * Fixed: Shortpixel icon + exclamation mark in toolbar showing on every page load.
383
  * Fixed: Add Custom media browser doesn't display files anymore
384
- * Fixed: WebP option adds an extra border if image already has a border -> borders will not be replicated to <picture> tags.
385
  * Fixed: Validating empty key doesn't show any message.
386
  * Fixed: on Nginx writes .htaccess files.
387
  * Fixed: Bug with safeGetAttachmentUrl for URLs that start with //.
@@ -394,7 +410,7 @@ Release date: 27th November 2019
394
  = 4.14.6 =
395
 
396
  Release date: 9th October 2019
397
- * Don't convert to <picture> the <img>s with backgrounds.
398
  * Remove unused eval() call.
399
  * Restore the validate button next to API Key but change label to "Save and validate"
400
  * Fixed: PNGtoJPG issue with already uploaded images
@@ -466,7 +482,7 @@ Release date: 17th June 2019
466
  * Adaptive Max execution time and capped to 90 sec. for the bulk background AJAX calls. (Kinsta has a max_execution_time of 300 sec. in PHP but the HTTP connection is cut after 180 sec.)
467
  * Fix custom 404 page for missing images not working when using .htaccess for WebP
468
  * Fix WebP picture tag with relative URLs not working in some circumstances
469
- * Fix replacing the <img> inside an existing <picture> tag with another <picture> tag.
470
  * Clear SP optimization cache in order to be able to optimize an image which initially had permissions error, after changing the permissions.
471
  * Fix being able to list the contents of ShortpixelBackups on some badly configured servers.
472
  * Fix error when inputting D'Artagnan in the AUTH pass field of settings.
@@ -491,7 +507,7 @@ Release date: 10th April 2019
491
  * resolve the Settings inconsistency in Other Media (settings displayed were from when adding the folder not from when actually optimizing)
492
  * Make pressing Escape or clicking outside of any popup close it.
493
  * Fixed: Restoring an Other Media item and then Optimizing it again optimizes it Lossless
494
- * fix generating the WebP <picture> tags when the images are either on a subdomain or on a CDN domain having the same root domain as the main site.
495
 
496
  = EARLIER VERSIONS =
497
  * please refer to the changelog.txt file inside the plugin archive.
2
  Contributors: ShortPixel
3
  Tags: compressor, image, compression, optimize, image optimizer, image optimiser, image compression, resize, compress pdf, compress jpg, compress png, image compression
4
  Requires at least: 3.2.0
5
+ Tested up to: 5.4
6
  Requires PHP: 5.3
7
+ Stable tag: 4.17.0
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
58
  * option to deactivate auto-optimizing images on upload
59
  * images that are optimized less that 5% are bonus
60
  * WooCommerce, WP offload S3 and WP Stateless compatible
61
+ * 30 days optimization report with all image details and overall statistics
62
  * We are GDPR compliant! <a href="https://shortpixel.com/privacy#gdpr" target="_blank">Read more.</a>
63
  * **free optimization credits for non-profits**, <a href="https://shortpixel.com/contact" target="_blank">contact us</a> for details
64
 
281
 
282
  == Changelog ==
283
 
284
+ = 4.17.0 =
285
+
286
+ Release date: 2nd April 2020
287
+ * Complete rewrite of the Other Media part of the plugin. It now looks closer to the standard Media Library, having thumbnails and actions like Compare, Re-optimize and Restore from backup for all images when you have Backups activated;
288
+ * Added notification to activate the integration with NextGen Gallery, when the plugin is active and the integration is not activated;
289
+ * Improved the way Other Media folders are added and it should not crash anymore for folders with a very large number of images;
290
+ * Fix for the extra information (i) next to each Other Media folder in the Advanced Settings;
291
+ * Fixes for multiple issues reagrding the NextGen Gallery plugin integration;
292
+ * Fix for notififcations showing up when they're not supposed to show up;
293
+ * Fix for multiple notifications when backup files are not found. These are now merged together;
294
+ * Fix for notifications that were crashing outside ShortPixel screens;
295
+ * Fix for the report that was wrongly stating 40 days, when actually the report is only for 30 days;
296
+ * Fix for the exclude regex section that was returning true even if no matches were found;
297
+ * Removed from the plugin the files that are not used anymore;
298
+ * Language – 15 new strings added, 0 updated, 0 fuzzied, and 8 obsoleted.
299
+
300
  = 4.16.4 =
301
 
302
  Release date: 26th March 2020
397
  * Fixed: check for DOING_AJAX on redirect to settings.
398
  * Fixed: Shortpixel icon + exclamation mark in toolbar showing on every page load.
399
  * Fixed: Add Custom media browser doesn't display files anymore
400
+ * Fixed: WebP option adds an extra border if image already has a border -> borders will not be replicated to `<picture>` tags.
401
  * Fixed: Validating empty key doesn't show any message.
402
  * Fixed: on Nginx writes .htaccess files.
403
  * Fixed: Bug with safeGetAttachmentUrl for URLs that start with //.
410
  = 4.14.6 =
411
 
412
  Release date: 9th October 2019
413
+ * Don't convert to `<picture>` the `<img>`s with backgrounds.
414
  * Remove unused eval() call.
415
  * Restore the validate button next to API Key but change label to "Save and validate"
416
  * Fixed: PNGtoJPG issue with already uploaded images
482
  * Adaptive Max execution time and capped to 90 sec. for the bulk background AJAX calls. (Kinsta has a max_execution_time of 300 sec. in PHP but the HTTP connection is cut after 180 sec.)
483
  * Fix custom 404 page for missing images not working when using .htaccess for WebP
484
  * Fix WebP picture tag with relative URLs not working in some circumstances
485
+ * Fix replacing the `<img>` inside an existing `<picture>` tag with another `<picture>` tag.
486
  * Clear SP optimization cache in order to be able to optimize an image which initially had permissions error, after changing the permissions.
487
  * Fix being able to list the contents of ShortpixelBackups on some badly configured servers.
488
  * Fix error when inputting D'Artagnan in the AUTH pass field of settings.
507
  * resolve the Settings inconsistency in Other Media (settings displayed were from when adding the folder not from when actually optimizing)
508
  * Make pressing Escape or clicking outside of any popup close it.
509
  * Fixed: Restoring an Other Media item and then Optimizing it again optimizes it Lossless
510
+ * fix generating the WebP `<picture>` tags when the images are either on a subdomain or on a CDN domain having the same root domain as the main site.
511
 
512
  = EARLIER VERSIONS =
513
  * please refer to the changelog.txt file inside the plugin archive.
res/css/short-pixel.css CHANGED
@@ -226,12 +226,7 @@ input.dial {
226
  .form-table td {
227
  position: relative;
228
  }
229
- .form-table table.shortpixel-folders-list tr {
230
- background-color: #eee;
231
- }
232
- .form-table table.shortpixel-folders-list td {
233
- padding: 5px 10px;
234
- }
235
  div.shortpixel-rate-us {
236
  display:inline-block;
237
  margin-left: 10px;
226
  .form-table td {
227
  position: relative;
228
  }
229
+
 
 
 
 
 
230
  div.shortpixel-rate-us {
231
  display:inline-block;
232
  margin-left: 10px;
res/css/short-pixel.min.css CHANGED
@@ -1 +1 @@
1
- .reset{font-weight:400;font-style:normal}.clearfix:after,.clearfix:before{content:" ";display:table}.clearfix:after{clear:both}.clearfix{zoom:1}.resumeLabel{float:right;line-height:30px;margin-right:20px;font-size:16px}.sp-dropbtn.button{padding:1px 24px 20px 5px;font-size:20px;line-height:28px;cursor:pointer}.sp-dropdown{position:relative;display:inline-block}.sp-dropdown-content{display:none;right:0;position:absolute;background-color:#f9f9f9;min-width:190px;box-shadow:0 8px 16px 0 rgba(0,0,0,.2);z-index:1}.sp-dropdown-content a{color:#000;padding:12px 16px;text-decoration:none;display:block}.sp-dropdown-content a:hover{background-color:#f1f1f1}.sp-dropdown.sp-show .sp-dropdown-content{display:block}div.fb-like{transform:scale(1.3);-ms-transform:scale(1.3);-webkit-transform:scale(1.3);-o-transform:scale(1.3);-moz-transform:scale(1.3);transform-origin:bottom left;-ms-transform-origin:bottom left;-webkit-transform-origin:bottom left;-moz-transform-origin:bottom left;-webkit-transform-origin:bottom left}.wp-core-ui .button.button-alert,.wp-core-ui .button.button-alert:hover{background:#f79797}.wp-core-ui .button.remove-folder-button{min-width:120px}.sp-notice{background:#fff;border-left:4px solid #fff;-webkit-box-shadow:0 1px 1px 0 rgba(0,0,0,.1);box-shadow:0 1px 1px 0 rgba(0,0,0,.1);padding:1px 12px}.sp-notice img{vertical-align:bottom}@media(max-width:1249px){.sp-notice{margin:5px 15px 2px}}.sp-notice-info{border-left-color:#00a0d2}.sp-notice-success{border-left-color:#46b450}.sp-notice-warning{border-left-color:#f1e02a}div.short-pixel-bulk-page input.dial{font-size:16px!important}div.short-pixel-bulk-page h1{margin-bottom:20px}div.bulk-progress div.sp-h2{margin-top:0;margin-bottom:10px;font-size:23px;font-weight:400;padding:9px 15px 4px 0;line-height:29px}div.bulk-progress-partners{margin-top:20px}div.bulk-progress.bulk-progress-partners a div{display:inline-block;vertical-align:top;line-height:50px;margin-left:30px;font-size:1.2em}div.bulk-progress .bulk-progress-indicator,div.sp-quota-exceeded-alert .bulk-progress-indicator{display:inline-block;text-align:center;padding:0 10px;margin-left:10px;float:left;height:90px;overflow:hidden;border:1px solid #1caecb}div.wrap.short-pixel-bulk-page .bulk-notice-container{margin-top:15px;position:absolute;width:500px}div.wrap.short-pixel-bulk-page .bulk-notice-container .bulk-notice-msg{text-align:center;margin:10px 0 0 32px;overflow:hidden;border:1px solid #1caecb;background-color:#9ddbe0;border-radius:5px;padding:7px 10px 10px;display:none;max-width:600px;margin-right:20px}div.wrap.short-pixel-bulk-page .bulk-notice-container .bulk-notice-msg.bulk-error{border:1px solid #b5914d;background-color:#ffe996;margin-right:20px;position:relative;z-index:10}div.wrap.short-pixel-bulk-page .bulk-notice-container .bulk-notice-msg.bulk-error.bulk-error-fatal{border:1px solid #c32525;background-color:#ff969d}div.wrap.short-pixel-bulk-page .bulk-notice-msg img{float:left;margin-top:3px;margin-right:5px}div.sp-bulk-summary{float:right;margin:8px 5px 3px 20px}.sp-notice .bulk-error-show{cursor:pointer}.sp-notice div.bulk-error-list{background-color:#f1f1f1;padding:0 10px;display:none;max-height:200px;overflow-y:scroll}.sp-notice div.bulk-error-list ul{padding:3px 0 0;margin-top:5px}.sp-notice div.bulk-error-list ul>li:not(:last-child){border-bottom:1px solid #fff;padding-bottom:4px}input.dial{box-shadow:none}.shortpixel-table .column-filename{max-width:32em;width:40%}.shortpixel-table .column-folder{max-width:20em;width:20%}.shortpixel-table .column-media_type{max-width:8em;width:10%}.shortpixel-table .column-status{max-width:16em;width:15%}.shortpixel-table .column-options{max-width:16em;width:15%}.form-table th{width:220px}.form-table td{position:relative}.form-table table.shortpixel-folders-list tr{background-color:#eee}.form-table table.shortpixel-folders-list td{padding:5px 10px}div.shortpixel-rate-us{display:inline-block;margin-left:10px;vertical-align:top;font-weight:700}div.shortpixel-rate-us>a{vertical-align:middle;padding:1px 5px 0;text-align:center;display:inline-block}div.shortpixel-rate-us>a>span{display:inline-block;vertical-align:top;margin-top:5px}div.shortpixel-rate-us>a>img{padding-top:7px}div.shortpixel-rate-us>a:active,div.shortpixel-rate-us>a:focus,div.shortpixel-rate-us>a:hover{outline:0;border-style:none}.sp-loading-small{margin-top:2px;float:left;margin-right:5px}.twentytwenty-horizontal .twentytwenty-after-label:before,.twentytwenty-horizontal .twentytwenty-before-label:before{font-family:inherit;font-size:16px}.short-pixel-bulk-page p{margin:.6em 0}.short-pixel-bulk-page form.start{display:table;content:" ";width:98%;background-color:#fff;padding:10px 10px 0;position:relative}.bulk-stats-container{display:inline-block;min-width:450px;width:45%;float:left;padding-right:50px;font-size:1.1em;line-height:1.5em}.bulk-text-container{display:inline-block;min-width:440px;width:45%;float:left;padding-right:50px}.bulk-text-container h3{border-bottom:1px solid #a8a8a8;margin-bottom:.5em;padding-bottom:.5em}.bulk-wide{display:inline-block;width:90%;float:left;margin-top:25px}.bulk-stats-container .bulk-label{width:220px;display:inline-block}.bulk-stats-container .bulk-val{width:50px;display:inline-block;text-align:right}.bulk-stats-container .bulk-total{font-weight:700;margin-top:10px;margin-bottom:10px}.wp-core-ui .bulk-play{display:inline;width:310px;float:left;margin-bottom:20px}.wp-core-ui .bulk-play.bulk-nothing-optimize{font-weight:700;color:#0080b2;border:1px solid;border-radius:5px;margin-top:60px;padding:5px 12px}.wp-core-ui .bulk-play a.button{height:60px;margin-top:27px;overflow:hidden}.wp-core-ui .column-wp-shortPixel .sp-column-actions{max-width:140px;float:right;text-align:right}.wp-core-ui .column-wp-shortPixel .sp-column-actions .button.button-smaller{margin-right:0}.wp-core-ui .column-wp-shortPixel .button.button-smaller{font-size:13px;padding:0 5px;margin-bottom:4px;min-height:30px;float:right}th.sortable.column-wp-shortPixel a,th.sorted.column-wp-shortPixel a{display:inline-block}.column-wp-shortPixel .sorting-indicator{display:inline-block}.wp-core-ui .bulk-play a.button .bulk-btn-img{display:inline-block;padding-top:6px}.wp-core-ui .bulk-play a.button .bulk-btn-txt{display:inline-block;text-align:right;line-height:1.3em;margin:11px 10px}.wp-core-ui .bulk-play a.button .bulk-btn-txt span.label{font-size:1.6em}.wp-core-ui .bulk-play a.button .bulk-btn-txt span.total{font-size:1.4em}.bulk-progress{padding:20px 32px 17px;background-color:#fff}.bulk-progress.bulk-stats>div{display:inline-block}.bulk-progress.bulk-stats>div.label{width:320px}.bulk-progress.bulk-stats>div.stat-value{width:80px;text-align:right}.short-pixel-bulk-page .progress{background-color:#ecedee;height:30px;position:relative;width:60%;display:inline-block;margin-right:28px;overflow:visible}.progress .progress-img{position:absolute;top:-10px;z-index:2;margin-left:-35px;line-height:48px;font-size:22px;font-weight:700}.progress .progress-img span{vertical-align:top;margin-left:-7px}.progress .progress-left{background-color:#1cbecb;bottom:0;left:0;position:absolute;top:0;z-index:1;font-size:22px;font-weight:700;line-height:28px;text-align:center;color:#fff}.bulk-estimate{font-size:20px;line-height:30px;vertical-align:top;display:inline-block}.wp-core-ui .button-primary.bulk-cancel{float:right;height:30px}.short-pixel-block-title{font-size:22px;font-weight:700;text-align:center;margin-bottom:30px}.sp-floating-block.bulk-slider-container{display:none}.sp-floating-block.sp-notice.bulk-notices-parent{padding:0;margin:0;float:right;margin-right:500px!important}.bulk-slider-container{margin-top:20px;min-height:300px;overflow:hidden}.bulk-slider-container h2{margin-bottom:15px}.bulk-slider-container span.filename{font-weight:400}.bulk-slider{display:table;margin:0 auto}.bulk-slider .bulk-slide{margin:0 auto;padding-left:120px;display:inline-block;font-weight:700}.bulk-slider .img-optimized,.bulk-slider .img-original{display:inline-block;margin-right:20px;text-align:center}.bulk-slider .img-optimized div,.bulk-slider .img-original div{max-height:450px;overflow:hidden}.bulk-slider .img-optimized img,.bulk-slider .img-original img{max-width:300px}.bulk-slider .img-info{display:inline-block;vertical-align:top;font-size:48px;max-width:150px;padding:10px 0 0 20px}.bulk-slide-images{display:inline-block;border:1px solid #1caecb;padding:15px 0 0 20px}p.settings-info{padding-top:0;color:#818181;font-size:13px!important}p.settings-info.shortpixel-settings-error{color:#c32525}.shortpixel-key-valid{font-weight:700}.shortpixel-key-valid .dashicons-yes:before{font-size:2em;line-height:25px;color:#3485ba;margin-left:-20px}.shortpixel-compression .shortpixel-compression-options{color:#999}.shortpixel-compression strong{line-height:22px}.shortpixel-compression .shortpixel-compression-options{display:inline-block}.shortpixel-compression label{width:158px;margin:0 -2px;background-color:#e2faff;font-weight:700;display:inline-block}.shortpixel-compression label span{text-align:center;font-size:18px;padding:8px 0;display:block}.shortpixel-compression label input{display:none}.shortpixel-compression input:checked+span{background-color:#0085ba;color:#f7f7f7}.shortpixel-compression .shortpixel-radio-info{min-height:60px}article.sp-tabs{position:relative;display:block;width:100%;margin:2em auto}article.sp-tabs section{position:absolute;display:block;top:1.8em;left:0;width:100%;max-width:100%;box-sizing:border-box;padding:10px 20px;z-index:0}article.sp-tabs section.sel-tab{box-shadow:0 3px 3px rgba(0,0,0,.1)}article.sp-tabs section .wp-shortpixel-tab-content{visibility:hidden}article.sp-tabs section.sel-tab .wp-shortpixel-tab-content{visibility:visible!important}article.sp-tabs section:first-child{z-index:1}article.sp-tabs section h2 a:focus,article.sp-tabs section#tab-resources a:focus{box-shadow:none;outline:0}article.sp-tabs section.sel-tab,article.sp-tabs section.sel-tab h2{color:#333;background-color:#fff;z-index:2}#tab-stats .sp-bulk-summary{position:absolute;right:0;top:0;z-index:100}.deliverWebpAlteringTypes,.deliverWebpSettings,.deliverWebpTypes{display:none}.deliverWebpTypes .sp-notice{color:red}.deliverWebpSettings{margin:16px 0}.deliverWebpSettings input:disabled+label{color:#818181}.deliverWebpAlteringTypes,.deliverWebpTypes{margin:16px 0 16px 16px}#png2jpg:not(:checked)~#png2jpgForce,#png2jpg:not(:checked)~label[for=png2jpgForce]{display:none}article.sp-tabs section #createWebp:checked~.deliverWebpSettings,article.sp-tabs section #deliverWebp:checked~.deliverWebpTypes,article.sp-tabs section #deliverWebpAltered:checked~.deliverWebpAlteringTypes{display:block}.shortpixel-help-link span.dashicons{text-decoration:none;margin-top:-1px}@media(min-width:1000px){section#tab-resources .col-md-6{display:inline-block;width:45%}}@media(max-width:999px){section#tab-resources .col-sm-12{display:inline-block;width:100%}}section#tab-resources .text-center{text-align:center}section#tab-resources p{font-size:16px}.wrap.short-pixel-bulk-page{margin-right:0}.sp-container{overflow:hidden;display:block;width:100%}.sp-floating-block{overflow:hidden;display:inline-block;float:left;margin-right:1.1%!important}.sp-full-width{width:98.8%;box-sizing:border-box}.sp-double-width{width:65.52%;box-sizing:border-box}.sp-single-width{width:32.23%;box-sizing:border-box}@media(max-width:1759px){.sp-floating-block{margin-right:1.3%!important}.sp-double-width,.sp-full-width{width:98.65%}.sp-single-width{width:48.7%}}@media(max-width:1249px){.sp-floating-block{margin-right:2%!important}.sp-double-width,.sp-full-width,.sp-single-width{width:97%}}.sp-tabs h2:before{content:none}.sp-column-actions-template+.sp-column-info{display:none}
1
+ .reset{font-weight:400;font-style:normal}.clearfix:after,.clearfix:before{content:" ";display:table}.clearfix:after{clear:both}.clearfix{zoom:1}.resumeLabel{float:right;line-height:30px;margin-right:20px;font-size:16px}.sp-dropbtn.button{padding:1px 24px 20px 5px;font-size:20px;line-height:28px;cursor:pointer}.sp-dropdown{position:relative;display:inline-block}.sp-dropdown-content{display:none;right:0;position:absolute;background-color:#f9f9f9;min-width:190px;box-shadow:0 8px 16px 0 rgba(0,0,0,.2);z-index:1}.sp-dropdown-content a{color:#000;padding:12px 16px;text-decoration:none;display:block}.sp-dropdown-content a:hover{background-color:#f1f1f1}.sp-dropdown.sp-show .sp-dropdown-content{display:block}div.fb-like{transform:scale(1.3);-ms-transform:scale(1.3);-webkit-transform:scale(1.3);-o-transform:scale(1.3);-moz-transform:scale(1.3);transform-origin:bottom left;-ms-transform-origin:bottom left;-webkit-transform-origin:bottom left;-moz-transform-origin:bottom left;-webkit-transform-origin:bottom left}.wp-core-ui .button.button-alert,.wp-core-ui .button.button-alert:hover{background:#f79797}.wp-core-ui .button.remove-folder-button{min-width:120px}.sp-notice{background:#fff;border-left:4px solid #fff;-webkit-box-shadow:0 1px 1px 0 rgba(0,0,0,.1);box-shadow:0 1px 1px 0 rgba(0,0,0,.1);padding:1px 12px}.sp-notice img{vertical-align:bottom}@media(max-width:1249px){.sp-notice{margin:5px 15px 2px}}.sp-notice-info{border-left-color:#00a0d2}.sp-notice-success{border-left-color:#46b450}.sp-notice-warning{border-left-color:#f1e02a}div.short-pixel-bulk-page input.dial{font-size:16px!important}div.short-pixel-bulk-page h1{margin-bottom:20px}div.bulk-progress div.sp-h2{margin-top:0;margin-bottom:10px;font-size:23px;font-weight:400;padding:9px 15px 4px 0;line-height:29px}div.bulk-progress-partners{margin-top:20px}div.bulk-progress.bulk-progress-partners a div{display:inline-block;vertical-align:top;line-height:50px;margin-left:30px;font-size:1.2em}div.bulk-progress .bulk-progress-indicator,div.sp-quota-exceeded-alert .bulk-progress-indicator{display:inline-block;text-align:center;padding:0 10px;margin-left:10px;float:left;height:90px;overflow:hidden;border:1px solid #1caecb}div.wrap.short-pixel-bulk-page .bulk-notice-container{margin-top:15px;position:absolute;width:500px}div.wrap.short-pixel-bulk-page .bulk-notice-container .bulk-notice-msg{text-align:center;margin:10px 0 0 32px;overflow:hidden;border:1px solid #1caecb;background-color:#9ddbe0;border-radius:5px;padding:7px 10px 10px;display:none;max-width:600px;margin-right:20px}div.wrap.short-pixel-bulk-page .bulk-notice-container .bulk-notice-msg.bulk-error{border:1px solid #b5914d;background-color:#ffe996;margin-right:20px;position:relative;z-index:10}div.wrap.short-pixel-bulk-page .bulk-notice-container .bulk-notice-msg.bulk-error.bulk-error-fatal{border:1px solid #c32525;background-color:#ff969d}div.wrap.short-pixel-bulk-page .bulk-notice-msg img{float:left;margin-top:3px;margin-right:5px}div.sp-bulk-summary{float:right;margin:8px 5px 3px 20px}.sp-notice .bulk-error-show{cursor:pointer}.sp-notice div.bulk-error-list{background-color:#f1f1f1;padding:0 10px;display:none;max-height:200px;overflow-y:scroll}.sp-notice div.bulk-error-list ul{padding:3px 0 0;margin-top:5px}.sp-notice div.bulk-error-list ul>li:not(:last-child){border-bottom:1px solid #fff;padding-bottom:4px}input.dial{box-shadow:none}.shortpixel-table .column-filename{max-width:32em;width:40%}.shortpixel-table .column-folder{max-width:20em;width:20%}.shortpixel-table .column-media_type{max-width:8em;width:10%}.shortpixel-table .column-status{max-width:16em;width:15%}.shortpixel-table .column-options{max-width:16em;width:15%}.form-table th{width:220px}.form-table td{position:relative}div.shortpixel-rate-us{display:inline-block;margin-left:10px;vertical-align:top;font-weight:700}div.shortpixel-rate-us>a{vertical-align:middle;padding:1px 5px 0;text-align:center;display:inline-block}div.shortpixel-rate-us>a>span{display:inline-block;vertical-align:top;margin-top:5px}div.shortpixel-rate-us>a>img{padding-top:7px}div.shortpixel-rate-us>a:active,div.shortpixel-rate-us>a:focus,div.shortpixel-rate-us>a:hover{outline:0;border-style:none}.sp-loading-small{margin-top:2px;float:left;margin-right:5px}.twentytwenty-horizontal .twentytwenty-after-label:before,.twentytwenty-horizontal .twentytwenty-before-label:before{font-family:inherit;font-size:16px}.short-pixel-bulk-page p{margin:.6em 0}.short-pixel-bulk-page form.start{display:table;content:" ";width:98%;background-color:#fff;padding:10px 10px 0;position:relative}.bulk-stats-container{display:inline-block;min-width:450px;width:45%;float:left;padding-right:50px;font-size:1.1em;line-height:1.5em}.bulk-text-container{display:inline-block;min-width:440px;width:45%;float:left;padding-right:50px}.bulk-text-container h3{border-bottom:1px solid #a8a8a8;margin-bottom:.5em;padding-bottom:.5em}.bulk-wide{display:inline-block;width:90%;float:left;margin-top:25px}.bulk-stats-container .bulk-label{width:220px;display:inline-block}.bulk-stats-container .bulk-val{width:50px;display:inline-block;text-align:right}.bulk-stats-container .bulk-total{font-weight:700;margin-top:10px;margin-bottom:10px}.wp-core-ui .bulk-play{display:inline;width:310px;float:left;margin-bottom:20px}.wp-core-ui .bulk-play.bulk-nothing-optimize{font-weight:700;color:#0080b2;border:1px solid;border-radius:5px;margin-top:60px;padding:5px 12px}.wp-core-ui .bulk-play a.button{height:60px;margin-top:27px;overflow:hidden}.wp-core-ui .column-wp-shortPixel .sp-column-actions{max-width:140px;float:right;text-align:right}.wp-core-ui .column-wp-shortPixel .sp-column-actions .button.button-smaller{margin-right:0}.wp-core-ui .column-wp-shortPixel .button.button-smaller{font-size:13px;padding:0 5px;margin-bottom:4px;min-height:30px;float:right}th.sortable.column-wp-shortPixel a,th.sorted.column-wp-shortPixel a{display:inline-block}.column-wp-shortPixel .sorting-indicator{display:inline-block}.wp-core-ui .bulk-play a.button .bulk-btn-img{display:inline-block;padding-top:6px}.wp-core-ui .bulk-play a.button .bulk-btn-txt{display:inline-block;text-align:right;line-height:1.3em;margin:11px 10px}.wp-core-ui .bulk-play a.button .bulk-btn-txt span.label{font-size:1.6em}.wp-core-ui .bulk-play a.button .bulk-btn-txt span.total{font-size:1.4em}.bulk-progress{padding:20px 32px 17px;background-color:#fff}.bulk-progress.bulk-stats>div{display:inline-block}.bulk-progress.bulk-stats>div.label{width:320px}.bulk-progress.bulk-stats>div.stat-value{width:80px;text-align:right}.short-pixel-bulk-page .progress{background-color:#ecedee;height:30px;position:relative;width:60%;display:inline-block;margin-right:28px;overflow:visible}.progress .progress-img{position:absolute;top:-10px;z-index:2;margin-left:-35px;line-height:48px;font-size:22px;font-weight:700}.progress .progress-img span{vertical-align:top;margin-left:-7px}.progress .progress-left{background-color:#1cbecb;bottom:0;left:0;position:absolute;top:0;z-index:1;font-size:22px;font-weight:700;line-height:28px;text-align:center;color:#fff}.bulk-estimate{font-size:20px;line-height:30px;vertical-align:top;display:inline-block}.wp-core-ui .button-primary.bulk-cancel{float:right;height:30px}.short-pixel-block-title{font-size:22px;font-weight:700;text-align:center;margin-bottom:30px}.sp-floating-block.bulk-slider-container{display:none}.sp-floating-block.sp-notice.bulk-notices-parent{padding:0;margin:0;float:right;margin-right:500px!important}.bulk-slider-container{margin-top:20px;min-height:300px;overflow:hidden}.bulk-slider-container h2{margin-bottom:15px}.bulk-slider-container span.filename{font-weight:400}.bulk-slider{display:table;margin:0 auto}.bulk-slider .bulk-slide{margin:0 auto;padding-left:120px;display:inline-block;font-weight:700}.bulk-slider .img-optimized,.bulk-slider .img-original{display:inline-block;margin-right:20px;text-align:center}.bulk-slider .img-optimized div,.bulk-slider .img-original div{max-height:450px;overflow:hidden}.bulk-slider .img-optimized img,.bulk-slider .img-original img{max-width:300px}.bulk-slider .img-info{display:inline-block;vertical-align:top;font-size:48px;max-width:150px;padding:10px 0 0 20px}.bulk-slide-images{display:inline-block;border:1px solid #1caecb;padding:15px 0 0 20px}p.settings-info{padding-top:0;color:#818181;font-size:13px!important}p.settings-info.shortpixel-settings-error{color:#c32525}.shortpixel-key-valid{font-weight:700}.shortpixel-key-valid .dashicons-yes:before{font-size:2em;line-height:25px;color:#3485ba;margin-left:-20px}.shortpixel-compression .shortpixel-compression-options{color:#999}.shortpixel-compression strong{line-height:22px}.shortpixel-compression .shortpixel-compression-options{display:inline-block}.shortpixel-compression label{width:158px;margin:0 -2px;background-color:#e2faff;font-weight:700;display:inline-block}.shortpixel-compression label span{text-align:center;font-size:18px;padding:8px 0;display:block}.shortpixel-compression label input{display:none}.shortpixel-compression input:checked+span{background-color:#0085ba;color:#f7f7f7}.shortpixel-compression .shortpixel-radio-info{min-height:60px}article.sp-tabs{position:relative;display:block;width:100%;margin:2em auto}article.sp-tabs section{position:absolute;display:block;top:1.8em;left:0;width:100%;max-width:100%;box-sizing:border-box;padding:10px 20px;z-index:0}article.sp-tabs section.sel-tab{box-shadow:0 3px 3px rgba(0,0,0,.1)}article.sp-tabs section .wp-shortpixel-tab-content{visibility:hidden}article.sp-tabs section.sel-tab .wp-shortpixel-tab-content{visibility:visible!important}article.sp-tabs section:first-child{z-index:1}article.sp-tabs section h2 a:focus,article.sp-tabs section#tab-resources a:focus{box-shadow:none;outline:0}article.sp-tabs section.sel-tab,article.sp-tabs section.sel-tab h2{color:#333;background-color:#fff;z-index:2}#tab-stats .sp-bulk-summary{position:absolute;right:0;top:0;z-index:100}.deliverWebpAlteringTypes,.deliverWebpSettings,.deliverWebpTypes{display:none}.deliverWebpTypes .sp-notice{color:red}.deliverWebpSettings{margin:16px 0}.deliverWebpSettings input:disabled+label{color:#818181}.deliverWebpAlteringTypes,.deliverWebpTypes{margin:16px 0 16px 16px}#png2jpg:not(:checked)~#png2jpgForce,#png2jpg:not(:checked)~label[for=png2jpgForce]{display:none}article.sp-tabs section #createWebp:checked~.deliverWebpSettings,article.sp-tabs section #deliverWebp:checked~.deliverWebpTypes,article.sp-tabs section #deliverWebpAltered:checked~.deliverWebpAlteringTypes{display:block}.shortpixel-help-link span.dashicons{text-decoration:none;margin-top:-1px}@media(min-width:1000px){section#tab-resources .col-md-6{display:inline-block;width:45%}}@media(max-width:999px){section#tab-resources .col-sm-12{display:inline-block;width:100%}}section#tab-resources .text-center{text-align:center}section#tab-resources p{font-size:16px}.wrap.short-pixel-bulk-page{margin-right:0}.sp-container{overflow:hidden;display:block;width:100%}.sp-floating-block{overflow:hidden;display:inline-block;float:left;margin-right:1.1%!important}.sp-full-width{width:98.8%;box-sizing:border-box}.sp-double-width{width:65.52%;box-sizing:border-box}.sp-single-width{width:32.23%;box-sizing:border-box}@media(max-width:1759px){.sp-floating-block{margin-right:1.3%!important}.sp-double-width,.sp-full-width{width:98.65%}.sp-single-width{width:48.7%}}@media(max-width:1249px){.sp-floating-block{margin-right:2%!important}.sp-double-width,.sp-full-width,.sp-single-width{width:97%}}.sp-tabs h2:before{content:none}.sp-column-actions-template+.sp-column-info{display:none}
res/css/shortpixel-admin.css CHANGED
@@ -36,9 +36,29 @@
36
  max-width: 70%; }
37
  #shortpixel-settings-tabs #tab-adv-settings .addCustomFolder input[name="saveAdv"] {
38
  margin-left: 8px; }
39
- #shortpixel-settings-tabs #tab-adv-settings .shortpixel-folders-list th {
40
- width: auto;
41
- padding: 12px 16px 12px 12px; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
 
43
  .cf_switch label {
44
  width: 100%;
36
  max-width: 70%; }
37
  #shortpixel-settings-tabs #tab-adv-settings .addCustomFolder input[name="saveAdv"] {
38
  margin-left: 8px; }
39
+ #shortpixel-settings-tabs #tab-adv-settings .shortpixel-folders-list {
40
+ display: table;
41
+ border-collapse: separate; }
42
+ #shortpixel-settings-tabs #tab-adv-settings .shortpixel-folders-list div.heading {
43
+ width: auto;
44
+ display: table-header-group;
45
+ padding: 12px 16px 12px 12px; }
46
+ #shortpixel-settings-tabs #tab-adv-settings .shortpixel-folders-list div.heading span {
47
+ font-weight: 600;
48
+ font-size: 14px; }
49
+ #shortpixel-settings-tabs #tab-adv-settings .shortpixel-folders-list div {
50
+ display: table-row; }
51
+ #shortpixel-settings-tabs #tab-adv-settings .shortpixel-folders-list div > span {
52
+ display: table-cell;
53
+ padding: 5px 10px;
54
+ vertical-align: middle;
55
+ background-color: #eee; }
56
+ #shortpixel-settings-tabs #tab-adv-settings .shortpixel-folders-list div > span.action {
57
+ background-color: unset; }
58
+ #shortpixel-settings-tabs #tab-adv-settings .shortpixel-folders-list .refresh-folder {
59
+ text-decoration: none; }
60
+ #shortpixel-settings-tabs #tab-adv-settings .shortpixel-folders-list .info-icon {
61
+ cursor: pointer; }
62
 
63
  .cf_switch label {
64
  width: 100%;
res/css/shortpixel-admin.min.css DELETED
@@ -1 +0,0 @@
1
- .shortpixel.notice{min-height:50px;padding:8px}.shortpixel.notice img{display:inline-block;margin:0 25px 0 0;max-height:50px}.shortpixel.notice .notice-dismiss{margin-top:10px}.view-notice{box-shadow:0 1px 1px 0 rgba(0,0,0,0.1);border:4px solid #fff;padding:1px 12px}.view-notice p{margin:1em 0 !important}.view-notice.warning{border-left-color:#ffb900}.view-notice-row{display:none}.short-pixel-bulk-page.bulk-restore-all ol li{font-weight:700}.short-pixel-bulk-page.bulk-restore-all section.select_folders{margin:20px 0}.short-pixel-bulk-page.bulk-restore-all section.select_folders .input{margin:10px 0 10px 15px;font-size:16px;display:block;clear:both}.short-pixel-bulk-page.bulk-restore-all section.select_folders .filecount{font-size:12px}.short-pixel-bulk-page.bulk-restore-all section.random_check .random_answer{font-size:16px;font-weight:700;padding:8px;border:1px solid #ccc;display:inline-block}.short-pixel-bulk-page.bulk-restore-all section.random_check .inputs{margin:15px 0}.short-pixel-bulk-page.bulk-restore-all section.random_check .inputs span{margin-right:8px}.short-pixel-bulk-page.bulk-restore-all .button{margin:10px 0;margin-right:8px}.short-pixel-bulk-page .sp-hidden{display:none}#shortpixel-settings-tabs #tab-adv-settings .addCustomFolder{margin:10px 0}#shortpixel-settings-tabs #tab-adv-settings .addCustomFolder .add-folder-text{margin-left:5px}#shortpixel-settings-tabs #tab-adv-settings .addCustomFolder input[type="text"]{width:50em;max-width:70%}#shortpixel-settings-tabs #tab-adv-settings .addCustomFolder input[name="saveAdv"]{margin-left:8px}.settings_page_wp-shortpixel-settings .top-menu{font-size:18px}.settings_page_wp-shortpixel-settings .top-menu a{font-size:18px}.settings_page_wp-shortpixel-settings .wp-shortpixel-tab-content{transition:all 1000ms linear}.settings_page_wp-shortpixel-settings article.sp-tabs section .wp-shortpixel-tab-content{opacity:0}.settings_page_wp-shortpixel-settings article.sp-tabs section.sel-tab .wp-shortpixel-tab-content{opacity:1}.settings_page_wp-shortpixel-settings article.sp-tabs section h2{position:absolute;font-size:1.3em;font-weight:normal;width:180px;height:1.8em;top:-1.8em;left:10px;padding:0;margin:0;color:#999;background-color:#ddd}.settings_page_wp-shortpixel-settings article.sp-tabs section h2 a{display:block;width:100%;line-height:1.8em;text-align:center;text-decoration:none;color:#23282d;outline:0 none}.settings_page_wp-shortpixel-settings article.sp-tabs section:nth-child(2) h2{left:192px}.settings_page_wp-shortpixel-settings article.sp-tabs section:nth-child(3) h2{left:374px}.settings_page_wp-shortpixel-settings article.sp-tabs section:nth-child(4) h2{left:556px}.settings_page_wp-shortpixel-settings article.sp-tabs section:nth-child(5) h2{left:738px}.settings_page_wp-shortpixel-settings article.sp-tabs section:nth-child(6) h2{left:920px}.settings_page_wp-shortpixel-settings section#tab-debug .flex{display:flex}.settings_page_wp-shortpixel-settings section#tab-debug .env .flex{flex-wrap:wrap;max-width:450px}.settings_page_wp-shortpixel-settings section#tab-debug .env .flex span{width:45%;padding:4px}
 
res/css/shortpixel-notices.css CHANGED
@@ -18,6 +18,8 @@
18
  display: table-row; }
19
  .shortpixel.notice .sp-conflict-plugins li > * {
20
  display: table-cell; }
 
 
21
  .shortpixel.notice li.sp-conflict-plugins-list {
22
  line-height: 28px;
23
  list-style: disc;
18
  display: table-row; }
19
  .shortpixel.notice .sp-conflict-plugins li > * {
20
  display: table-cell; }
21
+ .shortpixel.notice .content button {
22
+ background-color: #007cba; }
23
  .shortpixel.notice li.sp-conflict-plugins-list {
24
  line-height: 28px;
25
  list-style: disc;
res/css/shortpixel-othermedia.css ADDED
@@ -0,0 +1,102 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @media (max-width: 1250px) {
2
+ #shortpixel-hs-blind, #shortpixel-hs-tools, #botbutton, #beacon-container {
3
+ display: none !important; } }
4
+ .shortpixel-other-media {
5
+ margin-bottom: 120px; }
6
+ .shortpixel-other-media .search-form {
7
+ float: right; }
8
+ .shortpixel-other-media .search-form label {
9
+ margin-right: 8px; }
10
+ .shortpixel-other-media .pagination {
11
+ margin: 25px 0; }
12
+ @media (max-width: 782px) {
13
+ .shortpixel-other-media .pagination .pagination-links {
14
+ float: right;
15
+ margin: 8px 0; }
16
+ .shortpixel-other-media .pagination .displaying-num {
17
+ display: none; } }
18
+ .shortpixel-other-media .list-overview {
19
+ width: 100%;
20
+ background: #fff;
21
+ border: 1px solid #ccd0d4;
22
+ box-shadow: 0 1px 1px rgba(0, 0, 0, 0.04);
23
+ clear: both;
24
+ display: table; }
25
+ .shortpixel-other-media .list-overview .heading, .shortpixel-other-media .list-overview .item {
26
+ display: table-row; }
27
+ .shortpixel-other-media .list-overview .heading > span, .shortpixel-other-media .list-overview .item > span {
28
+ display: table-cell;
29
+ padding: 8px 10px;
30
+ line-height: 1.5em;
31
+ vertical-align: top; }
32
+ .shortpixel-other-media .list-overview .heading {
33
+ border-bottom: 1px solid #ccc;
34
+ font-size: 14px; }
35
+ .shortpixel-other-media .list-overview .heading a {
36
+ text-decoration: none;
37
+ display: inline-block;
38
+ width: 100%; }
39
+ .shortpixel-other-media .list-overview .heading a .sorted::before {
40
+ visibility: visible; }
41
+ .shortpixel-other-media .list-overview .heading a .sorted.desc::before {
42
+ content: "\f140"; }
43
+ .shortpixel-other-media .list-overview .heading a:hover .sorting-indicator::before {
44
+ content: "\f142";
45
+ visibility: visible; }
46
+ .shortpixel-other-media .list-overview .heading a:hover .sorting-indicator.asc::before {
47
+ content: "\f140"; }
48
+ .shortpixel-other-media .list-overview .heading span.heading span {
49
+ float: left;
50
+ cursor: pointer; }
51
+ .shortpixel-other-media .list-overview .item:nth-child(odd) {
52
+ background-color: #f9f9f9; }
53
+ .shortpixel-other-media .list-overview .item:hover .row-actions {
54
+ left: 0;
55
+ color: #ddd; }
56
+ .shortpixel-other-media .list-overview .item:hover .row-actions a {
57
+ text-decoration: none;
58
+ padding-right: 4px;
59
+ padding-left: 4px; }
60
+ .shortpixel-other-media .list-overview .item:hover .row-actions a:first-child {
61
+ padding-left: 0; }
62
+ .shortpixel-other-media .list-overview .item .filename {
63
+ font-size: 14px; }
64
+ .shortpixel-other-media .list-overview .item .thumb {
65
+ min-width: 60px;
66
+ min-height: 60px;
67
+ display: inline-block;
68
+ border: 1px solid #ccc; }
69
+ .shortpixel-other-media .list-overview .item .thumb img {
70
+ max-width: 60px;
71
+ max-height: 60px;
72
+ border: 1px solid #ccc;
73
+ background: #eee; }
74
+ .shortpixel-other-media .list-overview .item .actions {
75
+ min-width: 105px; }
76
+ .shortpixel-other-media .list-overview .item .single-action.button-primary a {
77
+ color: #fff;
78
+ text-decoration: none; }
79
+ .shortpixel-other-media .list-overview .item .sp-column-info {
80
+ width: 400px;
81
+ display: inline-block; }
82
+ @media (max-width: 1550px) {
83
+ .shortpixel-other-media .list-overview .item .sp-column-info {
84
+ width: auto; } }
85
+ @media (max-width: 1250px) {
86
+ .shortpixel-other-media .list-overview .heading .type {
87
+ display: none; }
88
+ .shortpixel-other-media .list-overview .item .mediatype {
89
+ display: none; }
90
+ .shortpixel-other-media .list-overview .item .filename, .shortpixel-other-media .list-overview .item .folderpath {
91
+ max-width: 250px;
92
+ overflow: hidden;
93
+ text-overflow: ellipsis; } }
94
+ @media (max-width: 1200px) {
95
+ .shortpixel-other-media .list-overview .heading .date {
96
+ display: none; }
97
+ .shortpixel-other-media .list-overview .item .date {
98
+ display: none; } }
99
+ .shortpixel-other-media .list-overview .no-items {
100
+ padding: 10px; }
101
+ .shortpixel-other-media .list-overview .no-items p {
102
+ font-size: 14px; }
res/js/shortpixel.js CHANGED
@@ -3,7 +3,7 @@
3
  */
4
 
5
  // init checks bulkProcess on each page. initSettings is when the settings View is being loaded.
6
- jQuery(document).ready(function(){ShortPixel.init();});
7
 
8
  var ShortPixel = function() {
9
 
@@ -189,10 +189,11 @@ var ShortPixel = function() {
189
 
190
  function setupAdvancedTab() {
191
  jQuery("input.remove-folder-button").click(function(){
192
- var path = jQuery(this).data("value");
 
193
  var r = confirm( SPstringFormat(_spTr.areYouSureStopOptimizing, path) );
194
  if (r == true) {
195
- jQuery("#removeFolder").val(path);
196
  jQuery('#wp_shortpixel_options').submit();
197
  }
198
  });
@@ -577,7 +578,8 @@ var ShortPixel = function() {
577
 
578
  if(subPath) {
579
  var fullPath = jQuery("#customFolderBase").val() + subPath;
580
- if(fullPath.slice(-1) == '/') fullPath = fullPath.slice(0, -1);
 
581
  jQuery("#addCustomFolder").val(fullPath);
582
  jQuery("#addCustomFolderView").val(fullPath);
583
  jQuery(".sp-folder-picker-shade").fadeOut(100);
@@ -877,7 +879,7 @@ function showToolBarAlert($status, $message, id) {
877
  case ShortPixel.STATUS_QUOTA_EXCEEDED:
878
  if( window.location.href.search("wp-short-pixel-bulk") > 0
879
  && jQuery(".sp-quota-exceeded-alert").length == 0) { //if we're in bulk and the alert is not displayed reload to see all options
880
- // location.reload();
881
  return;
882
  }
883
  robo.addClass("shortpixel-alert");
@@ -1108,8 +1110,10 @@ function checkBulkProcessingCallApi(){
1108
  // [BS] Only update date on Custom Media Page.
1109
  if (ShortPixel.isCustomImageId(id) && data['TsOptimized'] && data['TsOptimized'].length > 0)
1110
  {
1111
- console.log(id);
1112
- jQuery('.date-' + id).text(data['TsOptimized']);
 
 
1113
  }
1114
 
1115
 
@@ -1180,7 +1184,19 @@ function checkBulkProcessingCallApi(){
1180
  default:
1181
  ShortPixel.retry("Unknown status " + data["Status"] + ". Retrying...");
1182
  break;
 
 
 
 
 
 
 
 
 
 
 
1183
  }
 
1184
  }
1185
  },
1186
  error: function(response){
3
  */
4
 
5
  // init checks bulkProcess on each page. initSettings is when the settings View is being loaded.
6
+ jQuery(document).ready(function(){ShortPixel.init(); });
7
 
8
  var ShortPixel = function() {
9
 
189
 
190
  function setupAdvancedTab() {
191
  jQuery("input.remove-folder-button").click(function(){
192
+ var id = jQuery(this).data("value");
193
+ var path = jQuery(this).data('name');
194
  var r = confirm( SPstringFormat(_spTr.areYouSureStopOptimizing, path) );
195
  if (r == true) {
196
+ jQuery("#removeFolder").val(id);
197
  jQuery('#wp_shortpixel_options').submit();
198
  }
199
  });
578
 
579
  if(subPath) {
580
  var fullPath = jQuery("#customFolderBase").val() + subPath;
581
+ fullPath = fullPath.replace(/\/\//,'/');
582
+ console.debug('FullPath' + fullPath);
583
  jQuery("#addCustomFolder").val(fullPath);
584
  jQuery("#addCustomFolderView").val(fullPath);
585
  jQuery(".sp-folder-picker-shade").fadeOut(100);
879
  case ShortPixel.STATUS_QUOTA_EXCEEDED:
880
  if( window.location.href.search("wp-short-pixel-bulk") > 0
881
  && jQuery(".sp-quota-exceeded-alert").length == 0) { //if we're in bulk and the alert is not displayed reload to see all options
882
+
883
  return;
884
  }
885
  robo.addClass("shortpixel-alert");
1110
  // [BS] Only update date on Custom Media Page.
1111
  if (ShortPixel.isCustomImageId(id) && data['TsOptimized'] && data['TsOptimized'].length > 0)
1112
  {
1113
+ var row = jQuery('.list-overview .item-' + id);
1114
+
1115
+ jQuery(row).children('.date').text(data['TsOptimized']);
1116
+ jQuery(row).find('.row-actions .action-optimize').remove(); // gets complicated
1117
  }
1118
 
1119
 
1184
  default:
1185
  ShortPixel.retry("Unknown status " + data["Status"] + ". Retrying...");
1186
  break;
1187
+ } // switch
1188
+
1189
+ // If custom, if has ID ( returned something about image )
1190
+ if (typeof id != 'undefined' && ShortPixel.isCustomImageId(id))
1191
+ {
1192
+ var row = jQuery('.list-overview .item-' + id);
1193
+ jQuery(row).find('.row-actions .action-optimize').remove(); // gets complicated
1194
+ if (data['actions'])
1195
+ {
1196
+ jQuery(row).children('.actions').html(data['actions']);
1197
+ }
1198
  }
1199
+
1200
  }
1201
  },
1202
  error: function(response){
res/js/shortpixel.min.js CHANGED
@@ -1 +1 @@
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;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(e){var r=jQuery("li.shortpixel-toolbar-processing.shortpixel-processing");ShortPixel.STATUS_EMPTY_QUEUE==e&&(r.hasClass("shortpixel-alert")||r.hasClass("shortpixel-quota-exceeded"))||r.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)),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+"', true)\">"+_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(r.Status);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' alt='"+_spTr.loading+"' 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' alt='"+_spTr.loading+"' 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' alt='"+_spTr.loading+"' 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 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 dismissFileError(){jQuery(".shortpixel-alert").hide();var e={action:"shortpixel_dismissFileError"};jQuery.get(ShortPixel.AJAX_URL,e,function(r){(e=JSON.parse(r)).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)},validateKey:function(e){jQuery("#valid").val("validate"),jQuery(e).parents("form").submit()},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(),jQuery('input[name="backupImages"]').on("change",function(){ShortPixel.checkBackUpWarning()}),ShortPixel.checkBackUpWarning()},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)),"undefined"!=typeof HS&&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()},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 alt="'+_spTr.originalImage+'" class="spUploadCompareOriginal"/><img alt="'+_spTr.optimizedImage+'" 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()},checkBackUpWarning:function(){jQuery('input[name="backupImages"]').is(":checked")?jQuery(".backup_warning").fadeOut():jQuery(".backup_warning").fadeIn()},comparerData:{cssLoaded:!1,jsLoaded:!1,origUrl:!1,optUrl:!1,width:0,height:0},toRefresh:!1,resizeSizesAlert:!1,returnedStatusSearching:0}}();
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;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(e){var r=jQuery("li.shortpixel-toolbar-processing.shortpixel-processing");ShortPixel.STATUS_EMPTY_QUEUE==e&&(r.hasClass("shortpixel-alert")||r.hasClass("shortpixel-quota-exceeded"))||r.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)),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+"', true)\">"+_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(r.Status);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);if(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){n=jQuery(".list-overview .item-"+t);jQuery(n).children(".date").text(r.TsOptimized),jQuery(n).find(".row-actions .action-optimize").remove()}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...")}if(void 0!==t&&ShortPixel.isCustomImageId(t)){var n=jQuery(".list-overview .item-"+t);jQuery(n).find(".row-actions .action-optimize").remove(),r.actions&&jQuery(n).children(".actions").html(r.actions)}}},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' alt='"+_spTr.loading+"' 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' alt='"+_spTr.loading+"' 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' alt='"+_spTr.loading+"' 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 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 dismissFileError(){jQuery(".shortpixel-alert").hide();var e={action:"shortpixel_dismissFileError"};jQuery.get(ShortPixel.AJAX_URL,e,function(r){(e=JSON.parse(r)).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}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)},validateKey:function(e){jQuery("#valid").val("validate"),jQuery(e).parents("form").submit()},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(SPstringFormat(_spTr.pleaseDoNotSetLesser1024,o)):alert(SPstringFormat(_spTr.pleaseDoNotSetLesserSize,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(),jQuery('input[name="backupImages"]').on("change",function(){ShortPixel.checkBackUpWarning()}),ShortPixel.checkBackUpWarning()},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="",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)),"undefined"!=typeof HS&&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>"+SPstringFormat(_spTr.plusXthumbsOpt,o):"")+(0+s>0?"<br>"+SPstringFormat(_spTr.plusXretinasOpt,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=o.replace(/\/\//,"/"),console.debug("FullPath"+o),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()},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 alt="'+_spTr.originalImage+'" class="spUploadCompareOriginal"/><img alt="'+_spTr.optimizedImage+'" 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()},checkBackUpWarning:function(){jQuery('input[name="backupImages"]').is(":checked")?jQuery(".backup_warning").fadeOut():jQuery(".backup_warning").fadeIn()},comparerData:{cssLoaded:!1,jsLoaded:!1,origUrl:!1,optUrl:!1,width:0,height:0},toRefresh:!1,resizeSizesAlert:!1,returnedStatusSearching:0}}();
res/scss/shortpixel-notices.scss CHANGED
@@ -45,6 +45,12 @@
45
  li > * {
46
  display: table-cell;
47
  }
 
 
 
 
 
 
48
  }
49
 
50
  li.sp-conflict-plugins-list {
45
  li > * {
46
  display: table-cell;
47
  }
48
+
49
+ }
50
+
51
+ .content button
52
+ { // gets overwritten in NGG.
53
+ background-color: #007cba;
54
  }
55
 
56
  li.sp-conflict-plugins-list {
res/scss/shortpixel-othermedia.scss ADDED
@@ -0,0 +1,185 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @media(max-width: 1250px)
2
+ {
3
+ #shortpixel-hs-blind, #shortpixel-hs-tools, #botbutton, #beacon-container
4
+ {
5
+ display: none !important;
6
+ }
7
+ }
8
+
9
+ .shortpixel-other-media
10
+ {
11
+ margin-bottom: 120px; // leave space for the helpscout widget.
12
+ .search-form
13
+ {
14
+ float: right;
15
+ label
16
+ {
17
+ margin-right: 8px;
18
+ }
19
+ }
20
+ .pagination
21
+ {
22
+ margin: 25px 0;
23
+ @media(max-width: 782px) // wp breakpoint.
24
+ {
25
+ .pagination-links
26
+ {
27
+ float: right;
28
+ margin: 8px 0;
29
+ }
30
+ .displaying-num
31
+ {
32
+ display: none;
33
+ }
34
+ }
35
+ }
36
+
37
+ .list-overview
38
+ {
39
+ width: 100%;
40
+ background: #fff;
41
+ border: 1px solid #ccd0d4;
42
+ box-shadow: 0 1px 1px rgba(0,0,0,.04);
43
+ clear: both;
44
+ display: table;
45
+
46
+ .heading, .item
47
+ {
48
+ display: table-row;
49
+
50
+ > span
51
+ {
52
+ display: table-cell;
53
+ padding: 8px 10px;
54
+ line-height: 1.5em;
55
+ vertical-align: top;
56
+ }
57
+ }
58
+ .heading
59
+ {
60
+ border-bottom: 1px solid #ccc;
61
+ font-size: 14px;
62
+ a {
63
+ text-decoration: none;
64
+ display: inline-block;
65
+ width: 100%;
66
+ .sorted::before
67
+ {
68
+ visibility: visible;
69
+ }
70
+ .sorted.desc::before
71
+ {
72
+ content: "\f140";
73
+ }
74
+ &:hover
75
+ {
76
+ .sorting-indicator::before
77
+ {
78
+ content: "\f142";
79
+ visibility: visible;
80
+ }
81
+ .sorting-indicator.asc::before
82
+ {
83
+ content: "\f140";
84
+ }
85
+ }
86
+
87
+ }
88
+ span.heading span
89
+ {
90
+ float: left;
91
+ cursor: pointer;
92
+ }
93
+ }
94
+ .item
95
+ {
96
+ &:nth-child(odd) {
97
+ background-color: #f9f9f9;
98
+ }
99
+ &:hover
100
+ {
101
+ .row-actions
102
+ {
103
+ left: 0;
104
+ color: #ddd;
105
+ a
106
+ {
107
+ // margin-right: 4px;
108
+ text-decoration: none;
109
+ padding-right: 4px;
110
+ padding-left: 4px;
111
+ &:first-child{
112
+ padding-left: 0;
113
+ }
114
+ }
115
+ }
116
+ }
117
+ .filename
118
+ {
119
+ font-size: 14px;
120
+ }
121
+ .thumb
122
+ {
123
+ min-width: 60px;
124
+ min-height: 60px;
125
+ display: inline-block;
126
+ border: 1px solid #ccc;
127
+
128
+ img {
129
+ max-width: 60px;
130
+ max-height: 60px;
131
+ border: 1px solid #ccc;
132
+ background: #eee;
133
+ }
134
+ }
135
+ .actions
136
+ {
137
+ min-width: 105px;
138
+ }
139
+ .single-action.button-primary a
140
+ {
141
+ color: #fff;
142
+ text-decoration: none;
143
+ }
144
+ .sp-column-info {
145
+ width: 400px;
146
+ display: inline-block;
147
+ @media(max-width: 1550px) {
148
+ width: auto;
149
+ }
150
+ }
151
+ }
152
+ @media(max-width: 1250px)
153
+ {
154
+ .heading
155
+ {
156
+ .type { display: none; }
157
+ }
158
+ .item {
159
+ .mediatype { display: none; }
160
+ .filename, .folderpath { max-width: 250px; overflow: hidden; text-overflow: ellipsis; }
161
+ }
162
+
163
+ }
164
+ @media(max-width: 1200px)
165
+ {
166
+ .heading
167
+ {
168
+ .date { display: none; }
169
+ }
170
+
171
+ .item
172
+ {
173
+ .date { display: none; }
174
+ }
175
+ }
176
+ .no-items
177
+ {
178
+ padding: 10px;
179
+ p {
180
+ font-size: 14px;
181
+ }
182
+ }
183
+ }
184
+
185
+ } // list
res/scss/utils/_notices.scss DELETED
@@ -1,39 +0,0 @@
1
-
2
- .shortpixel.notice
3
- {
4
- //padding: 18px;
5
- min-height: 50px;
6
- padding: 8px;
7
- img
8
- {
9
- display:inline-block;
10
- margin: 0 25px 0 0;
11
- max-height: 50px;
12
- }
13
- .notice-dismiss
14
- {
15
- margin-top: 10px;
16
- }
17
- }
18
-
19
- /* In-view notice ( not on top, between the options ) - styled after WP notice */
20
- .view-notice
21
- {
22
-
23
- box-shadow: 0 1px 1px 0 rgba( 0, 0, 0, 0.1 );
24
- border: 4px solid #fff;
25
-
26
- padding: 1px 12px;
27
- p {
28
- margin: 1em 0 !important;
29
- }
30
- &.warning
31
- {
32
- border-left-color: #ffb900;
33
- }
34
- }
35
-
36
- .view-notice-row
37
- {
38
- display: none;
39
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
res/scss/view/_settings-advanced.scss CHANGED
@@ -24,11 +24,38 @@
24
  // additional media table
25
  .shortpixel-folders-list
26
  {
27
- th {
 
 
 
 
28
  width: auto;
 
29
  padding: 12px 16px 12px 12px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
 
31
  }
 
 
 
 
32
  }
33
 
34
 
24
  // additional media table
25
  .shortpixel-folders-list
26
  {
27
+ display: table;
28
+ border-collapse: separate;
29
+
30
+ div.heading
31
+ {
32
  width: auto;
33
+ display: table-header-group;
34
  padding: 12px 16px 12px 12px;
35
+ span
36
+ {
37
+ font-weight: 600;
38
+ font-size: 14px;
39
+ }
40
+ }
41
+ div
42
+ {
43
+
44
+ display: table-row;
45
+ &> span
46
+ {
47
+ display: table-cell;
48
+ padding: 5px 10px;
49
+ vertical-align: middle;
50
+ background-color: #eee;
51
+ &.action { background-color: unset; }
52
+ }
53
 
54
  }
55
+
56
+
57
+ .refresh-folder { text-decoration: none; }
58
+ .info-icon { cursor: pointer; }
59
  }
60
 
61
 
shortpixel-debug.php DELETED
@@ -1,47 +0,0 @@
1
- <?php
2
- function shortpixel_process_error_backtrace($errno, $errstr, $errfile, $errline, $errcontext) {
3
- if(!(error_reporting() & $errno))
4
- return;
5
- switch($errno) {
6
- case E_WARNING :
7
- case E_USER_WARNING :
8
- case E_STRICT :
9
- case E_NOTICE :
10
- case E_USER_NOTICE :
11
- $type = 'warning';
12
- $fatal = false;
13
- break;
14
- default :
15
- $type = 'fatal error';
16
- $fatal = true;
17
- break;
18
- }
19
- $trace = array_reverse(debug_backtrace());
20
- array_pop($trace);
21
- if(php_sapi_name() == 'cli') {
22
- echo 'Backtrace from ' . $type . ' \'' . $errstr . '\' at ' . $errfile . ' ' . $errline . ':' . "\n";
23
- foreach($trace as $item)
24
- echo ' ' . (isset($item['file']) ? $item['file'] : '<unknown file>') . ' ' . (isset($item['line']) ? $item['line'] : '<unknown line>') . ' calling ' . $item['function'] . '()' . "\n";
25
- } else {
26
- echo '<p class="error_backtrace">' . "\n";
27
- echo ' Backtrace from ' . $type . ' \'' . $errstr . '\' at ' . $errfile . ' ' . $errline . ':' . "\n";
28
- echo ' <ol>' . "\n";
29
- foreach($trace as $item)
30
- echo ' <li>' . (isset($item['file']) ? $item['file'] : '<unknown file>') . ' ' . (isset($item['line']) ? $item['line'] : '<unknown line>') . ' calling ' . $item['function'] . '()</li>' . "\n";
31
- echo ' </ol>' . "\n";
32
- echo '</p>' . "\n";
33
- }
34
- if(ini_get('log_errors')) {
35
- $items = array();
36
- foreach($trace as $item)
37
- $items[] = (isset($item['file']) ? $item['file'] : '<unknown file>') . ' ' . (isset($item['line']) ? $item['line'] : '<unknown line>') . ' calling ' . $item['function'] . '()';
38
- $message = 'Backtrace from ' . $type . ' \'' . $errstr . '\' at ' . $errfile . ' ' . $errline . ': ' . join(' | ', $items);
39
- error_log($message);
40
- }
41
- if($fatal)
42
- exit(1);
43
- }
44
-
45
- if(WP_DEBUG === true) {
46
- set_error_handler('shortpixel_process_error_backtrace');
47
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
shortpixel-plugin.php CHANGED
@@ -13,7 +13,7 @@ class ShortPixelPlugin
13
  private static $instance;
14
  protected static $modelsLoaded = array(); // don't require twice, limit amount of require looksups..
15
 
16
- private $paths = array('class', 'class/controller', 'class/external'); // classes that are autoloaded
17
 
18
  protected $is_noheaders = false;
19
 
@@ -159,9 +159,11 @@ class ShortPixelPlugin
159
  {
160
  add_action('admin_menu', array($this,'admin_pages'));
161
  add_action('admin_enqueue_scripts', array($this, 'admin_scripts')); // admin scripts
 
162
  // defer notices a little to allow other hooks ( notable adminnotices )
163
  add_action('admin_notices', array($this, 'admin_notices'), 50); // notices occured before page load
164
  add_action('admin_footer', array($this, 'admin_notices')); // called in views.
 
165
  }
166
 
167
  /** Hook in our admin pages */
@@ -173,7 +175,7 @@ class ShortPixelPlugin
173
 
174
  if($this->shortPixel->getSpMetaDao()->hasFoldersTable() && count($this->shortPixel->getSpMetaDao()->getFolders())) {
175
  /*translators: title and menu name for the Other media page*/
176
- $admin_pages[] = add_media_page( __('Other Media Optimized by ShortPixel','shortpixel-image-optimiser'), __('Other Media','shortpixel-image-optimiser'), 'edit_others_posts', 'wp-short-pixel-custom', array( $this->shortPixel, 'listCustomMedia' ) );
177
  }
178
  /*translators: title and menu name for the Bulk Processing page*/
179
  $admin_pages[] = add_media_page( __('ShortPixel Bulk Process','shortpixel-image-optimiser'), __('Bulk ShortPixel','shortpixel-image-optimiser'), 'edit_others_posts', 'wp-short-pixel-bulk', array( $this->shortPixel, 'bulkProcess' ) );
@@ -207,6 +209,9 @@ class ShortPixelPlugin
207
  // notices. additional styles for SPIO.
208
  wp_register_style('shortpixel-notices', plugins_url('/res/css/shortpixel-notices.css',SHORTPIXEL_PLUGIN_FILE), array(), SHORTPIXEL_IMAGE_OPTIMISER_VERSION);
209
 
 
 
 
210
 
211
  wp_register_script('shortpixel-debug', plugins_url('/res/js/debug.js',SHORTPIXEL_PLUGIN_FILE), array('jquery', 'jquery-ui-draggable'), SHORTPIXEL_IMAGE_OPTIMISER_VERSION);
212
 
@@ -214,10 +219,6 @@ class ShortPixelPlugin
214
 
215
  public function admin_notices()
216
  {
217
- if (! \wpSPIO()->env()->is_screen_to_use )
218
- {
219
- return;
220
- }
221
  $noticeControl = Notices::getInstance();
222
  $noticeControl->loadIcons(array(
223
  'normal' => '<img class="short-pixel-notice-icon" src="' . plugins_url('res/img/slider.png', SHORTPIXEL_PLUGIN_FILE) . '">',
@@ -244,6 +245,7 @@ class ShortPixelPlugin
244
  wp_enqueue_script('jquery.knob.min.js');
245
  wp_enqueue_script('jquery.tooltip.min.js');
246
  wp_enqueue_script('shortpixel');
 
247
  }
248
  }
249
  }
@@ -281,6 +283,27 @@ class ShortPixelPlugin
281
  }
282
  }
283
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
284
  /** Route, based on the page slug
285
  *
286
  * Principially all page controller should be routed from here.
@@ -292,7 +315,6 @@ class ShortPixelPlugin
292
 
293
  $default_action = 'load'; // generic action on controller.
294
  $action = isset($_REQUEST['sp-action']) ? sanitize_text_field($_REQUEST['sp-action']) : $default_action;
295
- Log::addDebug('Request', $_REQUEST);
296
  $controller = false;
297
 
298
  if ($this->env()->is_debug)
@@ -302,15 +324,20 @@ class ShortPixelPlugin
302
 
303
  switch($plugin_page)
304
  {
305
- case 'wp-shortpixel-settings':
306
- $this->load_style('shortpixel-admin');
307
  $this->load_style('shortpixel');
308
  $this->load_style('shortpixel-modal');
309
  $this->load_style('sp-file-tree');
310
- $this->load_script('sp-file-tree');
311
  $controller = \shortPixelTools::namespaceit("SettingsController");
312
  $url = menu_page_url($plugin_page, false);
313
  break;
 
 
 
 
 
314
  }
315
 
316
  if ($controller !== false)
@@ -399,6 +426,7 @@ class ShortPixelPlugin
399
  adminNoticesController::resetCompatNotice();
400
  adminNoticesController::resetAPINotices();
401
  adminNoticesController::resetQuotaNotices();
 
402
 
403
  \WPShortPixelSettings::onActivate();
404
 
13
  private static $instance;
14
  protected static $modelsLoaded = array(); // don't require twice, limit amount of require looksups..
15
 
16
+ private $paths = array('class', 'class/controller', 'class/external', 'class/controller/views'); // classes that are autoloaded
17
 
18
  protected $is_noheaders = false;
19
 
159
  {
160
  add_action('admin_menu', array($this,'admin_pages'));
161
  add_action('admin_enqueue_scripts', array($this, 'admin_scripts')); // admin scripts
162
+ add_action('admin_enqueue_scripts', array($this, 'load_admin_scripts'), 90); // loader via route.
163
  // defer notices a little to allow other hooks ( notable adminnotices )
164
  add_action('admin_notices', array($this, 'admin_notices'), 50); // notices occured before page load
165
  add_action('admin_footer', array($this, 'admin_notices')); // called in views.
166
+
167
  }
168
 
169
  /** Hook in our admin pages */
175
 
176
  if($this->shortPixel->getSpMetaDao()->hasFoldersTable() && count($this->shortPixel->getSpMetaDao()->getFolders())) {
177
  /*translators: title and menu name for the Other media page*/
178
+ $admin_pages[] = add_media_page( __('Other Media Optimized by ShortPixel','shortpixel-image-optimiser'), __('Other Media','shortpixel-image-optimiser'), 'edit_others_posts', 'wp-short-pixel-custom', array( $this, 'route' ) );
179
  }
180
  /*translators: title and menu name for the Bulk Processing page*/
181
  $admin_pages[] = add_media_page( __('ShortPixel Bulk Process','shortpixel-image-optimiser'), __('Bulk ShortPixel','shortpixel-image-optimiser'), 'edit_others_posts', 'wp-short-pixel-bulk', array( $this->shortPixel, 'bulkProcess' ) );
209
  // notices. additional styles for SPIO.
210
  wp_register_style('shortpixel-notices', plugins_url('/res/css/shortpixel-notices.css',SHORTPIXEL_PLUGIN_FILE), array(), SHORTPIXEL_IMAGE_OPTIMISER_VERSION);
211
 
212
+ // other media screen
213
+ wp_register_style('shortpixel-othermedia', plugins_url('/res/css/shortpixel-othermedia.css',SHORTPIXEL_PLUGIN_FILE), array(), SHORTPIXEL_IMAGE_OPTIMISER_VERSION);
214
+
215
 
216
  wp_register_script('shortpixel-debug', plugins_url('/res/js/debug.js',SHORTPIXEL_PLUGIN_FILE), array('jquery', 'jquery-ui-draggable'), SHORTPIXEL_IMAGE_OPTIMISER_VERSION);
217
 
219
 
220
  public function admin_notices()
221
  {
 
 
 
 
222
  $noticeControl = Notices::getInstance();
223
  $noticeControl->loadIcons(array(
224
  'normal' => '<img class="short-pixel-notice-icon" src="' . plugins_url('res/img/slider.png', SHORTPIXEL_PLUGIN_FILE) . '">',
245
  wp_enqueue_script('jquery.knob.min.js');
246
  wp_enqueue_script('jquery.tooltip.min.js');
247
  wp_enqueue_script('shortpixel');
248
+ $this->load_style('shortpixel-modal');
249
  }
250
  }
251
  }
283
  }
284
  }
285
 
286
+ /** This is separated from route to load in head, preventing unstyled content all the time */
287
+ public function load_admin_scripts()
288
+ {
289
+ global $plugin_page;
290
+
291
+ switch($plugin_page)
292
+ {
293
+ case 'wp-shortpixel-settings': // settings
294
+ $this->load_style('shortpixel-admin');
295
+ $this->load_style('shortpixel');
296
+ $this->load_style('shortpixel-modal');
297
+ $this->load_style('sp-file-tree');
298
+ $this->load_script('sp-file-tree');
299
+
300
+ break;
301
+ case 'wp-short-pixel-custom': // other media
302
+ $this->load_style('shortpixel-othermedia');
303
+ break;
304
+ }
305
+ }
306
+
307
  /** Route, based on the page slug
308
  *
309
  * Principially all page controller should be routed from here.
315
 
316
  $default_action = 'load'; // generic action on controller.
317
  $action = isset($_REQUEST['sp-action']) ? sanitize_text_field($_REQUEST['sp-action']) : $default_action;
 
318
  $controller = false;
319
 
320
  if ($this->env()->is_debug)
324
 
325
  switch($plugin_page)
326
  {
327
+ case 'wp-shortpixel-settings': // settings
328
+ /* $this->load_style('shortpixel-admin');
329
  $this->load_style('shortpixel');
330
  $this->load_style('shortpixel-modal');
331
  $this->load_style('sp-file-tree');
332
+ $this->load_script('sp-file-tree'); */
333
  $controller = \shortPixelTools::namespaceit("SettingsController");
334
  $url = menu_page_url($plugin_page, false);
335
  break;
336
+ case 'wp-short-pixel-custom': // other media
337
+ /* $this->load_style('shortpixel-othermedia'); */
338
+ $controller = \shortPixelTools::namespaceit('OtherMediaViewController');
339
+ $url = menu_page_url($plugin_page, false);
340
+ break;
341
  }
342
 
343
  if ($controller !== false)
426
  adminNoticesController::resetCompatNotice();
427
  adminNoticesController::resetAPINotices();
428
  adminNoticesController::resetQuotaNotices();
429
+ adminNoticesController::resetIntegrationNotices();
430
 
431
  \WPShortPixelSettings::onActivate();
432
 
shortpixel_api.php CHANGED
@@ -684,10 +684,12 @@ class ShortPixelAPI {
684
 
685
  $writeFailed = 0;
686
  $width = $height = null;
687
- $resize = $this->_settings->resizeImages;
688
  $retinas = 0;
689
  $thumbsOpt = 0;
690
  $thumbsOptList = array();
 
 
691
 
692
  $fs = new \ShortPixel\FileSystemController();
693
 
@@ -720,7 +722,7 @@ class ShortPixelAPI {
720
  if(ShortPixelMetaFacade::isRetina($targetFile->getFullPath())) {
721
  $retinas ++;
722
  }
723
- if($resize && $itemHandler->getMeta()->getPath() == $targetFile->getFullPath() ) { //this is the main image
724
  $size = getimagesize($PATHs[$tempFileID]);
725
  $width = $size[0];
726
  $height = $size[1];
@@ -823,10 +825,27 @@ class ShortPixelAPI {
823
  $meta->setActualWidth($width);
824
  $meta->setActualHeight($height);
825
  }
 
826
  $meta->setRetries($meta->getRetries() + 1);
827
  $meta->setBackup(!$NoBackup);
828
  $meta->setStatus(2);
829
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
830
  $itemHandler->updateMeta($meta);
831
  $itemHandler->optimizationSucceeded();
832
  Log::addDebug("HANDLE SUCCESS: Metadata saved.");
684
 
685
  $writeFailed = 0;
686
  $width = $height = null;
687
+ $do_resize = $this->_settings->resizeImages;
688
  $retinas = 0;
689
  $thumbsOpt = 0;
690
  $thumbsOptList = array();
691
+ // The settings model.
692
+ $settings = \wpSPIO()->settings();
693
 
694
  $fs = new \ShortPixel\FileSystemController();
695
 
722
  if(ShortPixelMetaFacade::isRetina($targetFile->getFullPath())) {
723
  $retinas ++;
724
  }
725
+ if($do_resize && $itemHandler->getMeta()->getPath() == $targetFile->getFullPath() ) { //this is the main image
726
  $size = getimagesize($PATHs[$tempFileID]);
727
  $width = $size[0];
728
  $height = $size[1];
825
  $meta->setActualWidth($width);
826
  $meta->setActualHeight($height);
827
  }
828
+
829
  $meta->setRetries($meta->getRetries() + 1);
830
  $meta->setBackup(!$NoBackup);
831
  $meta->setStatus(2);
832
 
833
+ if ($do_resize)
834
+ {
835
+
836
+ $resizeWidth = $settings->resizeWidth;
837
+ $resizeHeight = $settings->resizeHeight;
838
+
839
+ if ($resizeWidth == $width || $resizeHeight == $height) // resized.
840
+ {
841
+ $meta->setResizeWidth($width);
842
+ $meta->setResizeHeight($height);
843
+ $meta->setResize(true);
844
+ }
845
+ else
846
+ $meta->setResize(false);
847
+ }
848
+
849
  $itemHandler->updateMeta($meta);
850
  $itemHandler->optimizationSucceeded();
851
  Log::addDebug("HANDLE SUCCESS: Metadata saved.");
wp-shortpixel-req.php CHANGED
@@ -49,7 +49,7 @@ require_once('class/model/shortpixel-entity.php');
49
  require_once('class/model/shortpixel-meta.php');
50
  require_once('class/model/shortpixel-folder.php');
51
  //exceptions
52
- require_once('class/model/sp-file-rights-exception.php');
53
  //database access
54
  require_once('class/db/shortpixel-db.php');
55
  require_once('class/db/wp-shortpixel-db.php');
49
  require_once('class/model/shortpixel-meta.php');
50
  require_once('class/model/shortpixel-folder.php');
51
  //exceptions
52
+ //require_once('class/model/sp-file-rights-exception.php');
53
  //database access
54
  require_once('class/db/shortpixel-db.php');
55
  require_once('class/db/wp-shortpixel-db.php');
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.16.4
7
  * Author: ShortPixel
8
  * Author URI: https://shortpixel.com
9
  * Text Domain: shortpixel-image-optimiser
@@ -19,7 +19,7 @@ define('SHORTPIXEL_PLUGIN_DIR', __DIR__);
19
 
20
  //define('SHORTPIXEL_AFFILIATE_CODE', '');
21
 
22
- define('SHORTPIXEL_IMAGE_OPTIMISER_VERSION', "4.16.4");
23
  define('SHORTPIXEL_MAX_TIMEOUT', 10);
24
  define('SHORTPIXEL_VALIDATE_MAX_TIMEOUT', 15);
25
  define('SHORTPIXEL_BACKUP', 'ShortpixelBackups');
@@ -75,11 +75,13 @@ define("SHORTPIXEL_MAX_RESULTS_QUERY", 30);
75
  /* Function to reach core function of ShortPixel
76
  * Use to get plugin url, plugin path, or certain core controllers
77
  */
78
- function wpSPIO()
79
  {
80
- return \ShortPixel\ShortPixelPlugin::getInstance();
 
 
 
81
  }
82
-
83
  // [BS] Start runtime here
84
  require_once(SHORTPIXEL_PLUGIN_DIR . '/wp-shortpixel-req.php'); // @todo should be incorporated here.
85
  require_once(SHORTPIXEL_PLUGIN_DIR . '/class/controller/controller.php');
@@ -91,15 +93,17 @@ if (! defined('SHORTPIXEL_DEBUG'))
91
  {
92
  define('SHORTPIXEL_DEBUG', false);
93
  }
94
- $log = ShortPixel\ShortPixelLogger\ShortPixelLogger::getInstance();
95
- if (ShortPixel\ShortPixelLogger\ShortPixelLogger::debugIsActive())
96
  $log->setLogPath(SHORTPIXEL_BACKUP_FOLDER . "/shortpixel_log");
97
 
98
  // Pre-Runtime Checks
99
  // @todo Better solution for pre-runtime inclusions of externals.
100
  // Should not be required here. wpspio initruntime loads externals
101
 
102
- wpSPIO(); // let's go!
 
 
103
 
104
  register_activation_hook( __FILE__, array('\ShortPixel\ShortPixelPlugin','activatePlugin') );
105
  register_deactivation_hook( __FILE__, array('\ShortPixel\ShortPixelPlugin','deactivatePlugin') );
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.17.0
7
  * Author: ShortPixel
8
  * Author URI: https://shortpixel.com
9
  * Text Domain: shortpixel-image-optimiser
19
 
20
  //define('SHORTPIXEL_AFFILIATE_CODE', '');
21
 
22
+ define('SHORTPIXEL_IMAGE_OPTIMISER_VERSION', "4.17.0");
23
  define('SHORTPIXEL_MAX_TIMEOUT', 10);
24
  define('SHORTPIXEL_VALIDATE_MAX_TIMEOUT', 15);
25
  define('SHORTPIXEL_BACKUP', 'ShortpixelBackups');
75
  /* Function to reach core function of ShortPixel
76
  * Use to get plugin url, plugin path, or certain core controllers
77
  */
78
+ if (! function_exists('wpSPIO'))
79
  {
80
+ function wpSPIO()
81
+ {
82
+ return \ShortPixel\ShortPixelPlugin::getInstance();
83
+ }
84
  }
 
85
  // [BS] Start runtime here
86
  require_once(SHORTPIXEL_PLUGIN_DIR . '/wp-shortpixel-req.php'); // @todo should be incorporated here.
87
  require_once(SHORTPIXEL_PLUGIN_DIR . '/class/controller/controller.php');
93
  {
94
  define('SHORTPIXEL_DEBUG', false);
95
  }
96
+ $log = \ShortPixel\ShortPixelLogger\ShortPixelLogger::getInstance();
97
+ if (\ShortPixel\ShortPixelLogger\ShortPixelLogger::debugIsActive())
98
  $log->setLogPath(SHORTPIXEL_BACKUP_FOLDER . "/shortpixel_log");
99
 
100
  // Pre-Runtime Checks
101
  // @todo Better solution for pre-runtime inclusions of externals.
102
  // Should not be required here. wpspio initruntime loads externals
103
 
104
+ wpSPIO(); // let's go!
105
+
106
+
107
 
108
  register_activation_hook( __FILE__, array('\ShortPixel\ShortPixelPlugin','activatePlugin') );
109
  register_deactivation_hook( __FILE__, array('\ShortPixel\ShortPixelPlugin','deactivatePlugin') );