ShortPixel Image Optimizer - Version 4.16.0

Version Description

  • New - Token support for Cloudflare via config constant or settings.
  • Backup setting - add orange warning when backups are off.
  • Button to dismiss the top bar notification of missing files.
  • Shortpixel now loads scripts with 'defer' on front site, if it's configured to be loaded there.
  • Hiding Cloudflare details via wp-config.php.
  • Hide the option "Process in front-end" when "Optimize media on upload" is not checked.
  • Fixes for multibyte filenames with mixed locales.
  • Fixes for combination of S3-offload, webp pictures and cnames.
  • Reworked Notifications.
  • Fixed - PNG2JPG Retry button didn't work, now properly resets retry counter.
  • Fixed - Realpath in directory model throws off installations with symlinks.
  • Fixed - Thrown Exception in API with corrupted images now caught.
  • Fixed - Debug window link was visible when it should not.
  • Fixed - ExcludePattern without value would result in notices.
  • Language 7 new strings added, 0 updated, 0 fuzzied, and 0 obsoleted
Download this release

Release Info

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

Code changes from version 4.15.4 to 4.16.0

Files changed (45) hide show
  1. build/shortpixel/PackageLoader.php +5 -1
  2. build/shortpixel/log/src/ShortPixelLogger.php +22 -17
  3. build/shortpixel/notices/composer.json +1 -1
  4. build/shortpixel/notices/src/NoticeController.php +141 -12
  5. build/shortpixel/notices/src/NoticeModel.php +79 -6
  6. class/controller/adminnotices_controller.php +416 -0
  7. class/controller/front_controller.php +22 -2
  8. class/controller/settings.php +38 -64
  9. class/db/shortpixel-meta-facade.php +2 -2
  10. class/external/cloudflare.php +203 -0
  11. class/external/helpscout.php +0 -32
  12. class/external/wp-offload-media.php +87 -34
  13. class/front/img-to-picture-webp.php +152 -114
  14. class/model/apikey_model.php +6 -0
  15. class/model/directory_model.php +11 -7
  16. class/model/environment_model.php +6 -0
  17. class/model/file_model.php +47 -8
  18. class/shortpixel-png2jpg.php +3 -3
  19. class/shortpixel-tools.php +140 -1
  20. class/view/settings/part-cloudflare.php +63 -21
  21. class/view/settings/part-debug.php +2 -0
  22. class/view/settings/part-general.php +4 -0
  23. class/view/shortpixel_view.php +11 -3
  24. class/view/view-edit-media.php +1 -1
  25. class/view/view-settings.php +5 -2
  26. class/wp-short-pixel.php +130 -198
  27. class/wp-shortpixel-settings.php +7 -2
  28. readme.txt +23 -1
  29. res/css/short-pixel-bar.css +1 -29
  30. res/css/short-pixel-bar.min.css +1 -1
  31. res/css/short-pixel.css +1 -1
  32. res/css/short-pixel.min.css +1 -1
  33. res/css/shortpixel-admin.css +75 -71
  34. res/css/shortpixel-notices.css +26 -0
  35. res/js/debug.js +243 -0
  36. res/js/shortpixel.js +37 -5
  37. res/js/shortpixel.min.js +1 -1
  38. res/scss/shortpixel-admin.scss +1 -1
  39. res/scss/shortpixel-notices.scss +58 -0
  40. res/scss/view/_debug.scss +110 -0
  41. res/scss/view/_settings-cloudflare.scss +32 -0
  42. res/scss/view/_settings.scss +22 -0
  43. shortpixel-plugin.php +22 -5
  44. shortpixel_api.php +6 -1
  45. wp-shortpixel.php +2 -2
build/shortpixel/PackageLoader.php CHANGED
@@ -61,7 +61,11 @@ class PackageLoader
61
  if ($psr4) {
62
  $classname = str_replace($namespace, "", $classname);
63
  }
64
- $filename = preg_replace("#\\\\#", "", $classname).".php";
 
 
 
 
65
 
66
  foreach ($classpaths as $classpath) {
67
  $fullpath = trailingslashit($dir) . trailingslashit($classpath) .$filename;
61
  if ($psr4) {
62
  $classname = str_replace($namespace, "", $classname);
63
  }
64
+
65
+ // $filename = preg_replace("#\\\\#", "", $classname).".php";
66
+ // This is fix for nested classes which were losing a /
67
+ $filename = ltrim($classname .'.php', '\\');
68
+ $filename = str_replace('\\','/', $filename);
69
 
70
  foreach ($classpaths as $classpath) {
71
  $fullpath = trailingslashit($dir) . trailingslashit($classpath) .$filename;
build/shortpixel/log/src/ShortPixelLogger.php CHANGED
@@ -49,12 +49,6 @@ namespace ShortPixel\ShortPixelLogger;
49
  $ns = __NAMESPACE__;
50
  $this->namespace = substr($ns, 0, strpos($ns, '\\')); // try to get first part of namespace
51
 
52
- if ($this->logPath === false)
53
- {
54
- $upload_dir = wp_upload_dir(null,false,false);
55
- $this->logPath = $this->setLogPath($upload_dir['basedir'] . '/' . $this->namespace . ".log");
56
- }
57
-
58
  if (isset($_REQUEST['SHORTPIXEL_DEBUG'])) // manual takes precedence over constants
59
  {
60
  $this->is_manual_request = true;
@@ -134,26 +128,33 @@ namespace ShortPixel\ShortPixelLogger;
134
  {
135
  $this->logPath = $logPath;
136
  }
137
- protected static function addLog($message, $level, $data = array())
138
  {
139
- $log = self::getInstance();
140
 
141
- // don't log anything too low.
142
- if ($log->logLevel < $level)
143
  {
144
  return;
145
  }
146
 
 
 
 
 
 
 
 
147
  $arg = array();
148
  $args['level'] = $level;
149
  $args['data'] = $data;
150
 
151
  $newItem = new DebugItem($message, $args);
152
- $log->items[] = $newItem;
153
 
154
- if ($log->is_active)
155
  {
156
- $log->write($newItem);
157
  }
158
  }
159
 
@@ -227,22 +228,26 @@ namespace ShortPixel\ShortPixelLogger;
227
  public static function addError($message, $args = array())
228
  {
229
  $level = DebugItem::LEVEL_ERROR;
230
- static::addLog($message, $level, $args);
 
231
  }
232
  public static function addWarn($message, $args = array())
233
  {
234
  $level = DebugItem::LEVEL_WARN;
235
- static::addLog($message, $level, $args);
 
236
  }
237
  public static function addInfo($message, $args = array())
238
  {
239
  $level = DebugItem::LEVEL_INFO;
240
- static::addLog($message, $level, $args);
 
241
  }
242
  public static function addDebug($message, $args = array())
243
  {
244
  $level = DebugItem::LEVEL_DEBUG;
245
- static::addLog($message, $level, $args);
 
246
  }
247
 
248
  public static function logLevel($level)
49
  $ns = __NAMESPACE__;
50
  $this->namespace = substr($ns, 0, strpos($ns, '\\')); // try to get first part of namespace
51
 
 
 
 
 
 
 
52
  if (isset($_REQUEST['SHORTPIXEL_DEBUG'])) // manual takes precedence over constants
53
  {
54
  $this->is_manual_request = true;
128
  {
129
  $this->logPath = $logPath;
130
  }
131
+ protected function addLog($message, $level, $data = array())
132
  {
133
+ // $log = self::getInstance();
134
 
135
+ // don't log anything too low or when not active.
136
+ if ($this->logLevel < $level || ! $this->is_active)
137
  {
138
  return;
139
  }
140
 
141
+ // Check where to log to.
142
+ if ($this->logPath === false)
143
+ {
144
+ $upload_dir = wp_upload_dir(null,false,false);
145
+ $this->logPath = $this->setLogPath($upload_dir['basedir'] . '/' . $this->namespace . ".log");
146
+ }
147
+
148
  $arg = array();
149
  $args['level'] = $level;
150
  $args['data'] = $data;
151
 
152
  $newItem = new DebugItem($message, $args);
153
+ $this->items[] = $newItem;
154
 
155
+ if ($this->is_active)
156
  {
157
+ $this->write($newItem);
158
  }
159
  }
160
 
228
  public static function addError($message, $args = array())
229
  {
230
  $level = DebugItem::LEVEL_ERROR;
231
+ $log = self::getInstance();
232
+ $log->addLog($message, $level, $args);
233
  }
234
  public static function addWarn($message, $args = array())
235
  {
236
  $level = DebugItem::LEVEL_WARN;
237
+ $log = self::getInstance();
238
+ $log->addLog($message, $level, $args);
239
  }
240
  public static function addInfo($message, $args = array())
241
  {
242
  $level = DebugItem::LEVEL_INFO;
243
+ $log = self::getInstance();
244
+ $log->addLog($message, $level, $args);
245
  }
246
  public static function addDebug($message, $args = array())
247
  {
248
  $level = DebugItem::LEVEL_DEBUG;
249
+ $log = self::getInstance();
250
+ $log->addLog($message, $level, $args);
251
  }
252
 
253
  public static function logLevel($level)
build/shortpixel/notices/composer.json CHANGED
@@ -1,7 +1,7 @@
1
  {
2
  "name": "shortpixel/notices",
3
  "description": "ShortPixel WordPress Notice System",
4
- "version": "1.2",
5
  "type": "library",
6
  "license": "MIT",
7
  "authors": [
1
  {
2
  "name": "shortpixel/notices",
3
  "description": "ShortPixel WordPress Notice System",
4
+ "version": "1.3",
5
  "type": "library",
6
  "license": "MIT",
7
  "authors": [
build/shortpixel/notices/src/NoticeController.php CHANGED
@@ -8,6 +8,8 @@ class NoticeController //extends ShortPixelController
8
  protected static $instance = null;
9
  protected static $cssHookLoaded = false; // prevent css output more than once.
10
 
 
 
11
  public $notice_count = 0;
12
 
13
  protected $has_stored = false;
@@ -22,16 +24,29 @@ class NoticeController //extends ShortPixelController
22
  $ns = substr($ns, 0, strpos($ns, '\\')); // try to get first part of namespace
23
  $this->notice_option = $ns . '-notices';
24
 
 
 
25
  $this->loadNotices();
26
  //$this->loadConfig();
27
  }
28
 
 
 
 
 
 
 
 
 
 
 
29
  /** Load Notices Config File, if any
30
  *
31
  * [ Future Use ]
32
  */
33
  public function loadConfig()
34
  {
 
35
  if (file_exists('../notice_config.json'))
36
  {
37
  $config = file_get_contents('../notice_config.json');
@@ -50,8 +65,10 @@ class NoticeController //extends ShortPixelController
50
  {
51
  $notices = get_option($this->notice_option, false);
52
  $cnotice = (is_array($notices)) ? count($notices) : 0;
53
- Log::addDebug('Notice Control - #num notices' . $cnotice);
54
- if ($notices !== false)
 
 
55
  {
56
  self::$notices = $notices;
57
  $this->has_stored = true;
@@ -64,7 +81,7 @@ class NoticeController //extends ShortPixelController
64
  }
65
 
66
 
67
- public function addNotice($message, $code, $unique)
68
  {
69
  $notice = new NoticeModel($message, $code);
70
 
@@ -73,7 +90,7 @@ class NoticeController //extends ShortPixelController
73
  foreach(self::$notices as $nitem)
74
  {
75
  if ($nitem->message == $notice->message && $nitem->code == $notice->code) // same message.
76
- return false;
77
  }
78
  }
79
  self::$notices[] = $notice;
@@ -118,17 +135,97 @@ class NoticeController //extends ShortPixelController
118
 
119
  public function getNotices()
120
  {
121
- return self::$notices;
122
  }
123
 
124
- public static function getInstance()
125
  {
126
- if ( self::$instance === null)
127
- {
128
- self::$instance = new NoticeController();
129
- }
 
130
 
131
- return self::$instance;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
132
  }
133
 
134
  /** Adds a notice, quick and fast method
@@ -170,6 +267,37 @@ class NoticeController //extends ShortPixelController
170
 
171
  }
172
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
173
  public function admin_notices()
174
  {
175
  if ($this->countNotices() > 0)
@@ -179,7 +307,7 @@ class NoticeController //extends ShortPixelController
179
  add_action('admin_print_footer_scripts', array($this, 'printNoticeStyle'));
180
  self::$cssHookLoaded = true;
181
  }
182
- foreach($this->getNotices() as $notice)
183
  {
184
  echo $notice->getForDisplay();
185
  }
@@ -187,6 +315,7 @@ class NoticeController //extends ShortPixelController
187
  $this->update(); // puts views, and updates
188
  }
189
 
 
190
  public function printNoticeStyle()
191
  {
192
  if (file_exists(__DIR__ . '/css/notices.css'))
8
  protected static $instance = null;
9
  protected static $cssHookLoaded = false; // prevent css output more than once.
10
 
11
+ protected $notice_displayed = array();
12
+
13
  public $notice_count = 0;
14
 
15
  protected $has_stored = false;
24
  $ns = substr($ns, 0, strpos($ns, '\\')); // try to get first part of namespace
25
  $this->notice_option = $ns . '-notices';
26
 
27
+ add_action('wp_ajax_' . $this->notice_option, array($this, 'ajax_action'));
28
+
29
  $this->loadNotices();
30
  //$this->loadConfig();
31
  }
32
 
33
+ public static function getInstance()
34
+ {
35
+ if ( self::$instance === null)
36
+ {
37
+ self::$instance = new NoticeController();
38
+ }
39
+
40
+ return self::$instance;
41
+ }
42
+
43
  /** Load Notices Config File, if any
44
  *
45
  * [ Future Use ]
46
  */
47
  public function loadConfig()
48
  {
49
+ return;
50
  if (file_exists('../notice_config.json'))
51
  {
52
  $config = file_get_contents('../notice_config.json');
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
  {
73
  self::$notices = $notices;
74
  $this->has_stored = true;
81
  }
82
 
83
 
84
+ protected function addNotice($message, $code, $unique)
85
  {
86
  $notice = new NoticeModel($message, $code);
87
 
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;
135
 
136
  public function getNotices()
137
  {
138
+ return self::$notices;
139
  }
140
 
141
+ public function getNoticesForDisplay()
142
  {
143
+ $newNotices = array();
144
+ foreach(self::$notices as $notice)
145
+ {
146
+ if ($notice->isDismissed()) // dismissed never displays.
147
+ continue;
148
 
149
+ if ($notice->isPersistent())
150
+ {
151
+ $id = $notice->getID();
152
+ if (! is_null($id) && ! in_array($id, $this->notice_displayed))
153
+ {
154
+ $notice->notice_action = $this->notice_option;
155
+ $newNotices[] = $notice;
156
+ $this->notice_displayed[] = $id;
157
+ }
158
+
159
+ }
160
+ else
161
+ $newNotices[] = $notice;
162
+
163
+
164
+ }
165
+ return $newNotices;
166
+ }
167
+
168
+
169
+ public function getNoticeByID($id)
170
+ {
171
+ foreach(self::$notices as $notice)
172
+ {
173
+ if ($notice->getID() == $id)
174
+ return $notice;
175
+ }
176
+
177
+ return false;
178
+ }
179
+
180
+ public static function removeNoticeByID($id)
181
+ {
182
+ $noticeController = self::getInstance();
183
+
184
+ for($i = 0; $i < count(self::$notices); $i++)
185
+ {
186
+ $item = self::$notices[$i];
187
+ if ($item->getID() == $id)
188
+ {
189
+ Log::addDebug('Removing notice with ID ' . $id);
190
+ unset(self::$notices[$i]);
191
+ }
192
+ //if ($notice_item )
193
+ }
194
+ $noticeController->update();
195
+ }
196
+
197
+ public function ajax_action()
198
+ {
199
+ $response = array('result' => false, 'reason' => '');
200
+
201
+ if ( wp_verify_nonce( $_POST['nonce'], 'dismiss') )
202
+ {
203
+ if ($_POST['plugin_action'] == 'dismiss')
204
+ {
205
+ $id = sanitize_text_field($_POST['id']);
206
+ $notice = $this->getNoticeByID($id);
207
+
208
+ if($notice)
209
+ {
210
+ $notice->dismiss();
211
+ $this->update();
212
+ $response['result'] = true;
213
+ }
214
+ else
215
+ {
216
+ Log::addError('Notice not found when dismissing -> ' . $id, self::$notices);
217
+ $response['result'] = ' Notice ' . $id . ' not found. ';
218
+ }
219
+
220
+ }
221
+
222
+ }
223
+ else
224
+ {
225
+ Log::addError('Wrong Nonce when dismissed notice. ');
226
+ $response['reason'] = 'wrong nonce';
227
+ }
228
+ wp_send_json($response);
229
  }
230
 
231
  /** Adds a notice, quick and fast method
267
 
268
  }
269
 
270
+ public static function makePersistent($notice, $key, $suppress = -1)
271
+ {
272
+ $noticeController = self::getInstance();
273
+ $existing = $noticeController->getNoticeByID($key);
274
+
275
+ // if this key already exists, don't allow the new notice to be entered into the array. Remove it since it's already created.
276
+ if ($existing)
277
+ {
278
+ for($i = 0; $i < count(self::$notices); $i++)
279
+ {
280
+ $item = self::$notices[$i];
281
+
282
+ if ($item->message == $notice->message && $item->getID() == null)
283
+ {
284
+ if ($item->message != $existing->message) // allow the persistent message to be updated, if something else is served on this ID
285
+ {
286
+ $existing->message = $item->message;
287
+ }
288
+ unset(self::$notices[$i]);
289
+ }
290
+ //if ($notice_item )
291
+ }
292
+ }
293
+ else
294
+ {
295
+ $notice->setPersistent($key, $suppress); // set this notice persistent.
296
+ }
297
+
298
+ $noticeController->update();
299
+ }
300
+
301
  public function admin_notices()
302
  {
303
  if ($this->countNotices() > 0)
307
  add_action('admin_print_footer_scripts', array($this, 'printNoticeStyle'));
308
  self::$cssHookLoaded = true;
309
  }
310
+ foreach($this->getNoticesForDisplay() as $notice)
311
  {
312
  echo $notice->getForDisplay();
313
  }
315
  $this->update(); // puts views, and updates
316
  }
317
 
318
+
319
  public function printNoticeStyle()
320
  {
321
  if (file_exists(__DIR__ . '/css/notices.css'))
build/shortpixel/notices/src/NoticeModel.php CHANGED
@@ -3,14 +3,20 @@ namespace ShortPixel\Notices;
3
 
4
  class NoticeModel //extends ShortPixelModel
5
  {
6
- public $message;
7
  public $code;
8
 
9
- protected $viewed = false;
10
- public $is_persistent = false; // This is a fatal issue, display until something was fixed.
 
 
 
 
11
  public $is_removable = true; // if removable, display a notice dialog with red X or so.
12
  public $messageType = self::NOTICE_NORMAL;
13
 
 
 
14
  public static $icons = array();
15
 
16
  const NOTICE_NORMAL = 1;
@@ -18,7 +24,7 @@ class NoticeModel //extends ShortPixelModel
18
  const NOTICE_SUCCESS = 3;
19
  const NOTICE_WARNING = 4;
20
 
21
-
22
  public function __construct($message, $messageType = self::NOTICE_NORMAL)
23
  {
24
  $this->message = $message;
@@ -28,11 +34,53 @@ class NoticeModel //extends ShortPixelModel
28
 
29
  public function isDone()
30
  {
 
 
 
 
 
 
 
 
 
 
 
31
  if ($this->viewed && ! $this->is_persistent)
32
  return true;
33
  else
34
  return false;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
  }
37
 
38
  public static function setIcon($notice_type, $icon)
@@ -96,12 +144,37 @@ class NoticeModel //extends ShortPixelModel
96
 
97
  if ($this->is_persistent)
98
  {
99
- $class .= '';
100
  }
101
 
102
- return "<div class='$class'>" . $icon . "<p>" . $this->message . "</p></div>";
 
 
 
 
 
 
 
103
 
104
  }
105
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
106
 
107
  }
3
 
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.
10
+ protected $viewed = false; // was this notice viewed?
11
+ protected $is_persistent = false; // This is a fatal issue, display until something was fixed.
12
+ protected $is_dismissed = false; // for persistent notices,
13
+ protected $suppress_until = null;
14
+ protected $suppress_period = -1;
15
  public $is_removable = true; // if removable, display a notice dialog with red X or so.
16
  public $messageType = self::NOTICE_NORMAL;
17
 
18
+ public $notice_action; // empty unless for display. Ajax action to talk back to controller.
19
+
20
  public static $icons = array();
21
 
22
  const NOTICE_NORMAL = 1;
24
  const NOTICE_SUCCESS = 3;
25
  const NOTICE_WARNING = 4;
26
 
27
+ /** Use this model in conjunction with NoticeController, do not call directly */
28
  public function __construct($message, $messageType = self::NOTICE_NORMAL)
29
  {
30
  $this->message = $message;
34
 
35
  public function isDone()
36
  {
37
+ // check suppressed
38
+ if ($this->is_dismissed && ! is_null($this->suppress_until))
39
+ {
40
+ if (time() >= $this->suppress_until)
41
+ {
42
+ //Log::addDebug('')
43
+ $this->is_persistent = false; // unpersist, so it will be cleaned and dropped.
44
+
45
+ }
46
+ }
47
+
48
  if ($this->viewed && ! $this->is_persistent)
49
  return true;
50
  else
51
  return false;
52
+ }
53
+
54
+ public function getID()
55
+ {
56
+ return $this->id;
57
+ }
58
+
59
+ public function isPersistent()
60
+ {
61
+ return $this->is_persistent;
62
+ }
63
+
64
+ public function isDismissed()
65
+ {
66
+ return $this->is_dismissed;
67
+ }
68
 
69
+ public function dismiss()
70
+ {
71
+ $this->is_dismissed = true;
72
+ $this->suppress_until = time() + $this->suppress_period;
73
+ }
74
+
75
+ /** Set a notice persistent. Meaning it shows every page load until dismissed.
76
+ * @param $key Unique Key of this message. Required
77
+ * @param $suppress When dismissed do not show this message again for X amount of time. When -1 it will just be dropped from the Notices and not suppressed
78
+ */
79
+ public function setPersistent($key, $suppress = -1)
80
+ {
81
+ $this->id = $key;
82
+ $this->is_persistent = true;
83
+ $this->suppress_period = $suppress;
84
  }
85
 
86
  public static function setIcon($notice_type, $icon)
144
 
145
  if ($this->is_persistent)
146
  {
147
+ $class .= 'is-persistent ';
148
  }
149
 
150
+ $id = ! is_null($this->id) ? 'id="' . $this->id . '"' : '';
151
+
152
+ $output = "<div $id class='$class'><span class='icon'> " . $icon . "</span> <span class='content'>" . $this->message . "</span></div>";
153
+ if ($this->is_persistent && $this->is_removable)
154
+ {
155
+ $output .= "<script type='text/javascript'>\n" . $this->getDismissJS() . "\n</script>";
156
+ }
157
+ return $output;
158
 
159
  }
160
 
161
+ private function getDismissJS()
162
+ {
163
+ $url = wp_json_encode(admin_url('admin-ajax.php'));
164
+ // $action = 'dismiss';
165
+ $nonce = wp_create_nonce('dismiss');
166
+
167
+ $data = wp_json_encode(array('action' => $this->notice_action, 'plugin_action' => 'dismiss', 'nonce' => $nonce, 'id' => $this->id, 'time' => $this->suppress_period));
168
+
169
+ // $data_string = "{action:'$this->notice_action'}";
170
+
171
+ $js = "jQuery(document).on('click','#$this->id button',
172
+ function() {
173
+ var data = $data;
174
+ var url = $url;
175
+ jQuery.post(url, data); }
176
+ );";
177
+ return "\n jQuery(document).ready(function(){ \n" . $js . "\n});";
178
+ }
179
 
180
  }
class/controller/adminnotices_controller.php ADDED
@@ -0,0 +1,416 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace ShortPixel;
3
+ use ShortPixel\Notices\NoticeController as Notices;
4
+ use ShortPixel\ShortpixelLogger\ShortPixelLogger as Log;
5
+
6
+
7
+ /* Controller for automatic Notices about status of the plugin.
8
+ * This controller is bound for automatic fire. Regular procedural notices should just be queued using the Notices modules.
9
+ * Called in admin_notices.
10
+ */
11
+
12
+ class adminNoticesController extends ShortPixelController
13
+ {
14
+ protected static $instance;
15
+
16
+ const MSG_COMPAT = 'Error100'; // Plugin Compatility, warn for the ones that disturb functions.
17
+ const MSG_FILEPERMS = 'Error101'; // File Permission check, if Queue is file-based.
18
+ const MSG_UNLISTED_FOUND = 'Error102'; // SPIO found unlisted images, but this setting is not on
19
+
20
+ //const MSG_NO_
21
+ const MSG_UPGRADE_MONTH = 'UpgradeNotice200'; // When processing more than the subscription allows on average..
22
+ const MSG_UPGRADE_BULK = 'UpgradeNotice201'; // when there is no enough for a bulk run.
23
+
24
+ const MSG_NO_APIKEY = 'ApiNotice300'; // API Key not found
25
+ const MSG_NO_APIKEY_REPEAT = 'ApiNotice301'; // First Repeat.
26
+ const MSG_NO_APIKEY_REPEAT_LONG = 'ApiNotice302'; // Last Repeat.
27
+
28
+ public function __construct()
29
+ {
30
+ add_action('admin_notices', array($this, 'check_admin_notices'), 5); // run before the plugin admin notices
31
+ }
32
+
33
+ public static function getInstance()
34
+ {
35
+ if (is_null(self::$instance))
36
+ self::$instance = new adminNoticesController();
37
+
38
+ return self::$instance;
39
+ }
40
+
41
+ /** Triggered when plugin is activated */
42
+ public static function resetCompatNotice()
43
+ {
44
+ Notices::removeNoticeByID(self::MSG_COMPAT);
45
+ }
46
+
47
+ public static function resetAPINotices()
48
+ {
49
+ Notices::removeNoticeByID(self::MSG_NO_APIKEY);
50
+ Notices::removeNoticeByID(self::MSG_NO_APIKEY_REPEAT);
51
+ Notices::removeNoticeByID(self::MSG_NO_APIKEY_REPEAT_LONG);
52
+ }
53
+
54
+ public static function resetQuotaNotices()
55
+ {
56
+ Notices::removeNoticeByID(self::MSG_UPGRADE_MONTH);
57
+ Notices::removeNoticeByID(self::MSG_UPGRADE_BULK);
58
+ }
59
+
60
+ /* General function to check on Hook for admin notices if there is something to show globally */
61
+ public function check_admin_notices()
62
+ {
63
+ $this->doFilePermNotice();
64
+ $this->doAPINotices();
65
+ $this->doCompatNotices();
66
+ $this->doUnlistedNotices();
67
+ $this->doQuotaNotices();
68
+ }
69
+
70
+ /** Load the various messages about the lack of API-keys in the plugin */
71
+ protected function doAPINotices()
72
+ {
73
+ if (\wpSPIO()->settings()->verifiedKey)
74
+ {
75
+ return; // all fine.
76
+ }
77
+
78
+ $activationDate = \wpSPIO()->settings()->activationDate;
79
+ $noticeController = Notices::getInstance();
80
+ $now = time();
81
+
82
+ if (! $activationDate)
83
+ {
84
+ $activationDate = $now;
85
+ \wpSPIO()->settings()->activationDate = $activationDate;
86
+ }
87
+
88
+ $notice = $noticeController->getNoticeByID(self::MSG_NO_APIKEY);
89
+ $notice_repeat = $noticeController->getNoticeByID(self::MSG_NO_APIKEY_REPEAT);
90
+ $notice_long = $noticeController->getNoticeByID(self::MSG_NO_APIKEY_REPEAT_LONG);
91
+
92
+ $notice_dismissed = ($notice && $notice->isDismissed()) ? true : false;
93
+ $notice_dismissed_repeat = ($notice_repeat && $notice_repeat->isDismissed()) ? true : false;
94
+ $notice_dismissed_long = ($notice_long && $notice_long->isDismissed()) ? true : false;
95
+
96
+ if (! $notice)
97
+ {
98
+ // If no key is activated, load the general one.
99
+ $message = $this->getActivationNotice();
100
+ $notice = Notices::addNormal($message);
101
+ Notices::makePersistent($notice, self::MSG_NO_APIKEY, YEAR_IN_SECONDS);
102
+ }
103
+
104
+ // The trick is that after X amount of time, the first message is replaced by one of those.
105
+ if ($notice_dismissed && ! $notice_dismissed_repeat && $now > $activationDate + (6 * HOUR_IN_SECONDS)) // after 6 hours.
106
+ {
107
+ //$notice->messageType = Notices::NOTICE_WARNING;
108
+ // $notice->
109
+ //Notices::removeNoticeByID(self::MSG_NO_APIKEY); // remove the previous one.
110
+ $message = __("Action needed. Please <a href='https://shortpixel.com/wp-apikey' target='_blank'>get your API key</a> to activate your ShortPixel plugin.",'shortpixel-image-optimiser');
111
+
112
+ $notice = Notices::addWarning($message);
113
+ Notices::makePersistent($notice, self::MSG_NO_APIKEY_REPEAT, YEAR_IN_SECONDS);
114
+ }
115
+ elseif ($notice_dismissed_repeat && $notice_dismissed && ! $notice_dismissed_long && $now > $activationDate + (3 * DAY_IN_SECONDS) ) // after 3 days
116
+ {
117
+ // Notices::removeNoticeByID(self::MSG_NO_APIKEY); // remove the previous one.
118
+ $message = __("Your image gallery is not optimized. It takes 2 minutes to <a href='https://shortpixel.com/wp-apikey' target='_blank'>get your API key</a> and activate your ShortPixel plugin.",'shortpixel-image-optimiser') . "<BR><BR>";
119
+
120
+ $notice = Notices::addWarning($message);
121
+ Notices::makePersistent($notice, self::MSG_NO_APIKEY_REPEAT_LONG, YEAR_IN_SECONDS);
122
+
123
+ }
124
+
125
+ }
126
+
127
+ protected function doFilePermNotice()
128
+ {
129
+ $testQ = (! defined('SHORTPIXEL_NOFLOCK')) ? \ShortPixelQueue::testQ() : \ShortPixelQueueDB::testQ();
130
+
131
+ if( $testQ) {
132
+ return; // all fine.
133
+ }
134
+
135
+ // Keep this thing out of others screens.
136
+ if (! \wpSPIO()->env()->is_our_screen)
137
+ return;
138
+
139
+ $message = sprintf(__("ShortPixel is not able to write to the uploads folder so it cannot optimize images, please check permissions (tried to create the file %s/.shortpixel-q-1).",'shortpixel-image-optimiser'),
140
+ SHORTPIXEL_UPLOADS_BASE);
141
+ Notices::addError($message, true);
142
+
143
+ }
144
+
145
+ protected function doCompatNotices()
146
+ {
147
+ $noticeController = Notices::getInstance();
148
+
149
+ $notice = $noticeController->getNoticeByID(self::MSG_COMPAT);
150
+ $conflictPlugins = \ShortPixelTools::getConflictingPlugins();
151
+
152
+ if ($notice)
153
+ {
154
+ if (count($conflictPlugins) == 0)
155
+ Notices::removeNoticeByID(self::MSG_COMPAT); // remove when not actual anymore.
156
+ if ($notice->isDismissed() )
157
+ return; // notice not wanted, don't bother.
158
+ }
159
+
160
+ // If this notice is not already out there, and there are conflicting plugins, go for display.
161
+ if (count($conflictPlugins) > 0)
162
+ {
163
+ // var_dump($this->getConflictMessage($conflictPlugins));
164
+ $notice = Notices::addWarning($this->getConflictMessage($conflictPlugins));
165
+ Notices::makePersistent($notice, self::MSG_COMPAT, YEAR_IN_SECONDS);
166
+ }
167
+ }
168
+
169
+ protected function doUnlistedNotices()
170
+ {
171
+ $settings = \wpSPIO()->settings();
172
+ if ($settings->optimizeUnlisted)
173
+ return;
174
+
175
+ if(isset($settings->currentStats['foundUnlistedThumbs']) && is_array($settings->currentStats['foundUnlistedThumbs'])) {
176
+ $notice = Notices::addNormal($this->getUnlistedMessage($settings->currentStats['foundUnlistedThumbs']));
177
+ Notices::makePersistent($notice, self::MSG_UNLISTED_FOUND, YEAR_IN_SECONDS);
178
+ }
179
+ }
180
+
181
+ protected function doQuotaNotices()
182
+ {
183
+ $settings = \wpSPIO()->settings();
184
+ $currentStats = $settings->currentStats;
185
+ $shortpixel = \wpSPIO()->getShortPixel();
186
+
187
+ if (! \wpSPIO()->settings()->verifiedKey)
188
+ {
189
+ return; // no key, no quota.
190
+ }
191
+
192
+ if(!is_array($currentStats) || isset($_GET['checkquota']) || isset($currentStats["quotaData"])) {
193
+ $shortpixel->getQuotaInformation();
194
+ }
195
+
196
+ /** Comment for historical reasons, this seems strange in the original, excluding.
197
+ * isset($this->_settings->currentStats['optimizePdfs'])
198
+ * && $this->_settings->currentStats['optimizePdfs'] == $this->_settings->optimizePdfs )
199
+ */
200
+ if(!$settings->quotaExceeded)
201
+ {
202
+ // $screen = get_current_screen();
203
+ $env = \wpSPIO()->env();
204
+ $stats = $shortpixel->countAllIfNeeded($settings->currentStats, 86400);
205
+ $quotaData = $stats;
206
+ $noticeController = Notices::getInstance();
207
+
208
+ $bulk_notice = $noticeController->getNoticeByID(self::MSG_UPGRADE_BULK);
209
+ $bulk_is_dismissed = ($bulk_notice && $bulk_notice->isDismissed() ) ? true : false;
210
+
211
+ $month_notice = $noticeController->getNoticeByID(self::MSG_UPGRADE_MONTH);
212
+
213
+ //this is for bulk page - alert on the total credits for total images
214
+ if( ! $bulk_is_dismissed && $env->is_bulk_page && $this->bulkUpgradeNeeded($stats)) {
215
+ //looks like the user hasn't got enough credits to bulk process all media library
216
+ $message = $this->getBulkUpgradeMessage(array('filesTodo' => $stats['totalFiles'] - $stats['totalProcessedFiles'],
217
+ 'quotaAvailable' => max(0, $quotaData['APICallsQuotaNumeric'] + $quotaData['APICallsQuotaOneTimeNumeric'] - $quotaData['APICallsMadeNumeric'] - $quotaData['APICallsMadeOneTimeNumeric'])));
218
+ $notice = Notices::addNormal($message);
219
+ Notices::makePersistent($notice, self::MSG_UPGRADE_BULK, YEAR_IN_SECONDS);
220
+ //ShortPixelView::displayActivationNotice('upgbulk', );
221
+ }
222
+ //consider the monthly plus 1/6 of the available one-time credits.
223
+ elseif( $this->monthlyUpgradeNeeded($stats)) {
224
+ //looks like the user hasn't got enough credits to process the monthly images, display a notice telling this
225
+ $message = $this->getMonthlyUpgradeMessage(array('monthAvg' => $this->getMonthAvg($stats), 'monthlyQuota' => $quotaData['APICallsQuotaNumeric']));
226
+ //ShortPixelView::displayActivationNotice('upgmonth', );
227
+ $notice = Notices::addNormal($message);
228
+ Notices::makePersistent($notice, self::MSG_UPGRADE_MONTH, YEAR_IN_SECONDS);
229
+ }
230
+ }
231
+ elseif ($settings->quotaExceeded && \wpSPIO()->env()->is_screen_to_use)
232
+ {
233
+ $stats = $shortpixel->countAllIfNeeded($settings->currentStats, 86400);
234
+ $quotaData = $stats;
235
+
236
+ $message = $this->getQuotaExceededMessage($quotaData);
237
+ $notice = Notices::addError($message);
238
+ }
239
+
240
+ }
241
+
242
+ protected function getActivationNotice()
243
+ {
244
+ $message = "<p>" . __('In order to start the optimization process, you need to validate your API Key in the '
245
+ . '<a href="options-general.php?page=wp-shortpixel-settings">ShortPixel Settings</a> page in your WordPress Admin.','shortpixel-image-optimiser') . "
246
+ </p>
247
+ <p>" . __('If you don’t have an API Key, you can get one delivered to your inbox, for free.','shortpixel-image-optimiser') . "</p>
248
+ <p>" . __('Please <a href="https://shortpixel.com/wp-apikey" target="_blank">sign up to get your API key.</a>','shortpixel-image-optimiser') . "</p>";
249
+
250
+ return $message;
251
+ }
252
+
253
+ protected function getConflictMessage($conflicts)
254
+ {
255
+ $message = __("The following plugins are not compatible with ShortPixel and may lead to unexpected results: ",'shortpixel-image-optimiser');
256
+ $message .= '<ul class="sp-conflict-plugins">';
257
+ foreach($conflicts as $plugin) {
258
+ //ShortPixelVDD($plugin);
259
+ $action = $plugin['action'];
260
+ $link = ( $action == 'Deactivate' )
261
+ ? wp_nonce_url( admin_url( 'admin-post.php?action=shortpixel_deactivate_plugin&plugin=' . urlencode( $plugin['path'] ) ), 'sp_deactivate_plugin_nonce' )
262
+ : $plugin['href'];
263
+ $message .= '<li class="sp-conflict-plugins-list"><strong>' . $plugin['name'] . '</strong>';
264
+ $message .= '<a href="' . $link . '" class="button button-primary">' . __( $action, 'shortpixel_image_optimiser' ) . '</a>';
265
+
266
+ if($plugin['details']) $message .= '<br>';
267
+ if($plugin['details']) $message .= '<span>' . $plugin['details'] . '</span>';
268
+ }
269
+ $message .= "</ul>";
270
+
271
+ return $message;
272
+ }
273
+
274
+ protected function getUnlistedMessage($unlisted)
275
+ {
276
+ $message = __("<p>ShortPixel found thumbnails which are not registered in the metadata but present alongside the other thumbnails. These thumbnails could be created and needed by some plugin or by the theme. Let ShortPixel optimize them as well?</p>", 'shortpixel-image-optimiser');
277
+ $message .= '<p>' . __("For example, the image", 'shortpixel-image-optimiser') . '
278
+ <a href="post.php?post=' . $unlisted->id . '&action=edit" target="_blank">
279
+ ' . $unlisted->name . '
280
+ </a> has also these thumbs not listed in metadata: ' . (implode(', ', $unlisted->unlisted)) . '
281
+ </p>';
282
+
283
+ return $message;
284
+ }
285
+
286
+ protected function getBulkUpgradeMessage($extra)
287
+ {
288
+ $message = '<p>' . sprintf(__("You currently have <strong>%d images and thumbnails to optimize</strong> but you only have <strong>%d images</strong> available in your current plan."
289
+ . " You might need to upgrade your plan in order to have all your images optimized.", 'shortpixel-image-optimiser'), $extra['filesTodo'], $extra['quotaAvailable']) . '</p>';
290
+ $message .= $this->proposeUpgradePopup();
291
+ //self::includeProposeUpgradePopup();
292
+ return $message;
293
+ }
294
+
295
+ protected function getMonthlyUpgradeMessage($extra)
296
+ {
297
+ $message = '<p>' . sprintf(__("You are adding an average of <strong>%d images and thumbnails every month</strong> to your Media Library and you have <strong>a plan of %d images/month</strong>."
298
+ . " You might need to upgrade your plan in order to have all your images optimized.", 'shortpixel-image-optimiser'), $extra['monthAvg'], $extra['monthlyQuota']) . '</p>';
299
+ $message .= $this->proposeUpgradePopup();
300
+ return $message;
301
+ }
302
+
303
+ protected function getQuotaExceededMessage($quotaData)
304
+ {
305
+ $averageCompression = \wpSPIO()->getShortPixel()->getAverageCompression();
306
+ $recheck = isset($_GET['checkquota']) ? true : false;
307
+ \wpSPIO()->loadModel('apikey');
308
+
309
+ $keyModel = new apiKeyModel();
310
+ $keyModel->loadKey();
311
+
312
+
313
+ $login_url = 'https://shortpixel.com/login/';
314
+ $friend_url = $login_url;
315
+ if (! $keyModel->is_hidden())
316
+ {
317
+ $login_url .= $keyModel->getkey() . '/';
318
+ $friend_url = $login_url . 'tellafriend';
319
+ }
320
+
321
+ $message = '<div class="wrap sp-quota-exceeded-alert" id="short-pixel-notice-exceed">';
322
+
323
+ if($averageCompression) {
324
+
325
+ $message .= '<div style="float:right; margin-top: 10px">
326
+ <div class="bulk-progress-indicator" style="height: 110px">
327
+ <div style="margin-bottom:5px">' . __('Average image<br>reduction so far:','shortpixel-image-optimiser') . '</div>
328
+ <div id="sp-avg-optimization"><input type="text" id="sp-avg-optimization-dial" value="' . round($averageCompression) . '" class="dial"></div>
329
+ <script>
330
+ jQuery(function() {
331
+ ShortPixel.percentDial("#sp-avg-optimization-dial", 60);
332
+ });
333
+ </script>
334
+ </div>
335
+ </div>';
336
+
337
+ }
338
+
339
+ /* <img src="<?php echo(wpSPIO()->plugin_url('res/img/robo-scared.png'));?>"
340
+ srcset='<?php echo(wpSPIO()->plugin_url('res/img/robo-scared.png' ));?> 1x, <?php echo(wpSPIO()->plugin_url('res/img/robo-scared@2x.png' ));?> 2x'
341
+ class='short-pixel-notice-icon'> */
342
+
343
+ $message .= '<h3>' . __('Quota Exceeded','shortpixel-image-optimiser') . '</h3>';
344
+
345
+ if($recheck) {
346
+ $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>';
347
+ }
348
+
349
+ $message .= '<p>' . sprintf(__('The plugin has optimized <strong>%s images</strong> and stopped because it reached the available quota limit.','shortpixel-image-optimiser'),
350
+ number_format(max(0, $quotaData['APICallsMadeNumeric'] + $quotaData['APICallsMadeOneTimeNumeric'])));
351
+
352
+ if($quotaData['totalProcessedFiles'] < $quotaData['totalFiles']) {
353
+
354
+ $message .= sprintf(__('<strong> %s images and %s thumbnails</strong> are not yet optimized by ShortPixel.','shortpixel-image-optimiser'),
355
+ number_format(max(0, $quotaData['mainFiles'] - $quotaData['mainProcessedFiles'])),
356
+ number_format(max(0, ($quotaData['totalFiles'] - $quotaData['mainFiles']) - ($quotaData['totalProcessedFiles'] - $quotaData['mainProcessedFiles']))));
357
+ }
358
+
359
+ $message .= '</p>
360
+ <div>
361
+ <button class="button button-primary" id="shortpixel-upgrade-advice" onclick="ShortPixel.proposeUpgrade()" style="margin-right:10px;"><strong>' . __('Show me the best available options', 'shortpixel-image-optimiser') . '</strong></button>
362
+ <a class="button button-primary" href="' . $login_url . '"
363
+ title="' . __('Go to my account and select a plan','shortpixel-image-optimiser') . '" target="_blank" style="margin-right:10px;">
364
+ <strong>' . __('Upgrade','shortpixel-image-optimiser') . '</strong>
365
+ </a>
366
+ <input type="button" name="checkQuota" class="button" value="'. __('Confirm New Credits','shortpixel-image-optimiser') . '"
367
+ onclick="ShortPixel.recheckQuota()">
368
+ </div>';
369
+
370
+ $message .= '<p>' . __('Get more image credits by referring ShortPixel to your friends!','shortpixel-image-optimiser') . '
371
+ <a href="' . $friend_url . '" target="_blank">' . __('Check your account','shortpixel-image-optimiser') .
372
+ '</a> ' . __('for your unique referral link. For each user that joins, you will receive +100 additional image credits/month.','shortpixel-image-optimiser') . '
373
+ </p>
374
+ </div>';
375
+
376
+ $message .= $this->proposeUpgradePopup();
377
+ return $message;
378
+ }
379
+
380
+ protected function proposeUpgradePopup() {
381
+ wp_enqueue_style('short-pixel-modal.min.css', plugins_url('/res/css/short-pixel-modal.min.css',SHORTPIXEL_PLUGIN_FILE), array(), SHORTPIXEL_IMAGE_OPTIMISER_VERSION);
382
+
383
+ $message = '<div id="shortPixelProposeUpgradeShade" class="sp-modal-shade" style="display:none;">
384
+ <div id="shortPixelProposeUpgrade" class="shortpixel-modal shortpixel-hide" style="min-width:610px;margin-left:-305px;">
385
+ <div class="sp-modal-title">
386
+ <button type="button" class="sp-close-upgrade-button" onclick="ShortPixel.closeProposeUpgrade()">&times;</button>' .
387
+ __('Upgrade your ShortPixel account', 'shortpixel-image-optimiser') . '
388
+ </div>
389
+ <div class="sp-modal-body sptw-modal-spinner" style="height:auto;min-height:400px;padding:0;">
390
+ </div>
391
+ </div>
392
+ </div>';
393
+ return $message;
394
+ }
395
+
396
+ protected function monthlyUpgradeNeeded($quotaData) {
397
+ return isset($quotaData['APICallsQuotaNumeric']) && $this->getMonthAvg($quotaData) > $quotaData['APICallsQuotaNumeric'] + ($quotaData['APICallsQuotaOneTimeNumeric'] - $quotaData['APICallsMadeOneTimeNumeric'])/6 + 20;
398
+ }
399
+
400
+ protected function bulkUpgradeNeeded($stats) {
401
+ $quotaData = $stats;
402
+ return $stats['totalFiles'] - $stats['totalProcessedFiles'] > $quotaData['APICallsQuotaNumeric'] + $quotaData['APICallsQuotaOneTimeNumeric'] - $quotaData['APICallsMadeNumeric'] - $quotaData['APICallsMadeOneTimeNumeric'];
403
+ }
404
+
405
+ protected function getMonthAvg($stats) {
406
+ for($i = 4, $count = 0; $i>=1; $i--) {
407
+ if($count == 0 && $stats['totalM' . $i] == 0) continue;
408
+ $count++;
409
+ }
410
+ return ($stats['totalM1'] + $stats['totalM2'] + $stats['totalM3'] + $stats['totalM4']) / max(1,$count);
411
+ }
412
+
413
+
414
+
415
+
416
+ } // class
class/controller/front_controller.php CHANGED
@@ -49,14 +49,31 @@ class frontController extends ShortPixelController
49
 
50
  $prio = (! defined('SHORTPIXEL_NOFLOCK')) ? \ShortPixelQueue::get() : \ShortPixelQueueDB::get();
51
 
52
- if ($prio && is_array($prio) && count($prio))
53
  {
54
  //also need to have it in the front footer then
55
  add_action( 'wp_footer', array( \wpSPIO()->getShortPixel(), 'shortPixelJS') );
 
 
 
56
  //need to add the nopriv action for when items exist in the queue and no user is logged in
57
  add_action( 'wp_ajax_nopriv_shortpixel_image_processing', array( \wpSPIO()->getShortPixel(), 'handleImageProcessing') );
 
 
 
 
58
 
 
 
 
 
 
 
 
 
59
  }
 
 
60
  }
61
 
62
  /* Picture generation, hooked on the_content filter
@@ -70,7 +87,10 @@ class frontController extends ShortPixelController
70
  return $content . (isset($_GET['SHORTPIXEL_DEBUG']) ? '<!-- SPDBG is AMP -->' : '');
71
  }
72
  require_once(\ShortPixelTools::getPluginPath() . 'class/front/img-to-picture-webp.php');
73
- return \ShortPixelImgToPictureWebp::convert($content);// . "<!-- PICTURE TAGS BY SHORTPIXEL -->";
 
 
 
74
  }
75
 
76
  public function addPictureJs() {
49
 
50
  $prio = (! defined('SHORTPIXEL_NOFLOCK')) ? \ShortPixelQueue::get() : \ShortPixelQueueDB::get();
51
 
52
+ if ($prio && is_array($prio) && count($prio) > 0)
53
  {
54
  //also need to have it in the front footer then
55
  add_action( 'wp_footer', array( \wpSPIO()->getShortPixel(), 'shortPixelJS') );
56
+ add_filter('script_loader_tag', array($this, 'load_sp_async'), 10, 3);
57
+
58
+
59
  //need to add the nopriv action for when items exist in the queue and no user is logged in
60
  add_action( 'wp_ajax_nopriv_shortpixel_image_processing', array( \wpSPIO()->getShortPixel(), 'handleImageProcessing') );
61
+ add_action( 'wp_ajax_shortpixel_image_processing', array( \wpSPIO()->getShortPixel(), 'handleImageProcessing') );
62
+
63
+ }
64
+ }
65
 
66
+ /* When loading on front, asynd defer ourselves */
67
+ public function load_sp_async($tag, $handle, $src)
68
+ {
69
+ $defer = array('shortpixel.js','shortpixel.min.js', 'jquery.knob.min.js', 'jquery.tooltip.min.js', 'punycode.min.js');
70
+
71
+ if (in_array($handle, $defer))
72
+ {
73
+ return '<script src="' . $src . '" defer="defer" type="text/javascript"></script>' . "\n";
74
  }
75
+
76
+ return $tag;
77
  }
78
 
79
  /* Picture generation, hooked on the_content filter
87
  return $content . (isset($_GET['SHORTPIXEL_DEBUG']) ? '<!-- SPDBG is AMP -->' : '');
88
  }
89
  require_once(\ShortPixelTools::getPluginPath() . 'class/front/img-to-picture-webp.php');
90
+
91
+ $webpObj = new ShortPixelImgToPictureWebp();
92
+ return $webpObj->convert($content);
93
+ // return \::convert($content);// . "<!-- PICTURE TAGS BY SHORTPIXEL -->";
94
  }
95
 
96
  public function addPictureJs() {
class/controller/settings.php CHANGED
@@ -171,6 +171,8 @@ class SettingsController extends shortPixelController
171
  if (is_wp_error($this->view->resources))
172
  $this->view->resources = null;
173
 
 
 
174
  $settings = $this->shortPixel->getSettings();
175
  $this->view->dismissedNotices = $settings->dismissedNotices;
176
 
@@ -197,68 +199,6 @@ class SettingsController extends shortPixelController
197
  }
198
 
199
 
200
- /** Check if everything is OK with the Key **/
201
- /*public function checkKey()
202
- {
203
- //$this->is_constant_key = (defined("SHORTPIXEL_API_KEY")) ? true : false;
204
- // $this->hide_api_key = (defined("SHORTPIXEL_HIDE_API_KEY")) ? SHORTPIXEL_HIDE_API_KEY : false;
205
-
206
- $verified_key = $this->model->verifiedKey;
207
- $this->is_verifiedkey = ($verified_key) ? true : false;
208
-
209
- $key_in_db = $this->model->apiKey;
210
-
211
- // if form submit, but no validation already pushed, check if api key was changed.
212
- if ($this->is_form_submit && ! $this->postkey_needs_validation)
213
- {
214
- // api key was changed on the form.
215
- if ($this->postData['apiKey'] != $key_in_db)
216
- {
217
- $this->postkey_needs_validation = true;
218
- }
219
- }
220
-
221
- if($this->is_constant_key)
222
- {
223
- if ($key_in_db != SHORTPIXEL_API_KEY)
224
- {
225
- $this->validateKey(SHORTPIXEL_API_KEY);
226
- }
227
- }
228
- elseif ($this->postkey_needs_validation)
229
- {
230
- $key = isset($this->postData['apiKey']) ? $this->postData['apiKey'] : $this->model->apiKey;
231
- $this->validateKey($key);
232
-
233
- } // postkey_needs_validation
234
- } */
235
-
236
- /** Check remotely if key is alright **/
237
- /*public function validateKey($key)
238
- {
239
- Log::addDebug('Validating Key ' . $key);
240
- // first, save Auth to satisfy getquotainformation
241
- if ($this->is_form_submit)
242
- {
243
- if (strlen($this->postData['siteAuthUser']) > 0 || strlen($this->postData['siteAuthPass']) > 0)
244
- {
245
- $this->model->siteAuthUser = $this->postData['siteAuthUser'];
246
- $this->model->siteAuthPass = $this->postData['siteAuthPass'];
247
- }
248
- }
249
-
250
- /*if (! $this->is_verifiedkey)
251
- {
252
- Notice::addError(sprintf(__('Error during verifying API key: %s','shortpixel-image-optimiser'), $this->quotaData['Message'] ));
253
- }
254
- elseif ($this->is_form_submit) {
255
- $this->processNewKey();
256
- }
257
-
258
- } */
259
-
260
-
261
-
262
  /* Temporary function to check if HTaccess is writable.
263
  * HTaccess is writable if it exists *and* is_writable, or can be written if directory is writable.
264
  * @todo Should be replaced when File / Folder model are complete. Function check should go there.
@@ -426,6 +366,7 @@ class SettingsController extends shortPixelController
426
 
427
  $post = $this->processWebp($post);
428
  $post = $this->processExcludeFolders($post);
 
429
 
430
  parent::processPostData($post);
431
 
@@ -483,11 +424,24 @@ class SettingsController extends shortPixelController
483
  $items = explode(',', $post['excludePatterns']);
484
  foreach($items as $pat) {
485
  $parts = explode(':', $pat);
486
- if(count($parts) == 1) {
 
 
 
 
 
 
 
 
 
 
 
 
 
487
  $patterns[] = array("type" =>"name", "value" => str_replace('\\\\','\\',trim($pat)));
488
  } else {
489
  $patterns[] = array("type" =>trim($parts[0]), "value" => str_replace('\\\\','\\',trim($parts[1])));
490
- }
491
  }
492
 
493
  }
@@ -495,6 +449,26 @@ class SettingsController extends shortPixelController
495
  return $post;
496
  }
497
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
498
 
499
  protected function doRedirect($redirect = 'self')
500
  {
171
  if (is_wp_error($this->view->resources))
172
  $this->view->resources = null;
173
 
174
+ $this->view->cloudflare_constant = defined('SHORTPIXEL_CFTOKEN') ? true : false;
175
+
176
  $settings = $this->shortPixel->getSettings();
177
  $this->view->dismissedNotices = $settings->dismissedNotices;
178
 
199
  }
200
 
201
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
202
  /* Temporary function to check if HTaccess is writable.
203
  * HTaccess is writable if it exists *and* is_writable, or can be written if directory is writable.
204
  * @todo Should be replaced when File / Folder model are complete. Function check should go there.
366
 
367
  $post = $this->processWebp($post);
368
  $post = $this->processExcludeFolders($post);
369
+ $post = $this->processCloudFlare($post);
370
 
371
  parent::processPostData($post);
372
 
424
  $items = explode(',', $post['excludePatterns']);
425
  foreach($items as $pat) {
426
  $parts = explode(':', $pat);
427
+ if (count($parts) == 1)
428
+ {
429
+ $type = 'name';
430
+ $value = str_replace('\\\\','\\', trim($parts[0]));
431
+ }
432
+ else
433
+ {
434
+ $type = trim($parts[0]);
435
+ $value = str_replace('\\\\','\\',trim($parts[1]));
436
+ }
437
+
438
+ if (strlen($value) > 0) // omit faulty empty statements.
439
+ $patterns[] = array('type' => $type, 'value' => $value);
440
+ /* if(count($parts) == 1) {
441
  $patterns[] = array("type" =>"name", "value" => str_replace('\\\\','\\',trim($pat)));
442
  } else {
443
  $patterns[] = array("type" =>trim($parts[0]), "value" => str_replace('\\\\','\\',trim($parts[1])));
444
+ } */
445
  }
446
 
447
  }
449
  return $post;
450
  }
451
 
452
+ protected function processCloudFlare($post)
453
+ {
454
+ if (isset($post['cf_auth_switch']) && $post['cf_auth_switch'] == 'token')
455
+ {
456
+ if (isset($post['cloudflareAuthKey']))
457
+ unset($post['cloudflareAuthKey']);
458
+
459
+ if (isset($post['cloudflareEmail']))
460
+ unset($post['cloudflareEmail']);
461
+
462
+ }
463
+ elseif (isset($post['cloudflareAuthKey']) && $post['cf_auth_switch'] == 'global')
464
+ {
465
+ if (isset($post['cloudflareToken']))
466
+ unset($post['cloudflareToken']);
467
+ }
468
+
469
+ return $post;
470
+ }
471
+
472
 
473
  protected function doRedirect($redirect = 'self')
474
  {
class/db/shortpixel-meta-facade.php CHANGED
@@ -528,7 +528,7 @@ class ShortPixelMetaFacade {
528
  $cacheController = new Cache();
529
  Log::adDDebug('Removing Item Cache -> ' . $this->getCacheName() );
530
  $cacheController->deleteItem( $this->getCacheName());
531
- $this->getMeta(true); // reload the meta.
532
 
533
  }
534
 
@@ -584,7 +584,7 @@ class ShortPixelMetaFacade {
584
  return array("URLs" => array(), "PATHs" => array(), "sizesMissing" => array());
585
  }
586
  $urlList = array(); $filePaths = array();
587
- Log::addDebug('attached file path: ' . (string) $fsFile, array( (string) $fsFile->getFileDir() ) );
588
  if ($no_exist_check)
589
  $mainExists = true;
590
 
528
  $cacheController = new Cache();
529
  Log::adDDebug('Removing Item Cache -> ' . $this->getCacheName() );
530
  $cacheController->deleteItem( $this->getCacheName());
531
+ $this->getMeta(true); // reload the meta.
532
 
533
  }
534
 
584
  return array("URLs" => array(), "PATHs" => array(), "sizesMissing" => array());
585
  }
586
  $urlList = array(); $filePaths = array();
587
+ Log::addDebug('attached file path: ' . (string) $fsFile);
588
  if ($no_exist_check)
589
  $mainExists = true;
590
 
class/external/cloudflare.php ADDED
@@ -0,0 +1,203 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace ShortPixel;
3
+ use ShortPixel\ShortpixelLogger\ShortPixelLogger as Log;
4
+ use ShortPixel\Notices\NoticeController as Notices;
5
+
6
+
7
+ class CloudFlareAPI {
8
+ private $email; // $_cloudflareEmail
9
+ private $authkey; // $_cloudflareAuthKey
10
+ private $zone_id; // $_cloudflareZoneID
11
+ private $token;
12
+
13
+ private $setup_done = false;
14
+ private $config_ok = false;
15
+ private $use_token = false;
16
+
17
+ private $cf_exists = true;
18
+
19
+ private $api_url = 'https://api.cloudflare.com/client/v4/zones/';
20
+
21
+ /*public function __construct($cloudflareEmail, $cloudflareAuthKey, $cloudflareZoneID) {
22
+ $this->set_up($cloudflareEmail, $cloudflareAuthKey, $cloudflareZoneID);
23
+ $this->set_up_required_hooks();
24
+ } */
25
+
26
+ public function __construct()
27
+ {
28
+ add_action( 'shortpixel_image_optimised', array( $this, 'check_cloudflare' ) );
29
+ }
30
+
31
+
32
+ public function setup()
33
+ {
34
+ $this->email = \wpSPIO()->settings()->cloudflareEmail;
35
+ $this->authkey = \wpSPIO()->settings()->cloudflareAuthKey;
36
+ $this->zone_id = (defined('SHORTPIXEL_CFZONE') ) ? SHORTPIXEL_CFZONE : \wpSPIO()->settings()->cloudflareZoneID;
37
+
38
+ $this->token = (defined('SHORTPIXEL_CFTOKEN') ) ? SHORTPIXEL_CFTOKEN : \wpSPIO()->settings()->cloudflareToken;
39
+
40
+ if (! empty($this->token) && ! empty($this->zone_id))
41
+ {
42
+ $this->use_token = true;
43
+ $this->config_ok = true;
44
+ }
45
+ elseif(! empty($this->email) && ! empty($this->authkey) && ! empty($this->zone_id))
46
+ {
47
+ $this->config_ok = true;
48
+ }
49
+
50
+ if (empty($this->zone_id))
51
+ {
52
+ Log::addWarn('CF - ZoneID setting is obligatory');
53
+ }
54
+
55
+ $this->setup_done = true;
56
+ }
57
+
58
+ public function check_cloudflare($image_id)
59
+ {
60
+ if (! $this->setup_done)
61
+ $this->setup();
62
+
63
+ if ($this->config_ok)
64
+ {
65
+ if (! function_exists('curl_init'))
66
+ {
67
+ Log::addWarn('Cloudflare Config OK, but no CURL to request');
68
+ }
69
+ else
70
+ $this->start_cloudflare_cache_purge_process($image_id);
71
+ }
72
+
73
+ }
74
+
75
+ /**
76
+ * @desc Start the process of purging all cache for image URL (includes all the image sizes/thumbnails)f1
77
+ *
78
+ * @param $image_id - WordPress image media ID
79
+ */
80
+ private function start_cloudflare_cache_purge_process( $image_id ) {
81
+
82
+ // Fetch CloudFlare API credentials
83
+ /*$cloudflare_auth_email = $this->_cloudflareEmail;
84
+ $cloudflare_auth_key = $this->_cloudflareAuthKey;
85
+ $cloudflare_zone_id = $this->_cloudflareZoneID; */
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
+ $purge_array = 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( $purge_array, $image_attributes[0] );
103
+ }
104
+
105
+ if ( ! empty( $purge_array ) ) {
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
+
110
+ // Set headers for remote API to authenticate for the request
111
+ /* $dispatch_header = array(
112
+ 'X-Auth-Email: ' . $cloudflare_auth_email,
113
+ 'X-Auth-Key: ' . $cloudflare_auth_key,
114
+ 'Content-Type: application/json'
115
+ ); */
116
+
117
+ $response = $this->delete_url_cache_request_action($purge_array);
118
+
119
+ // Start the process of cache purge
120
+ /* $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 ); */
121
+
122
+
123
+ } else {
124
+ // No use in running the process
125
+ }
126
+ }
127
+
128
+ /**
129
+ * @desc Send a delete cache request to CloudFlare for specified URL(s)
130
+ * Implements -> https://api.cloudflare.com/#zone-purge-files-by-url
131
+ * @return array|mixed|object - Request response as decoded JSON
132
+ */
133
+ private function delete_url_cache_request_action( $files ) {
134
+ $request_url = $this->api_url . $this->zone_id . '/purge_cache';
135
+ $postfields = array('files' => $files);
136
+
137
+ return $this->doRequest($request_url, $postfields);
138
+ }
139
+
140
+ private function addAuth($headers)
141
+ {
142
+ if ($this->use_token)
143
+ {
144
+ $headers['authorization'] = 'Authorization: Bearer ' . $this->token;
145
+ }
146
+ else
147
+ {
148
+ $headers['x-auth-email'] = 'X-Auth-Email: ' . $this->email;
149
+ $headers['x-auth-key'] = 'X-Auth-Key: ' . $this->authkey;
150
+ }
151
+
152
+ return $headers;
153
+
154
+ }
155
+
156
+
157
+ /**
158
+ * @param $url String . Api Url to target with zone_id and acton
159
+ * @param $postfields Array . Fields for POST
160
+ * @param $headers Valid HTTP headers to add.
161
+ */
162
+ private function doRequest($url, $postfields, $headers = array())
163
+ {
164
+ if(!function_exists('curl_init'))
165
+ { return false; }
166
+
167
+ $curl_connection = curl_init();
168
+
169
+ $default_headers =
170
+ array('content_type' => 'Content-Type: application/json');
171
+
172
+ $default_headers = $this->addAuth($default_headers);
173
+
174
+ $headers = wp_parse_args($headers, $default_headers);
175
+ $headers = array_filter(array_values($headers));
176
+
177
+ $postfields = wp_json_encode($postfields);
178
+
179
+ curl_setopt( $curl_connection, CURLOPT_URL, $url );
180
+ curl_setopt( $curl_connection, CURLOPT_CUSTOMREQUEST, "POST" );
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 );
187
+ $result = json_decode( $request_response, true );
188
+ curl_close( $curl_connection );
189
+
190
+ if ( ! is_array( $result ) ) {
191
+ Log::addWarn( 'Shortpixel - CloudFlare: The CloudFlare API is not responding correctly', $result);
192
+ } elseif ( isset( $result['success'] ) && isset( $result['errors'] ) && false === (bool) $result['success'] ) {
193
+ Log::addWarn( 'Shortpixel - CloudFlare, Error messages: '
194
+ . (isset($result['errors']['message']) ? $result['errors']['message'] : json_encode($result['errors'])) );
195
+ } else {
196
+ Log::addInfo('Shortpixel - CloudFlare successfully requested clear cache for: ', array($postfields));
197
+ }
198
+
199
+ return $result;
200
+ }
201
+ }
202
+
203
+ $c = new CloudFlareAPI(); // monitor hook.
class/external/helpscout.php CHANGED
@@ -103,9 +103,7 @@ class HelpScout
103
  // HS.beacon.init();
104
  //}
105
  if(window.shortpixelHSOpen == 1) {
106
- //HS.beacon.close();
107
  window.Beacon('close');
108
- //jQuery("#shortpixel-hs-button-blind").css('display', 'none');
109
  jQuery('#botbutton').addClass('show');
110
  jQuery('div.shortpixel-hs-tools').css('bottom', '116px');
111
  jQuery('div.shortpixel-hs-blind').css('height', '188px');
@@ -113,9 +111,7 @@ class HelpScout
113
  jQuery('div.shortpixel-hs-blind a').css('display', 'inline');
114
  window.shortpixelHSOpen = 0;
115
  } else {
116
- //HS.beacon.open();
117
  window.Beacon('open');
118
- //jQuery("#shortpixel-hs-button-blind").css('display', 'block');
119
  jQuery('#botbutton').removeClass('show');
120
  jQuery('div.shortpixel-hs-tools').css('bottom', '40px');
121
  jQuery('div.shortpixel-hs-blind').css('height', '93px');
@@ -160,34 +156,6 @@ class HelpScout
160
  }(window,document,window.Beacon||function(){});
161
  window.Beacon('init', 'e41d21e0-f3c4-4399-bcfe-358e59a860de');
162
 
163
- /*
164
- !function(e,o,n){ window.HSCW=o,window.HS=n,n.beacon=n.beacon||{};var t=n.beacon;t.userConfig={
165
- color: "#1CBECB",
166
- icon: "question",
167
- instructions: "Send ShortPixel a message",
168
- topArticles: true,
169
- poweredBy: false,
170
- showContactFields: true,
171
- showName: false,
172
- showSubject: true,
173
- translation: {
174
- searchLabel: "What can ShortPixel help you with?",
175
- contactSuccessDescription: "Thanks for reaching out! Someone from our team will get back to you in 24h max."
176
- }
177
-
178
- },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");
179
- c.type="text/javascript",c.async=!0,c.src="https://djtflbt20bdde.cloudfront.net/",r.parentNode.insertBefore(c,r);
180
- }(document,window.HSCW||{},window.HS||{});
181
- */
182
- /*
183
- window.HS.beacon.ready(function(){
184
- HS.beacon.identify({
185
- email: "<?php $u = wp_get_current_user(); echo($u->user_email); ?>",
186
- apiKey: "<?php echo($apiKey);?>"
187
- });
188
- HS.beacon.suggest( <?php echo( $suggestions ) ?> );
189
- });
190
- */
191
  window.Beacon('identify', {
192
  email: "<?php $u = wp_get_current_user(); echo($u->user_email); ?>",
193
  apiKey: "<?php echo($apiKey);?>"
103
  // HS.beacon.init();
104
  //}
105
  if(window.shortpixelHSOpen == 1) {
 
106
  window.Beacon('close');
 
107
  jQuery('#botbutton').addClass('show');
108
  jQuery('div.shortpixel-hs-tools').css('bottom', '116px');
109
  jQuery('div.shortpixel-hs-blind').css('height', '188px');
111
  jQuery('div.shortpixel-hs-blind a').css('display', 'inline');
112
  window.shortpixelHSOpen = 0;
113
  } else {
 
114
  window.Beacon('open');
 
115
  jQuery('#botbutton').removeClass('show');
116
  jQuery('div.shortpixel-hs-tools').css('bottom', '40px');
117
  jQuery('div.shortpixel-hs-blind').css('height', '93px');
156
  }(window,document,window.Beacon||function(){});
157
  window.Beacon('init', 'e41d21e0-f3c4-4399-bcfe-358e59a860de');
158
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
159
  window.Beacon('identify', {
160
  email: "<?php $u = wp_get_current_user(); echo($u->user_email); ?>",
161
  apiKey: "<?php echo($apiKey);?>"
class/external/wp-offload-media.php CHANGED
@@ -12,6 +12,9 @@ class wpOffload
12
 
13
  protected $settings;
14
 
 
 
 
15
  public function __construct()
16
  {
17
  // This must be called before WordPress' init.
@@ -37,6 +40,12 @@ class wpOffload
37
  return;
38
  }
39
 
 
 
 
 
 
 
40
  add_action('shortpixel_image_optimised', array($this, 'image_upload'));
41
  add_action('shortpixel_after_restore_image', array($this, 'image_restore')); // hit this when restoring.
42
  add_action('shortpixel/image/convertpng2jpg_after', array($this, 'image_converted'));
@@ -51,6 +60,10 @@ class wpOffload
51
 
52
  add_filter('shortpixel_get_attached_file', array($this, 'get_raw_attached_file'),10, 2);
53
  add_filter('shortpixel_get_original_image_path', array($this, 'get_raw_original_path'), 10, 2);
 
 
 
 
54
  }
55
 
56
  public function get_raw_attached_file($file, $id)
@@ -101,42 +114,8 @@ class wpOffload
101
 
102
  public function image_restore($id)
103
  {
104
- /* voodoo . When images is excluded via S3, it might not exist anymore on server (when option is on). And it will not be in the backups. So before removing remote, and restoring, check this */
105
- /*
106
- Seems not needed to make it work, for now.
107
- $settings = \wpSPIO()->settings();
108
- $fs = \wpSPIO()->filesystem();
109
- $excludeSizes = $settings->excludeSizes;
110
-
111
- $itemHandler = new \ShortPixelMetaFacade($id);
112
- $itemHandler->deleteItemCache();
113
-
114
- // get all paths, without anything excluded.
115
- $paths_all = $itemHandler->getURLsAndPATHs(true, false, true, array(), true,true);
116
- Log::addDebug('Image Restore, Paths ALL', array($paths_all));
117
-
118
- if (isset($paths_all['PATHs']))
119
- {
120
- foreach($paths_all['PATHs'] as $index => $path)
121
- {
122
- $restoredFile = $fs->getFile($path);
123
- if (! $restoredFile->exists())
124
- {
125
- $url = $paths_all['URLs'][$index];
126
- Log::addDebug('Missing size on restored image data, doing remote download :' . $path);
127
- $itemHandler->attemptRemoteDownload($url, $path, $id);
128
- }
129
- }
130
- } */
131
- // sizes without excluded paths
132
- //$paths_excludes = $itemHandler->getURLsAndPATHs(true, false, true, $excludeSizes, true,true);
133
-
134
- //$itemHandler->deleteItemCache();
135
-
136
  $this->remove_remote($id);
137
-
138
  $this->image_upload($id);
139
-
140
  }
141
 
142
  public function remove_remote($id)
@@ -159,6 +138,17 @@ class wpOffload
159
  return $mediaItem;
160
  }
161
 
 
 
 
 
 
 
 
 
 
 
 
162
  public function image_converted($id)
163
  {
164
  $fs = new \ShortPixel\FileSystemController();
@@ -302,6 +292,69 @@ class wpOffload
302
  return $paths;
303
  }
304
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
305
  }
306
 
307
  $wpOff = new wpOffload();
12
 
13
  protected $settings;
14
 
15
+ protected $is_cname = false;
16
+ protected $cname;
17
+
18
  public function __construct()
19
  {
20
  // This must be called before WordPress' init.
40
  return;
41
  }
42
 
43
+ if ('cloudfront' === $this->as3cf->get_setting( 'domain' ))
44
+ {
45
+ $this->is_cname = true;
46
+ $this->cname = $this->as3cf->get_setting( 'cloudfront' );
47
+ }
48
+
49
  add_action('shortpixel_image_optimised', array($this, 'image_upload'));
50
  add_action('shortpixel_after_restore_image', array($this, 'image_restore')); // hit this when restoring.
51
  add_action('shortpixel/image/convertpng2jpg_after', array($this, 'image_converted'));
60
 
61
  add_filter('shortpixel_get_attached_file', array($this, 'get_raw_attached_file'),10, 2);
62
  add_filter('shortpixel_get_original_image_path', array($this, 'get_raw_original_path'), 10, 2);
63
+
64
+ // for webp picture paths rendered via output
65
+ add_filter('shortpixel_webp_image_base', array($this, 'checkWebpRemotePath'), 10, 2);
66
+ add_filter('shortpixel/front/webp_notfound', array($this, 'fixWebpRemotePath'), 10, 4);
67
  }
68
 
69
  public function get_raw_attached_file($file, $id)
114
 
115
  public function image_restore($id)
116
  {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
117
  $this->remove_remote($id);
 
118
  $this->image_upload($id);
 
119
  }
120
 
121
  public function remove_remote($id)
138
  return $mediaItem;
139
  }
140
 
141
+ protected function getByURL($url)
142
+ {
143
+ $class = $this->itemClassName;
144
+ $source_id = $class::get_source_id_by_remote_url($url);
145
+
146
+ if ($source_id !== false)
147
+ return $this->getItemById($source_id);
148
+ else
149
+ return false;
150
+ }
151
+
152
  public function image_converted($id)
153
  {
154
  $fs = new \ShortPixel\FileSystemController();
292
  return $paths;
293
  }
294
 
295
+ public function checkWebpRemotePath($url, $original)
296
+ {
297
+ if ($url === false)
298
+ {
299
+ return $this->convertWebPRemotePath($url, $original);
300
+ // return $url;
301
+ }
302
+ elseif($this->is_cname) // check this. the webp to picture will convert subdomains with CNAME to some local path when offloaded.
303
+ {
304
+ Log::addDebug('S3 active, checking on CNAME for path' . $this->cname);
305
+ if (strpos($original, $this->cname) !== false)
306
+ return $this->convertWebPRemotePath($url, $original);
307
+ }
308
+
309
+ return $url;
310
+
311
+ }
312
+
313
+ private function convertWebPRemotePath($url, $original)
314
+ {
315
+ $mediaItem = $this->getByURL($original); // test if exists remote.
316
+ Log::addDebug('ImageBaseName check for S3 - ', array($original, $mediaItem));
317
+
318
+ if ($mediaItem === false)
319
+ {
320
+ $pattern = '/-\d+x\d*/i';
321
+ $replaced_url = preg_replace($pattern, '', $original);
322
+ $mediaItem = $this->getByURL($replaced_url);
323
+ }
324
+
325
+ if ($mediaItem === false)
326
+ {
327
+ return $url;
328
+ }
329
+ $parsed = parse_url($original);
330
+ $url = str_replace($parsed['scheme'], '', $original);
331
+ $url = str_replace(basename($url), '', $url);
332
+ Log::addDebug('New BasePath, External' . $url);
333
+
334
+ return $url;
335
+ }
336
+
337
+ // GetbyURL can't find thumbnails, only the main image. We are going to assume, if imagebase is ok, the webp might be there.
338
+ public function fixWebpRemotePath($bool, $file, $url, $imagebase)
339
+ {
340
+ if (strpos($url, $imagebase) !== false)
341
+ return $file;
342
+ else
343
+ return $bool;
344
+
345
+ /* $mediaItem = $this->getByURL($url);
346
+ if ($mediaItem !== false)
347
+ {
348
+ return $file;
349
+ }
350
+ else
351
+ {
352
+ // Log::addDebug('Fixing Remote Path failed', array($file->getFullPath(), $url));
353
+ }
354
+ return false; */
355
+
356
+ }
357
+
358
  }
359
 
360
  $wpOff = new wpOffload();
class/front/img-to-picture-webp.php CHANGED
@@ -1,32 +1,15 @@
1
  <?php
 
 
 
2
  /**
3
  * Class ShortPixelImgToPictureWebp - convert an <img> tag to a <picture> tag and add the webp versions of the images
4
  * thanks to the Responsify WP plugin for some of the code
5
  */
6
-
7
- //use ShortPixel\DebugItem as DebugItem;
8
- use ShortPixel\ShortpixelLogger\ShortPixelLogger as Log;
9
-
10
  class ShortPixelImgToPictureWebp
11
  {
12
- /** If lazy loading is happening, get source (src) from those values */
13
- public static function lazyGet($img, $type)
14
- {
15
- return array(
16
- 'value' =>
17
- (isset($img['data-lazy-' . $type]) && strlen($img['data-lazy-' . $type])) ?
18
- $img['data-lazy-' . $type]
19
- : (isset($img['data-' . $type]) && strlen($img['data-' . $type]) ?
20
- $img['data-' . $type]
21
- : (isset($img[$type]) && strlen($img[$type]) ? $img[$type] : false)),
22
- 'prefix' =>
23
- (isset($img['data-lazy-' . $type]) && strlen($img['data-lazy-' . $type])) ? 'data-lazy-'
24
- : (isset($img['data-' . $type]) && strlen($img['data-' . $type]) ? 'data-'
25
- : (isset($img[$type]) && strlen($img[$type]) ? '' : false))
26
- );
27
- }
28
 
29
- public static function convert($content)
30
  {
31
 
32
  // Don't do anything with the RSS feed.
@@ -35,15 +18,21 @@ class ShortPixelImgToPictureWebp
35
  return $content; // . (isset($_GET['SHORTPIXEL_DEBUG']) ? '<!-- -->' : '');
36
  }
37
 
38
- $new_content = self::testPictures($content);
39
  if ($new_content !== false)
 
40
  $content = $new_content;
 
 
 
 
 
41
 
42
- $content = preg_replace_callback('/<img[^>]*>/i', array('self', 'convertImage'), $content);
43
  //$content = preg_replace_callback('/background.*[^:](url\(.*\)[,;])/im', array('self', 'convertInlineStyle'), $content);
44
 
45
  // [BS] No callback because we need preg_match_all
46
- $content = self::testInlineStyle($content);
47
  // $content = preg_replace_callback('/background.*[^:]url\([\'|"](.*)[\'|"]\)[,;]/imU',array('self', 'convertInlineStyle'), $content);
48
  Log::addDebug('SPDBG WebP process done');
49
 
@@ -51,12 +40,43 @@ class ShortPixelImgToPictureWebp
51
 
52
  }
53
 
54
- public static function testPictures($content)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
  {
56
  // [BS] Escape when DOM Module not installed
57
  //if (! class_exists('DOMDocument'))
58
  // return false;
59
-
60
  //$pattern =''
61
  //$pattern ='/(?<=(<picture>))(.*)(?=(<\/picture>))/mi';
62
  $pattern = '/<picture.*?>.*?(<img.*?>).*?<\/picture>/is';
@@ -89,10 +109,7 @@ class ShortPixelImgToPictureWebp
89
  }
90
  }
91
 
92
-
93
-
94
  return $content;
95
-
96
  }
97
 
98
  /* This might be a future solution for regex callbacks.
@@ -103,15 +120,21 @@ class ShortPixelImgToPictureWebp
103
  $imgs = $node->getElementsByTagName('img');
104
  } */
105
 
106
- public static function convertImage($match)
 
 
 
 
107
  {
 
 
108
  // Do nothing with images that have the 'sp-no-webp' class.
109
  if (strpos($match[0], 'sp-no-webp') || strpos($match[0], 'rev-sildebg')) {
110
  Log::addInfo('SPDBG convertImage skipped, sp-no-webp found');
111
  return $match[0]; //. (isset($_GET['SHORTPIXEL_DEBUG']) ? '<!-- SPDBG convertImage sp-no-webp -->' : '');
112
  }
113
 
114
- $img = self::get_attributes($match[0]);
115
 
116
  if(isset($img['style']) && strpos($img['style'], 'background') !== false) {
117
  //don't replace for <img>'s that have background
@@ -120,67 +143,22 @@ class ShortPixelImgToPictureWebp
120
 
121
  // [BS] Can return false in case of Module fail. Escape in that case with unmodified image
122
  if ($img === false)
 
 
123
  return $match[0];
124
-
125
- $srcInfo = self::lazyGet($img, 'src');
126
- $src = $srcInfo['value'];
127
- $parsed_url = parse_url($src);
128
- $srcPrefix = $srcInfo['prefix'];
129
-
130
- $srcsetInfo = self::lazyGet($img, 'srcset');
131
- $srcset = $srcsetInfo['value'];
132
- $srcsetPrefix = $srcset ? $srcsetInfo['prefix'] : $srcInfo['prefix'];
133
-
134
- $sizesInfo = self::lazyGet($img, 'sizes');
135
- $sizes = $sizesInfo['value'];
136
- $sizesPrefix = $sizesInfo['prefix'];
137
-
138
- //check if there are webps
139
- /*$id = $thisClass::url_to_attachment_id( $src );
140
- if(!$id) {
141
- return $match[0];
142
  }
143
- */
144
-
145
- /* [BS] $updir = wp_upload_dir();
146
- $proto = explode("://", $src);
147
- if (count($proto) > 1) {
148
- //check that baseurl uses the same http/https proto and if not, change
149
- $proto = $proto[0];
150
- if (strpos($updir['baseurl'], $proto."://") === false) {
151
- $base = explode("://", $updir['baseurl']);
152
- if (count($base) > 1) {
153
- $updir['baseurl'] = $proto . "://" . $base[1];
154
- }
155
- }
156
- } */
157
 
 
 
 
158
 
159
- /* [BS] $imageBase = str_replace($updir['baseurl'], SHORTPIXEL_UPLOADS_BASE, $src);
160
- if ($imageBase == $src) { //maybe the site uses a CDN or a subdomain?
161
- $urlParsed = parse_url($src);
162
- $srcHost = array_reverse(explode('.', $urlParsed['host']));
163
- $baseParsed = parse_url($updir['baseurl']);
164
- $baseurlHost = array_reverse(explode('.', $baseParsed['host']));
165
- if ($srcHost[0] == $baseurlHost[0] && $srcHost[1] == $baseurlHost[1]
166
- && (strlen($srcHost[1]) > 3 || isset($srcHost[2]) && isset($srcHost[2]) && $srcHost[2] == $baseurlHost[2])) {
167
- $baseurl = str_replace($baseParsed['scheme'] . '://' . $baseParsed['host'], $urlParsed['scheme'] . '://' . $urlParsed['host'], $updir['baseurl']);
168
- $imageBase = str_replace($baseurl, SHORTPIXEL_UPLOADS_BASE, $src);
169
- }
170
- if ($imageBase == $src) { //looks like it's an external URL though...
171
- if(isset($_GET['SHORTPIXEL_DEBUG'])) WPShortPixel::log('SPDBG baseurl ' . $updir['baseurl'] . ' doesn\'t match ' . $src, true);
172
- return $match[0] . (isset($_GET['SHORTPIXEL_DEBUG']) ? '<!-- SPDBG baseurl ' . $updir['baseurl'] . ' doesn\'t match ' . $src . ' -->' : '');
173
- }
174
- }
175
- $imageBase = dirname($imageBase) . '/';
176
- */
177
-
178
- $imageBase = apply_filters( 'shortpixel_webp_image_base', static::getImageBase($src), $src);
179
 
180
  if($imageBase === false) {
 
181
  return $match[0]; // . (isset($_GET['SHORTPIXEL_DEBUG']) ? '<!-- SPDBG baseurl doesn\'t match ' . $src . ' -->' : '');
182
- Log::addInfo('SPDBG baseurl doesn\'t match ' . $src);
183
  }
 
184
 
185
  //some attributes should not be moved from <img>
186
  $altAttr = isset($img['alt']) && strlen($img['alt']) ? ' alt="' . $img['alt'] . '"' : '';
@@ -193,26 +171,67 @@ class ShortPixelImgToPictureWebp
193
  unset($img['data-src']);
194
  unset($img['data-lazy-src']);
195
  unset($img['srcset']);
 
196
  unset($img['sizes']);
197
 
 
198
  //nor the ones that belong to <img>
199
  unset($img['alt']);
200
  unset($img['id']);
201
  unset($img['width']);
202
  unset($img['height']);
203
 
204
- $srcsetWebP = '';
 
 
 
 
 
 
 
 
 
 
 
 
205
 
206
- if ($srcset) {
207
- $defs = explode(",", $srcset);
208
- foreach ($defs as $item) {
209
  $parts = preg_split('/\s+/', trim($item));
210
 
211
- //echo(" file: " . $parts[0] . " ext: " . pathinfo($parts[0], PATHINFO_EXTENSION) . " basename: " . wp_basename($parts[0], '.' . pathinfo($parts[0], PATHINFO_EXTENSION)));
 
 
 
 
 
 
212
 
213
- $fileWebPCompat = $imageBase . wp_basename($parts[0], '.' . pathinfo($parts[0], PATHINFO_EXTENSION)) . '.webp';
214
- $fileWebP = $imageBase . wp_basename($parts[0]) . '.webp';
215
- if (apply_filters( 'shortpixel_image_exists', file_exists($fileWebP), $fileWebP)) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
216
  $srcsetWebP .= (strlen($srcsetWebP) ? ',': '')
217
  . $parts[0].'.webp'
218
  . (isset($parts[1]) ? ' ' . $parts[1] : '');
@@ -223,14 +242,14 @@ class ShortPixelImgToPictureWebp
223
  .(isset($parts[1]) ? ' ' . $parts[1] : '');
224
  }
225
  else {
 
226
  Log::addDebug('Image srcset for webp doesn\'t exist', array($fileWebP));
227
- }
228
- }
229
  //$srcsetWebP = preg_replace('/\.[a-zA-Z0-9]+\s+/', '.webp ', $srcset);
230
- } else {
231
  $srcset = trim($src);
232
 
233
-
234
  $fileWebPCompat = $imageBase . wp_basename($srcset, '.' . pathinfo($srcset, PATHINFO_EXTENSION)) . '.webp';
235
  $fileWebP = $imageBase . wp_basename($srcset) . '.webp';
236
  if (apply_filters( 'shortpixel_image_exists', file_exists($fileWebP), $fileWebP)) {
@@ -243,9 +262,11 @@ class ShortPixelImgToPictureWebp
243
  Log::addDebug('Image file for webp doesn\'t exist', array($fileWebP));
244
  }
245
  }
246
- }
247
  //return($match[0]. "<!-- srcsetTZF:".$srcsetWebP." -->");
248
- if (!strlen($srcsetWebP)) {
 
 
249
  return $match[0]; //. (isset($_GET['SHORTPIXEL_DEBUG']) ? '<!-- SPDBG no srcsetWebP found (' . $srcsetWebP . ') -->' : '');
250
  Log::addInfo(' SPDBG no srcsetWebP found (' . $srcsetWebP . ')');
251
  }
@@ -255,18 +276,31 @@ class ShortPixelImgToPictureWebp
255
 
256
  $imgpicture = $img;
257
  // remove certain elements for the main picture element.
258
- $imgpicture = self::filterForPicture($imgpicture);
 
 
 
 
 
 
259
 
260
- return '<picture ' . self::create_attributes($imgpicture) . '>'
 
 
 
 
 
 
 
261
  .'<source ' . $srcsetPrefix . 'srcset="' . $srcsetWebP . '"' . ($sizes ? ' ' . $sizesPrefix . 'sizes="' . $sizes . '"' : '') . ' type="image/webp">'
262
  .'<source ' . $srcsetPrefix . 'srcset="' . $srcset . '"' . ($sizes ? ' ' . $sizesPrefix . 'sizes="' . $sizes . '"' : '') . '>'
263
- .'<img ' . $srcPrefix . 'src="' . $src . '" ' . self::create_attributes($img) . $idAttr . $altAttr . $heightAttr . $widthAttr
264
  . (strlen($srcset) ? ' srcset="' . $srcset . '"': '') . (strlen($sizes) ? ' sizes="' . $sizes . '"': '') . '>'
265
  .'</picture>';
266
  }
267
 
268
  /** Check and remove elements that should not be in the picture tag. Especially items within attributes. */
269
- private static function filterForPicture($img)
270
  {
271
 
272
  if (isset($img['style']))
@@ -290,7 +324,7 @@ class ShortPixelImgToPictureWebp
290
  return $img;
291
  }
292
 
293
- public static function testInlineStyle($content)
294
  {
295
  //preg_match_all('/background.*[^:](url\(.*\))[;]/isU', $content, $matches);
296
  preg_match_all('/url\(.*\)/isU', $content, $matches);
@@ -298,7 +332,7 @@ class ShortPixelImgToPictureWebp
298
  if (count($matches) == 0)
299
  return $content;
300
 
301
- $content = self::convertInlineStyle($matches, $content);
302
  return $content;
303
  }
304
 
@@ -307,7 +341,7 @@ class ShortPixelImgToPictureWebp
307
  * @return String Replaced (or not) content for webp.
308
  * @author Bas Schuiling
309
  */
310
- public static function convertInlineStyle($matches, $content)
311
  {
312
  // ** matches[0] = url('xx') matches[1] the img URL.
313
  // preg_match_all('/url\(\'(.*)\'\)/imU', $match, $matches);
@@ -328,7 +362,7 @@ class ShortPixelImgToPictureWebp
328
  continue;
329
 
330
  $url = $match[1];
331
- $parsed_url = parse_url($url);
332
  $filename = basename($url);
333
 
334
  $fileonly = pathinfo($url, PATHINFO_FILENAME);
@@ -353,6 +387,10 @@ class ShortPixelImgToPictureWebp
353
  {
354
  $checkedFile = $imageBaseURL . $fileonly . '.webp';
355
  }
 
 
 
 
356
 
357
  if ($checkedFile)
358
  {
@@ -375,7 +413,7 @@ class ShortPixelImgToPictureWebp
375
  ** @param String $src Image Source
376
  ** @returns String The Image Base
377
  **/
378
- public static function getImageBase($src)
379
  {
380
  $urlParsed = parse_url($src);
381
  if(!isset($urlParsed['host'])) {
@@ -416,7 +454,6 @@ class ShortPixelImgToPictureWebp
416
 
417
  if ($srcHost[0] == $baseurlHost[0] && $srcHost[1] == $baseurlHost[1]
418
  && (strlen($srcHost[1]) > 3 || isset($srcHost[2]) && isset($srcHost[2]) && $srcHost[2] == $baseurlHost[2])) {
419
-
420
  $baseurl = str_replace($baseParsed['scheme'] . '://' . $baseParsed['host'], $urlParsed['scheme'] . '://' . $urlParsed['host'], $updir['baseurl']);
421
  $imageBase = str_replace($baseurl, SHORTPIXEL_UPLOADS_BASE, $src);
422
  }
@@ -425,12 +462,12 @@ class ShortPixelImgToPictureWebp
425
  }
426
  }
427
 
428
-
429
  $imageBase = trailingslashit(dirname($imageBase));
430
  return $imageBase;
431
  }
432
 
433
- public static function get_attributes($image_node)
434
  {
435
  if (function_exists("mb_convert_encoding")) {
436
  $image_node = mb_convert_encoding($image_node, 'HTML-ENTITIES', 'UTF-8');
@@ -441,7 +478,7 @@ class ShortPixelImgToPictureWebp
441
  Log::addWarn('Webp Active, but DomDocument class not found ( missing xmldom library )');
442
  return false;
443
  }
444
- $dom = new DOMDocument();
445
  @$dom->loadHTML($image_node);
446
  $image = $dom->getElementsByTagName('img')->item(0);
447
  $attributes = array();
@@ -463,7 +500,7 @@ class ShortPixelImgToPictureWebp
463
  * @param $attribute_array
464
  * @return string
465
  */
466
- public static function create_attributes($attribute_array)
467
  {
468
  $attributes = '';
469
  foreach ($attribute_array as $attribute => $value) {
@@ -478,7 +515,8 @@ class ShortPixelImgToPictureWebp
478
  * @param $image_url
479
  * @return array
480
  */
481
- public static function url_to_attachment_id($image_url)
 
482
  {
483
  // Thx to https://github.com/kylereicks/picturefill.js.wp/blob/master/inc/class-model-picturefill-wp.php
484
  global $wpdb;
@@ -506,5 +544,5 @@ class ShortPixelImgToPictureWebp
506
  $attachment_id = $wpdb->get_col($wpdb->prepare("SELECT ID FROM " . $prefix . "posts" . " WHERE guid='%s';", $original_image_url));
507
  }
508
  return !empty($attachment_id) ? $attachment_id[0] : false;
509
- }
510
  }
1
  <?php
2
+ namespace ShortPixel;
3
+ use ShortPixel\ShortPixelLogger\ShortPixelLogger as Log;
4
+
5
  /**
6
  * Class ShortPixelImgToPictureWebp - convert an <img> tag to a <picture> tag and add the webp versions of the images
7
  * thanks to the Responsify WP plugin for some of the code
8
  */
 
 
 
 
9
  class ShortPixelImgToPictureWebp
10
  {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
 
12
+ public function convert($content)
13
  {
14
 
15
  // Don't do anything with the RSS feed.
18
  return $content; // . (isset($_GET['SHORTPIXEL_DEBUG']) ? '<!-- -->' : '');
19
  }
20
 
21
+ $new_content = $this->testPictures($content);
22
  if ($new_content !== false)
23
+ {
24
  $content = $new_content;
25
+ }
26
+ else
27
+ {
28
+ Log::addDebug('Test Pictures returned empty.');
29
+ }
30
 
31
+ $content = preg_replace_callback('/<img[^>]*>/i', array($this, 'convertImage'), $content);
32
  //$content = preg_replace_callback('/background.*[^:](url\(.*\)[,;])/im', array('self', 'convertInlineStyle'), $content);
33
 
34
  // [BS] No callback because we need preg_match_all
35
+ $content = $this->testInlineStyle($content);
36
  // $content = preg_replace_callback('/background.*[^:]url\([\'|"](.*)[\'|"]\)[,;]/imU',array('self', 'convertInlineStyle'), $content);
37
  Log::addDebug('SPDBG WebP process done');
38
 
40
 
41
  }
42
 
43
+ /** If lazy loading is happening, get source (src) from those values
44
+ * Otherwise pass back image data in a regular way.
45
+ */
46
+ private function lazyGet($img, $type)
47
+ {
48
+
49
+ $value = false;
50
+ $prefix = false;
51
+
52
+ if (isset($img['data-lazy-' . $type]) && strlen($img['data-lazy-' . $type]) > 0)
53
+ {
54
+ $value = $img['data-lazy-' . $type];
55
+ $prefix = 'data-lazy-';
56
+ }
57
+ elseif( isset($img['data-' . $type]) && strlen($img['data-' . $type]) > 0)
58
+ {
59
+ $value = $img['data-' . $type];
60
+ $prefix = 'data-';
61
+ }
62
+ elseif(isset($img[$type]) && strlen($img[$type]) > 0)
63
+ {
64
+ $value = $img[$type];
65
+ $prefix = '';
66
+ }
67
+
68
+ return array(
69
+ 'value' => $value,
70
+ 'prefix' => $prefix,
71
+ );
72
+ }
73
+
74
+ /* Find image tags within picture definitions and make sure they are converted only by block, */
75
+ private function testPictures($content)
76
  {
77
  // [BS] Escape when DOM Module not installed
78
  //if (! class_exists('DOMDocument'))
79
  // return false;
 
80
  //$pattern =''
81
  //$pattern ='/(?<=(<picture>))(.*)(?=(<\/picture>))/mi';
82
  $pattern = '/<picture.*?>.*?(<img.*?>).*?<\/picture>/is';
109
  }
110
  }
111
 
 
 
112
  return $content;
 
113
  }
114
 
115
  /* This might be a future solution for regex callbacks.
120
  $imgs = $node->getElementsByTagName('img');
121
  } */
122
 
123
+ /** Callback function with received an <img> tag match
124
+ * @param $match Image declaration block
125
+ * @return String Replacement image declaration block
126
+ */
127
+ protected function convertImage($match)
128
  {
129
+ $fs = \wpSPIO()->filesystem();
130
+
131
  // Do nothing with images that have the 'sp-no-webp' class.
132
  if (strpos($match[0], 'sp-no-webp') || strpos($match[0], 'rev-sildebg')) {
133
  Log::addInfo('SPDBG convertImage skipped, sp-no-webp found');
134
  return $match[0]; //. (isset($_GET['SHORTPIXEL_DEBUG']) ? '<!-- SPDBG convertImage sp-no-webp -->' : '');
135
  }
136
 
137
+ $img = $this->get_attributes($match[0]);
138
 
139
  if(isset($img['style']) && strpos($img['style'], 'background') !== false) {
140
  //don't replace for <img>'s that have background
143
 
144
  // [BS] Can return false in case of Module fail. Escape in that case with unmodified image
145
  if ($img === false)
146
+ {
147
+ Log::addDebug('Webp convert failed, no image found in convertImage');
148
  return $match[0];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
149
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
150
 
151
+ $srcInfo = $this->lazyGet($img, 'src');
152
+ $srcsetInfo = $this->lazyGet($img, 'srcset');
153
+ $sizesInfo = $this->lazyGet($img, 'sizes');
154
 
155
+ $imageBase = apply_filters( 'shortpixel_webp_image_base', $this->getImageBase($srcInfo['value']), $srcInfo['value']);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
156
 
157
  if($imageBase === false) {
158
+ Log::addInfo('SPDBG baseurl doesn\'t match ' . $srcInfo['value'], array($imageBase) );
159
  return $match[0]; // . (isset($_GET['SHORTPIXEL_DEBUG']) ? '<!-- SPDBG baseurl doesn\'t match ' . $src . ' -->' : '');
 
160
  }
161
+ Log::addDebug('ImageBase'. $imageBase);
162
 
163
  //some attributes should not be moved from <img>
164
  $altAttr = isset($img['alt']) && strlen($img['alt']) ? ' alt="' . $img['alt'] . '"' : '';
171
  unset($img['data-src']);
172
  unset($img['data-lazy-src']);
173
  unset($img['srcset']);
174
+ // unset($img['data-srcset']); // lazyload - don't know if this solves anything.
175
  unset($img['sizes']);
176
 
177
+
178
  //nor the ones that belong to <img>
179
  unset($img['alt']);
180
  unset($img['id']);
181
  unset($img['width']);
182
  unset($img['height']);
183
 
184
+ $srcsetWebP = array();
185
+
186
+ $imagePaths = array();
187
+
188
+ if ($srcsetInfo['value']) {
189
+ $definitions = explode(',', $srcsetInfo['value']);
190
+ }
191
+ else
192
+ {
193
+ $definitions = array($srcInfo['value']);
194
+ }
195
+
196
+ // $defs = explode(",", $srcset);
197
 
198
+ foreach ($definitions as $item) {
 
 
199
  $parts = preg_split('/\s+/', trim($item));
200
 
201
+ $fileurl = $parts[0];
202
+ $condition = isset($parts[1]) ? ' ' . $parts[1] : '';
203
+
204
+ Log::addDebug('Running item - ' . $item, $fileurl);
205
+
206
+ $fsFile = $fs->getFile($fileurl);
207
+ $extension = $fsFile->getExtension(); // trigger setFileinfo, which will resolve URL -> Path
208
 
209
+ $fileWebp = $fs->getFile($imageBase . $fsFile->getFileBase() . '.webp');
210
+ $fileWebpCompat = $fs->getFile($imageBase . $fsFile->getFileName() . '.webp');
211
+ //$fileWebp = $fs->getFile($filepath);
212
+
213
+ $fileurl_base = str_replace($fsFile->getFileName(), '', $fileurl);
214
+ $files = array($fileWebp, $fileWebpCompat);
215
+
216
+ foreach($files as $thisfile)
217
+ {
218
+ $fileWebp_exists = apply_filters('shortpixel_image_exists', $thisfile->exists(), $thisfile);
219
+ if (! $fileWebp_exists)
220
+ {
221
+ $thisfile = $fileWebp_exists = apply_filters('shortpixel/front/webp_notfound', false, $thisfile, $fileurl, $imageBase);
222
+ }
223
+
224
+ if ($thisfile !== false)
225
+ {
226
+ // base url + found filename + optional condition ( in case of sourceset, as in 1400w or similar)
227
+ Log::addDebug('Adding new URL', $fileurl_base . $thisfile->getFileName() . $condition);
228
+ $srcsetWebP[] = $fileurl_base . $thisfile->getFileName() . $condition;
229
+ break;
230
+ }
231
+ }
232
+ }
233
+
234
+ /* if () {
235
  $srcsetWebP .= (strlen($srcsetWebP) ? ',': '')
236
  . $parts[0].'.webp'
237
  . (isset($parts[1]) ? ' ' . $parts[1] : '');
242
  .(isset($parts[1]) ? ' ' . $parts[1] : '');
243
  }
244
  else {
245
+ $notfound = apply_filters('shortpixel/front/webp_notfound', false, $fileWebP, $fileWebpCompat, $item);
246
  Log::addDebug('Image srcset for webp doesn\'t exist', array($fileWebP));
247
+ } */
248
+ // }
249
  //$srcsetWebP = preg_replace('/\.[a-zA-Z0-9]+\s+/', '.webp ', $srcset);
250
+ /* } else {
251
  $srcset = trim($src);
252
 
 
253
  $fileWebPCompat = $imageBase . wp_basename($srcset, '.' . pathinfo($srcset, PATHINFO_EXTENSION)) . '.webp';
254
  $fileWebP = $imageBase . wp_basename($srcset) . '.webp';
255
  if (apply_filters( 'shortpixel_image_exists', file_exists($fileWebP), $fileWebP)) {
262
  Log::addDebug('Image file for webp doesn\'t exist', array($fileWebP));
263
  }
264
  }
265
+ } */
266
  //return($match[0]. "<!-- srcsetTZF:".$srcsetWebP." -->");
267
+
268
+
269
+ if (count($srcsetWebP) == 0) {
270
  return $match[0]; //. (isset($_GET['SHORTPIXEL_DEBUG']) ? '<!-- SPDBG no srcsetWebP found (' . $srcsetWebP . ') -->' : '');
271
  Log::addInfo(' SPDBG no srcsetWebP found (' . $srcsetWebP . ')');
272
  }
276
 
277
  $imgpicture = $img;
278
  // remove certain elements for the main picture element.
279
+ $imgpicture = $this->filterForPicture($imgpicture);
280
+
281
+ $sizes = $sizesInfo['value'];
282
+ $sizesPrefix = $sizesInfo['prefix'];
283
+
284
+ $srcsetPrefix = $srcsetInfo['value'] ? $srcsetInfo['prefix'] : $srcInfo['prefix'];
285
+ $srcset = $srcsetInfo['value'];
286
 
287
+ $src = trim($srcInfo['value']);
288
+ if (! $srcset)
289
+ $srcset = $src; // if not srcset ( it's a src ), replace those.
290
+ $srcPrefix = $srcInfo['prefix'];
291
+
292
+ $srcsetWebP = implode(',', $srcsetWebP);
293
+
294
+ return '<picture ' . $this->create_attributes($imgpicture) . '>'
295
  .'<source ' . $srcsetPrefix . 'srcset="' . $srcsetWebP . '"' . ($sizes ? ' ' . $sizesPrefix . 'sizes="' . $sizes . '"' : '') . ' type="image/webp">'
296
  .'<source ' . $srcsetPrefix . 'srcset="' . $srcset . '"' . ($sizes ? ' ' . $sizesPrefix . 'sizes="' . $sizes . '"' : '') . '>'
297
+ .'<img ' . $srcPrefix . 'src="' . $src . '" ' . $this->create_attributes($img) . $idAttr . $altAttr . $heightAttr . $widthAttr
298
  . (strlen($srcset) ? ' srcset="' . $srcset . '"': '') . (strlen($sizes) ? ' sizes="' . $sizes . '"': '') . '>'
299
  .'</picture>';
300
  }
301
 
302
  /** Check and remove elements that should not be in the picture tag. Especially items within attributes. */
303
+ private function filterForPicture($img)
304
  {
305
 
306
  if (isset($img['style']))
324
  return $img;
325
  }
326
 
327
+ public function testInlineStyle($content)
328
  {
329
  //preg_match_all('/background.*[^:](url\(.*\))[;]/isU', $content, $matches);
330
  preg_match_all('/url\(.*\)/isU', $content, $matches);
332
  if (count($matches) == 0)
333
  return $content;
334
 
335
+ $content = $this->convertInlineStyle($matches, $content);
336
  return $content;
337
  }
338
 
341
  * @return String Replaced (or not) content for webp.
342
  * @author Bas Schuiling
343
  */
344
+ public function convertInlineStyle($matches, $content)
345
  {
346
  // ** matches[0] = url('xx') matches[1] the img URL.
347
  // preg_match_all('/url\(\'(.*)\'\)/imU', $match, $matches);
362
  continue;
363
 
364
  $url = $match[1];
365
+ //$parsed_url = parse_url($url);
366
  $filename = basename($url);
367
 
368
  $fileonly = pathinfo($url, PATHINFO_FILENAME);
387
  {
388
  $checkedFile = $imageBaseURL . $fileonly . '.webp';
389
  }
390
+ else
391
+ {
392
+ Log::addDebug('convertInlineStyle, no webp existing', $checkedFile);
393
+ }
394
 
395
  if ($checkedFile)
396
  {
413
  ** @param String $src Image Source
414
  ** @returns String The Image Base
415
  **/
416
+ public function getImageBase($src)
417
  {
418
  $urlParsed = parse_url($src);
419
  if(!isset($urlParsed['host'])) {
454
 
455
  if ($srcHost[0] == $baseurlHost[0] && $srcHost[1] == $baseurlHost[1]
456
  && (strlen($srcHost[1]) > 3 || isset($srcHost[2]) && isset($srcHost[2]) && $srcHost[2] == $baseurlHost[2])) {
 
457
  $baseurl = str_replace($baseParsed['scheme'] . '://' . $baseParsed['host'], $urlParsed['scheme'] . '://' . $urlParsed['host'], $updir['baseurl']);
458
  $imageBase = str_replace($baseurl, SHORTPIXEL_UPLOADS_BASE, $src);
459
  }
462
  }
463
  }
464
 
465
+ Log::addDebug('Webp Image Base found: ' . $imageBase);
466
  $imageBase = trailingslashit(dirname($imageBase));
467
  return $imageBase;
468
  }
469
 
470
+ public function get_attributes($image_node)
471
  {
472
  if (function_exists("mb_convert_encoding")) {
473
  $image_node = mb_convert_encoding($image_node, 'HTML-ENTITIES', 'UTF-8');
478
  Log::addWarn('Webp Active, but DomDocument class not found ( missing xmldom library )');
479
  return false;
480
  }
481
+ $dom = new \DOMDocument();
482
  @$dom->loadHTML($image_node);
483
  $image = $dom->getElementsByTagName('img')->item(0);
484
  $attributes = array();
500
  * @param $attribute_array
501
  * @return string
502
  */
503
+ public function create_attributes($attribute_array)
504
  {
505
  $attributes = '';
506
  foreach ($attribute_array as $attribute => $value) {
515
  * @param $image_url
516
  * @return array
517
  */
518
+ /* Seems not in use. @todo be removed later on.
519
+ public function url_to_attachment_id($image_url)
520
  {
521
  // Thx to https://github.com/kylereicks/picturefill.js.wp/blob/master/inc/class-model-picturefill-wp.php
522
  global $wpdb;
544
  $attachment_id = $wpdb->get_col($wpdb->prepare("SELECT ID FROM " . $prefix . "posts" . " WHERE guid='%s';", $original_image_url));
545
  }
546
  return !empty($attachment_id) ? $attachment_id[0] : false;
547
+ } */
548
  }
class/model/apikey_model.php CHANGED
@@ -76,7 +76,10 @@ class ApiKeyModel extends ShortPixelModel
76
  update_option($this->model['verifiedKey']['key'], $this->verifiedKey);
77
  update_option($this->model['redirectedSettings']['key'], $this->redirectedSettings);
78
  update_option($this->model['apiKeyTried']['key'], $this->apiKeyTried);
 
 
79
  Log::addDebug('Update Verified', array($this->apiKey, $this->verifiedKey));
 
80
  }
81
 
82
  /** Resets the last APIkey that was attempted with validation
@@ -218,6 +221,7 @@ class ApiKeyModel extends ShortPixelModel
218
  {
219
  $settingsObj = $this->shortPixel->getSettings();
220
  $lastStatus = $settingsObj->bulkLastStatus;
 
221
  if(isset($lastStatus['Status']) && $lastStatus['Status'] == \ShortPixelAPI::STATUS_NO_KEY) {
222
  $settingsObj->bulkLastStatus = null;
223
  }
@@ -243,6 +247,8 @@ class ApiKeyModel extends ShortPixelModel
243
  WP_CONTENT_DIR . '/' . SHORTPIXEL_UPLOADS_NAME );
244
  Notice::addError($notice);
245
  }
 
 
246
  }
247
 
248
 
76
  update_option($this->model['verifiedKey']['key'], $this->verifiedKey);
77
  update_option($this->model['redirectedSettings']['key'], $this->redirectedSettings);
78
  update_option($this->model['apiKeyTried']['key'], $this->apiKeyTried);
79
+
80
+
81
  Log::addDebug('Update Verified', array($this->apiKey, $this->verifiedKey));
82
+
83
  }
84
 
85
  /** Resets the last APIkey that was attempted with validation
221
  {
222
  $settingsObj = $this->shortPixel->getSettings();
223
  $lastStatus = $settingsObj->bulkLastStatus;
224
+
225
  if(isset($lastStatus['Status']) && $lastStatus['Status'] == \ShortPixelAPI::STATUS_NO_KEY) {
226
  $settingsObj->bulkLastStatus = null;
227
  }
247
  WP_CONTENT_DIR . '/' . SHORTPIXEL_UPLOADS_NAME );
248
  Notice::addError($notice);
249
  }
250
+
251
+ adminNoticesController::resetAPINotices();
252
  }
253
 
254
 
class/model/directory_model.php CHANGED
@@ -20,8 +20,6 @@ class DirectoryModel extends ShortPixelModel
20
  protected $is_writable = false;
21
  protected $is_readable = false;
22
 
23
-
24
-
25
  protected $new_directory_permission = 0755;
26
 
27
  /** Creates a directory model object. DirectoryModel directories don't need to exist on FileSystem
@@ -31,11 +29,7 @@ class DirectoryModel extends ShortPixelModel
31
  */
32
  public function __construct($path)
33
  {
34
- /* Check if realpath improves things. We support non-existing paths, which realpath fails on, so only apply on result.
35
- */
36
- $testpath = realpath($path);
37
- if ($testpath)
38
- $path = $testpath;
39
 
40
  $path = wp_normalize_path($path);
41
  if (! is_dir($path)) // path is wrong, *or* simply doesn't exist.
@@ -53,6 +47,16 @@ class DirectoryModel extends ShortPixelModel
53
  $path = dirname($path);
54
  }
55
 
 
 
 
 
 
 
 
 
 
 
56
  $this->path = trailingslashit($path);
57
  $this->name = basename($this->path);
58
 
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
  */
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.
47
  $path = dirname($path);
48
  }
49
 
50
+ if (! is_dir($path))
51
+ {
52
+ /* Check if realpath improves things. We support non-existing paths, which realpath fails on, so only apply on result.
53
+ Moved realpath to check after main pathinfo is set. Reason is that symlinked directories which don't include the WordPress upload dir will start to fail in file_model on processpath ( doesn't see it as a wp path, starts to try relative path). Not sure if realpath should be used anyhow in this model /BS
54
+ */
55
+ $testpath = realpath($path);
56
+ if ($testpath)
57
+ $path = $testpath;
58
+ }
59
+
60
  $this->path = trailingslashit($path);
61
  $this->name = basename($this->path);
62
 
class/model/environment_model.php CHANGED
@@ -29,6 +29,7 @@ class EnvironmentModel extends ShortPixelModel
29
  private $screen_is_set = false;
30
  public $is_screen_to_use = false; // where shortpixel optimizer loads
31
  public $is_our_screen = false; // where shortpixel hooks in more complicated functions.
 
32
 
33
  // Debug flag
34
  public $is_debug = false;
@@ -136,8 +137,13 @@ class EnvironmentModel extends ShortPixelModel
136
  {
137
  $this->is_screen_to_use = true;
138
  $this->is_our_screen = true;
 
 
 
139
  }
140
 
 
 
141
  $this->screen_is_set = true;
142
  }
143
 
29
  private $screen_is_set = false;
30
  public $is_screen_to_use = false; // where shortpixel optimizer loads
31
  public $is_our_screen = false; // where shortpixel hooks in more complicated functions.
32
+ public $is_bulk_page = false; // Shortpixel bulk screen.
33
 
34
  // Debug flag
35
  public $is_debug = false;
137
  {
138
  $this->is_screen_to_use = true;
139
  $this->is_our_screen = true;
140
+
141
+ if ($screen->id == 'media_page_wp-short-pixel-bulk')
142
+ $this->is_bulk_page = true;
143
  }
144
 
145
+
146
+
147
  $this->screen_is_set = true;
148
  }
149
 
class/model/file_model.php CHANGED
@@ -53,16 +53,13 @@ class FileModel extends ShortPixelModel
53
 
54
  protected function setFileInfo()
55
  {
56
-
57
  $processed_path = $this->processPath($this->fullpath);
58
  if ($processed_path !== false)
59
  $this->fullpath = $processed_path; // set processed path if that went alright
60
 
61
- /* else {
62
- $this->fullpath = $path; // fallback, but there should be error state
63
- } */
64
 
65
- $info = pathinfo($this->fullpath);
 
66
  // Todo, maybe replace this with splFileINfo.
67
  if ($this->is_file()) // only set fileinfo when it's an actual file.
68
  {
@@ -118,7 +115,7 @@ class FileModel extends ShortPixelModel
118
  //$pathinfo = pathinfo($this->fullpath);
119
  //if (isset($pathinfo['extension'])) // extension means file.
120
 
121
- // if file does not exist on disk, anything can become a file ( with/ without extension, etc). Meaning everything non-existing is a potential file ( or directory ) until created.
122
  $this->is_file = true;
123
 
124
  }
@@ -292,6 +289,7 @@ class FileModel extends ShortPixelModel
292
  {
293
  if (is_null($this->getFileDir()))
294
  {
 
295
  return false;
296
  }
297
  if (is_null($this->backupDirectory))
@@ -301,8 +299,10 @@ class FileModel extends ShortPixelModel
301
  $directory = new DirectoryModel($backupDirectory);
302
 
303
  if (! $directory->exists()) // check if exists. FileModel should not attempt to create.
 
 
304
  return false;
305
-
306
  $this->backupDirectory = $directory;
307
  }
308
 
@@ -334,7 +334,6 @@ class FileModel extends ShortPixelModel
334
  if (strpos($path, ABSPATH) === false && strpos($path, $uploadPath) === false)
335
  $path = $this->relativeToFullPath($path);
336
 
337
-
338
  $path = apply_filters('shortpixel/filesystem/processFilePath', $path, $original_path);
339
  /* This needs some check here on malformed path's, but can't be test for existing since that's not a requirement.
340
  if (file_exists($path) === false) // failed to process path to something workable.
@@ -433,6 +432,46 @@ class FileModel extends ShortPixelModel
433
  return $basedir;
434
  }
435
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
436
  } // FileModel Class
437
 
438
  /*
53
 
54
  protected function setFileInfo()
55
  {
 
56
  $processed_path = $this->processPath($this->fullpath);
57
  if ($processed_path !== false)
58
  $this->fullpath = $processed_path; // set processed path if that went alright
59
 
 
 
 
60
 
61
+ $info = $this->mb_pathinfo($this->fullpath);
62
+
63
  // Todo, maybe replace this with splFileINfo.
64
  if ($this->is_file()) // only set fileinfo when it's an actual file.
65
  {
115
  //$pathinfo = pathinfo($this->fullpath);
116
  //if (isset($pathinfo['extension'])) // extension means file.
117
 
118
+ // if file does not exist on disk, anything can become a file ( with/ without extension, etc). Meaning everything non-existing is a potential file ( or directory ) until created.
119
  $this->is_file = true;
120
 
121
  }
289
  {
290
  if (is_null($this->getFileDir()))
291
  {
292
+ Log::addWarn('Could not establish FileDir ' . $this->fullpath);
293
  return false;
294
  }
295
  if (is_null($this->backupDirectory))
299
  $directory = new DirectoryModel($backupDirectory);
300
 
301
  if (! $directory->exists()) // check if exists. FileModel should not attempt to create.
302
+ {
303
+ Log::addWarn('Backup Directory not existing ' . $backupDirectory);
304
  return false;
305
+ }
306
  $this->backupDirectory = $directory;
307
  }
308
 
334
  if (strpos($path, ABSPATH) === false && strpos($path, $uploadPath) === false)
335
  $path = $this->relativeToFullPath($path);
336
 
 
337
  $path = apply_filters('shortpixel/filesystem/processFilePath', $path, $original_path);
338
  /* This needs some check here on malformed path's, but can't be test for existing since that's not a requirement.
339
  if (file_exists($path) === false) // failed to process path to something workable.
432
  return $basedir;
433
  }
434
 
435
+ /** Fix for multibyte pathnames and pathinfo which doesn't take into regard the locale.
436
+ * This snippet taken from PHPMailer.
437
+ */
438
+ private function mb_pathinfo($path, $options = null)
439
+ {
440
+ $ret = ['dirname' => '', 'basename' => '', 'extension' => '', 'filename' => ''];
441
+ $pathinfo = [];
442
+ if (preg_match('#^(.*?)[\\\\/]*(([^/\\\\]*?)(\.([^.\\\\/]+?)|))[\\\\/.]*$#m', $path, $pathinfo)) {
443
+ if (array_key_exists(1, $pathinfo)) {
444
+ $ret['dirname'] = $pathinfo[1];
445
+ }
446
+ if (array_key_exists(2, $pathinfo)) {
447
+ $ret['basename'] = $pathinfo[2];
448
+ }
449
+ if (array_key_exists(5, $pathinfo)) {
450
+ $ret['extension'] = $pathinfo[5];
451
+ }
452
+ if (array_key_exists(3, $pathinfo)) {
453
+ $ret['filename'] = $pathinfo[3];
454
+ }
455
+ }
456
+ switch ($options) {
457
+ case PATHINFO_DIRNAME:
458
+ case 'dirname':
459
+ return $ret['dirname'];
460
+ case PATHINFO_BASENAME:
461
+ case 'basename':
462
+ return $ret['basename'];
463
+ case PATHINFO_EXTENSION:
464
+ case 'extension':
465
+ return $ret['extension'];
466
+ case PATHINFO_FILENAME:
467
+ case 'filename':
468
+ return $ret['filename'];
469
+ default:
470
+ return $ret;
471
+ }
472
+ }
473
+
474
+
475
  } // FileModel Class
476
 
477
  /*
class/shortpixel-png2jpg.php CHANGED
@@ -151,7 +151,7 @@ class ShortPixelPng2Jpg {
151
  }
152
  //unlink($image);
153
  $params['file'] = $newPath;
154
- WPShortPixel::log("original_file should be PNG: $image");
155
  $params['original_file'] = $image;
156
  $params['url'] = $newUrl;
157
  $params['type'] = 'image/jpeg';
@@ -261,7 +261,7 @@ class ShortPixelPng2Jpg {
261
  }
262
  if($this->isExcluded($meta)) { return; }
263
 
264
- WPShortPixel::log("Send to processing: Convert Media PNG to JPG #{$ID} META: " . json_encode($meta));
265
 
266
  $image = $meta['file']; // This is not a full path!
267
  $imageFile = $fs->getAttachedFile($ID);
@@ -515,7 +515,7 @@ class ShortPixelPng2Jpg {
515
  * @param bool|false $serialised
516
  * @return array|mixed|string
517
  */
518
- static function png2JpgUnserializeReplace( $from = '', $to = '', $data = '', $serialised = false ) {
519
  $replaced = false;
520
  try {
521
  if ( false !== is_serialized( $data ) ) {
151
  }
152
  //unlink($image);
153
  $params['file'] = $newPath;
154
+ Log::addDebug("Original_file should be PNG: $image");
155
  $params['original_file'] = $image;
156
  $params['url'] = $newUrl;
157
  $params['type'] = 'image/jpeg';
261
  }
262
  if($this->isExcluded($meta)) { return; }
263
 
264
+ Log::addDebug("Send to processing: Convert Media PNG to JPG #{$ID} META: " . json_encode($meta));
265
 
266
  $image = $meta['file']; // This is not a full path!
267
  $imageFile = $fs->getAttachedFile($ID);
515
  * @param bool|false $serialised
516
  * @return array|mixed|string
517
  */
518
+ public static function png2JpgUnserializeReplace( $from = '', $to = '', $data = '', $serialised = false ) {
519
  $replaced = false;
520
  try {
521
  if ( false !== is_serialized( $data ) ) {
class/shortpixel-tools.php CHANGED
@@ -132,7 +132,146 @@ static public function formatBytes($bytes, $precision = 2) {
132
  }
133
  return false;
134
  }
135
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
136
 
137
  function ShortPixelVDD($v){
138
  return highlight_string("<?php\n\$data =\n" . var_export($v, true) . ";\n?>");
132
  }
133
  return false;
134
  }
135
+
136
+
137
+ public static function getConflictingPlugins() {
138
+ $settings = \wpSPIO()->settings();
139
+
140
+ $conflictPlugins = array(
141
+ 'WP Smush - Image Optimization'
142
+ => array(
143
+ 'action'=>'Deactivate',
144
+ 'data'=>'wp-smushit/wp-smush.php',
145
+ 'page'=>'wp-smush-bulk'
146
+ ),
147
+ 'Imagify Image Optimizer'
148
+ => array(
149
+ 'action'=>'Deactivate',
150
+ 'data'=>'imagify/imagify.php',
151
+ 'page'=>'imagify'
152
+ ),
153
+ 'Compress JPEG & PNG images (TinyPNG)'
154
+ => array(
155
+ 'action'=>'Deactivate',
156
+ 'data'=>'tiny-compress-images/tiny-compress-images.php',
157
+ 'page'=>'tinify'
158
+ ),
159
+ 'Kraken.io Image Optimizer'
160
+ => array(
161
+ 'action'=>'Deactivate',
162
+ 'data'=>'kraken-image-optimizer/kraken.php',
163
+ 'page'=>'wp-krakenio'
164
+ ),
165
+ 'Optimus - WordPress Image Optimizer'
166
+ => array(
167
+ 'action'=>'Deactivate',
168
+ 'data'=>'optimus/optimus.php',
169
+ 'page'=>'optimus'
170
+ ),
171
+ 'EWWW Image Optimizer'
172
+ => array(
173
+ 'action'=>'Deactivate',
174
+ 'data'=>'ewww-image-optimizer/ewww-image-optimizer.php',
175
+ 'page'=>'ewww-image-optimizer%2F'
176
+ ),
177
+ 'EWWW Image Optimizer Cloud'
178
+ => array(
179
+ 'action'=>'Deactivate',
180
+ 'data'=>'ewww-image-optimizer-cloud/ewww-image-optimizer-cloud.php',
181
+ 'page'=>'ewww-image-optimizer-cloud%2F'
182
+ ),
183
+ 'ImageRecycle pdf & image compression'
184
+ => array(
185
+ 'action'=>'Deactivate',
186
+ 'data'=>'imagerecycle-pdf-image-compression/wp-image-recycle.php',
187
+ 'page'=>'option-image-recycle'
188
+ ),
189
+ 'CheetahO Image Optimizer'
190
+ => array(
191
+ 'action'=>'Deactivate',
192
+ 'data'=>'cheetaho-image-optimizer/cheetaho.php',
193
+ 'page'=>'cheetaho'
194
+ ),
195
+ 'Zara 4 Image Compression'
196
+ => array(
197
+ 'action'=>'Deactivate',
198
+ 'data'=>'zara-4/zara-4.php',
199
+ 'page'=>'zara-4'
200
+ ),
201
+ 'CW Image Optimizer'
202
+ => array(
203
+ 'action'=>'Deactivate',
204
+ 'data'=>'cw-image-optimizer/cw-image-optimizer.php',
205
+ 'page'=>'cw-image-optimizer'
206
+ ),
207
+ 'Simple Image Sizes'
208
+ => array(
209
+ 'action'=>'Deactivate',
210
+ 'data'=>'simple-image-sizes/simple_image_sizes.php'
211
+ ),
212
+ 'Regenerate Thumbnails and Delete Unused'
213
+ => array(
214
+ 'action' => 'Deactivate',
215
+ 'data' => 'regenerate-thumbnails-and-delete-unused/regenerate_wpregenerate.php',
216
+ ),
217
+ //DEACTIVATED TEMPORARILY - it seems that the customers get scared.
218
+ /* 'Jetpack by WordPress.com - The Speed up image load times Option'
219
+ => array(
220
+ 'action'=>'Change Setting',
221
+ 'data'=>'jetpack/jetpack.php',
222
+ 'href'=>'admin.php?page=jetpack#/settings'
223
+ )
224
+ */
225
+ );
226
+ if($settings->processThumbnails) {
227
+ $details = __('Details: recreating image files may require re-optimization of the resulting thumbnails, even if they were previously optimized. Please use <a href="https://wordpress.org/plugins/regenerate-thumbnails-advanced/" target="_blank">reGenerate Thumbnails Advanced</a> instead.','shortpixel-image-optimiser');
228
+
229
+ $conflictPlugins = array_merge($conflictPlugins, array(
230
+ 'Regenerate Thumbnails'
231
+ => array(
232
+ 'action'=>'Deactivate',
233
+ 'data'=>'regenerate-thumbnails/regenerate-thumbnails.php',
234
+ 'page'=>'regenerate-thumbnails',
235
+ 'details' => $details
236
+ ),
237
+ 'Force Regenerate Thumbnails'
238
+ => array(
239
+ 'action'=>'Deactivate',
240
+ 'data'=>'force-regenerate-thumbnails/force-regenerate-thumbnails.php',
241
+ 'page'=>'force-regenerate-thumbnails',
242
+ 'details' => $details
243
+ )
244
+ ));
245
+ }
246
+ if(!$settings->frontBootstrap){
247
+ $conflictPlugins['Bulk Images to Posts Frontend'] = array (
248
+ 'action'=>'Change Setting',
249
+ 'data'=>'bulk-images-to-posts-front/bulk-images-to-posts.php',
250
+ 'href'=>'options-general.php?page=wp-shortpixel-settings&part=adv-settings#siteAuthUser',
251
+ 'details' => __('This plugin is uploading images in front-end so please activate the "Process in front-end" advanced option in ShortPixel in order to have your images optimized.','shortpixel-image-optimiser')
252
+ );
253
+ }
254
+
255
+ $found = array();
256
+ foreach($conflictPlugins as $name => $path) {
257
+ $action = ( isset($path['action']) ) ? $path['action'] : null;
258
+ $data = ( isset($path['data']) ) ? $path['data'] : null;
259
+ $href = ( isset($path['href']) ) ? $path['href'] : null;
260
+ $page = ( isset($path['page']) ) ? $path['page'] : null;
261
+ $details = ( isset($path['details']) ) ? $path['details'] : null;
262
+ if(is_plugin_active($data)) {
263
+ if( $data == 'jetpack/jetpack.php' ){
264
+ $jetPackPhoton = get_option('jetpack_active_modules') ? in_array('photon', get_option('jetpack_active_modules')) : false;
265
+ if( !$jetPackPhoton ){ continue; }
266
+ }
267
+ $found[] = array( 'name' => $name, 'action'=> $action, 'path' => $data, 'href' => $href , 'page' => $page, 'details' => $details);
268
+ }
269
+ }
270
+ return $found;
271
+ }
272
+
273
+
274
+ } // class
275
 
276
  function ShortPixelVDD($v){
277
  return highlight_string("<?php\n\$data =\n" . var_export($v, true) . ";\n?>");
class/view/settings/part-cloudflare.php CHANGED
@@ -1,5 +1,6 @@
1
  <?php
2
  namespace ShortPixel;
 
3
  ?>
4
 
5
  <section id="tab-cloudflare" <?php echo ($this->display_part == 'cloudflare') ? ' class="sel-tab" ' :''; ?>>
@@ -18,42 +19,66 @@ namespace ShortPixel;
18
 
19
  <table class="form-table">
20
  <tbody>
 
 
 
 
 
 
 
 
 
 
 
 
 
21
  <tr>
22
- <th scope="row">
23
- <label for="cloudflare-email"><?php _e('Cloudflare E-mail:', 'shortpixel-image-optimiser'); ?></label>
24
- </th>
25
- <td>
26
- <input name="cloudflareEmail" type="text" id="cloudflare-email" <?php echo(! $this->is_curl_installed ? 'disabled' : '');?>
27
- value="<?php echo( stripslashes(esc_html($view->data->cloudflareEmail))); ?>" class="regular-text">
28
- <p class="settings-info">
29
- <?php _e('The e-mail address you use to login to CloudFlare.','shortpixel-image-optimiser');?>
30
- </p>
31
- </td>
32
  </tr>
 
33
  <tr>
34
- <th scope="row"><label
35
- for="cloudflare-auth-key"><?php _e('Global API Key:', 'shortpixel-image-optimiser'); ?></label>
 
 
 
 
 
 
 
 
 
 
36
  </th>
37
- <td>
38
- <input name="cloudflareAuthKey" type="text" id="cloudflare-auth-key" <?php echo(! $this->is_curl_installed ? 'disabled' : '');?>
39
- value="<?php echo(stripslashes(esc_html($view->data->cloudflareAuthKey))); ?>" class="regular-text">
 
 
 
 
 
 
 
40
  <p class="settings-info">
41
  <?php _e("This can be found when you're logged into your account, on the My Profile page:",'shortpixel-image-optimiser');?> <a href='https://www.cloudflare.com/a/profile' target='_blank'>https://www.cloudflare.com/a/profile</a>
42
  </p>
43
  </td>
44
  </tr>
45
- <tr>
46
- <th scope="row"><label
47
- for="cloudflare-zone-id"><?php _e('Zone ID:', 'shortpixel-image-optimiser'); ?></label>
48
  </th>
49
  <td>
50
- <input name="cloudflareZoneID" type="text" id="cloudflare-zone-id" <?php echo(! $this->is_curl_installed ? 'disabled' : '');?>
51
- value="<?php echo(stripslashes(esc_html($view->data->cloudflareZoneID))); ?>" class="regular-text">
52
  <p class="settings-info">
53
- <?php _e('This can be found in your Cloudflare account in the "Overview" section for your domain.','shortpixel-image-optimiser');?>
54
  </p>
55
  </td>
56
  </tr>
 
57
  </tbody>
58
  </table>
59
  <p class="submit">
@@ -62,5 +87,22 @@ namespace ShortPixel;
62
  value="<?php _e('Save Changes', 'shortpixel-image-optimiser'); ?>"> &nbsp;
63
  </p>
64
  </div>
 
65
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
  </section>
1
  <?php
2
  namespace ShortPixel;
3
+
4
  ?>
5
 
6
  <section id="tab-cloudflare" <?php echo ($this->display_part == 'cloudflare') ? ' class="sel-tab" ' :''; ?>>
19
 
20
  <table class="form-table">
21
  <tbody>
22
+ <tr>
23
+ <th scope="row"><label
24
+ for="cloudflare-zone-id"><?php _e('Zone ID:', 'shortpixel-image-optimiser'); ?></label>
25
+ </th>
26
+ <td>
27
+ <input name="cloudflareZoneID" type="text" id="cloudflare-zone-id" <?php echo(! $this->is_curl_installed ? 'disabled' : '');?>
28
+ value="<?php echo(stripslashes(esc_html($view->data->cloudflareZoneID))); ?>" class="regular-text">
29
+ <p class="settings-info">
30
+ <?php _e('This can be found in your Cloudflare account in the "Overview" section for your domain.','shortpixel-image-optimiser');?>
31
+ </p>
32
+ </td>
33
+ </tr>
34
+
35
  <tr>
36
+ <th scope="row">&nbsp;</th>
37
+ <td><h3><?php _e('Cloudflare Authentication', 'shortpixel-image-optimiser'); ?></h3></td>
 
 
 
 
 
 
 
 
38
  </tr>
39
+
40
  <tr>
41
+ <th scope="row" class='cf_switch'>
42
+ <?php
43
+ $token_checked = (strlen($view->data->cloudflareToken) > 0) ? 'checked' : '';
44
+ $global_checked = (strlen($view->data->cloudflareAuthKey) > 0) ? 'checked' : '';
45
+
46
+ if ($token_checked == '' && $global_checked == '')
47
+ $token_checked = 'checked'; // default.
48
+
49
+
50
+ ?>
51
+ <label><input type='radio' name='cf_auth_switch' value='token' <?php echo $token_checked ?> ><span><?php _e('Cloudflare Token', 'shortpixel-image-optimiser'); ?></span></label>
52
+ <label><input type='radio' name='cf_auth_switch' value='global' <?php echo $global_checked ?> ><span><?php _e('Global API Key', 'shortpixel-image-optimiser') ?></span></label>
53
  </th>
54
+ <td class='token-cell'>
55
+ <input name="cloudflareToken" type="text" id="cloudflare-token" <?php echo(! $this->is_curl_installed ? 'disabled' : '');?> value="<?php echo $view->data->cloudflareToken ?>" class='regular-text' autocomplete="off">
56
+ <p class='settings-info'><?php printf(__('%s Preferred Method %s. Enter your %s site token %s for authentication. This token needs %s Cache Purge permission %s! ', 'shortpixel-image-optimiser'), '<b>', '</b>', '<a href="https://dash.cloudflare.com/profile/api-tokens" target="_blank">', '</a>', '<a href="https://shortpixel.helpscoutdocs.com/article/325-using-shortpixel-image-optimizer-with-cloudflare-api-token" target="_blank">', '</a>'); ?></p>
57
+ <p class='settings-info'><?php _e('When using a token, leave the email and global API key fields empty.', 'shortpixel-image-optimiser'); ?>
58
+ <a href="https://shortpixel.helpscoutdocs.com/article/325-using-shortpixel-image-optimizer-with-cloudflare-api-token/" target="_blank" class="shortpixel-help-link">
59
+ <span class="dashicons dashicons-editor-help"></span><?php _e('How to set it up','shortpixel-image-optimiser');?>
60
+ </a></p>
61
+ </td>
62
+ <td class='authkey-cell'>
63
+ <input name="cloudflareAuthKey" type="text" id="cloudflare-auth-key" <?php echo(! $this->is_curl_installed ? 'disabled' : '');?> value="<?php echo(stripslashes(esc_html($view->data->cloudflareAuthKey))); ?>" class="regular-text" autocomplete="off">
64
  <p class="settings-info">
65
  <?php _e("This can be found when you're logged into your account, on the My Profile page:",'shortpixel-image-optimiser');?> <a href='https://www.cloudflare.com/a/profile' target='_blank'>https://www.cloudflare.com/a/profile</a>
66
  </p>
67
  </td>
68
  </tr>
69
+ <tr class='email-cell'>
70
+ <th scope="row">
71
+ <label for="cloudflare-email"><?php _e('Cloudflare E-mail:', 'shortpixel-image-optimiser'); ?></label>
72
  </th>
73
  <td>
74
+ <input name="cloudflareEmail" type="text" id="cloudflare-email" <?php echo(! $this->is_curl_installed ? 'disabled' : '');?>
75
+ value="<?php echo( stripslashes(esc_html($view->data->cloudflareEmail))); ?>" class="regular-text">
76
  <p class="settings-info">
77
+ <?php _e('The e-mail address you use to login to CloudFlare.','shortpixel-image-optimiser');?>
78
  </p>
79
  </td>
80
  </tr>
81
+
82
  </tbody>
83
  </table>
84
  <p class="submit">
87
  value="<?php _e('Save Changes', 'shortpixel-image-optimiser'); ?>"> &nbsp;
88
  </p>
89
  </div>
90
+ <script language="javascript">
91
 
92
+ function switchCF()
93
+ {
94
+ if ( jQuery('input[name="cf_auth_switch"]:checked').val() == 'token')
95
+ {
96
+ jQuery('.authkey-cell, .email-cell').hide();
97
+ jQuery('.token-cell').show();
98
+ }
99
+ else
100
+ {
101
+ jQuery('.token-cell').hide();
102
+ jQuery('.authkey-cell, .email-cell').show();
103
+ }
104
+ }
105
+ switchCF();
106
+ jQuery('input[name="cf_auth_switch"]').on('change', switchCF);
107
+ </script>
108
  </section>
class/view/settings/part-debug.php CHANGED
@@ -1,8 +1,10 @@
1
  <?php
2
  namespace ShortPixel;
 
3
 
4
  $path = '/var/www/shortpixel/wp-content/uploads/2019/09/';
5
 
 
6
  ?>
7
 
8
  <section id="tab-debug" <?php echo ($this->display_part == 'debug') ? ' class="sel-tab" ' :''; ?>>
1
  <?php
2
  namespace ShortPixel;
3
+ use ShortPixel\Notices\NoticeController as Notices;
4
 
5
  $path = '/var/www/shortpixel/wp-content/uploads/2019/09/';
6
 
7
+
8
  ?>
9
 
10
  <section id="tab-debug" <?php echo ($this->display_part == 'debug') ? ' class="sel-tab" ' :''; ?>>
class/view/settings/part-general.php CHANGED
@@ -120,6 +120,10 @@
120
  <p class="settings-info"><?php _e('You <strong>need to have backup active</strong> in order to be able to restore images to originals or to convert from Lossy to Lossless and back.','shortpixel-image-optimiser');?></p>
121
  </td>
122
  </tr>
 
 
 
 
123
  <tr>
124
  <th scope="row"><?php _e('Remove EXIF','shortpixel-image-optimiser');?></th>
125
  <td>
120
  <p class="settings-info"><?php _e('You <strong>need to have backup active</strong> in order to be able to restore images to originals or to convert from Lossy to Lossless and back.','shortpixel-image-optimiser');?></p>
121
  </td>
122
  </tr>
123
+ <tr class='view-notice-row backup_warning'>
124
+ <th scope='row'>&nbsp;</th>
125
+ <td><div class='view-notice warning'><p><?php _e('Make sure you have a backup in place. When optimizing Shortpixel will overwrite your images without recovery. This may result in lost images.', 'shortpixel-image-optimiser') ?></p></div></td>
126
+ </tr>
127
  <tr>
128
  <th scope="row"><?php _e('Remove EXIF','shortpixel-image-optimiser');?></th>
129
  <td>
class/view/shortpixel_view.php CHANGED
@@ -16,8 +16,11 @@ class ShortPixelView {
16
  $this->__construct($controller);
17
  }
18
 
 
19
  public function displayQuotaExceededAlert($quotaData, $averageCompression = false, $recheck = false)
20
- { ?>
 
 
21
  <br/>
22
  <div class="wrap sp-quota-exceeded-alert" id="short-pixel-notice-exceed">
23
  <?php if($averageCompression) { ?>
@@ -68,6 +71,7 @@ class ShortPixelView {
68
  </div> <?php self::includeProposeUpgradePopup();
69
  }
70
 
 
71
  public static function displayApiKeyAlert()
72
  { ?>
73
  <p><?php _e('In order to start the optimization process, you need to validate your API Key in the '
@@ -129,7 +133,7 @@ class ShortPixelView {
129
  ?></h3> <?php
130
  switch($when) {
131
  case '2h' :
132
- _e("Action needed. Please <a href='https://shortpixel.com/wp-apikey' target='_blank'>get your API key</a> to activate your ShortPixel plugin.",'shortpixel-image-optimiser') . "<BR><BR>";
133
  break;
134
  case '3d':
135
  _e("Your image gallery is not optimized. It takes 2 minutes to <a href='https://shortpixel.com/wp-apikey' target='_blank'>get your API key</a> and activate your ShortPixel plugin.",'shortpixel-image-optimiser') . "<BR><BR>";
@@ -190,6 +194,9 @@ class ShortPixelView {
190
  </div>
191
  <?php
192
  }
 
 
 
193
  protected static function includeProposeUpgradePopup() {
194
  wp_enqueue_style('short-pixel-modal.min.css', plugins_url('/res/css/short-pixel-modal.min.css',SHORTPIXEL_PLUGIN_FILE), array(), SHORTPIXEL_IMAGE_OPTIMISER_VERSION);
195
  ?>
@@ -205,6 +212,7 @@ class ShortPixelView {
205
  </div>
206
  </div>
207
  <?php }
 
208
 
209
  public function displayBulkProcessingForm($quotaData, $thumbsProcessedCount, $under5PercentCount, $bulkRan,
210
  $averageCompression, $filesOptimized, $savedSpace, $percent, $customCount) {
@@ -1691,7 +1699,7 @@ class ShortPixelView {
1691
  }
1692
  return;
1693
  }
1694
-
1695
  ?>
1696
  <div id='sp-msg-<?php echo($id);?>' class='column-wp-shortPixel'>
1697
 
16
  $this->__construct($controller);
17
  }
18
 
19
+ /** @todo REMOVE this from this view. Moved to adminnotices controller */
20
  public function displayQuotaExceededAlert($quotaData, $averageCompression = false, $recheck = false)
21
+ {
22
+ return; // no longer active.
23
+ ?>
24
  <br/>
25
  <div class="wrap sp-quota-exceeded-alert" id="short-pixel-notice-exceed">
26
  <?php if($averageCompression) { ?>
71
  </div> <?php self::includeProposeUpgradePopup();
72
  }
73
 
74
+ /*
75
  public static function displayApiKeyAlert()
76
  { ?>
77
  <p><?php _e('In order to start the optimization process, you need to validate your API Key in the '
133
  ?></h3> <?php
134
  switch($when) {
135
  case '2h' :
136
+ _e("Action needed. Please <a href='https://shortpixel.com/wp-apikey' target='_blank'>get your API key</a> to activate your ShortPixel plugin.",'shortpixel-image-optimiser');
137
  break;
138
  case '3d':
139
  _e("Your image gallery is not optimized. It takes 2 minutes to <a href='https://shortpixel.com/wp-apikey' target='_blank'>get your API key</a> and activate your ShortPixel plugin.",'shortpixel-image-optimiser') . "<BR><BR>";
194
  </div>
195
  <?php
196
  }
197
+ */
198
+
199
+ /*
200
  protected static function includeProposeUpgradePopup() {
201
  wp_enqueue_style('short-pixel-modal.min.css', plugins_url('/res/css/short-pixel-modal.min.css',SHORTPIXEL_PLUGIN_FILE), array(), SHORTPIXEL_IMAGE_OPTIMISER_VERSION);
202
  ?>
212
  </div>
213
  </div>
214
  <?php }
215
+ */
216
 
217
  public function displayBulkProcessingForm($quotaData, $thumbsProcessedCount, $under5PercentCount, $bulkRan,
218
  $averageCompression, $filesOptimized, $savedSpace, $percent, $customCount) {
1699
  }
1700
  return;
1701
  }
1702
+
1703
  ?>
1704
  <div id='sp-msg-<?php echo($id);?>' class='column-wp-shortPixel'>
1705
 
class/view/view-edit-media.php CHANGED
@@ -6,7 +6,7 @@ use ShortPixel\ShortpixelLogger\ShortPixelLogger as Log;
6
 
7
  <div id='sp-msg-<?php echo($view->id);?>' class='column-wp-shortPixel view-edit-media'>
8
  <?php // Debug Data
9
- if (! is_null($view->debugInfo)): ?>
10
  <div class='debugInfo' id='debugInfo'>
11
  <a class='debugModal' data-modal="debugInfo" ><?php _e('Debug Window', 'shortpixel-image-optimiser') ?></a>
12
  <div class='content wrapper'>
6
 
7
  <div id='sp-msg-<?php echo($view->id);?>' class='column-wp-shortPixel view-edit-media'>
8
  <?php // Debug Data
9
+ if (! is_null($view->debugInfo) && is_array($view->debugInfo) && count($view->debugInfo) > 0 ): ?>
10
  <div class='debugInfo' id='debugInfo'>
11
  <a class='debugModal' data-modal="debugInfo" ><?php _e('Debug Window', 'shortpixel-image-optimiser') ?></a>
12
  <div class='content wrapper'>
class/view/view-settings.php CHANGED
@@ -13,7 +13,7 @@ HelpScout::outputBeacon($this->hide_api_key ? '' : $view->data->apiKey);
13
  echo(($view->data->apiKey ? "login/".( $this->hide_api_key ? '' : $view->data->apiKey) : "pricing"));
14
  ?>" target="_blank">
15
  <?php _e('Upgrade now','shortpixel-image-optimiser');?>
16
- </a> | <a href="https://shortpixel.com/pricing>#faq" target="_blank"><?php _e('FAQ','shortpixel-image-optimiser');?> </a> |
17
  <a href="https://shortpixel.com/contact" target="_blank"><?php _e('Support','shortpixel-image-optimiser');?> </a>
18
  </p>
19
 
@@ -34,7 +34,10 @@ HelpScout::outputBeacon($this->hide_api_key ? '' : $view->data->apiKey);
34
  <?php
35
  $this->loadView('settings/part-general');
36
  $this->loadView('settings/part-advanced');
37
- $this->loadView('settings/part-cloudflare');
 
 
 
38
  if ($view->averageCompression !== null)
39
  {
40
  $this->loadView('settings/part-statistics');
13
  echo(($view->data->apiKey ? "login/".( $this->hide_api_key ? '' : $view->data->apiKey) : "pricing"));
14
  ?>" target="_blank">
15
  <?php _e('Upgrade now','shortpixel-image-optimiser');?>
16
+ </a> | <a href="https://shortpixel.com/pricing#faq" target="_blank"><?php _e('FAQ','shortpixel-image-optimiser');?> </a> |
17
  <a href="https://shortpixel.com/contact" target="_blank"><?php _e('Support','shortpixel-image-optimiser');?> </a>
18
  </p>
19
 
34
  <?php
35
  $this->loadView('settings/part-general');
36
  $this->loadView('settings/part-advanced');
37
+ if (! $this->view->cloudflare_constant)
38
+ {
39
+ $this->loadView('settings/part-cloudflare');
40
+ }
41
  if ($view->averageCompression !== null)
42
  {
43
  $this->loadView('settings/part-statistics');
class/wp-short-pixel.php CHANGED
@@ -41,7 +41,7 @@ class WPShortPixel {
41
 
42
  $this->_settings = new WPShortPixelSettings();
43
  $this->_apiInterface = new ShortPixelAPI($this->_settings);
44
- $this->cloudflareApi = new ShortPixelCloudFlareApi($this->_settings->cloudflareEmail, $this->_settings->cloudflareAuthKey, $this->_settings->cloudflareZoneID);
45
  $this->hasNextGen = wpSPIO()->env()->has_nextgen; //ShortPixelNextGenAdapter::hasNextGen();
46
  $this->spMetaDao = new ShortPixelCustomMetaDao(new WpShortPixelDb(), $this->_settings->excludePatterns);
47
  $this->prioQ = (! defined('SHORTPIXEL_NOFLOCK')) ? new ShortPixelQueue($this, $this->_settings) : new ShortPixelQueueDB($this, $this->_settings);
@@ -166,8 +166,12 @@ class WPShortPixel {
166
  //check status
167
  add_action( 'wp_ajax_shortpixel_check_status', array(&$this, 'checkStatus'));
168
  //dismiss notices
169
- add_action( 'wp_ajax_shortpixel_dismiss_notice', array(&$this, 'dismissAdminNotice'));
170
- add_action( 'wp_ajax_shortpixel_dismiss_media_alert', array(&$this, 'dismissMediaAlert'));
 
 
 
 
171
  //check quota
172
  add_action('wp_ajax_shortpixel_check_quota', array(&$this, 'handleCheckQuota'));
173
  add_action('admin_action_shortpixel_check_quota', array(&$this, 'handleCheckQuota'));
@@ -241,155 +245,22 @@ class WPShortPixel {
241
  }
242
  } */
243
 
244
- public function getConflictingPlugins() {
245
- $conflictPlugins = array(
246
- 'WP Smush - Image Optimization'
247
- => array(
248
- 'action'=>'Deactivate',
249
- 'data'=>'wp-smushit/wp-smush.php',
250
- 'page'=>'wp-smush-bulk'
251
- ),
252
- 'Imagify Image Optimizer'
253
- => array(
254
- 'action'=>'Deactivate',
255
- 'data'=>'imagify/imagify.php',
256
- 'page'=>'imagify'
257
- ),
258
- 'Compress JPEG & PNG images (TinyPNG)'
259
- => array(
260
- 'action'=>'Deactivate',
261
- 'data'=>'tiny-compress-images/tiny-compress-images.php',
262
- 'page'=>'tinify'
263
- ),
264
- 'Kraken.io Image Optimizer'
265
- => array(
266
- 'action'=>'Deactivate',
267
- 'data'=>'kraken-image-optimizer/kraken.php',
268
- 'page'=>'wp-krakenio'
269
- ),
270
- 'Optimus - WordPress Image Optimizer'
271
- => array(
272
- 'action'=>'Deactivate',
273
- 'data'=>'optimus/optimus.php',
274
- 'page'=>'optimus'
275
- ),
276
- 'EWWW Image Optimizer'
277
- => array(
278
- 'action'=>'Deactivate',
279
- 'data'=>'ewww-image-optimizer/ewww-image-optimizer.php',
280
- 'page'=>'ewww-image-optimizer%2F'
281
- ),
282
- 'EWWW Image Optimizer Cloud'
283
- => array(
284
- 'action'=>'Deactivate',
285
- 'data'=>'ewww-image-optimizer-cloud/ewww-image-optimizer-cloud.php',
286
- 'page'=>'ewww-image-optimizer-cloud%2F'
287
- ),
288
- 'ImageRecycle pdf & image compression'
289
- => array(
290
- 'action'=>'Deactivate',
291
- 'data'=>'imagerecycle-pdf-image-compression/wp-image-recycle.php',
292
- 'page'=>'option-image-recycle'
293
- ),
294
- 'CheetahO Image Optimizer'
295
- => array(
296
- 'action'=>'Deactivate',
297
- 'data'=>'cheetaho-image-optimizer/cheetaho.php',
298
- 'page'=>'cheetaho'
299
- ),
300
- 'Zara 4 Image Compression'
301
- => array(
302
- 'action'=>'Deactivate',
303
- 'data'=>'zara-4/zara-4.php',
304
- 'page'=>'zara-4'
305
- ),
306
- 'CW Image Optimizer'
307
- => array(
308
- 'action'=>'Deactivate',
309
- 'data'=>'cw-image-optimizer/cw-image-optimizer.php',
310
- 'page'=>'cw-image-optimizer'
311
- ),
312
- 'Simple Image Sizes'
313
- => array(
314
- 'action'=>'Deactivate',
315
- 'data'=>'simple-image-sizes/simple_image_sizes.php'
316
- ),
317
- 'Regenerate Thumbnails and Delete Unused'
318
- => array(
319
- 'action' => 'Deactivate',
320
- 'data' => 'regenerate-thumbnails-and-delete-unused/regenerate_wpregenerate.php',
321
- ),
322
- //DEACTIVATED TEMPORARILY - it seems that the customers get scared.
323
- /* 'Jetpack by WordPress.com - The Speed up image load times Option'
324
- => array(
325
- 'action'=>'Change Setting',
326
- 'data'=>'jetpack/jetpack.php',
327
- 'href'=>'admin.php?page=jetpack#/settings'
328
- )
329
- */
330
- );
331
- if($this->_settings->processThumbnails) {
332
- $details = __('Details: recreating image files may require re-optimization of the resulting thumbnails, even if they were previously optimized. Please use <a href="https://wordpress.org/plugins/regenerate-thumbnails-advanced/" target="_blank">reGenerate Thumbnails Advanced</a> instead.','shortpixel-image-optimiser');
333
-
334
- $conflictPlugins = array_merge($conflictPlugins, array(
335
- 'Regenerate Thumbnails'
336
- => array(
337
- 'action'=>'Deactivate',
338
- 'data'=>'regenerate-thumbnails/regenerate-thumbnails.php',
339
- 'page'=>'regenerate-thumbnails',
340
- 'details' => $details
341
- ),
342
- 'Force Regenerate Thumbnails'
343
- => array(
344
- 'action'=>'Deactivate',
345
- 'data'=>'force-regenerate-thumbnails/force-regenerate-thumbnails.php',
346
- 'page'=>'force-regenerate-thumbnails',
347
- 'details' => $details
348
- )
349
- ));
350
- }
351
- if(!$this->_settings->frontBootstrap){
352
- $conflictPlugins['Bulk Images to Posts Frontend'] = array (
353
- 'action'=>'Change Setting',
354
- 'data'=>'bulk-images-to-posts-front/bulk-images-to-posts.php',
355
- 'href'=>'options-general.php?page=wp-shortpixel-settings&part=adv-settings#siteAuthUser',
356
- 'details' => __('This plugin is uploading images in front-end so please activate the "Process in front-end" advanced option in ShortPixel in order to have your images optimized.','shortpixel-image-optimiser')
357
- );
358
- }
359
-
360
- $found = array();
361
- foreach($conflictPlugins as $name => $path) {
362
- $action = ( isset($path['action']) ) ? $path['action'] : null;
363
- $data = ( isset($path['data']) ) ? $path['data'] : null;
364
- $href = ( isset($path['href']) ) ? $path['href'] : null;
365
- $page = ( isset($path['page']) ) ? $path['page'] : null;
366
- $details = ( isset($path['details']) ) ? $path['details'] : null;
367
- if(is_plugin_active($data)) {
368
- if( $data == 'jetpack/jetpack.php' ){
369
- $jetPackPhoton = get_option('jetpack_active_modules') ? in_array('photon', get_option('jetpack_active_modules')) : false;
370
- if( !$jetPackPhoton ){ continue; }
371
- }
372
- $found[] = array( 'name' => $name, 'action'=> $action, 'path' => $data, 'href' => $href , 'page' => $page, 'details' => $details);
373
- }
374
- }
375
- return $found;
376
- }
377
 
378
  /** Displays notices to admin, if there are any
379
  * TODO - Probably should be a controller
380
  */
381
  public function displayAdminNotices() {
382
- $testQ = (! defined('SHORTPIXEL_NOFLOCK')) ? ShortPixelQueue::testQ() : ShortPixelQueueDB::testQ();
383
  if(! $testQ) {
384
  ShortPixelView::displayActivationNotice('fileperms');
385
- }
386
- if($this->catchNotice()) { //notices for errors like for example a failed restore notice - these are one time so display them with priority.
387
- return;
388
- }
389
- $dismissed = $this->_settings->dismissedNotices ? $this->_settings->dismissedNotices : array();
390
- $this->_settings->dismissedNotices = $dismissed;
391
 
392
- if(!$this->_settings->verifiedKey) {
393
  $now = time();
394
  $act = $this->_settings->activationDate ? $this->_settings->activationDate : $now;
395
  if($this->_settings->activationNotice && $this->_settings->redirectedSettings >= 2) {
@@ -401,21 +272,21 @@ class WPShortPixel {
401
  } else if( ($now > $act + 72 * 3600) && !isset($dismissed['3d'])) {
402
  ShortPixelView::displayActivationNotice('3d');
403
  }
404
- }
405
- if(!isset($dismissed['compat'])) {
406
  $conflictPlugins = $this->getConflictingPlugins();
407
  if(count($conflictPlugins)) {
408
  ShortPixelView::displayActivationNotice('compat', $conflictPlugins);
409
  return;
410
  }
411
- }
412
- if( !isset($dismissed['unlisted']) && !$this->_settings->optimizeUnlisted
413
  && isset($this->_settings->currentStats['foundUnlistedThumbs']) && is_array($this->_settings->currentStats['foundUnlistedThumbs'])) {
414
  ShortPixelView::displayActivationNotice('unlisted', $this->_settings->currentStats['foundUnlistedThumbs']);
415
  return;
416
- }
417
  //if(false)
418
- $currentStats = $this->_settings->currentStats;
419
  if(!is_array($currentStats) || isset($_GET['checkquota']) || isset($currentStats["quotaData"])) {
420
  $this->getQuotaInformation();
421
  }
@@ -437,9 +308,10 @@ class WPShortPixel {
437
  //looks like the user hasn't got enough credits to process the monthly images, display a notice telling this
438
  ShortPixelView::displayActivationNotice('upgmonth', array('monthAvg' => $this->getMonthAvg($stats), 'monthlyQuota' => $quotaData['APICallsQuotaNumeric']));
439
  }
440
- }
441
  }
442
 
 
443
  public function dismissAdminNotice() {
444
  $noticeId = preg_replace('|[^a-z0-9]|i', '', $_GET['notice_id']);
445
  $dismissed = $this->_settings->dismissedNotices ? $this->_settings->dismissedNotices : array();
@@ -451,27 +323,20 @@ class WPShortPixel {
451
  die(json_encode(array("Status" => 'success', "Message" => 'Notice ID: ' . $noticeId . ' dismissed')));
452
  }
453
 
 
 
 
 
454
  public function dismissMediaAlert() {
455
  $this->_settings->mediaAlert = 1;
456
  die(json_encode(array("Status" => 'success', "Message" => __('Media alert dismissed','shortpixel-image-optimiser'))));
457
  }
458
 
459
- protected function getMonthAvg($stats) {
460
- for($i = 4, $count = 0; $i>=1; $i--) {
461
- if($count == 0 && $stats['totalM' . $i] == 0) continue;
462
- $count++;
463
- }
464
- return ($stats['totalM1'] + $stats['totalM2'] + $stats['totalM3'] + $stats['totalM4']) / max(1,$count);
465
- }
466
-
467
- protected function monthlyUpgradeNeeded($quotaData) {
468
- return isset($quotaData['APICallsQuotaNumeric']) && $this->getMonthAvg($quotaData) > $quotaData['APICallsQuotaNumeric'] + ($quotaData['APICallsQuotaOneTimeNumeric'] - $quotaData['APICallsMadeOneTimeNumeric'])/6 + 20;
469
  }
470
 
471
- protected function bulkUpgradeNeeded($stats) {
472
- $quotaData = $stats;
473
- return $stats['totalFiles'] - $stats['totalProcessedFiles'] > $quotaData['APICallsQuotaNumeric'] + $quotaData['APICallsQuotaOneTimeNumeric'] - $quotaData['APICallsMadeNumeric'] - $quotaData['APICallsMadeOneTimeNumeric'];
474
- }
475
 
476
  //set default move as "list". only set once, it won't try to set the default mode again.
477
  public function setDefaultViewModeList()
@@ -507,9 +372,12 @@ class WPShortPixel {
507
 
508
  if (! \wpSPIO()->env()->is_screen_to_use )
509
  {
510
- if (! wpSPIO()->env()->is_front) // exeception if this is called to load from your frontie.
511
  return; // not ours, don't load JS and such.
512
  }
 
 
 
513
  // load everywhere, because we are inconsistent.
514
  wp_enqueue_style('short-pixel-bar.min.css', plugins_url('/res/css/short-pixel-bar.min.css',SHORTPIXEL_PLUGIN_FILE), array(), SHORTPIXEL_IMAGE_OPTIMISER_VERSION);
515
 
@@ -678,10 +546,24 @@ class WPShortPixel {
678
  //$icon = "shortpixel-alert.png";
679
  }
680
  $lastStatus = $this->_settings->bulkLastStatus;
681
- if($lastStatus && $lastStatus['Status'] != ShortPixelAPI::STATUS_SUCCESS) {
682
  $extraClasses = " shortpixel-alert shortpixel-processing";
683
- $tooltip = $lastStatus['Message'];
684
  $successLink = $link = admin_url(current_user_can( 'edit_others_posts')? 'post.php?post=' . $lastStatus['ImageID'] . '&action=edit' : 'upload.php');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
685
  }
686
 
687
  $args = array(
@@ -693,6 +575,7 @@ class WPShortPixel {
693
  'meta' => array('target'=> $blank, 'class' => 'shortpixel-toolbar-processing' . $extraClasses)
694
  );
695
  $wp_admin_bar->add_node( $args );
 
696
  if($this->_settings->quotaExceeded && !isset($this->_settings->dismissedNotices['exceed'])) {
697
  $wp_admin_bar->add_node( array(
698
  'id' => 'shortpixel_processing-title',
@@ -700,13 +583,13 @@ class WPShortPixel {
700
  'title' => $exceedTooltip,
701
  'href' => $link
702
  ));
703
- $wp_admin_bar->add_node( array(
704
  'id' => 'shortpixel_processing-dismiss',
705
  'parent' => 'shortpixel_processing',
706
  'title' => '<div style="text-align: right;">Dismiss</div>',
707
  'href' => "#",
708
  'meta' => array('onclick'=> 'dismissShortPixelNoticeExceed(event)')
709
- ));
710
  }
711
  }
712
 
@@ -1334,11 +1217,7 @@ class WPShortPixel {
1334
  * @param String $ID ApiKey
1335
  */
1336
  public function handleImageProcessing($ID = null) {
1337
- //if(rand(1,2) == 2) {
1338
- // header($_SERVER['SERVER_PROTOCOL'] . ' 500 Internal Server Error', true, 500);
1339
- // die("za stop");
1340
- //}
1341
- //0: check key
1342
  $this->checkKey($ID);
1343
 
1344
  if($this->_settings->frontBootstrap && is_admin() && !ShortPixelTools::requestIsFrontendAjax()) {
@@ -1643,8 +1522,10 @@ class WPShortPixel {
1643
  }
1644
 
1645
  if($result["Status"] !== ShortPixelAPI::STATUS_RETRY) {
 
1646
  $this->_settings->bulkLastStatus = $result;
1647
  }
 
1648
  $ret = json_encode($result);
1649
  self::log("HIP RET " . $ret);
1650
  die($ret);
@@ -1835,9 +1716,16 @@ class WPShortPixel {
1835
  $thumbObtList = $meta->getThumbsOptList();
1836
  $missing = $meta->getThumbsMissing();
1837
 
1838
-
 
1839
  $this->_apiInterface->doRequests($URLsAndPATHs['URLs'], false, $itemHandler,
1840
  $compressionType === false ? $this->_settings->compressionType : $compressionType, $refresh);//send a request, do NOT wait for response
 
 
 
 
 
 
1841
  //$meta = wp_get_attachment_metadata($ID);
1842
  //$meta['ShortPixel']['WaitingProcessing'] = true;
1843
  //wp_update_attachment_metadata($ID, $meta);
@@ -1904,6 +1792,7 @@ class WPShortPixel {
1904
  $meta = $itemHandler->getMeta();
1905
  $meta->setRetries(0);
1906
  $meta->setStatus(\ShortPixelMeta::FILE_STATUS_PENDING);
 
1907
  }
1908
 
1909
 
@@ -2020,7 +1909,7 @@ class WPShortPixel {
2020
  update_post_meta($ID, '_wp_attachment_metadata', $meta);
2021
  }
2022
 
2023
- /* Gets backup folder of file
2024
  * @param string $file Filepath - probably ( or directory )
2025
  * @return string | boolean backupFolder or false.
2026
  */
@@ -2028,6 +1917,7 @@ class WPShortPixel {
2028
  $fs = \wpSPIO()->filesystem();
2029
  $fsFile = $fs->getFile($file);
2030
 
 
2031
  $directory = $this->getBackupFolderInternal($fsFile);
2032
  if ($directory !== false)
2033
  return $directory->getPath();
@@ -2055,6 +1945,7 @@ class WPShortPixel {
2055
 
2056
  // $backupFolder = $file->getBackUpDirectory();
2057
 
 
2058
  $backupFile = $file->getBackupFile();
2059
  if ($backupFile)
2060
  {
@@ -2082,7 +1973,7 @@ class WPShortPixel {
2082
  return $backupFile->getFileDir();
2083
  }
2084
 
2085
- Log::addError('Backup Directory could not be established! ', array($file->getFullPath()) );
2086
  return false; // $backupFile->getFileDir(); // if all else fails.
2087
 
2088
 
@@ -2465,12 +2356,13 @@ class WPShortPixel {
2465
  * @param string $extra
2466
  */
2467
  public function throwNotice($when = 'activate', $extra = '') {
2468
- set_transient("shortpixel_thrown_notice", array('when' => $when, 'extra' => $extra), 120);
 
2469
  }
2470
 
2471
- /** Checks if a notice was thrown
2472
  * @return boolean true, if there are notices */
2473
- protected function catchNotice() {
2474
  $notice = get_transient("shortpixel_thrown_notice");
2475
  if(isset($notice['when'])) {
2476
  if($notice['when'] == 'spai' && ($this->_settings->deliverWebp == 0 || $this->_settings->deliverWebp == 3)) {
@@ -2482,7 +2374,7 @@ class WPShortPixel {
2482
  return true;
2483
  }
2484
  return false;
2485
- }
2486
 
2487
  /** Restores a non-media-library image
2488
  * @param int $ID image_id, without any prefixes
@@ -2774,7 +2666,7 @@ class WPShortPixel {
2774
  }
2775
 
2776
  $referrer_url = wp_get_referer();
2777
- $conflict = $this->getConflictingPlugins();
2778
  foreach($conflict as $c => $value) {
2779
  $conflictingString = $value['page'];
2780
  if($conflictingString != null && strpos($referrer_url, $conflictingString) !== false){
@@ -2853,7 +2745,7 @@ class WPShortPixel {
2853
  ?><script>var shortPixelQuotaExceeded = 0;</script><?php
2854
  }
2855
  else {
2856
- $this->view->displayQuotaExceededAlert($quotaData, self::getAverageCompression(), $recheck);
2857
  ?><script>var shortPixelQuotaExceeded = 1;</script><?php
2858
  }
2859
  return $quotaData;
@@ -2935,8 +2827,9 @@ class WPShortPixel {
2935
  public function bulkProcess() {
2936
  global $wpdb;
2937
 
 
2938
  if( $this->_settings->verifiedKey == false ) {//invalid API Key
2939
- ShortPixelView::displayActivationNotice();
2940
  return;
2941
  }
2942
 
@@ -2945,6 +2838,8 @@ class WPShortPixel {
2945
  //return;
2946
  //}
2947
 
 
 
2948
  if(isset($_POST['bulkProcessPause']))
2949
  {//pause an ongoing bulk processing, it might be needed sometimes
2950
  $this->prioQ->pauseBulk();
@@ -2980,7 +2875,6 @@ class WPShortPixel {
2980
  if($this->_settings->hasCustomFolders) {
2981
  $this->spMetaDao->resetFailed();
2982
  $this->spMetaDao->resetRestored();
2983
-
2984
  }
2985
 
2986
  $this->prioQ->startBulk(ShortPixelQueue::BULK_TYPE_OPTIMIZE);
@@ -3685,7 +3579,8 @@ class WPShortPixel {
3685
  $this->_settings->quotaExceeded = 1;//activate quota limiting
3686
 
3687
  //if a non-valid status exists, delete it
3688
- $lastStatus = $this->_settings->bulkLastStatus = null;
 
3689
  if($lastStatus && $lastStatus['Status'] == ShortPixelAPI::STATUS_NO_KEY) {
3690
  $this->_settings->bulkLastStatus = null;
3691
  }
@@ -4015,12 +3910,20 @@ class WPShortPixel {
4015
  public function onDeleteImage($post_id) {
4016
  Log::addDebug('onDeleteImage - Image Removal Detected ' . $post_id);
4017
  \wpSPIO()->loadModel('image');
 
4018
 
4019
- $imageObj = new ImageModel();
4020
- $imageObj->setbyPostID($post_id);
4021
-
4022
- return $imageObj->delete();
 
 
 
 
 
 
4023
 
 
4024
  }
4025
 
4026
  /** Removes webp and backup from specified paths
@@ -4224,9 +4127,32 @@ class WPShortPixel {
4224
  }
4225
 
4226
  static public function matchExcludePattern($target, $pattern) {
4227
- return (
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4228
  $pattern[0] == '/' && @preg_match($pattern, false) !== false && preg_match($pattern, $target) //search as regex pattern if starts with a / and regex is valid
4229
- || $pattern[0] != '/' && strpos($target, $pattern) !== false ); //search as a substring if not
4230
  }
4231
 
4232
  //return an array with URL(s) and PATH(s) for this file
@@ -4262,6 +4188,7 @@ class WPShortPixel {
4262
  $total_size = 0;
4263
  $fs = wpSPIO()->filesystem();
4264
  $dir = $fs->getDirectory($path);
 
4265
 
4266
  if($dir->exists()) {
4267
  $files = $dir->getFiles(); // @todo This gives a warning if directory is not writable.
@@ -4271,16 +4198,21 @@ class WPShortPixel {
4271
  return $total_size;
4272
  }
4273
  //$cleanPath = rtrim($path, '/'). '/';
4274
- foreach($files as $file)
4275
  {
4276
- $total_size += $file->getFileSize();
 
 
 
4277
  }
4278
 
4279
- foreach($subdirs as $dir)
4280
  {
4281
- $total_size += self::folderSize($dir->getPath());
 
 
 
4282
  }
4283
-
4284
  return $total_size;
4285
 
4286
  /* foreach($files as $t) {
41
 
42
  $this->_settings = new WPShortPixelSettings();
43
  $this->_apiInterface = new ShortPixelAPI($this->_settings);
44
+ // $this->cloudflareApi = new ShortPixelCloudFlareApi($this->_settings->cloudflareEmail, $this->_settings->cloudflareAuthKey, $this->_settings->cloudflareZoneID);
45
  $this->hasNextGen = wpSPIO()->env()->has_nextgen; //ShortPixelNextGenAdapter::hasNextGen();
46
  $this->spMetaDao = new ShortPixelCustomMetaDao(new WpShortPixelDb(), $this->_settings->excludePatterns);
47
  $this->prioQ = (! defined('SHORTPIXEL_NOFLOCK')) ? new ShortPixelQueue($this, $this->_settings) : new ShortPixelQueueDB($this, $this->_settings);
166
  //check status
167
  add_action( 'wp_ajax_shortpixel_check_status', array(&$this, 'checkStatus'));
168
  //dismiss notices
169
+
170
+ // deprecated - dismissAdminNotice should not be called no longer.
171
+ // add_action( 'wp_ajax_shortpixel_dismiss_notice', array(&$this, 'dismissAdminNotice'));
172
+ add_action( 'wp_ajax_shortpixel_dismiss_media_alert', array($this, 'dismissMediaAlert'));
173
+ add_action( 'wp_ajax_shortpixel_dismissFileError', array($this, 'dismissFileError'));
174
+
175
  //check quota
176
  add_action('wp_ajax_shortpixel_check_quota', array(&$this, 'handleCheckQuota'));
177
  add_action('admin_action_shortpixel_check_quota', array(&$this, 'handleCheckQuota'));
245
  }
246
  } */
247
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
248
 
249
  /** Displays notices to admin, if there are any
250
  * TODO - Probably should be a controller
251
  */
252
  public function displayAdminNotices() {
253
+ /* $testQ = (! defined('SHORTPIXEL_NOFLOCK')) ? ShortPixelQueue::testQ() : ShortPixelQueueDB::testQ();
254
  if(! $testQ) {
255
  ShortPixelView::displayActivationNotice('fileperms');
256
+ } */
257
+ // if($this->catchNotice()) { //notices for errors like for example a failed restore notice - these are one time so display them with priority.
258
+ // return;
259
+ // }
260
+ // $dismissed = $this->_settings->dismissedNotices ? $this->_settings->dismissedNotices : array();
261
+ // $this->_settings->dismissedNotices = $dismissed;
262
 
263
+ /*if(!$this->_settings->verifiedKey) {
264
  $now = time();
265
  $act = $this->_settings->activationDate ? $this->_settings->activationDate : $now;
266
  if($this->_settings->activationNotice && $this->_settings->redirectedSettings >= 2) {
272
  } else if( ($now > $act + 72 * 3600) && !isset($dismissed['3d'])) {
273
  ShortPixelView::displayActivationNotice('3d');
274
  }
275
+ } */
276
+ /*if(!isset($dismissed['compat'])) {
277
  $conflictPlugins = $this->getConflictingPlugins();
278
  if(count($conflictPlugins)) {
279
  ShortPixelView::displayActivationNotice('compat', $conflictPlugins);
280
  return;
281
  }
282
+ } */
283
+ /* if( !isset($dismissed['unlisted']) && !$this->_settings->optimizeUnlisted
284
  && isset($this->_settings->currentStats['foundUnlistedThumbs']) && is_array($this->_settings->currentStats['foundUnlistedThumbs'])) {
285
  ShortPixelView::displayActivationNotice('unlisted', $this->_settings->currentStats['foundUnlistedThumbs']);
286
  return;
287
+ } */
288
  //if(false)
289
+ /* $currentStats = $this->_settings->currentStats;
290
  if(!is_array($currentStats) || isset($_GET['checkquota']) || isset($currentStats["quotaData"])) {
291
  $this->getQuotaInformation();
292
  }
308
  //looks like the user hasn't got enough credits to process the monthly images, display a notice telling this
309
  ShortPixelView::displayActivationNotice('upgmonth', array('monthAvg' => $this->getMonthAvg($stats), 'monthlyQuota' => $quotaData['APICallsQuotaNumeric']));
310
  }
311
+ } */
312
  }
313
 
314
+ /* Deprecated in favor of NoticeController.
315
  public function dismissAdminNotice() {
316
  $noticeId = preg_replace('|[^a-z0-9]|i', '', $_GET['notice_id']);
317
  $dismissed = $this->_settings->dismissedNotices ? $this->_settings->dismissedNotices : array();
323
  die(json_encode(array("Status" => 'success', "Message" => 'Notice ID: ' . $noticeId . ' dismissed')));
324
  }
325
 
326
+
327
+ */
328
+
329
+ // This probably displays an alert when requesting the user to switch from grid to list in media library
330
  public function dismissMediaAlert() {
331
  $this->_settings->mediaAlert = 1;
332
  die(json_encode(array("Status" => 'success', "Message" => __('Media alert dismissed','shortpixel-image-optimiser'))));
333
  }
334
 
335
+ public function dismissFileError() {
336
+ $this->_settings->bulkLastStatus = null;
337
+ die(json_encode(array("Status" => 'success', "Message" => __('Error dismissed','shortpixel-image-optimiser'))));
 
 
 
 
 
 
 
338
  }
339
 
 
 
 
 
340
 
341
  //set default move as "list". only set once, it won't try to set the default mode again.
342
  public function setDefaultViewModeList()
372
 
373
  if (! \wpSPIO()->env()->is_screen_to_use )
374
  {
375
+ if (! wpSPIO()->env()->is_front) // exeception if this is called to load from your frontie.
376
  return; // not ours, don't load JS and such.
377
  }
378
+
379
+ $is_front = (wpSPIO()->env()->is_front) ? true : false;
380
+
381
  // load everywhere, because we are inconsistent.
382
  wp_enqueue_style('short-pixel-bar.min.css', plugins_url('/res/css/short-pixel-bar.min.css',SHORTPIXEL_PLUGIN_FILE), array(), SHORTPIXEL_IMAGE_OPTIMISER_VERSION);
383
 
546
  //$icon = "shortpixel-alert.png";
547
  }
548
  $lastStatus = $this->_settings->bulkLastStatus;
549
+ if($lastStatus && $lastStatus['Status'] !== ShortPixelAPI::STATUS_SUCCESS) {
550
  $extraClasses = " shortpixel-alert shortpixel-processing";
551
+ $tooltip = '';
552
  $successLink = $link = admin_url(current_user_can( 'edit_others_posts')? 'post.php?post=' . $lastStatus['ImageID'] . '&action=edit' : 'upload.php');
553
+
554
+ $wp_admin_bar->add_node( array(
555
+ 'id' => 'shortpixel_processing-title',
556
+ 'parent' => 'shortpixel_processing',
557
+ 'title' => $lastStatus['Message'],
558
+ 'href' => $successLink
559
+ ));
560
+ $wp_admin_bar->add_node( array(
561
+ 'id' => 'shortpixel_processing-dismiss',
562
+ 'parent' => 'shortpixel_processing',
563
+ 'title' => '<div style="text-align: right;">Dismiss</div>',
564
+ 'href' => "#",
565
+ 'meta' => array('onclick'=> 'dismissFileError(event)')
566
+ ));
567
  }
568
 
569
  $args = array(
575
  'meta' => array('target'=> $blank, 'class' => 'shortpixel-toolbar-processing' . $extraClasses)
576
  );
577
  $wp_admin_bar->add_node( $args );
578
+
579
  if($this->_settings->quotaExceeded && !isset($this->_settings->dismissedNotices['exceed'])) {
580
  $wp_admin_bar->add_node( array(
581
  'id' => 'shortpixel_processing-title',
583
  'title' => $exceedTooltip,
584
  'href' => $link
585
  ));
586
+ /*$wp_admin_bar->add_node( array(
587
  'id' => 'shortpixel_processing-dismiss',
588
  'parent' => 'shortpixel_processing',
589
  'title' => '<div style="text-align: right;">Dismiss</div>',
590
  'href' => "#",
591
  'meta' => array('onclick'=> 'dismissShortPixelNoticeExceed(event)')
592
+ )); */
593
  }
594
  }
595
 
1217
  * @param String $ID ApiKey
1218
  */
1219
  public function handleImageProcessing($ID = null) {
1220
+
 
 
 
 
1221
  $this->checkKey($ID);
1222
 
1223
  if($this->_settings->frontBootstrap && is_admin() && !ShortPixelTools::requestIsFrontendAjax()) {
1522
  }
1523
 
1524
  if($result["Status"] !== ShortPixelAPI::STATUS_RETRY) {
1525
+ $this->_settings->bulkLastStatus = null;
1526
  $this->_settings->bulkLastStatus = $result;
1527
  }
1528
+
1529
  $ret = json_encode($result);
1530
  self::log("HIP RET " . $ret);
1531
  die($ret);
1716
  $thumbObtList = $meta->getThumbsOptList();
1717
  $missing = $meta->getThumbsMissing();
1718
 
1719
+ try
1720
+ {
1721
  $this->_apiInterface->doRequests($URLsAndPATHs['URLs'], false, $itemHandler,
1722
  $compressionType === false ? $this->_settings->compressionType : $compressionType, $refresh);//send a request, do NOT wait for response
1723
+ }
1724
+ catch(Exception $e) {
1725
+ Log::addError('Api DoRequest Thrown ' . $e->getMessage());
1726
+ //$meta['ShortPixelImprovement'] = $e->getMessage();
1727
+ //return $meta;
1728
+ }
1729
  //$meta = wp_get_attachment_metadata($ID);
1730
  //$meta['ShortPixel']['WaitingProcessing'] = true;
1731
  //wp_update_attachment_metadata($ID, $meta);
1792
  $meta = $itemHandler->getMeta();
1793
  $meta->setRetries(0);
1794
  $meta->setStatus(\ShortPixelMeta::FILE_STATUS_PENDING);
1795
+ $itemHandler->updateMeta($meta);
1796
  }
1797
 
1798
 
1909
  update_post_meta($ID, '_wp_attachment_metadata', $meta);
1910
  }
1911
 
1912
+ /* Gets backup folder of file. This backup must exist already, or false is given.
1913
  * @param string $file Filepath - probably ( or directory )
1914
  * @return string | boolean backupFolder or false.
1915
  */
1917
  $fs = \wpSPIO()->filesystem();
1918
  $fsFile = $fs->getFile($file);
1919
 
1920
+ // Log::addDebug('Get BackUp Folder', array($fsFile->getFileName(), pathinfo($fsFile->getFullPath())));
1921
  $directory = $this->getBackupFolderInternal($fsFile);
1922
  if ($directory !== false)
1923
  return $directory->getPath();
1945
 
1946
  // $backupFolder = $file->getBackUpDirectory();
1947
 
1948
+ // returns true only if a backup-file already exists.
1949
  $backupFile = $file->getBackupFile();
1950
  if ($backupFile)
1951
  {
1973
  return $backupFile->getFileDir();
1974
  }
1975
 
1976
+ Log::addError('Backup Directory could not be established! ', array($file->getFullPath(), $SubDir, $SubDirOld, $basename) );
1977
  return false; // $backupFile->getFileDir(); // if all else fails.
1978
 
1979
 
2356
  * @param string $extra
2357
  */
2358
  public function throwNotice($when = 'activate', $extra = '') {
2359
+ // set_transient("shortpixel_thrown_notice", array('when' => $when, 'extra' => $extra), 120);
2360
+ Notices::addError($extra); // whatever error is in the extra. Seems that normal messages don't pass here.
2361
  }
2362
 
2363
+ /** Checks if a notice was thrown || Deprecated in favor or Notices.
2364
  * @return boolean true, if there are notices */
2365
+ /* protected function catchNotice() {
2366
  $notice = get_transient("shortpixel_thrown_notice");
2367
  if(isset($notice['when'])) {
2368
  if($notice['when'] == 'spai' && ($this->_settings->deliverWebp == 0 || $this->_settings->deliverWebp == 3)) {
2374
  return true;
2375
  }
2376
  return false;
2377
+ } */
2378
 
2379
  /** Restores a non-media-library image
2380
  * @param int $ID image_id, without any prefixes
2666
  }
2667
 
2668
  $referrer_url = wp_get_referer();
2669
+ $conflict = \ShortPixelTools::getConflictingPlugins();
2670
  foreach($conflict as $c => $value) {
2671
  $conflictingString = $value['page'];
2672
  if($conflictingString != null && strpos($referrer_url, $conflictingString) !== false){
2745
  ?><script>var shortPixelQuotaExceeded = 0;</script><?php
2746
  }
2747
  else {
2748
+ // $this->view->displayQuotaExceededAlert($quotaData, self::getAverageCompression(), $recheck);
2749
  ?><script>var shortPixelQuotaExceeded = 1;</script><?php
2750
  }
2751
  return $quotaData;
2827
  public function bulkProcess() {
2828
  global $wpdb;
2829
 
2830
+
2831
  if( $this->_settings->verifiedKey == false ) {//invalid API Key
2832
+ //ShortPixelView::displayActivationNotice();
2833
  return;
2834
  }
2835
 
2838
  //return;
2839
  //}
2840
 
2841
+
2842
+
2843
  if(isset($_POST['bulkProcessPause']))
2844
  {//pause an ongoing bulk processing, it might be needed sometimes
2845
  $this->prioQ->pauseBulk();
2875
  if($this->_settings->hasCustomFolders) {
2876
  $this->spMetaDao->resetFailed();
2877
  $this->spMetaDao->resetRestored();
 
2878
  }
2879
 
2880
  $this->prioQ->startBulk(ShortPixelQueue::BULK_TYPE_OPTIMIZE);
3579
  $this->_settings->quotaExceeded = 1;//activate quota limiting
3580
 
3581
  //if a non-valid status exists, delete it
3582
+ // @todo Clarify the reason for this statement
3583
+ $lastStatus = $this->_settings->bulkLastStatus;
3584
  if($lastStatus && $lastStatus['Status'] == ShortPixelAPI::STATUS_NO_KEY) {
3585
  $this->_settings->bulkLastStatus = null;
3586
  }
3910
  public function onDeleteImage($post_id) {
3911
  Log::addDebug('onDeleteImage - Image Removal Detected ' . $post_id);
3912
  \wpSPIO()->loadModel('image');
3913
+ $result = null;
3914
 
3915
+ try
3916
+ {
3917
+ $imageObj = new ImageModel();
3918
+ $imageObj->setbyPostID($post_id);
3919
+ $result = $imageObj->delete();
3920
+ }
3921
+ catch(Exception $e)
3922
+ {
3923
+ Log::addError('OndeleteImage triggered an error. ' . $e->getMessage(), $e);
3924
+ }
3925
 
3926
+ return $result;
3927
  }
3928
 
3929
  /** Removes webp and backup from specified paths
4127
  }
4128
 
4129
  static public function matchExcludePattern($target, $pattern) {
4130
+ if(strlen($pattern) == 0) // can happen on faulty input in settings.
4131
+ return false;
4132
+
4133
+ $first = substr($pattern, 0,1);
4134
+
4135
+ if ($first == '/')
4136
+ {
4137
+ if (@preg_match($pattern, false) !== false)
4138
+ {
4139
+ $m = preg_match($pattern, $target);
4140
+ if ($m !== false)
4141
+ return true;
4142
+ }
4143
+ }
4144
+ else
4145
+ {
4146
+ if (strpos($target, $pattern) !== false)
4147
+ {
4148
+ return true;
4149
+ }
4150
+ }
4151
+ return false;
4152
+
4153
+ /*return (
4154
  $pattern[0] == '/' && @preg_match($pattern, false) !== false && preg_match($pattern, $target) //search as regex pattern if starts with a / and regex is valid
4155
+ || $pattern[0] != '/' && strpos($target, $pattern) !== false ); //search as a substring if not */
4156
  }
4157
 
4158
  //return an array with URL(s) and PATH(s) for this file
4188
  $total_size = 0;
4189
  $fs = wpSPIO()->filesystem();
4190
  $dir = $fs->getDirectory($path);
4191
+ $files = $subdirs = array();
4192
 
4193
  if($dir->exists()) {
4194
  $files = $dir->getFiles(); // @todo This gives a warning if directory is not writable.
4198
  return $total_size;
4199
  }
4200
  //$cleanPath = rtrim($path, '/'). '/';
4201
+ if ($files)
4202
  {
4203
+ foreach($files as $file)
4204
+ {
4205
+ $total_size += $file->getFileSize();
4206
+ }
4207
  }
4208
 
4209
+ if ($subdirs)
4210
  {
4211
+ foreach($subdirs as $dir)
4212
+ {
4213
+ $total_size += self::folderSize($dir->getPath());
4214
+ }
4215
  }
 
4216
  return $total_size;
4217
 
4218
  /* foreach($files as $t) {
class/wp-shortpixel-settings.php CHANGED
@@ -1,4 +1,5 @@
1
  <?php
 
2
  /** Settings Model **/
3
  class WPShortPixelSettings extends ShortPixel\ShortPixelModel {
4
  private $_apiKey = '';
@@ -46,6 +47,7 @@ class WPShortPixelSettings extends ShortPixel\ShortPixelModel {
46
  'cloudflareEmail' => array( 'key' => 'wp-short-pixel-cloudflareAPIEmail', 'default' => '', 'group' => 'options'),
47
  'cloudflareAuthKey' => array( 'key' => 'wp-short-pixel-cloudflareAuthKey', 'default' => '', 'group' => 'options'),
48
  'cloudflareZoneID' => array( 'key' => 'wp-short-pixel-cloudflareAPIZoneID', 'default' => '', 'group' => 'options'),
 
49
 
50
  //optimize other images than the ones in Media Library
51
  'includeNextGen' => array('key' => 'wp-short-pixel-include-next-gen', 'default' => null, 'group' => 'options'),
@@ -132,6 +134,7 @@ class WPShortPixelSettings extends ShortPixel\ShortPixelModel {
132
  'cloudflareEmail' => array('s' => 'string'), // string
133
  'cloudflareAuthKey' => array('s' => 'string'), // string
134
  'cloudflareZoneID' => array('s' => 'string'), // string
 
135
  'savedSpace' => array('s' => 'skip'),
136
  'fileCount' => array('s' => 'skip'), // int
137
  'under5Percent' => array('s' => 'skip'), // int
@@ -179,11 +182,13 @@ class WPShortPixelSettings extends ShortPixel\ShortPixelModel {
179
  delete_option( 'wp-short-pixel-bulk-last-status');
180
  delete_option( 'wp-short-pixel-current-total-files');
181
  delete_option(self::$_optionsMap['removeSettingsOnDeletePlugin']['key']);
182
- $dismissed = get_option('wp-short-pixel-dismissed-notices', array());
 
183
  if(isset($dismissed['compat'])) {
184
  unset($dismissed['compat']);
185
  update_option('wp-short-pixel-dismissed-notices', $dismissed, 'no');
186
- }
 
187
  $formerPrio = get_option('wp-short-pixel-priorityQueue');
188
  $qGet = (! defined('SHORTPIXEL_NOFLOCK')) ? ShortPixelQueue::get() : ShortPixelQueueDB::get();
189
  if(is_array($formerPrio) && !count($qGet)) {
1
  <?php
2
+
3
  /** Settings Model **/
4
  class WPShortPixelSettings extends ShortPixel\ShortPixelModel {
5
  private $_apiKey = '';
47
  'cloudflareEmail' => array( 'key' => 'wp-short-pixel-cloudflareAPIEmail', 'default' => '', 'group' => 'options'),
48
  'cloudflareAuthKey' => array( 'key' => 'wp-short-pixel-cloudflareAuthKey', 'default' => '', 'group' => 'options'),
49
  'cloudflareZoneID' => array( 'key' => 'wp-short-pixel-cloudflareAPIZoneID', 'default' => '', 'group' => 'options'),
50
+ 'cloudflareToken' => array( 'key' => 'wp-short-pixel-cloudflareToken', 'default' => '', 'group' => 'options'),
51
 
52
  //optimize other images than the ones in Media Library
53
  'includeNextGen' => array('key' => 'wp-short-pixel-include-next-gen', 'default' => null, 'group' => 'options'),
134
  'cloudflareEmail' => array('s' => 'string'), // string
135
  'cloudflareAuthKey' => array('s' => 'string'), // string
136
  'cloudflareZoneID' => array('s' => 'string'), // string
137
+ 'cloudflareToken' => array('s' => 'string'),
138
  'savedSpace' => array('s' => 'skip'),
139
  'fileCount' => array('s' => 'skip'), // int
140
  'under5Percent' => array('s' => 'skip'), // int
182
  delete_option( 'wp-short-pixel-bulk-last-status');
183
  delete_option( 'wp-short-pixel-current-total-files');
184
  delete_option(self::$_optionsMap['removeSettingsOnDeletePlugin']['key']);
185
+ // Dismissed now via Notices Controller.
186
+ /* $dismissed = get_option('wp-short-pixel-dismissed-notices', array());
187
  if(isset($dismissed['compat'])) {
188
  unset($dismissed['compat']);
189
  update_option('wp-short-pixel-dismissed-notices', $dismissed, 'no');
190
+ } */
191
+
192
  $formerPrio = get_option('wp-short-pixel-priorityQueue');
193
  $qGet = (! defined('SHORTPIXEL_NOFLOCK')) ? ShortPixelQueue::get() : ShortPixelQueueDB::get();
194
  if(is_array($formerPrio) && !count($qGet)) {
readme.txt CHANGED
@@ -4,7 +4,7 @@ Tags: compressor, image, compression, optimize, image optimizer, image optimiser
4
  Requires at least: 3.2.0
5
  Tested up to: 5.3
6
  Requires PHP: 5.3
7
- Stable tag: 4.15.4
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
@@ -238,6 +238,9 @@ define("SHORTPIXEL_NOFLOCK", true); // don't use flock queue, only activate this
238
  .
239
  define("SHORTPIXEL_EXPERIMENTAL_SECURICACHE", true); // adds timestamps to URLS, to prevent hitting the cache. Useful for persistent caches.
240
 
 
 
 
241
 
242
  == Screenshots ==
243
 
@@ -261,6 +264,25 @@ define("SHORTPIXEL_EXPERIMENTAL_SECURICACHE", true); // adds timestamps to URLS
261
 
262
  == Changelog ==
263
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
264
  = 4.15.4 =
265
 
266
  Release date: 29th January 2020
4
  Requires at least: 3.2.0
5
  Tested up to: 5.3
6
  Requires PHP: 5.3
7
+ Stable tag: 4.16.0
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
238
  .
239
  define("SHORTPIXEL_EXPERIMENTAL_SECURICACHE", true); // adds timestamps to URLS, to prevent hitting the cache. Useful for persistent caches.
240
 
241
+ //Hide the Cloudflare settings by defining these constants in wp-config.php
242
+ define('SHORTPIXEL_CFTOKEN', 'the Cloudflare API token that has Purge Cache right');
243
+ define('SHORTPIXEL_CFZONE', 'The Zone ID from the domain settings in Cloudflare');
244
 
245
  == Screenshots ==
246
 
264
 
265
  == Changelog ==
266
 
267
+
268
+ = 4.16.0 =
269
+
270
+ * New - Token support for Cloudflare via config constant or settings.
271
+ * Backup setting - add orange warning when backups are off.
272
+ * Button to dismiss the top bar notification of missing files.
273
+ * Shortpixel now loads scripts with 'defer' on front site, if it's configured to be loaded there.
274
+ * Hiding Cloudflare details via wp-config.php.
275
+ * Hide the option "Process in front-end" when "Optimize media on upload" is not checked.
276
+ * Fixes for multibyte filenames with mixed locales.
277
+ * Fixes for combination of S3-offload, webp pictures and cnames.
278
+ * Reworked Notifications.
279
+ * Fixed - PNG2JPG Retry button didn't work, now properly resets retry counter.
280
+ * Fixed - Realpath in directory model throws off installations with symlinks.
281
+ * Fixed - Thrown Exception in API with corrupted images now caught.
282
+ * Fixed - Debug window link was visible when it should not.
283
+ * Fixed - ExcludePattern without value would result in notices.
284
+ * Language – 7 new strings added, 0 updated, 0 fuzzied, and 0 obsoleted
285
+
286
  = 4.15.4 =
287
 
288
  Release date: 29th January 2020
res/css/short-pixel-bar.css CHANGED
@@ -84,37 +84,9 @@ li.shortpixel-toolbar-processing.shortpixel-alert > a.ab-item > div,
84
 
85
 
86
  .sp-quota-exceeded-alert {
87
- background-color: #fff;
88
- border-left: 4px solid #ff0000;
89
- box-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.1);
90
- padding: 1px 12px;
91
  }
92
  .shortpixel-clearfix {
93
  width:100%;
94
  float:left;
95
  }
96
- .short-pixel-notice-icon {
97
- float:left;
98
- margin: 10px 10px 10px 0;
99
- }
100
-
101
- .sp-conflict-plugins {
102
- display: table;
103
- border-spacing: 10px;
104
- border-collapse: separate;
105
- }
106
- .sp-conflict-plugins li {
107
- display: table-row;
108
- }
109
- .sp-conflict-plugins li > * {
110
- display: table-cell;
111
- }
112
-
113
- li.sp-conflict-plugins-list {
114
- line-height: 28px;
115
- list-style: disc;
116
- margin-left: 80px;
117
- }
118
- li.sp-conflict-plugins-list a.button {
119
- margin-left: 10px;
120
- }
84
 
85
 
86
  .sp-quota-exceeded-alert {
87
+
 
 
 
88
  }
89
  .shortpixel-clearfix {
90
  width:100%;
91
  float:left;
92
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
res/css/short-pixel-bar.min.css CHANGED
@@ -1 +1 @@
1
- #wpadminbar li.shortpixel-toolbar-processing>a.ab-item>div,li.shortpixel-toolbar-processing>a.ab-item>div{height:33px;margin-top:-1px;padding:0 3px}#wpadminbar li.shortpixel-toolbar-processing>a.ab-item>div>img,li.shortpixel-toolbar-processing>a.ab-item>div>img{margin-right:2px;margin-top:6px;vertical-align:top}#wpadminbar li.shortpixel-toolbar-processing>a.ab-item>div>span.shp-alert,li.shortpixel-toolbar-processing span.shp-alert{display:none}#wpadminbar li.shortpixel-toolbar-processing.shortpixel-alert>a.ab-item>div>span.shp-alert,li.shortpixel-toolbar-processing.shortpixel-alert>a.ab-item>div>span.shp-alert{display:inline;font-size:26px;line-height:26px;color:red;font-weight:700;vertical-align:middle}#wpadminbar li.shortpixel-toolbar-processing.shortpixel-alert>a.ab-item>div,li.shortpixel-toolbar-processing.shortpixel-alert>a.ab-item>div{background-image:none}#wpadminbar .shortpixel-toolbar-processing .cssload-container{width:100%;height:24px;text-align:center;position:absolute;top:0;left:-1px}#wpadminbar .shortpixel-toolbar-processing.shortpixel-alert .cssload-container,#wpadminbar .shortpixel-toolbar-processing.shortpixel-quota-exceeded .cssload-container{display:none}#wpadminbar .shortpixel-toolbar-processing .cssload-speeding-wheel{width:24px;height:24px;opacity:.7;margin:0 auto;border:4px solid #1cbfcb;border-radius:50%;border-left-color:transparent;animation:cssload-spin 2s infinite linear;-o-animation:cssload-spin 2s infinite linear;-ms-animation:cssload-spin 2s infinite linear;-webkit-animation:cssload-spin 2s infinite linear;-moz-animation:cssload-spin 2s infinite linear}@keyframes cssload-spin{100%{transform:rotate(360deg);transform:rotate(360deg)}}@-o-keyframes cssload-spin{100%{-o-transform:rotate(360deg);transform:rotate(360deg)}}@-ms-keyframes cssload-spin{100%{-ms-transform:rotate(360deg);transform:rotate(360deg)}}@-webkit-keyframes cssload-spin{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@-moz-keyframes cssload-spin{100%{-moz-transform:rotate(360deg);transform:rotate(360deg)}}.sp-quota-exceeded-alert{background-color:#fff;border-left:4px solid red;box-shadow:0 1px 1px 0 rgba(0,0,0,.1);padding:1px 12px}.shortpixel-clearfix{width:100%;float:left}.short-pixel-notice-icon{float:left;margin:10px 10px 10px 0}.sp-conflict-plugins{display:table;border-spacing:10px;border-collapse:separate}.sp-conflict-plugins li{display:table-row}.sp-conflict-plugins li>*{display:table-cell}li.sp-conflict-plugins-list{line-height:28px;list-style:disc;margin-left:80px}li.sp-conflict-plugins-list a.button{margin-left:10px}
1
+ #wpadminbar li.shortpixel-toolbar-processing>a.ab-item>div,li.shortpixel-toolbar-processing>a.ab-item>div{height:33px;margin-top:-1px;padding:0 3px}#wpadminbar li.shortpixel-toolbar-processing>a.ab-item>div>img,li.shortpixel-toolbar-processing>a.ab-item>div>img{margin-right:2px;margin-top:6px;vertical-align:top}#wpadminbar li.shortpixel-toolbar-processing>a.ab-item>div>span.shp-alert,li.shortpixel-toolbar-processing span.shp-alert{display:none}#wpadminbar li.shortpixel-toolbar-processing.shortpixel-alert>a.ab-item>div>span.shp-alert,li.shortpixel-toolbar-processing.shortpixel-alert>a.ab-item>div>span.shp-alert{display:inline;font-size:26px;line-height:26px;color:red;font-weight:700;vertical-align:middle}#wpadminbar li.shortpixel-toolbar-processing.shortpixel-alert>a.ab-item>div,li.shortpixel-toolbar-processing.shortpixel-alert>a.ab-item>div{background-image:none}#wpadminbar .shortpixel-toolbar-processing .cssload-container{width:100%;height:24px;text-align:center;position:absolute;top:0;left:-1px}#wpadminbar .shortpixel-toolbar-processing.shortpixel-alert .cssload-container,#wpadminbar .shortpixel-toolbar-processing.shortpixel-quota-exceeded .cssload-container{display:none}#wpadminbar .shortpixel-toolbar-processing .cssload-speeding-wheel{width:24px;height:24px;opacity:.7;margin:0 auto;border:4px solid #1cbfcb;border-radius:50%;border-left-color:transparent;animation:cssload-spin 2s infinite linear;-o-animation:cssload-spin 2s infinite linear;-ms-animation:cssload-spin 2s infinite linear;-webkit-animation:cssload-spin 2s infinite linear;-moz-animation:cssload-spin 2s infinite linear}@keyframes cssload-spin{100%{transform:rotate(360deg);transform:rotate(360deg)}}@-o-keyframes cssload-spin{100%{-o-transform:rotate(360deg);transform:rotate(360deg)}}@-ms-keyframes cssload-spin{100%{-ms-transform:rotate(360deg);transform:rotate(360deg)}}@-webkit-keyframes cssload-spin{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@-moz-keyframes cssload-spin{100%{-moz-transform:rotate(360deg);transform:rotate(360deg)}}.shortpixel-clearfix{width:100%;float:left}
res/css/short-pixel.css CHANGED
@@ -354,7 +354,7 @@ div.shortpixel-rate-us > a:focus {
354
  font-size: 13px;
355
  padding:0px 5px;
356
  margin-bottom: 4px;
357
- height:20px;
358
 
359
  float:right;
360
  }
354
  font-size: 13px;
355
  padding:0px 5px;
356
  margin-bottom: 4px;
357
+ min-height:30px;
358
 
359
  float:right;
360
  }
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;height:20px;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}.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}
res/css/shortpixel-admin.css CHANGED
@@ -1,26 +1,3 @@
1
- .shortpixel.notice {
2
- min-height: 50px;
3
- padding: 8px; }
4
- .shortpixel.notice img {
5
- display: inline-block;
6
- margin: 0 25px 0 0;
7
- max-height: 50px; }
8
- .shortpixel.notice .notice-dismiss {
9
- margin-top: 10px; }
10
-
11
- /* In-view notice ( not on top, between the options ) - styled after WP notice */
12
- .view-notice {
13
- box-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.1);
14
- border: 4px solid #fff;
15
- padding: 1px 12px; }
16
- .view-notice p {
17
- margin: 1em 0 !important; }
18
- .view-notice.warning {
19
- border-left-color: #ffb900; }
20
-
21
- .view-notice-row {
22
- display: none; }
23
-
24
  .short-pixel-bulk-page.bulk-restore-all ol li {
25
  font-weight: 700; }
26
  .short-pixel-bulk-page.bulk-restore-all section.select_folders {
@@ -60,55 +37,82 @@
60
  #shortpixel-settings-tabs #tab-adv-settings .addCustomFolder input[name="saveAdv"] {
61
  margin-left: 8px; }
62
 
63
- .settings_page_wp-shortpixel-settings .top-menu {
64
- font-size: 18px; }
65
- .settings_page_wp-shortpixel-settings .top-menu a {
66
- font-size: 18px; }
67
- .settings_page_wp-shortpixel-settings .wp-shortpixel-tab-content {
68
- transition: all 1000ms linear; }
69
- .settings_page_wp-shortpixel-settings article.sp-tabs section .wp-shortpixel-tab-content {
70
- opacity: 0; }
71
- .settings_page_wp-shortpixel-settings article.sp-tabs section.sel-tab .wp-shortpixel-tab-content {
72
- opacity: 1; }
73
- .settings_page_wp-shortpixel-settings article.sp-tabs section h2 {
74
- position: absolute;
75
- font-size: 1.3em;
76
- font-weight: normal;
77
- width: 180px;
78
- height: 1.8em;
79
- top: -1.8em;
80
- left: 10px;
81
- padding: 0;
82
- margin: 0;
83
- color: #999;
84
- background-color: #ddd;
85
- /* border-radius: 5px 5px 0 0; */ }
86
- .settings_page_wp-shortpixel-settings article.sp-tabs section h2 a {
87
  display: block;
88
- width: 100%;
89
- line-height: 1.8em;
90
- text-align: center;
91
- text-decoration: none;
92
- color: #23282d;
93
- outline: 0 none; }
94
- .settings_page_wp-shortpixel-settings article.sp-tabs section:nth-child(2) h2 {
95
- left: 192px; }
96
- .settings_page_wp-shortpixel-settings article.sp-tabs section:nth-child(3) h2 {
97
- left: 374px; }
98
- .settings_page_wp-shortpixel-settings article.sp-tabs section:nth-child(4) h2 {
99
- left: 556px; }
100
- .settings_page_wp-shortpixel-settings article.sp-tabs section:nth-child(5) h2 {
101
- left: 738px; }
102
- .settings_page_wp-shortpixel-settings article.sp-tabs section:nth-child(6) h2 {
103
- left: 920px; }
104
- .settings_page_wp-shortpixel-settings section#tab-debug .flex {
105
- display: flex; }
106
- .settings_page_wp-shortpixel-settings section#tab-debug .env .flex {
107
- flex-wrap: wrap;
108
- max-width: 450px; }
109
- .settings_page_wp-shortpixel-settings section#tab-debug .env .flex span {
110
- width: 45%;
111
- padding: 4px; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
112
 
113
  .view-edit-media .debugInfo pre {
114
  font-size: 11px; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  .short-pixel-bulk-page.bulk-restore-all ol li {
2
  font-weight: 700; }
3
  .short-pixel-bulk-page.bulk-restore-all section.select_folders {
37
  #shortpixel-settings-tabs #tab-adv-settings .addCustomFolder input[name="saveAdv"] {
38
  margin-left: 8px; }
39
 
40
+ .cf_switch label {
41
+ width: 100%;
42
+ margin: 0 -2px;
43
+ background-color: #e2faff;
44
+ display: inline-block; }
45
+ .cf_switch label span {
46
+ padding: 8px 0px 8px 15px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
  display: block;
48
+ font-size: 13px; }
49
+ .cf_switch label input {
50
+ display: none; }
51
+ .cf_switch label input:checked + span {
52
+ background-color: #0085ba;
53
+ color: #F7F7F7; }
54
+
55
+ .settings_page_wp-shortpixel-settings {
56
+ /* In-view notice ( not on top, between the options ) - styled after WP notice */ }
57
+ .settings_page_wp-shortpixel-settings .top-menu {
58
+ font-size: 18px; }
59
+ .settings_page_wp-shortpixel-settings .top-menu a {
60
+ font-size: 18px; }
61
+ .settings_page_wp-shortpixel-settings .wp-shortpixel-tab-content {
62
+ transition: all 1000ms linear; }
63
+ .settings_page_wp-shortpixel-settings article.sp-tabs section .wp-shortpixel-tab-content {
64
+ opacity: 0; }
65
+ .settings_page_wp-shortpixel-settings article.sp-tabs section.sel-tab .wp-shortpixel-tab-content {
66
+ opacity: 1; }
67
+ .settings_page_wp-shortpixel-settings article.sp-tabs section h2 {
68
+ position: absolute;
69
+ font-size: 1.3em;
70
+ font-weight: normal;
71
+ width: 180px;
72
+ height: 1.8em;
73
+ top: -1.8em;
74
+ left: 10px;
75
+ padding: 0;
76
+ margin: 0;
77
+ color: #999;
78
+ background-color: #ddd;
79
+ /* border-radius: 5px 5px 0 0; */ }
80
+ .settings_page_wp-shortpixel-settings article.sp-tabs section h2 a {
81
+ display: block;
82
+ width: 100%;
83
+ line-height: 1.8em;
84
+ text-align: center;
85
+ text-decoration: none;
86
+ color: #23282d;
87
+ outline: 0 none; }
88
+ .settings_page_wp-shortpixel-settings article.sp-tabs section:nth-child(2) h2 {
89
+ left: 192px; }
90
+ .settings_page_wp-shortpixel-settings article.sp-tabs section:nth-child(3) h2 {
91
+ left: 374px; }
92
+ .settings_page_wp-shortpixel-settings article.sp-tabs section:nth-child(4) h2 {
93
+ left: 556px; }
94
+ .settings_page_wp-shortpixel-settings article.sp-tabs section:nth-child(5) h2 {
95
+ left: 738px; }
96
+ .settings_page_wp-shortpixel-settings article.sp-tabs section:nth-child(6) h2 {
97
+ left: 920px; }
98
+ .settings_page_wp-shortpixel-settings section#tab-debug .flex {
99
+ display: flex; }
100
+ .settings_page_wp-shortpixel-settings section#tab-debug .env .flex {
101
+ flex-wrap: wrap;
102
+ max-width: 450px; }
103
+ .settings_page_wp-shortpixel-settings section#tab-debug .env .flex span {
104
+ width: 45%;
105
+ padding: 4px; }
106
+ .settings_page_wp-shortpixel-settings .view-notice {
107
+ box-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.1);
108
+ border: 4px solid #fff;
109
+ padding: 1px 12px; }
110
+ .settings_page_wp-shortpixel-settings .view-notice p {
111
+ margin: 1em 0 !important; }
112
+ .settings_page_wp-shortpixel-settings .view-notice.warning {
113
+ border-left-color: #ffb900; }
114
+ .settings_page_wp-shortpixel-settings .view-notice-row {
115
+ display: none; }
116
 
117
  .view-edit-media .debugInfo pre {
118
  font-size: 11px; }
res/css/shortpixel-notices.css ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .shortpixel.notice {
2
+ min-height: 75px;
3
+ padding: 8px;
4
+ display: flex;
5
+ align-items: center; }
6
+ .shortpixel.notice .notice-dismiss {
7
+ margin-top: 10px; }
8
+ .shortpixel.notice span {
9
+ vertical-align: middle; }
10
+ .shortpixel.notice span.icon {
11
+ margin: 0 25px 0 0; }
12
+
13
+ .shortpixel.notice .sp-conflict-plugins {
14
+ display: table;
15
+ border-spacing: 10px;
16
+ border-collapse: separate; }
17
+ .shortpixel.notice .sp-conflict-plugins li {
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;
24
+ margin-left: 80px; }
25
+ .shortpixel.notice li.sp-conflict-plugins-list a.button {
26
+ margin-left: 10px; }
res/js/debug.js ADDED
@@ -0,0 +1,243 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ var debugModal;
2
+
3
+ jQuery(document).ready(function(jq) {
4
+ $ = jq;
5
+
6
+ debugModal = function() {
7
+
8
+ }
9
+
10
+ debugModal.prototype = {
11
+ currentModal: null,
12
+ modals: [],
13
+ parent: '#wpbody', // modal will be written to this element.
14
+ multiple: false,
15
+ windowHeight: false,
16
+ windowWidth: false,
17
+ setWidth: false,
18
+ setHeight: false,
19
+ target: false,
20
+ }
21
+
22
+ debugModal.prototype.init = function()
23
+ {
24
+ this.windowHeight = $(window).height();
25
+ this.windowWidth = $(window).width();
26
+
27
+ $(document).off('click', '.debugModal');
28
+ $(document).on('click', '.debugModal', $.proxy(this.buildModal, this));
29
+ $(window).on('resize', $.proxy(this.checkResize, this));
30
+
31
+ }
32
+
33
+ debugModal.prototype.focus = function()
34
+ {
35
+ this.currentModal.show();
36
+
37
+ }
38
+
39
+ debugModal.prototype.get = function()
40
+ {
41
+ return this.currentModal;
42
+ }
43
+
44
+ debugModal.prototype.show = function()
45
+ {
46
+
47
+ $('.debugModal_overlay').remove();
48
+ $('body').removeClass('debug-modal-active');
49
+ this.writeOverlay();
50
+ this.currentModal.show();
51
+
52
+ if (this.setWidth)
53
+ {
54
+ this.currentModal.width(this.setWidth);
55
+ }
56
+ if (this.setHeight)
57
+ {
58
+ this.currentModal.height(this.setHeight);
59
+ }
60
+
61
+ $m = this.currentModal;
62
+
63
+ var headerHeight = $m.find('.modal_header').outerHeight();
64
+
65
+ var contentHeight = $m.find('.modal_content').outerHeight();
66
+ var contentWidth = $m.find('.modal_content').width();
67
+
68
+ var modalHeight = headerHeight + contentHeight; //this.currentModal.height();
69
+ var modalWidth = contentWidth; //this.currentModal.width();
70
+ var top = (this.windowHeight - modalHeight) / 2;
71
+ var left = (this.windowWidth - modalWidth) / 2;
72
+
73
+ if (top < 30)
74
+ {
75
+ top = 30; // top + admin bar
76
+ }
77
+ if (left < 0)
78
+ {
79
+ left: 0;
80
+ }
81
+
82
+ if (modalHeight > this.windowHeight) // if height is higher than screen supports
83
+ {
84
+ newHeight = this.windowHeight - top - 5;
85
+ this.currentModal.height(newHeight);
86
+
87
+ var newContentH = newHeight - headerHeight;
88
+ $m.find('.modal_content').height(newContentH);
89
+
90
+ }
91
+ this.currentModal.css('left', left + 'px');
92
+ this.currentModal.css('top', top + 'px');
93
+ this.currentModal.css('height', modalHeight);
94
+
95
+
96
+ $('.debugModal_overlay').show();
97
+ $('body').addClass('max-modal-active');
98
+
99
+ $(document).off('keydown', $.proxy(this.keyPressHandler, this));
100
+ $(document).on('keydown', $.proxy(this.keyPressHandler, this));
101
+
102
+ this.currentModal.focus();
103
+ }
104
+
105
+ debugModal.prototype.keyPressHandler = function (e)
106
+ {
107
+ if (e.keyCode === 27)
108
+ this.close();
109
+ }
110
+
111
+ debugModal.prototype.checkResize = function ()
112
+ {
113
+ this.windowHeight = $(window).height();
114
+ this.windowWidth = $(window).width();
115
+
116
+ if (this.currentModal === null)
117
+ return;
118
+
119
+ this.currentModal.removeAttr('style');
120
+ this.currentModal.find('.modal_content').removeAttr('style');
121
+ this.currentModal.removeAttr('style');
122
+
123
+ // redo sizes, repaint.
124
+
125
+ this.show();
126
+ }
127
+
128
+ debugModal.prototype.close = function()
129
+ {
130
+ this.currentModal.trigger('modal_close', [this]);
131
+ this.currentModal.remove();
132
+ this.currentModal = null;
133
+ $('.debugModal_overlay').remove();
134
+ $('body').removeClass('max-modal-active');
135
+ $(document).off('keydown', $.proxy(this.keyPressHandler, this));
136
+
137
+ }
138
+
139
+ debugModal.prototype.fadeOut = function (timeOut)
140
+ {
141
+ if (typeof timeOut == undefined)
142
+ timeOut = 600;
143
+
144
+ var self = this;
145
+ this.currentModal.fadeOut(timeOut, function() { self.close(); } );
146
+
147
+ }
148
+ /* Set the modal content
149
+
150
+ Sets the content of the modal. Do not run this function after adding controls.
151
+ @param string HTML,text content of the modal
152
+ */
153
+ debugModal.prototype.setContent = function(content)
154
+ {
155
+ this.currentModal.find('.modal_content').html(content);
156
+ }
157
+
158
+ /* Builds modal from hidden data
159
+
160
+ Builds modal from an formatted data object in DOM. Triggered on Click
161
+
162
+ */
163
+ debugModal.prototype.buildModal = function(e)
164
+ {
165
+ e.preventDefault();
166
+
167
+ var target = $(e.target);
168
+ if (typeof target.data('modal') == 'undefined')
169
+ target = target.parents('.debugModal');
170
+
171
+ this.target = target;
172
+ var id = target.data('modal');
173
+ var data = $('#' + id);
174
+
175
+ // options
176
+ if (typeof data.data('width') !== 'undefined')
177
+ this.setWidth = data.data('width');
178
+ else
179
+ this.setWidth = false;
180
+
181
+ if (typeof data.data('height') !== 'undefined')
182
+ this.setHeight = data.data('height');
183
+ else
184
+ this.setHeight = false;
185
+
186
+ // var title = $(data).find('.title').text();
187
+ // var controls = $(data).find('.controls').html();
188
+ var content = $(data).find('.content').html();
189
+
190
+ this.newModal(id);
191
+ this.setContent(content);
192
+
193
+ // callback on init
194
+ if (typeof $(data).data('load') !== 'undefined')
195
+ {
196
+
197
+ // default call
198
+ var funcName = data.data('load') + '(modal)';
199
+ var callFunc = new Function ('modal', funcName);
200
+
201
+ }
202
+
203
+ this.show();
204
+ }
205
+
206
+ debugModal.prototype.newModal = function(id)
207
+ {
208
+ if (this.currentModal !== null)
209
+ this.close();
210
+
211
+ var modal = $('<div class="debug-modal ' + id + '" > \
212
+ <div class="modal_header"> \
213
+ <div class="modal_close dashicons dashicons-no"></div><h3 class="modal_title">Debug</h3> \
214
+ </div> \
215
+ <div class="inner modal_content"></div>\
216
+ </div>');
217
+ if ($(this.parent).length > 0)
218
+ $(this.parent).append(modal);
219
+ else
220
+ $('body').append(modal); // fallback in case of interrupting page builders
221
+
222
+ $(modal).draggable({
223
+ handle: '.modal_header'
224
+ });
225
+
226
+ this.modals.push(modal);
227
+ this.currentModal = modal;
228
+
229
+ return this;
230
+
231
+ }
232
+
233
+ debugModal.prototype.writeOverlay = function()
234
+ {
235
+
236
+ $(this.parent).append('<div class="debugModal_overlay"></div>');
237
+ $('.debugModal_overlay').on('click', $.proxy(this.close, this));
238
+
239
+ }
240
+
241
+ var shortpixelDebug = new debugModal();
242
+ shortpixelDebug.init();
243
+ }); // jquery
res/js/shortpixel.js CHANGED
@@ -97,6 +97,17 @@ var ShortPixel = function() {
97
  }
98
  }
99
 
 
 
 
 
 
 
 
 
 
 
 
100
  function setupGeneralTab() {
101
  var rad = 0;
102
  if (typeof document.wp_shortpixel_options !== 'undefined')
@@ -163,6 +174,12 @@ var ShortPixel = function() {
163
  });
164
  ShortPixel.checkExifWarning();
165
 
 
 
 
 
 
 
166
  }
167
 
168
  function apiKeyChanged() {
@@ -309,7 +326,7 @@ var ShortPixel = function() {
309
  }
310
 
311
  function checkQuota() {
312
- var data = { action : 'shortpixel_check_quota'};
313
  jQuery.get(ShortPixel.AJAX_URL, data, function() {
314
  console.log("quota refreshed");
315
  });
@@ -507,7 +524,7 @@ var ShortPixel = function() {
507
  }
508
  }
509
 
510
- function includeUnlisted() {
511
  jQuery("#short-pixel-notice-unlisted").hide();
512
  jQuery("#optimizeUnlisted").prop('checked', true);
513
  var data = { action : 'shortpixel_dismiss_notice',
@@ -519,7 +536,7 @@ var ShortPixel = function() {
519
  console.log("dismissed");
520
  }
521
  });
522
- }
523
 
524
 
525
  function initFolderSelector() {
@@ -819,7 +836,7 @@ var ShortPixel = function() {
819
  newApiKey : newApiKey,
820
  proposeUpgrade : proposeUpgrade,
821
  closeProposeUpgrade : closeProposeUpgrade,
822
- includeUnlisted : includeUnlisted,
823
  bulkShowLengthyMsg : bulkShowLengthyMsg,
824
  bulkHideLengthyMsg : bulkHideLengthyMsg,
825
  bulkShowMaintenanceMsg : bulkShowMaintenanceMsg,
@@ -837,6 +854,7 @@ var ShortPixel = function() {
837
  closeComparerPopup : closeComparerPopup,
838
  convertPunycode : convertPunycode,
839
  checkExifWarning : checkExifWarning,
 
840
  comparerData : {
841
  cssLoaded : false,
842
  jsLoaded : false,
@@ -1265,6 +1283,7 @@ function optimizeThumbs(id) {
1265
  });
1266
  }
1267
 
 
1268
  function dismissShortPixelNoticeExceed(e) {
1269
  jQuery("#wp-admin-bar-shortpixel_processing").hide();
1270
  var data = { action : 'shortpixel_dismiss_notice',
@@ -1276,8 +1295,9 @@ function dismissShortPixelNoticeExceed(e) {
1276
  }
1277
  });
1278
  e.preventDefault();
1279
- }
1280
 
 
1281
  function dismissShortPixelNotice(id) {
1282
  jQuery("#short-pixel-notice-" + id).hide();
1283
  var data = { action : 'shortpixel_dismiss_notice',
@@ -1288,6 +1308,18 @@ function dismissShortPixelNotice(id) {
1288
  console.log("dismissed");
1289
  }
1290
  });
 
 
 
 
 
 
 
 
 
 
 
 
1291
  }
1292
 
1293
  function PercentageAnimator(outputSelector, targetPercentage) {
97
  }
98
  }
99
 
100
+ function checkBackUpWarning()
101
+ {
102
+ if (! jQuery('input[name="backupImages"]').is(':checked') )
103
+ {
104
+ jQuery('.backup_warning').fadeIn();
105
+ }
106
+ else {
107
+ jQuery('.backup_warning').fadeOut();
108
+ }
109
+ }
110
+
111
  function setupGeneralTab() {
112
  var rad = 0;
113
  if (typeof document.wp_shortpixel_options !== 'undefined')
174
  });
175
  ShortPixel.checkExifWarning();
176
 
177
+ jQuery('input[name="backupImages"]').on('change', function()
178
+ {
179
+ ShortPixel.checkBackUpWarning();
180
+ });
181
+ ShortPixel.checkBackUpWarning();
182
+
183
  }
184
 
185
  function apiKeyChanged() {
326
  }
327
 
328
  function checkQuota() {
329
+ var data = {action:'shortpixel_check_quota'};
330
  jQuery.get(ShortPixel.AJAX_URL, data, function() {
331
  console.log("quota refreshed");
332
  });
524
  }
525
  }
526
 
527
+ /* function includeUnlisted() {
528
  jQuery("#short-pixel-notice-unlisted").hide();
529
  jQuery("#optimizeUnlisted").prop('checked', true);
530
  var data = { action : 'shortpixel_dismiss_notice',
536
  console.log("dismissed");
537
  }
538
  });
539
+ } */
540
 
541
 
542
  function initFolderSelector() {
836
  newApiKey : newApiKey,
837
  proposeUpgrade : proposeUpgrade,
838
  closeProposeUpgrade : closeProposeUpgrade,
839
+ // includeUnlisted : includeUnlisted,
840
  bulkShowLengthyMsg : bulkShowLengthyMsg,
841
  bulkHideLengthyMsg : bulkHideLengthyMsg,
842
  bulkShowMaintenanceMsg : bulkShowMaintenanceMsg,
854
  closeComparerPopup : closeComparerPopup,
855
  convertPunycode : convertPunycode,
856
  checkExifWarning : checkExifWarning,
857
+ checkBackUpWarning : checkBackUpWarning,
858
  comparerData : {
859
  cssLoaded : false,
860
  jsLoaded : false,
1283
  });
1284
  }
1285
 
1286
+ /*
1287
  function dismissShortPixelNoticeExceed(e) {
1288
  jQuery("#wp-admin-bar-shortpixel_processing").hide();
1289
  var data = { action : 'shortpixel_dismiss_notice',
1295
  }
1296
  });
1297
  e.preventDefault();
1298
+ } */
1299
 
1300
+ /*
1301
  function dismissShortPixelNotice(id) {
1302
  jQuery("#short-pixel-notice-" + id).hide();
1303
  var data = { action : 'shortpixel_dismiss_notice',
1308
  console.log("dismissed");
1309
  }
1310
  });
1311
+ } */
1312
+
1313
+ function dismissFileError() {
1314
+ jQuery('.shortpixel-alert').hide();
1315
+ var data = { action : 'shortpixel_dismissFileError'
1316
+ };
1317
+ jQuery.get(ShortPixel.AJAX_URL, data, function(response) {
1318
+ data = JSON.parse(response);
1319
+ if(data["Status"] == ShortPixel.STATUS_SUCCESS) {
1320
+ console.log("dismissed");
1321
+ }
1322
+ });
1323
  }
1324
 
1325
  function PercentageAnimator(outputSelector, targetPercentage) {
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 void location.reload();s.addClass("shortpixel-alert"),s.addClass("shortpixel-quota-exceeded"),jQuery("a",s).attr("href","options-general.php?page=wp-shortpixel-settings"),jQuery("a div",s).attr("title","ShortPixel quota exceeded. Click for details.");break;case ShortPixel.STATUS_SKIP:case ShortPixel.STATUS_FAIL:s.addClass("shortpixel-alert shortpixel-processing"),jQuery("a div",s).attr("title",r),void 0!==t&&jQuery("a",s).attr("href","post.php?post="+t+"&action=edit");break;case ShortPixel.STATUS_NO_KEY:s.addClass("shortpixel-alert"),s.addClass("shortpixel-quota-exceeded"),jQuery("a",s).attr("href","options-general.php?page=wp-shortpixel-settings"),jQuery("a div",s).attr("title","Get API Key");break;case ShortPixel.STATUS_SUCCESS:case ShortPixel.STATUS_RETRY:s.addClass("shortpixel-processing"),s.removeClass("shortpixel-alert"),jQuery("a",s).removeAttr("target"),jQuery("a",s).attr("href",jQuery("a img",s).attr("success-url"))}s.removeClass("shortpixel-hide")}function hideToolBarAlert(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 dismissShortPixelNoticeExceed(e){jQuery("#wp-admin-bar-shortpixel_processing").hide();var r={action:"shortpixel_dismiss_notice",notice_id:"exceed"};jQuery.get(ShortPixel.AJAX_URL,r,function(e){(r=JSON.parse(e)).Status==ShortPixel.STATUS_SUCCESS&&console.log("dismissed")}),e.preventDefault()}function dismissShortPixelNotice(e){jQuery("#short-pixel-notice-"+e).hide();var r={action:"shortpixel_dismiss_notice",notice_id:e};jQuery.get(ShortPixel.AJAX_URL,r,function(e){(r=JSON.parse(e)).Status==ShortPixel.STATUS_SUCCESS&&console.log("dismissed")})}function PercentageAnimator(e,r){this.animationSpeed=10,this.increment=2,this.curPercentage=0,this.targetPercentage=r,this.outputSelector=e,this.animate=function(e){this.targetPercentage=e,setTimeout(PercentageTimer.bind(null,this),this.animationSpeed)}}function PercentageTimer(e){e.curPercentage-e.targetPercentage<-e.increment?e.curPercentage+=e.increment:e.curPercentage-e.targetPercentage>e.increment?e.curPercentage-=e.increment:e.curPercentage=e.targetPercentage,jQuery(e.outputSelector).text(e.curPercentage+"%"),e.curPercentage!=e.targetPercentage&&setTimeout(PercentageTimer.bind(null,e),e.animationSpeed)}function progressUpdate(e,r){var t=jQuery("#bulk-progress");t.length&&(jQuery(".progress-left",t).css("width",e+"%"),jQuery(".progress-img",t).css("left",e+"%"),e>24?(jQuery(".progress-img span",t).html(""),jQuery(".progress-left",t).html(e+"%")):(jQuery(".progress-img span",t).html(e+"%"),jQuery(".progress-left",t).html("")),jQuery(".bulk-estimate").html(r))}function sliderUpdate(e,r,t,s,o){var i=jQuery(".bulk-slider div.bulk-slide:first-child");if(0!==i.length){"empty-slide"!=i.attr("id")&&i.hide(),i.css("z-index",1e3),jQuery(".bulk-img-opt",i).attr("src",""),void 0===t&&(t=""),t.length>0&&jQuery(".bulk-img-orig",i).attr("src","");var a=i.clone();a.attr("id","slide-"+e),jQuery(".bulk-img-opt",a).attr("src",r),t.length>0?(jQuery(".img-original",a).css("display","inline-block"),jQuery(".bulk-img-orig",a).attr("src",t)):jQuery(".img-original",a).css("display","none"),jQuery(".bulk-opt-percent",a).html('<input type="text" class="dial" value="'+s+'"/>'),jQuery(".bulk-slider").append(a),ShortPixel.percentDial("#"+a.attr("id")+" .dial",100),jQuery(".bulk-slider-container span.filename").html("&nbsp;&nbsp;"+o),"empty-slide"==i.attr("id")?(i.remove(),jQuery(".bulk-slider-container").css("display","block")):i.animate({left:i.width()+i.position().left},"slow","swing",function(){i.remove(),a.fadeIn("slow")})}}function hideSlider(){jQuery(".bulk-slider-container").css("display","none")}function showStats(){jQuery(".bulk-stats").length}function SPstringFormat(){var e=Array.prototype.slice.call(arguments);if(0!==e.length){var r=e.shift();for(i=0;i<e.length;i++)r=r.replace(new RegExp("\\{"+i+"\\}","gm"),e[i]);return r}}jQuery(document).ready(function(){ShortPixel.init()});var ShortPixel=function(){function e(e){jQuery(e).is(":checked")?jQuery("#width,#height").removeAttr("disabled"):jQuery("#width,#height").attr("disabled","disabled")}function r(){jQuery("#shortpixel-hs-button-blind").remove(),jQuery("#shortpixel-hs-tools").remove(),jQuery("#hs-beacon").remove(),jQuery("#botbutton").remove(),jQuery("#shortpixel-hs-blind").remove()}return jQuery("#key").keypress(function(e){13==e.which&&jQuery("#valid").val("validate")}),{init:function(){void 0===ShortPixel.API_KEY&&(jQuery("table.wp-list-table.media").length>0&&jQuery('select[name^="action"] option:last-child').before('<option value="short-pixel-bulk">'+_spTr.optimizeWithSP+'</option><option value="short-pixel-bulk-lossy"> → '+_spTr.redoLossy+'</option><option value="short-pixel-bulk-glossy"> → '+_spTr.redoGlossy+'</option><option value="short-pixel-bulk-lossless"> → '+_spTr.redoLossless+'</option><option value="short-pixel-bulk-restore"> → '+_spTr.restoreOriginal+"</option>"),ShortPixel.setOptions(ShortPixelConstants[0]),jQuery("#backup-folder-size").length&&jQuery("#backup-folder-size").html(ShortPixel.getBackupSize()),"todo"==ShortPixel.MEDIA_ALERT&&jQuery("div.media-frame.mode-grid").length>0&&jQuery("div.media-frame.mode-grid").before('<div id="short-pixel-media-alert" class="notice notice-warning"><p>'+SPstringFormat(_spTr.changeMLToListMode,'<a href="upload.php?mode=list" class="view-list"><span class="screen-reader-text">'," </span>",'</a><a class="alignright" href="javascript:ShortPixel.dismissMediaAlert();">',"</a>")+"</p></div>"),jQuery(window).on("beforeunload",function(){1==ShortPixel.bulkProcessor&&clearBulkProcessor()}),checkQuotaExceededAlert(),checkBulkProgress())},setOptions:function(e){for(var r in e)ShortPixel[r]=e[r]},isEmailValid:function(e){return/^\w+([\.+-]?\w+)*@\w+([\.-]?\w+)*(\.\w{1,63})+$/.test(e)},updateSignupEmail:function(){var e=jQuery("#pluginemail").val();ShortPixel.isEmailValid(e)&&jQuery("#request_key").removeClass("disabled"),jQuery("#request_key").attr("href",jQuery("#request_key").attr("href").split("?")[0]+"?pluginemail="+e)},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()},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()},includeUnlisted:function(){jQuery("#short-pixel-notice-unlisted").hide(),jQuery("#optimizeUnlisted").prop("checked",!0);var e={action:"shortpixel_dismiss_notice",notice_id:"unlisted",notice_data:"true"};jQuery.get(ShortPixel.AJAX_URL,e,function(r){(e=JSON.parse(r)).Status==ShortPixel.STATUS_SUCCESS&&console.log("dismissed")})},bulkShowLengthyMsg:function(e,r,t){var s=jQuery(".bulk-notice-msg.bulk-lengthy");if(0!=s.length){var o=jQuery("a",s);o.text(r),t?o.attr("href",t):o.attr("href",o.data("href").replace("__ID__",e)),s.css("display","block")}},bulkHideLengthyMsg:function(){jQuery(".bulk-notice-msg.bulk-lengthy").css("display","none")},bulkShowMaintenanceMsg:function(e){var r=jQuery(".bulk-notice-msg.bulk-"+e);0!=r.length&&r.css("display","block")},bulkHideMaintenanceMsg:function(e){jQuery(".bulk-notice-msg.bulk-"+e).css("display","none")},bulkShowError:function(e,r,t,s){var o=jQuery("#bulk-error-template");if(0!=o.length){var i=o.clone();i.attr("id","bulk-error-"+e),-1==e?(jQuery("span.sp-err-title",i).remove(),i.addClass("bulk-error-fatal")):(jQuery("img",i).remove(),jQuery("#bulk-error-".id).remove()),jQuery("span.sp-err-content",i).html(r);var a=jQuery("a.sp-post-link",i);s?a.attr("href",s):a.attr("href",a.attr("href").replace("__ID__",e)),a.text(t),o.after(i),i.css("display","block")}},confirmBulkAction:function(e,r){return!!confirm(_spTr["confirmBulk"+e])||(r.stopPropagation(),r.preventDefault(),!1)},checkRandomAnswer:function(e){var r=jQuery(e.target).val(),t=jQuery('input[name="random_answer"]').val(),s=jQuery('input[name="random_answer"]').data("target");r==t?(jQuery(s).removeClass("disabled").prop("disabled",!1),jQuery(s).removeAttr("aria-disabled")):jQuery(s).addClass("disabled").prop("disabled",!0)},removeBulkMsg:function(e){jQuery(e).parent().parent().remove()},isCustomImageId:function(e){return"C-"==e.substring(0,2)},recheckQuota:function(){var e=window.location.href.split("#");window.location.href=e[0]+(e[0].indexOf("?")>0?"&":"?")+"checkquota=1"+(void 0===e[1]?"":"#"+e[1])},openImageMenu:function(e){e.preventDefault(),this.menuCloseEvent||(jQuery(window).click(function(e){e.target.matches(".sp-dropbtn")||jQuery(".sp-dropdown.sp-show").removeClass("sp-show")}),this.menuCloseEvent=!0);var r=e.target.parentElement.classList.contains("sp-show");jQuery(".sp-dropdown.sp-show").removeClass("sp-show"),r||e.target.parentElement.classList.add("sp-show")},menuCloseEvent:!1,loadComparer:function(e){this.comparerData.origUrl=!1,!1===this.comparerData.cssLoaded&&(jQuery("<link>").appendTo("head").attr({type:"text/css",rel:"stylesheet",href:this.WP_PLUGIN_URL+"/res/css/twentytwenty.min.css"}),this.comparerData.cssLoaded=2),!1===this.comparerData.jsLoaded&&(jQuery.getScript(this.WP_PLUGIN_URL+"/res/js/jquery.twentytwenty.min.js",function(){ShortPixel.comparerData.jsLoaded=2,ShortPixel.comparerData.origUrl.length>0&&ShortPixel.displayComparerPopup(ShortPixel.comparerData.width,ShortPixel.comparerData.height,ShortPixel.comparerData.origUrl,ShortPixel.comparerData.optUrl)}),this.comparerData.jsLoaded=1),!1===this.comparerData.origUrl&&(jQuery.ajax({type:"POST",url:ShortPixel.AJAX_URL,data:{action:"shortpixel_get_comparer_data",id:e},success:function(e){data=JSON.parse(e),jQuery.extend(ShortPixel.comparerData,data),2==ShortPixel.comparerData.jsLoaded&&ShortPixel.displayComparerPopup(ShortPixel.comparerData.width,ShortPixel.comparerData.height,ShortPixel.comparerData.origUrl,ShortPixel.comparerData.optUrl)}}),this.comparerData.origUrl="")},displayComparerPopup:function(e,r,t,s){var o=e,i=r<150||e<350,a=jQuery(i?"#spUploadCompareSideBySide":"#spUploadCompare"),l=jQuery(".sp-modal-shade");i||jQuery("#spCompareSlider").html('<img 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()},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 s=jQuery("li.shortpixel-toolbar-processing");switch(e){case ShortPixel.STATUS_QUOTA_EXCEEDED:if(window.location.href.search("wp-short-pixel-bulk")>0&&0==jQuery(".sp-quota-exceeded-alert").length)return void location.reload();s.addClass("shortpixel-alert"),s.addClass("shortpixel-quota-exceeded"),jQuery("a",s).attr("href","options-general.php?page=wp-shortpixel-settings"),jQuery("a div",s).attr("title","ShortPixel quota exceeded. Click for details.");break;case ShortPixel.STATUS_SKIP:case ShortPixel.STATUS_FAIL:s.addClass("shortpixel-alert shortpixel-processing"),jQuery("a div",s).attr("title",r),void 0!==t&&jQuery("a",s).attr("href","post.php?post="+t+"&action=edit");break;case ShortPixel.STATUS_NO_KEY:s.addClass("shortpixel-alert"),s.addClass("shortpixel-quota-exceeded"),jQuery("a",s).attr("href","options-general.php?page=wp-shortpixel-settings"),jQuery("a div",s).attr("title","Get API Key");break;case ShortPixel.STATUS_SUCCESS:case ShortPixel.STATUS_RETRY:s.addClass("shortpixel-processing"),s.removeClass("shortpixel-alert"),jQuery("a",s).removeAttr("target"),jQuery("a",s).attr("href",jQuery("a img",s).attr("success-url"))}s.removeClass("shortpixel-hide")}function hideToolBarAlert(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 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}}();
res/scss/shortpixel-admin.scss CHANGED
@@ -1,8 +1,8 @@
1
 
2
- @import 'utils/notices';
3
  @import 'view/bulk-restore-all';
4
  @import 'view/bulk_dashboard';
5
  @import 'view/settings-advanced';
 
6
  @import 'view/settings';
7
  @import 'view/edit-media';
8
  @import 'view/debug';
1
 
 
2
  @import 'view/bulk-restore-all';
3
  @import 'view/bulk_dashboard';
4
  @import 'view/settings-advanced';
5
+ @import 'view/settings-cloudflare';
6
  @import 'view/settings';
7
  @import 'view/edit-media';
8
  @import 'view/debug';
res/scss/shortpixel-notices.scss ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ .shortpixel.notice
3
+ {
4
+ //padding: 18px;
5
+ min-height: 75px;
6
+ padding: 8px;
7
+ display: flex;
8
+ align-items: center;
9
+
10
+ img
11
+ {
12
+ // max-height: 50px;
13
+ }
14
+ .notice-dismiss
15
+ {
16
+ margin-top: 10px;
17
+ }
18
+ span
19
+ {
20
+ vertical-align: middle;
21
+ &.icon {
22
+ //float: left;
23
+ margin: 0 25px 0 0;
24
+ // display: inline-block;
25
+ }
26
+ &.content
27
+ {
28
+ //j display: inline-block;
29
+ //max-width: 600px;
30
+ }
31
+
32
+ }
33
+ }
34
+
35
+ // compat list if.
36
+ .shortpixel.notice
37
+ {
38
+ .sp-conflict-plugins {
39
+ display: table;
40
+ border-spacing: 10px;
41
+ border-collapse: separate;
42
+ li {
43
+ display: table-row;
44
+ }
45
+ li > * {
46
+ display: table-cell;
47
+ }
48
+ }
49
+
50
+ li.sp-conflict-plugins-list {
51
+ line-height: 28px;
52
+ list-style: disc;
53
+ margin-left: 80px;
54
+ }
55
+ li.sp-conflict-plugins-list a.button {
56
+ margin-left: 10px;
57
+ }
58
+ }
res/scss/view/_debug.scss ADDED
@@ -0,0 +1,110 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+
3
+ body.debug-model-active {
4
+ overflow: hidden;
5
+ }
6
+
7
+ .debugInfo .content.wrapper
8
+ {
9
+ display: none;
10
+ li strong {
11
+ margin-right: 15px;
12
+ }
13
+ ul
14
+ {
15
+ margin: 25px 0;
16
+ }
17
+ }
18
+
19
+
20
+ .debug-modal {
21
+ display: none;
22
+ width: 75%;
23
+ max-width: 90%;
24
+ height: auto;
25
+ max-height: 90vh;
26
+ overflow: hidden;
27
+ border-radius: 4px;
28
+ box-shadow: -3px -3px 10px rgba(0, 0, 0, 0.5);
29
+
30
+ position: fixed;
31
+ left: 20%;
32
+ top: 10%;
33
+ //overflow-y: auto;
34
+ z-index: 10020; // just trying to stay on top, don't blame me.
35
+
36
+
37
+ display: none;
38
+ background: #ffffff;
39
+
40
+ &.success {
41
+ //borer: solgreen;
42
+ border: 4px solid green;
43
+
44
+ }
45
+ &.error {
46
+ border: 4px solid red;
47
+ h3 { background-color: #ff0000;}
48
+ }
49
+
50
+ .content-area {
51
+ background-color: #fff;
52
+
53
+ }
54
+
55
+ .modal_header {
56
+ text-align: center;
57
+ font-size: 16px;
58
+ font-weight: 700;
59
+ background-color: #f3f3f3;
60
+ border-bottom: 1px solid #ccc;
61
+ padding: 8px 5px;
62
+ cursor: move;
63
+
64
+ h3 {
65
+ margin: 0;
66
+ color: #444;
67
+ font-weight: 400;
68
+ padding: 0;
69
+ text-align: center;
70
+ text-shadow: none;
71
+ font-size: 16px;
72
+ }
73
+
74
+ .modal_close {
75
+ position: absolute;
76
+ right: 5px;
77
+ top: 8px;
78
+ width: 20px;
79
+ height: 20px;
80
+ cursor: pointer;
81
+ color: #444;
82
+ &:hover {
83
+ cursor: pointer;
84
+ color: #111;
85
+ }
86
+ }
87
+ }
88
+ .content, .modal_content {
89
+ padding: 5px 15px 10px;
90
+ //display: inline-block;
91
+ //height: 100%;
92
+ //margin-top: -40px;
93
+ overflow-y: auto;
94
+ }
95
+
96
+ }
97
+
98
+ .debugModal_overlay
99
+ {
100
+ background: #000;
101
+ left: 0;
102
+ right: 0;
103
+ bottom: 0;
104
+ top: 0;
105
+ height: 100%;
106
+ position: fixed;
107
+ opacity : 0.7;
108
+ z-index: 10000;
109
+ display: none;
110
+ }
res/scss/view/_settings-cloudflare.scss ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+
3
+ .cf_switch
4
+ {
5
+
6
+ label {
7
+ width: 100%;
8
+ margin: 0 -2px;
9
+ background-color: #e2faff;
10
+ // font-weight: 700;
11
+ display: inline-block;
12
+ // font-size: 13px;
13
+
14
+ span
15
+ {
16
+ //text-align:center;
17
+ // font-size: 18px;
18
+ padding:8px 0px 8px 15px;
19
+ display:block;
20
+ font-size: 13px;
21
+
22
+ }
23
+ input {
24
+ display: none;
25
+ }
26
+ input:checked + span
27
+ {
28
+ background-color:#0085ba;
29
+ color:#F7F7F7;
30
+ }
31
+ }
32
+ }
res/scss/view/_settings.scss CHANGED
@@ -82,4 +82,26 @@
82
  }
83
  }
84
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
85
  }
82
  }
83
  }
84
 
85
+ /* In-view notice ( not on top, between the options ) - styled after WP notice */
86
+ .view-notice
87
+ {
88
+
89
+ box-shadow: 0 1px 1px 0 rgba( 0, 0, 0, 0.1 );
90
+ border: 4px solid #fff;
91
+
92
+ padding: 1px 12px;
93
+ p {
94
+ margin: 1em 0 !important;
95
+ }
96
+ &.warning
97
+ {
98
+ border-left-color: #ffb900;
99
+ }
100
+ }
101
+
102
+ .view-notice-row
103
+ {
104
+ display: none;
105
+ }
106
+
107
  }
shortpixel-plugin.php CHANGED
@@ -55,7 +55,8 @@ class ShortPixelPlugin
55
 
56
  $front = new frontController();
57
  $admin = adminController::getInstance();
58
-
 
59
 
60
  if ($this->settings()->autoMediaLibrary)
61
  {
@@ -160,7 +161,8 @@ class ShortPixelPlugin
160
  {
161
  add_action('admin_menu', array($this,'admin_pages'));
162
  add_action('admin_enqueue_scripts', array($this, 'admin_scripts')); // admin scripts
163
- add_action('admin_notices', array($this, 'admin_notices')); // notices occured before page load
 
164
  add_action('admin_footer', array($this, 'admin_notices')); // called in views.
165
  }
166
 
@@ -204,6 +206,9 @@ class ShortPixelPlugin
204
  //modal - used in settings for selecting folder
205
  wp_register_style('shortpixel-modal', plugins_url('/res/css/short-pixel-modal.min.css',SHORTPIXEL_PLUGIN_FILE), array(), SHORTPIXEL_IMAGE_OPTIMISER_VERSION);
206
 
 
 
 
207
 
208
  wp_register_script('shortpixel-debug', plugins_url('/res/js/debug.js',SHORTPIXEL_PLUGIN_FILE), array('jquery', 'jquery-ui-draggable'), SHORTPIXEL_IMAGE_OPTIMISER_VERSION);
209
 
@@ -213,7 +218,7 @@ class ShortPixelPlugin
213
  {
214
  $noticeControl = Notices::getInstance();
215
  $noticeControl->loadIcons(array(
216
- 'normal' => '<img class="short-pixel-notice-icon" src="' . plugins_url('res/img/robo-cool.png', SHORTPIXEL_PLUGIN_FILE) . '">',
217
  'success' => '<img class="short-pixel-notice-icon" src="' . plugins_url('res/img/robo-cool.png', SHORTPIXEL_PLUGIN_FILE) . '">',
218
  'warning' => '<img class="short-pixel-notice-icon" src="' . plugins_url('res/img/robo-scared.png', SHORTPIXEL_PLUGIN_FILE) . '">',
219
  'error' => '<img class="short-pixel-notice-icon" src="' . plugins_url('res/img/robo-scared.png', SHORTPIXEL_PLUGIN_FILE) . '">',
@@ -221,11 +226,17 @@ class ShortPixelPlugin
221
 
222
  if ($noticeControl->countNotices() > 0)
223
  {
224
- wp_enqueue_style('shortpixel-admin'); // queue on places when it's not our runtime.
225
- foreach($noticeControl->getNotices() as $notice)
 
 
 
 
 
226
  {
227
  echo $notice->getForDisplay();
228
  }
 
229
  }
230
  $noticeControl->update(); // puts views, and updates
231
  }
@@ -374,7 +385,13 @@ class ShortPixelPlugin
374
  if(\WPShortPixelSettings::getOpt('deliverWebp') == 3 && ! $env->is_nginx) {
375
  \WpShortPixel::alterHtaccess(); //add the htaccess lines
376
  }
 
 
 
 
 
377
  \WPShortPixelSettings::onActivate();
 
378
  }
379
 
380
  public static function deactivatePlugin()
55
 
56
  $front = new frontController();
57
  $admin = adminController::getInstance();
58
+ $adminNotices = adminNoticesController::getInstance(); // Hook in the admin notices.
59
+ $notices = Notices::getInstance(); // This hooks the ajax listener
60
 
61
  if ($this->settings()->autoMediaLibrary)
62
  {
161
  {
162
  add_action('admin_menu', array($this,'admin_pages'));
163
  add_action('admin_enqueue_scripts', array($this, 'admin_scripts')); // admin scripts
164
+ // defer notices a little to allow other hooks ( notable adminnotices )
165
+ add_action('admin_notices', array($this, 'admin_notices'), 50); // notices occured before page load
166
  add_action('admin_footer', array($this, 'admin_notices')); // called in views.
167
  }
168
 
206
  //modal - used in settings for selecting folder
207
  wp_register_style('shortpixel-modal', plugins_url('/res/css/short-pixel-modal.min.css',SHORTPIXEL_PLUGIN_FILE), array(), SHORTPIXEL_IMAGE_OPTIMISER_VERSION);
208
 
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
 
213
  wp_register_script('shortpixel-debug', plugins_url('/res/js/debug.js',SHORTPIXEL_PLUGIN_FILE), array('jquery', 'jquery-ui-draggable'), SHORTPIXEL_IMAGE_OPTIMISER_VERSION);
214
 
218
  {
219
  $noticeControl = Notices::getInstance();
220
  $noticeControl->loadIcons(array(
221
+ 'normal' => '<img class="short-pixel-notice-icon" src="' . plugins_url('res/img/slider.png', SHORTPIXEL_PLUGIN_FILE) . '">',
222
  'success' => '<img class="short-pixel-notice-icon" src="' . plugins_url('res/img/robo-cool.png', SHORTPIXEL_PLUGIN_FILE) . '">',
223
  'warning' => '<img class="short-pixel-notice-icon" src="' . plugins_url('res/img/robo-scared.png', SHORTPIXEL_PLUGIN_FILE) . '">',
224
  'error' => '<img class="short-pixel-notice-icon" src="' . plugins_url('res/img/robo-scared.png', SHORTPIXEL_PLUGIN_FILE) . '">',
226
 
227
  if ($noticeControl->countNotices() > 0)
228
  {
229
+ $notices = $noticeControl->getNoticesForDisplay();
230
+
231
+ if (count($notices) > 0)
232
+ {
233
+ wp_enqueue_style('shortpixel-notices');
234
+
235
+ foreach($notices as $notice)
236
  {
237
  echo $notice->getForDisplay();
238
  }
239
+ }
240
  }
241
  $noticeControl->update(); // puts views, and updates
242
  }
385
  if(\WPShortPixelSettings::getOpt('deliverWebp') == 3 && ! $env->is_nginx) {
386
  \WpShortPixel::alterHtaccess(); //add the htaccess lines
387
  }
388
+
389
+ adminNoticesController::resetCompatNotice();
390
+ adminNoticesController::resetAPINotices();
391
+ adminNoticesController::resetQuotaNotices();
392
+
393
  \WPShortPixelSettings::onActivate();
394
+
395
  }
396
 
397
  public static function deactivatePlugin()
shortpixel_api.php CHANGED
@@ -245,8 +245,13 @@ class ShortPixelAPI {
245
  //#$compressionType = isset($meta['ShortPixel']['type']) ? ($meta['ShortPixel']['type'] == 'lossy' ? 1 : 0) : $this->_settings->compressionType;
246
  $meta = $itemHandler->getMeta();
247
  $compressionType = $meta->getCompressionType() !== null ? $meta->getCompressionType() : $this->_settings->compressionType;
248
- $response = $this->doRequests($URLs, true, $itemHandler, $compressionType);//send requests to API
249
 
 
 
 
 
 
 
250
 
251
  //die($response['body']);
252
 
245
  //#$compressionType = isset($meta['ShortPixel']['type']) ? ($meta['ShortPixel']['type'] == 'lossy' ? 1 : 0) : $this->_settings->compressionType;
246
  $meta = $itemHandler->getMeta();
247
  $compressionType = $meta->getCompressionType() !== null ? $meta->getCompressionType() : $this->_settings->compressionType;
 
248
 
249
+ try {
250
+ $response = $this->doRequests($URLs, true, $itemHandler, $compressionType);//send requests to API
251
+ }
252
+ catch(Exception $e) {
253
+ Log::addError('Api DoRequest Thrown ' . $e->getMessage());
254
+ }
255
 
256
  //die($response['body']);
257
 
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.15.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.15.4");
23
  define('SHORTPIXEL_MAX_TIMEOUT', 10);
24
  define('SHORTPIXEL_VALIDATE_MAX_TIMEOUT', 15);
25
  define('SHORTPIXEL_BACKUP', 'ShortpixelBackups');
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.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.16.0");
23
  define('SHORTPIXEL_MAX_TIMEOUT', 10);
24
  define('SHORTPIXEL_VALIDATE_MAX_TIMEOUT', 15);
25
  define('SHORTPIXEL_BACKUP', 'ShortpixelBackups');