ShortPixel Image Optimizer - Version 4.1.0

Version Description

  • retina images support - optimize also retina images
  • WebP support - generate also WebP images option
  • optimize other media folders also from the root of the site, not only in wp-content
  • restore and re-optimize other media images
  • resize options - defined rectangle to be contained in the resized image or the resized image to contain the defined rectangle
Download this release

Release Info

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

Code changes from version 4.0.2 to 4.1.0

class/db/shortpixel-custom-meta-dao.php CHANGED
@@ -313,7 +313,7 @@ class ShortPixelCustomMetaDao {
313
  public function getPendingMetas($count) {
314
  return $this->db->query("SELECT sm.id from {$this->db->getPrefix()}shortpixel_meta sm "
315
  . "INNER JOIN {$this->db->getPrefix()}shortpixel_folders sf on sm.folder_id = sf.id "
316
- . "WHERE sf.status <> -1 AND ( sm.status = 0 OR sm.status = 1 OR (sm.status <> 2 AND sm.retries < 3)) "
317
  . "ORDER BY ts_added DESC LIMIT $count");
318
  }
319
 
@@ -347,7 +347,7 @@ class ShortPixelCustomMetaDao {
347
  foreach($rows as $row) {
348
  $meta = new ShortPixelMeta($row);
349
  if($meta->getPath()) {
350
- $meta->setWebPath(ShortPixelMetaFacade::filenameToContentRelative($meta->getPath()));
351
  }
352
  //die(var_dump($meta)."ZA META");
353
  return $meta;
313
  public function getPendingMetas($count) {
314
  return $this->db->query("SELECT sm.id from {$this->db->getPrefix()}shortpixel_meta sm "
315
  . "INNER JOIN {$this->db->getPrefix()}shortpixel_folders sf on sm.folder_id = sf.id "
316
+ . "WHERE sf.status <> -1 AND sm.status <> 3 AND ( sm.status = 0 OR sm.status = 1 OR (sm.status < 0 AND sm.retries < 3)) "
317
  . "ORDER BY ts_added DESC LIMIT $count");
318
  }
319
 
347
  foreach($rows as $row) {
348
  $meta = new ShortPixelMeta($row);
349
  if($meta->getPath()) {
350
+ $meta->setWebPath(ShortPixelMetaFacade::filenameToRootRelative($meta->getPath()));
351
  }
352
  //die(var_dump($meta)."ZA META");
353
  return $meta;
class/db/shortpixel-meta-facade.php CHANGED
@@ -187,7 +187,8 @@ class ShortPixelMetaFacade {
187
  $urlList[] = $url;
188
  $path = get_attached_file($this->ID);//get the full file PATH
189
  $filePath[] = $path;
190
-
 
191
  $meta = $this->getMeta();
192
  $sizes = $meta->getThumbs();
193
 
@@ -197,14 +198,17 @@ class ShortPixelMetaFacade {
197
  && count($sizes))
198
  {
199
  foreach( $sizes as $thumbnailInfo ) {
200
- $urlList[] = str_replace(ShortPixelAPI::MB_basename($urlList[0]), $thumbnailInfo['file'], $url);
201
- $filePath[] = str_replace(ShortPixelAPI::MB_basename($filePath[0]), $thumbnailInfo['file'], $path);
 
 
 
202
  }
203
  }
204
  if(!count($sizes)) {
205
  WPShortPixel::log("getURLsAndPATHs: no meta sizes for ID " . $this->ID . " : " . json_encode($this->rawMeta));
206
  }
207
-
208
  if($onlyThumbs) { //remove the main image
209
  array_shift($urlList);
210
  array_shift($filePath);
@@ -212,6 +216,16 @@ class ShortPixelMetaFacade {
212
  }
213
  return array("URLs" => $urlList, "PATHs" => $filePath);
214
  }
 
 
 
 
 
 
 
 
 
 
215
 
216
  public static function getWPMLDuplicates( $id ) {
217
  global $wpdb;
@@ -245,16 +259,16 @@ class ShortPixelMetaFacade {
245
  return str_replace(get_home_path(), site_url()."/", $path);
246
  }
247
 
248
- public static function pathToContentRelative($path) {
249
  //$upl = wp_upload_dir();
250
  $pathParts = explode(DIRECTORY_SEPARATOR, $path);
251
  unset($pathParts[count($pathParts) - 1]);
252
  $path = implode(DIRECTORY_SEPARATOR, $pathParts);
253
- return str_replace(WP_CONTENT_DIR . "/", "", $path);
254
  }
255
 
256
- public static function filenameToContentRelative($path) {
257
- return str_replace(WP_CONTENT_DIR . DIRECTORY_SEPARATOR, "", $path);
258
  }
259
 
260
  public static function getMaxMediaId() {
@@ -276,7 +290,7 @@ class ShortPixelMetaFacade {
276
  }
277
 
278
  public static function stripQueuedIdType($id) {
279
- return substr($id, 2);
280
  }
281
 
282
  public function getQueuedId() {
@@ -315,8 +329,8 @@ class ShortPixelMetaFacade {
315
  */
316
  static public function returnSubDir($file, $type)
317
  {
318
- if(strstr($file, WP_CONTENT_DIR . DIRECTORY_SEPARATOR)) {
319
- $path = str_replace( WP_CONTENT_DIR . DIRECTORY_SEPARATOR, "", $file);
320
  } else {
321
  $path = (substr($file, 1));
322
  }
187
  $urlList[] = $url;
188
  $path = get_attached_file($this->ID);//get the full file PATH
189
  $filePath[] = $path;
190
+ $this->addRetina($path, $url, $filePath, $urlList);
191
+
192
  $meta = $this->getMeta();
193
  $sizes = $meta->getThumbs();
194
 
198
  && count($sizes))
199
  {
200
  foreach( $sizes as $thumbnailInfo ) {
201
+ $tUrl = str_replace(ShortPixelAPI::MB_basename($urlList[0]), $thumbnailInfo['file'], $url);
202
+ $tPath = str_replace(ShortPixelAPI::MB_basename($filePath[0]), $thumbnailInfo['file'], $path);
203
+ $urlList[] = $tUrl;
204
+ $filePath[] = $tPath;
205
+ $this->addRetina($tPath, $tUrl, $filePath, $urlList);
206
  }
207
  }
208
  if(!count($sizes)) {
209
  WPShortPixel::log("getURLsAndPATHs: no meta sizes for ID " . $this->ID . " : " . json_encode($this->rawMeta));
210
  }
211
+
212
  if($onlyThumbs) { //remove the main image
213
  array_shift($urlList);
214
  array_shift($filePath);
216
  }
217
  return array("URLs" => $urlList, "PATHs" => $filePath);
218
  }
219
+
220
+ protected function addRetina($path, $url, &$fileList, &$urlList) {
221
+ $ext = pathinfo($path, PATHINFO_EXTENSION);
222
+ $retinaPath = substr($path, 0, strlen($path) - 1 - strlen($ext)) . "@2x." . $ext;
223
+ if(file_exists($retinaPath)) {
224
+ // echo($retinaPath . " added\n");
225
+ $urlList[] = substr($url, 0, strlen($url) -1 - strlen($ext)) . "@2x." . $ext;
226
+ $fileList[] = $retinaPath;
227
+ }
228
+ }
229
 
230
  public static function getWPMLDuplicates( $id ) {
231
  global $wpdb;
259
  return str_replace(get_home_path(), site_url()."/", $path);
260
  }
261
 
262
+ public static function pathToRootRelative($path) {
263
  //$upl = wp_upload_dir();
264
  $pathParts = explode(DIRECTORY_SEPARATOR, $path);
265
  unset($pathParts[count($pathParts) - 1]);
266
  $path = implode(DIRECTORY_SEPARATOR, $pathParts);
267
+ return str_replace(get_home_path(), "", $path);
268
  }
269
 
270
+ public static function filenameToRootRelative($path) {
271
+ return str_replace(get_home_path(), "", $path);
272
  }
273
 
274
  public static function getMaxMediaId() {
290
  }
291
 
292
  public static function stripQueuedIdType($id) {
293
+ return intval(substr($id, 2));
294
  }
295
 
296
  public function getQueuedId() {
329
  */
330
  static public function returnSubDir($file, $type)
331
  {
332
+ if(strstr($file, get_home_path())) {
333
+ $path = str_replace( get_home_path(), "", $file);
334
  } else {
335
  $path = (substr($file, 1));
336
  }
shortpixel_queue.php → class/shortpixel_queue.php RENAMED
File without changes
class/view/shortpixel-list-table.php CHANGED
@@ -45,25 +45,46 @@ class ShortPixelListTable extends WP_List_Table {
45
  case 'name':
46
  $title = '<a href="" title="'.$item->folder.'"><strong>' . $item->name . '</strong></a>';
47
 
48
- $actions = array();
49
- if($item->status <= 1) {
50
- // create the image web path
51
- $actions = array(
52
- 'optimize' => sprintf( '<a href="?page=%s&action=%s&image=%s&_wpnonce=%s">' . ($item->status == 0 ? 'Optimize' : 'Retry') . '</a>',
53
- esc_attr( $_REQUEST['page'] ), 'optimize', absint( $item->id ), wp_create_nonce( 'sp_optimize_image' ) )
54
- );
55
- }
56
  $url = ShortPixelMetaFacade::pathToWebPath($item->folder);
57
- $actions['view'] = sprintf( '<a href="%s" target="_blank">View</a>', $url );
58
- $title = $title . $this->row_actions( $actions );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59
  return $title;
60
  case 'folder':
61
- return ShortPixelMetaFacade::pathToContentRelative($item->folder);
62
  case 'status':
63
  switch($item->status) {
64
- case 2: $msg = 0 + $item->message == 0 ? "Bonus processing" : "Reduced by " . $item->message . "%" . (0 + $item->message < 5 ? "<br>Bonus processing." : "");
 
 
65
  break;
66
- case 1: $msg = "Pending";
67
  break;
68
  case 0: $msg = "Waiting";
69
  break;
@@ -143,22 +164,46 @@ class ShortPixelListTable extends WP_List_Table {
143
  $this->ctrl->optimizeCustomImage($id);
144
  }
145
 
 
 
 
 
 
 
 
 
146
  public function process_actions() {
147
 
148
  //Detect when a bulk action is being triggered...
149
- if ('optimize' === $this->current_action()) {
150
-
151
- // In our file that handles the request, verify the nonce.
152
- $nonce = esc_attr($_REQUEST['_wpnonce']);
153
-
154
- if (!wp_verify_nonce($nonce, 'sp_optimize_image')) {
155
- die('Error.');
156
- } else {
157
- $this->action_optimize_image(absint($_GET['image']));
158
-
159
- wp_redirect(esc_url(add_query_arg()));
160
- exit;
161
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
162
  }
163
 
164
  // If the delete bulk action is triggered
@@ -177,4 +222,28 @@ class ShortPixelListTable extends WP_List_Table {
177
  }
178
  }
179
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
180
  }
45
  case 'name':
46
  $title = '<a href="" title="'.$item->folder.'"><strong>' . $item->name . '</strong></a>';
47
 
 
 
 
 
 
 
 
 
48
  $url = ShortPixelMetaFacade::pathToWebPath($item->folder);
49
+ $actions = array(
50
+ 'optimize' => sprintf( '<a href="?page=%s&action=%s&image=%s&_wpnonce=%s">Optimize</a>',
51
+ esc_attr( $_REQUEST['page'] ), 'optimize', absint( $item->id ), wp_create_nonce( 'sp_optimize_image' ) ),
52
+ 'retry' => sprintf( '<a href="?page=%s&action=%s&image=%s&_wpnonce=%s">Retry</a>',
53
+ esc_attr( $_REQUEST['page'] ), 'optimize', absint( $item->id ), wp_create_nonce( 'sp_optimize_image' ) ),
54
+ 'restore' => sprintf( '<a href="?page=%s&action=%s&image=%s&_wpnonce=%s">Restore</a>',
55
+ esc_attr( $_REQUEST['page'] ), 'restore', absint( $item->id ), wp_create_nonce( 'sp_restore_image' ) ),
56
+ 'redolossless' => sprintf( '<a href="?page=%s&action=%s&image=%s&_wpnonce=%s">Re-optimize lossless</a>',
57
+ esc_attr( $_REQUEST['page'] ), 'redo', absint( $item->id ), wp_create_nonce( 'sp_redo_image' ) ),
58
+ 'redolossy' => sprintf( '<a href="?page=%s&action=%s&image=%s&_wpnonce=%s">Re-optimize lossy</a>',
59
+ esc_attr( $_REQUEST['page'] ), 'redo', absint( $item->id ), wp_create_nonce( 'sp_redo_image' ) ),
60
+ 'quota' => sprintf( '<a href="?page=%s&action=%s&image=%s&_wpnonce=%s">Check quota</a>',
61
+ esc_attr( $_REQUEST['page'] ), 'quota', absint( $item->id ), wp_create_nonce( 'sp_check_quota' ) ),
62
+ 'view' => sprintf( '<a href="%s" target="_blank">View</a>', $url )
63
+ );
64
+ $settings = $this->ctrl->getSettings();
65
+ $actionsEnabled = array();
66
+ if($settings->quotaExceeded) {
67
+ $actionsEnabled['quota'] = true;
68
+ } elseif($item->status == 0 || $item->status == 1 || $item->status == 3 ) {
69
+ $actionsEnabled['optimize'] = true;
70
+ } elseif($item->status == 2) {
71
+ $actionsEnabled['restore'] = true;
72
+ $actionsEnabled['redo'.($item->compression_type == 1 ? "lossless" : "lossy")] = true;
73
+ } elseif($item->status == 3) {
74
+ $actionsEnabled['retry'] = true;
75
+ }
76
+ $actionsEnabled['view'] = true;
77
+ $title = $title . $this->row_actions($actions, false, $item->id, $actionsEnabled );
78
  return $title;
79
  case 'folder':
80
+ return ShortPixelMetaFacade::pathToRootRelative($item->folder);
81
  case 'status':
82
  switch($item->status) {
83
+ case 3: $msg = "Restored";
84
+ break;
85
+ case 2: $msg = 0 + $item->message == 0 ? "Bonus processing" : "Reduced by <strong>" . $item->message . "%</strong>" . (0 + $item->message < 5 ? "<br>Bonus processing." : "");
86
  break;
87
+ case 1: $msg = "<img src=\"" . plugins_url( 'shortpixel-image-optimiser/res/img/loading.gif') . "\" class='sp-loading-small'>&nbsp;Pending";
88
  break;
89
  case 0: $msg = "Waiting";
90
  break;
164
  $this->ctrl->optimizeCustomImage($id);
165
  }
166
 
167
+ public function action_restore_image( $id ) {
168
+ $this->ctrl->doCustomRestore($id);
169
+ }
170
+
171
+ public function action_redo_image( $id ) {
172
+ $this->ctrl->redo('C-' . $id);
173
+ }
174
+
175
  public function process_actions() {
176
 
177
  //Detect when a bulk action is being triggered...
178
+ $nonce = isset($_REQUEST['_wpnonce']) ? esc_attr($_REQUEST['_wpnonce']) : false;
179
+ switch($this->current_action()) {
180
+ case 'optimize':
181
+ if (!wp_verify_nonce($nonce, 'sp_optimize_image')) {
182
+ die('Error.');
183
+ } else {
184
+ $this->action_optimize_image(absint($_GET['image']));
185
+ wp_redirect(esc_url(add_query_arg()));
186
+ exit;
187
+ }
188
+ break;
189
+ case 'restore':
190
+ if (!wp_verify_nonce($nonce, 'sp_restore_image')) {
191
+ die('Error.');
192
+ } else {
193
+ $this->action_restore_image(absint($_GET['image']));
194
+ wp_redirect(esc_url(add_query_arg()));
195
+ exit;
196
+ }
197
+ break;
198
+ case 'redo':
199
+ if (!wp_verify_nonce($nonce, 'sp_redo_image')) {
200
+ die('Error.');
201
+ } else {
202
+ $this->action_redo_image(absint($_GET['image']));
203
+ wp_redirect(esc_url(add_query_arg()));
204
+ exit;
205
+ }
206
+ break;
207
  }
208
 
209
  // If the delete bulk action is triggered
222
  }
223
  }
224
 
225
+ protected function row_actions($actions, $always_visible = false, $id = false, $actionsEnabled = false ) {
226
+ if($id === false) {
227
+ return parent::row_actions($actions, $always_visible);
228
+ }
229
+ $action_count = count( $actions );
230
+ $i = 0;
231
+
232
+ if ( !$action_count )
233
+ return '';
234
+
235
+ $out = '<div class="' . ( $always_visible ? 'row-actions visible' : 'row-actions' ) . '">';
236
+ foreach ( $actions as $action => $link ) {
237
+ ++$i;
238
+ ( $i == $action_count ) ? $sep = '' : $sep = ' | ';
239
+ $action_id = $action . "_" . $id;
240
+ $display = (isset($actionsEnabled[$action])?"":" style='display:none;'");
241
+ $out .= "<span id='$action_id' class='$action' $display>$link$sep</span>";
242
+ }
243
+ $out .= '</div>';
244
+
245
+ $out .= '<button type="button" class="toggle-row"><span class="screen-reader-text">' . __( 'Show more details' ) . '</span></button>';
246
+
247
+ return $out;
248
+ }
249
  }
class/view/shortpixel_view.php CHANGED
@@ -13,10 +13,23 @@ class ShortPixelView {
13
  $this->__construct($controller);
14
  }
15
 
16
- public function displayQuotaExceededAlert($quotaData)
17
  { ?>
18
  <br/>
19
  <div class="wrap sp-quota-exceeded-alert">
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  <h3>Quota Exceeded</h3>
21
  <p>The plugin has optimized <strong><?php echo(number_format($quotaData['APICallsMadeNumeric'] + $quotaData['APICallsMadeOneTimeNumeric']));?> images</strong> and stopped because it reached the available quota limit.
22
  <?php if($quotaData['totalProcessedFiles'] < $quotaData['totalFiles']) { ?>
@@ -256,7 +269,7 @@ class ShortPixelView {
256
  Some have errors:
257
  <?php foreach($quotaData['filesWithErrors'] as $id => $data) {
258
  if(ShortPixelMetaFacade::isCustomQueuedId($id)) {
259
- echo('<a href="'.trailingslashit(network_site_url("/")) . 'wp-content/' . ShortPixelMetaFacade::filenameToContentRelative($data['Path']).'" title="'.$data['Message'].'" target="_blank">'.$data['Name'].'</a>,&nbsp;');
260
  } else {
261
  echo('<a href="post.php?post='.$id.'&action=edit" title="'.$data['Message'].'">'.$data['Name'].'</a>,&nbsp;');
262
  }
@@ -446,7 +459,7 @@ class ShortPixelView {
446
  <?php foreach($failed as $fail) {
447
  if($fail->type == ShortPixelMetaFacade::CUSTOM_TYPE) {
448
  $meta = $fail->meta;
449
- ?> <div class="label"><a href="<?php echo(trailingslashit(network_site_url("/")) . "wp-content/" . $fail->meta->getWebPath());?>"><?php echo(substr($fail->meta->getName(), 0, 80));?> - ID: C-<?php echo($fail->id);?></a></div><br/>
450
  <?php } else {
451
  $meta = wp_get_attachment_metadata($fail);
452
  ?> <div class="label"><a href="/wp-admin/post.php?post=<?php echo($fail->id);?>&action=edit"><?php echo(substr($fail->meta["file"], 0, 80));?> - ID: <?php echo($fail->id);?></a></div><br/>
@@ -529,7 +542,7 @@ class ShortPixelView {
529
  $removeExif = ($settings->keepExif ? '' : 'checked');
530
  $resize = ($this->ctrl->getResizeImages() ? 'checked' : '');
531
  $resizeDisabled = ($this->ctrl->getResizeImages() ? '' : 'disabled');
532
- $minSizes = $this->ctrl->getMaxIntermediateImageSize();
533
  $thumbnailsToProcess = isset($quotaData['totalFiles']) ? ($quotaData['totalFiles'] - $quotaData['mainFiles']) - ($quotaData['totalProcessedFiles'] - $quotaData['mainProcessedFiles']) : 0;
534
  ?>
535
  <div class="wp-shortpixel-options">
@@ -621,12 +634,18 @@ class ShortPixelView {
621
  <th scope="row"><label for="resize">Resize large images</label></th>
622
  <td>
623
  <input name="resize" type="checkbox" id="resize" <?php echo( $resize );?>> to maximum
624
- <input type="text" name="width" id="width" style="width:70px" value="<?php echo( max($this->ctrl->getResizeWidth(), min(1024, $minSizes['width'])) );?>" <?php echo( $resizeDisabled );?>/> pixels wide &times;
625
- <input type="text" name="height" id="height" style="width:70px" value="<?php echo( max($this->ctrl->getResizeHeight(), min(1024, $minSizes['height'])) );?>" <?php echo( $resizeDisabled );?>/> pixels high (original aspect ratio is preserved)
626
- <p class="settings-info"> Recommended for large photos, like the ones taken with your phone. Saved space can go up to 80% or more after resizing.<br/>
627
- The new resolution should not be less than your largest thumbnail size, which is <?php echo($minSizes['width']);?> &times; <?php echo($minSizes['height']);?> pixels,
628
- or, if you have a Retina images plugin, <?php echo(2 * $minSizes['width']);?> &times; <?php echo(2 * $minSizes['height']);?> pixels.<br>
629
- The resize keeps the aspect ratio and is done so that the resulting image will be resized to no less than the configured sizes. For example, if you set the resize dimensions at 1000x1200, an image of 2000x3000px will be resized to 1000x1500px while an image of 3000x2000px will be resized to 1800x1200px</p>
 
 
 
 
 
 
630
  </td>
631
  </tr>
632
  </tbody>
@@ -645,6 +664,7 @@ class ShortPixelView {
645
  $hasNextGen = $this->ctrl->hasNextGen();
646
  $frontBootstrap = ($settings->frontBootstrap ? 'checked' : '');
647
  $includeNextGen = ($settings->includeNextGen ? 'checked' : '');
 
648
  ?>
649
  <div class="wp-shortpixel-options">
650
  <?php if(!$this->ctrl->getVerifiedKey()) { ?>
@@ -708,7 +728,7 @@ class ShortPixelView {
708
  <input type="hidden" id="customFolderBase" value="<?php echo $this->ctrl->getCustomFolderBase(); ?>">
709
  <a class="button button-primary select-folder-button" title="Select the images folder on your server" href="javascript:void(0);">Select ... </a>
710
  <input type="submit" name="saveAdv" id="saveAdvAddFolder" class="button button-primary" title="Add Folder" value="Add Folder">
711
- <p class="settings-info"> Use the Select... button to select folders from <i>wp-content</i>. ShortPixel will optimize images and PDFs from the specified folders and their subfolders. The optimization status for each image or PDF in these folders can be seen in the <a href="upload.php?page=wp-short-pixel-custom">Other Media list</a>, under the Media menu.</p>
712
  <div class="sp-folder-picker-shade">
713
  <div class="sp-folder-picker-popup">
714
  <div class="sp-folder-picker-title">Select the images folder</div>
@@ -726,13 +746,20 @@ class ShortPixelView {
726
  </tr>
727
  <?php if($hasNextGen) { ?>
728
  <tr>
729
- <th scope="row"><label for="resize">Optimize NextGen galleries</label></th>
730
  <td>
731
- <input name="nextGen" type="checkbox" id="resize" <?php echo( $includeNextGen );?>> Optimize NextGen galleries.
732
  <p class="settings-info">Check this to add all your current NextGen galleries to the custom folders list and to also have all the future NextGen galleries and images optimized automatically by ShortPixel.</p>
733
  </td>
734
  </tr>
735
  <?php } ?>
 
 
 
 
 
 
 
736
  <tr>
737
  <th scope="row"><label for="authentication">HTTP AUTH credentials</label></th>
738
  <td>
@@ -903,10 +930,10 @@ class ShortPixelView {
903
  echo($this->getQuotaExceededHTML(isset($data['message']) ? $data['message'] : ''));
904
  break;
905
  case 'optimizeNow':
906
- echo($data['message']);
907
  if($data['showActions']) { ?>
908
  <a class='button button-smaller button-primary' href="javascript:manualOptimization('<?php echo($id)?>')">Optimize now</a>
909
  <?php }
 
910
  if(isset($data['thumbsTotal']) && $data['thumbsTotal'] > 0) {
911
  echo("<br>+" . $data['thumbsTotal'] . " thumbnails");
912
  }
@@ -928,7 +955,7 @@ class ShortPixelView {
928
  }
929
 
930
  public function getSuccessText($percent, $bonus, $type, $thumbsOpt = 0, $thumbsTotal = 0) {
931
- return ($percent ? 'Reduced by ' . $percent . '% ' : '')
932
  .(!$bonus ? ' ('.$type.')':'')
933
  .($bonus && $percent ? '<br>' : '')
934
  .($bonus ? 'Bonus processing' : '')
13
  $this->__construct($controller);
14
  }
15
 
16
+ public function displayQuotaExceededAlert($quotaData, $averageCompression = false)
17
  { ?>
18
  <br/>
19
  <div class="wrap sp-quota-exceeded-alert">
20
+ <?php if($averageCompression) { ?>
21
+ <div style="float:right; margin-top: 10px">
22
+ <div class="bulk-progress-indicator">
23
+ <div style="margin-bottom:5px">Average reduction</div>
24
+ <div id="sp-avg-optimization"><input type="text" id="sp-avg-optimization-dial" value="<?php echo("" . round($averageCompression))?>" class="dial"></div>
25
+ <script>
26
+ jQuery(function() {
27
+ ShortPixel.percentDial("#sp-avg-optimization-dial", 60);
28
+ });
29
+ </script>
30
+ </div>
31
+ </div>
32
+ <?php } ?>
33
  <h3>Quota Exceeded</h3>
34
  <p>The plugin has optimized <strong><?php echo(number_format($quotaData['APICallsMadeNumeric'] + $quotaData['APICallsMadeOneTimeNumeric']));?> images</strong> and stopped because it reached the available quota limit.
35
  <?php if($quotaData['totalProcessedFiles'] < $quotaData['totalFiles']) { ?>
269
  Some have errors:
270
  <?php foreach($quotaData['filesWithErrors'] as $id => $data) {
271
  if(ShortPixelMetaFacade::isCustomQueuedId($id)) {
272
+ echo('<a href="'.trailingslashit(network_site_url("/")) . ShortPixelMetaFacade::filenameToRootRelative($data['Path']).'" title="'.$data['Message'].'" target="_blank">'.$data['Name'].'</a>,&nbsp;');
273
  } else {
274
  echo('<a href="post.php?post='.$id.'&action=edit" title="'.$data['Message'].'">'.$data['Name'].'</a>,&nbsp;');
275
  }
459
  <?php foreach($failed as $fail) {
460
  if($fail->type == ShortPixelMetaFacade::CUSTOM_TYPE) {
461
  $meta = $fail->meta;
462
+ ?> <div class="label"><a href="<?php echo(trailingslashit(network_site_url("/")) . $fail->meta->getWebPath());?>"><?php echo(substr($fail->meta->getName(), 0, 80));?> - ID: C-<?php echo($fail->id);?></a></div><br/>
463
  <?php } else {
464
  $meta = wp_get_attachment_metadata($fail);
465
  ?> <div class="label"><a href="/wp-admin/post.php?post=<?php echo($fail->id);?>&action=edit"><?php echo(substr($fail->meta["file"], 0, 80));?> - ID: <?php echo($fail->id);?></a></div><br/>
542
  $removeExif = ($settings->keepExif ? '' : 'checked');
543
  $resize = ($this->ctrl->getResizeImages() ? 'checked' : '');
544
  $resizeDisabled = ($this->ctrl->getResizeImages() ? '' : 'disabled');
545
+ //$minSizes = $this->ctrl->getMaxIntermediateImageSize();
546
  $thumbnailsToProcess = isset($quotaData['totalFiles']) ? ($quotaData['totalFiles'] - $quotaData['mainFiles']) - ($quotaData['totalProcessedFiles'] - $quotaData['mainProcessedFiles']) : 0;
547
  ?>
548
  <div class="wp-shortpixel-options">
634
  <th scope="row"><label for="resize">Resize large images</label></th>
635
  <td>
636
  <input name="resize" type="checkbox" id="resize" <?php echo( $resize );?>> to maximum
637
+ <input type="text" name="width" id="width" style="width:70px"
638
+ value="<?php echo( max($this->ctrl->getResizeWidth(), min(1024, $minSizes['width'])) );?>" <?php echo( $resizeDisabled );?>/> pixels wide &times;
639
+ <input type="text" name="height" id="height" style="width:70px" value="<?php echo( max($this->ctrl->getResizeHeight(), min(1024, $minSizes['height'])) );?>" <?php echo( $resizeDisabled );?>/> pixels high (original aspect ratio is preserved and image is not cropped)
640
+ <p class="settings-info">
641
+ Recommended for large photos, like the ones taken with your phone. Saved space can go up to 80% or more after resizing.<br/>
642
+ </p>
643
+ <div style="margin-top: 10px;">
644
+ <input type="radio" name="resize_type" id="resize_type_outer" value="outer" <?php echo($settings->resizeType == 'inner' ? '' : 'checked') ?> style="margin: -50px 10px 60px 0;">
645
+ <img src="<?php echo(plugins_url( 'shortpixel-image-optimiser/res/img/resize-outer.png' ));?>" title="Sizes will be greater or equal to the corresponding value. For example, if you set the resize dimensions at 1000x1200, an image of 2000x3000px will be resized to 1000x1500px while an image of 3000x2000px will be resized to 1800x1200px">
646
+ <input type="radio" name="resize_type" id="resize_type_inner" value="inner" <?php echo($settings->resizeType == 'inner' ? 'checked' : '') ?> style="margin: -50px 10px 60px 35px;">
647
+ <img src="<?php echo(plugins_url( 'shortpixel-image-optimiser/res/img/resize-inner.png' ));?>" title="Sizes will be smaller or equal to the corresponding value. For the same example values, an image of 2000x3000px will be resized to 800x1200px while an image of 3000x2000px will be resized to 1000x667px">
648
+ </div>
649
  </td>
650
  </tr>
651
  </tbody>
664
  $hasNextGen = $this->ctrl->hasNextGen();
665
  $frontBootstrap = ($settings->frontBootstrap ? 'checked' : '');
666
  $includeNextGen = ($settings->includeNextGen ? 'checked' : '');
667
+ $createWebp = ($settings->createWebp ? 'checked' : '');
668
  ?>
669
  <div class="wp-shortpixel-options">
670
  <?php if(!$this->ctrl->getVerifiedKey()) { ?>
728
  <input type="hidden" id="customFolderBase" value="<?php echo $this->ctrl->getCustomFolderBase(); ?>">
729
  <a class="button button-primary select-folder-button" title="Select the images folder on your server" href="javascript:void(0);">Select ... </a>
730
  <input type="submit" name="saveAdv" id="saveAdvAddFolder" class="button button-primary" title="Add Folder" value="Add Folder">
731
+ <p class="settings-info"> Use the Select... button to select site folders. ShortPixel will optimize images and PDFs from the specified folders and their subfolders. The optimization status for each image or PDF in these folders can be seen in the <a href="upload.php?page=wp-short-pixel-custom">Other Media list</a>, under the Media menu.</p>
732
  <div class="sp-folder-picker-shade">
733
  <div class="sp-folder-picker-popup">
734
  <div class="sp-folder-picker-title">Select the images folder</div>
746
  </tr>
747
  <?php if($hasNextGen) { ?>
748
  <tr>
749
+ <th scope="row"><label for="nextGen">Optimize NextGen galleries</label></th>
750
  <td>
751
+ <input name="nextGen" type="checkbox" id="nextGen" <?php echo( $includeNextGen );?>> Optimize NextGen galleries.
752
  <p class="settings-info">Check this to add all your current NextGen galleries to the custom folders list and to also have all the future NextGen galleries and images optimized automatically by ShortPixel.</p>
753
  </td>
754
  </tr>
755
  <?php } ?>
756
+ <tr>
757
+ <th scope="row"><label for="createWebp">WebP versions</label></th>
758
+ <td>
759
+ <input name="createWebp" type="checkbox" id="createWebp" <?php echo( $createWebp );?>> Create also <a href="http://blog.shortpixel.com/how-webp-images-can-speed-up-your-site/" target="_blank">WebP versions</a> of the images.
760
+ <p class="settings-info">WebP images can be up to three times smaller than PNGs and 25% smaller than JPGs.</p>
761
+ </td>
762
+ </tr>
763
  <tr>
764
  <th scope="row"><label for="authentication">HTTP AUTH credentials</label></th>
765
  <td>
930
  echo($this->getQuotaExceededHTML(isset($data['message']) ? $data['message'] : ''));
931
  break;
932
  case 'optimizeNow':
 
933
  if($data['showActions']) { ?>
934
  <a class='button button-smaller button-primary' href="javascript:manualOptimization('<?php echo($id)?>')">Optimize now</a>
935
  <?php }
936
+ echo($data['message']);
937
  if(isset($data['thumbsTotal']) && $data['thumbsTotal'] > 0) {
938
  echo("<br>+" . $data['thumbsTotal'] . " thumbnails");
939
  }
955
  }
956
 
957
  public function getSuccessText($percent, $bonus, $type, $thumbsOpt = 0, $thumbsTotal = 0) {
958
+ return ($percent ? 'Reduced by <strong>' . $percent . '%</strong> ' : '')
959
  .(!$bonus ? ' ('.$type.')':'')
960
  .($bonus && $percent ? '<br>' : '')
961
  .($bonus ? 'Bonus processing' : '')
wp-shortpixel-settings.php → class/wp-shortpixel-settings.php RENAMED
@@ -17,6 +17,7 @@ class WPShortPixelSettings {
17
  //This one is accessed also directly via get_option
18
  'frontBootstrap' => 'wp-short-pixel-front-bootstrap', //set to 1 when need the plugin active for logged in user in the front-end
19
  'lastBackAction' => 'wp-short-pixel-last-back-action', //when less than 10 min. passed from this timestamp, the front-bootstrap is ineffective.
 
20
  //optimization options
21
  'apiKey' => 'wp-short-pixel-apiKey',
22
  'verifiedKey' => 'wp-short-pixel-verifiedKey',
@@ -24,8 +25,10 @@ class WPShortPixelSettings {
24
  'processThumbnails' => 'wp-short-process_thumbnails',
25
  'keepExif' => 'wp-short-pixel-keep-exif',
26
  'CMYKtoRGBconversion' => 'wp-short-pixel_cmyk2rgb',
 
27
  'backupImages' => 'wp-short-backup_images',
28
  'resizeImages' => 'wp-short-pixel-resize-images',
 
29
  'resizeWidth' => 'wp-short-pixel-resize-width',
30
  'resizeHeight' => 'wp-short-pixel-resize-height',
31
  'siteAuthUser' => 'wp-short-pixel-site-auth-user',
17
  //This one is accessed also directly via get_option
18
  'frontBootstrap' => 'wp-short-pixel-front-bootstrap', //set to 1 when need the plugin active for logged in user in the front-end
19
  'lastBackAction' => 'wp-short-pixel-last-back-action', //when less than 10 min. passed from this timestamp, the front-bootstrap is ineffective.
20
+
21
  //optimization options
22
  'apiKey' => 'wp-short-pixel-apiKey',
23
  'verifiedKey' => 'wp-short-pixel-verifiedKey',
25
  'processThumbnails' => 'wp-short-process_thumbnails',
26
  'keepExif' => 'wp-short-pixel-keep-exif',
27
  'CMYKtoRGBconversion' => 'wp-short-pixel_cmyk2rgb',
28
+ 'createWebp' => 'wp-short-create-webp',
29
  'backupImages' => 'wp-short-backup_images',
30
  'resizeImages' => 'wp-short-pixel-resize-images',
31
+ 'resizeType' => 'wp-short-pixel-resize-type',
32
  'resizeWidth' => 'wp-short-pixel-resize-width',
33
  'resizeHeight' => 'wp-short-pixel-resize-height',
34
  'siteAuthUser' => 'wp-short-pixel-site-auth-user',
readme.txt CHANGED
@@ -5,91 +5,67 @@ Tags: image optimizer, image optimization, compress pdf, compress jpeg, compress
5
 
6
  Requires at least: 3.2.0
7
  Tested up to: 4.6
8
- Stable tag: 4.0.2
9
  License: GPLv2 or later
10
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
11
 
12
- Easy-to-use, lightweight plugin that optimizes images & PDFs. Make your website faster, keeping the images’ high quality. WooCommerce compatible
13
 
14
  == Description ==
15
 
16
- ShortPixel makes your website load faster by resizing/rescaling and then compressing the images. Optimized images mean better user experience, better PageSpeed Insights results, better Google PageRank (SEO) and more visitors. Both lossy and lossless <a rel="friend" href="https://shortpixel.com" target="_blank">image compression</a> available for all common image types (JPG, PNG and GIF), plus PDF files.
 
17
 
18
- **Compatible with**
19
 
20
- * any image gallery (including NextGEN)
21
- * any slider
22
- * Woo Commerce plugin
23
 
24
- ShortPixel is also able to optimize any images regardless of where they are located on disk (e.g. theme specific icons, logos, images).
25
 
26
- **How does it work?**
27
 
28
- * choose your favorite settings like lossy/lossless, keep/remove EXIF, backup, optimize thumbs, etc.
29
- * all your current pics can be easily scaled and optimized with a single click via our **bulk optimization** page.
30
- * new images are automatically resized and compressed in the cloud right after they are uploaded.
31
- * smaller images will start being served from your website once they are optimized
32
-
33
- It's that easy indeed.
34
-
35
- You can try a **live demo** <a href="https://addendio.com/try-plugin/?slug=shortpixel-image-optimiser" target="_blank">here</a> (via addendio.com) or you can watch a short intro video on how to optimize images with our plugin:
36
-
37
- [youtube https://www.youtube.com/watch?v=5EbX0Hsy6j4]
38
-
39
- **Why use ShortPixel to optimize your images? Here are some of the features:**
40
-
41
- * **24h support** (24/7) directly from the developers
42
- * compress JPG, PNG, GIF (still and animated) images and PDF documents
43
  * optimize thumbnails as well as featured images
44
- * ability to optimize any image on your site including images in NextGEN Gallery and any other image gallery or slider
45
- * featured images can be rescaled before being optimized. **No need for additional plugins** like Imsanity
46
  * CMYK to RGB conversion
47
- * skip already optimized images
48
- * easily test lossy/lossless versions of the images
49
- * great for photographers: **keep or remove EXIF** data from your images
50
- * no file size limit
51
  * works well with both HTTPS and HTTP websites
52
- * it is safe to test and use the plugin: all the original **images can be restored** with a click
53
- * 'Bulk' optimize existing images with one click
54
- * 40 days optimization report with all image details and overall statistics
55
- * works great for eCommerce websites using WooCommerce plugin
56
- * Use the **same API Key** on many sites (including multisites)
57
  * compatible with WP Engine hosted websites and all the major hosting providers
58
  * compatible with WPML and WPML Media plugins
59
- * receive **100 free image optimization credits** each month.
60
  * images that are optimized less that 5% are bonus
61
-
62
- ShortPixel free and paid plans offer the same features and deliver the same optimization quality. The difference is made by the available image quota. Additional image quota can be bought for as little as $4,99 for 5,000 image optimization credits.
63
-
64
- Both monthly subscriptions and one-time plans are available. The same plan can be used for multiple websites. Make an instant <a rel="friend" href="http://shortpixel.com/image-compression-test" target="_blank">image compression test</a> on your site or <a rel="friend" href="http://shortpixel.com/online-image-compression" target="_blank">compress some images</a> to make sure they are to your liking.
65
-
66
- We believe in a better society, so we support non-profits. <a href="http://shortpixel.com/contact" target="_blank">Contact us</a> and we’ll see how we can help!
67
-
68
- Help us spread a the word by recommending ShortPixel to your friends and collect 100 additional image credits for each referred sign up.
69
- Make money by promoting a great plugin with our <a href="https://shortpixel.com/free-sign-up-affiliate" target="_blank">50/50 affiliate program</a>.
70
-
71
-
72
- > ★★★★★ **Increased Page Speed and Optimizes Properly**
73
- > "I noticed a huge difference on page speed after running the bulk compression. Does exactly as promised. An excellent plugin for those that care about page speed, SEO and optimizing their sites to the fullest potential." — [BrowCo](https://wordpress.org/support/topic/increased-page-speed-and-optimizes-properly#post-)
74
- >
75
-
76
- > ★★★★★ **Great tool and excellent support**
77
- > "This tool does what it's supposed to do: automatically compress images with a great, clear interface. Also, support is more than excellent with the developers trying everything to help you, even beyond the scope of the plugin! Very recommended." — [Tomeranaray](https://wordpress.org/support/topic/great-tool-and-excellent-support-2?replies=1)
78
- >
79
-
80
- > ★★★★★ **Outstanding Time Saving Application**
81
- > "What a time saver! I bought Short Pixel on the advice of my website designer because it would save him time optimizing the photos in a website and therefore save me money. This has worked out for all of us- my client saved money on our time; and the software is bullet proof.
82
- We will continue to purchase this software for any site we develop with a lot of photos." — [amulhern](https://wordpress.org/support/topic/outstanding-time-saving-application?replies=1#post-)
83
- >
84
-
85
-
86
- **New features coming soon:**
87
-
88
- * new resize options
89
- * WebP support
90
- * Retina optimiziation and support
91
- * mass restore for backed-up images.
92
-
93
 
94
  **Get in touch!**
95
 
@@ -99,7 +75,7 @@ We will continue to purchase this software for any site we develop with a lot of
99
  * Facebook <a href="https://www.facebook.com/ShortPixel" target="_blank">https://www.facebook.com/ShortPixel</a>
100
  * LinkedIn <a href="https://www.linkedin.com/company/shortpixel" target="_blank">https://www.linkedin.com/company/shortpixel</a>
101
 
102
- **Keywords:** picture, optimization, image editor, pngout, upload speed, shortpixel, compression, nextgen jpegmini, webp, lossless, cwebp, media, jpegtran, image, image optimisation, image optimization, shrink, picture, photo, optimize photos, compress, performance, tinypng, crunch, pngquant, attachment, optimize, pictures, fast, images, image files, image quality, lossy, upload, kraken, resize, seo, smushit, optipng, kraken image optimizer, ewww, photo optimization, gifsicle, image optimizer, images, krakenio, png, gmagick, image optimize, pdf, pdf optimisation, pdf optimization, optimize pdf, optimise pdf, shrink pdf, jpg, jpeg, jpg optimisation, jpg optimization, optimize jpg, optimise jpg, shrink jpg, gif, animated gif, optimize gif, optimise gif, optimizer, optimiser, compresion, optimization, cruncher, image cruncher, compress png, compress jpg, compress jpeg, compress pdf, faster loading times, image optimiser, improve pagerank, optimise, optimize animated gif, optimise jpeg, optimize jpeg, optimize png, optimise png, optimise pdf, optimize pdf, tinyjpg, short pixel, shortpixel, woocommerce compatible, wpml compatible, smush, imsanity, scale, wp smush, compress images, pdf compression, optimize images, shrink jpeg, compressor, faster website, google pagerank, imagify, prizm, optimus, zara, improve page speed, PageSpeed Insights, sitespeed, smaller images, tinyjpeg, wordpress compression, wordPress image tool, reduce image size, bandwidth, pics, keep exif, remove exif, speed up site, speed up website, compress thumbnails, optimize thumbnails
103
 
104
 
105
  == Installation ==
@@ -201,6 +177,13 @@ The ShortPixel team is here to help. <a href="https://shortpixel.com/contact">Co
201
 
202
  == Changelog ==
203
 
 
 
 
 
 
 
 
204
 
205
  = 4.0.2 =
206
 
5
 
6
  Requires at least: 3.2.0
7
  Tested up to: 4.6
8
+ Stable tag: 4.1.0
9
  License: GPLv2 or later
10
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
11
 
12
+ Speed up your website and boost your SEO by compressing old & new images and PDFs. Compatible with any gallery, slider or ecommerce plugin.
13
 
14
  == Description ==
15
 
16
+ Increase your website's SEO ranking, number of visitors and ultimately your sales by optimizing any image or PDF document on your website.
17
+ ShortPixel is an easy to use, lightweight, install-and-forget-about-it <a rel="friend" href="https://shortpixel.com" target="_blank">image optimization</a> plugin that can compress all your past images and PDF documents with a single click. New images are automatically resized/rescaled and optimized on the fly, in the background.
18
 
19
+ This plugin uses minimal resources and works well with any shared, cloud, VPS or dedicated web hosting. It can optimize any image you have on your website even the images that aren't listed in Media Library like those in galleries like NextGEN or added directly via FTP!
20
 
21
+ Both lossy and lossless image compression is available for the most common image types (JPG, PNG, GIF and WebP) plus PDF files. Optimized images mean better user experience, better PageSpeed Insights or GTmetrix results, better Google PageRank and more visitors.
 
 
22
 
23
+ Make an instant <a rel="friend" href="http://shortpixel.com/image-compression-test" target="_blank">image compression test</a> on your site or <a rel="friend" href="http://shortpixel.com/online-image-compression" target="_blank">compress some images</a> to make sure they are to your liking.
24
 
25
+ **Why is ShortPixel the best choice when it comes to image optimization or PDF compression?**
26
 
27
+ * popular plugin with over 20,000 active installations according to WordPress
28
+ * compress JPG, PNG, GIF (still or animated) images and also PDF documents
29
+ * no file size limit
30
+ * option to convert any JPEG, PNG or GIF (even animated ones!) to **WebP** for more Google love
31
+ * compatible with WP Retina 2x - all **retina images** are automatically compressed
 
 
 
 
 
 
 
 
 
 
32
  * optimize thumbnails as well as featured images
33
+ * ability to optimize any image on your site including images in **NextGEN Gallery** and any other image gallery or slider
34
+ * featured images can be rescaled before being optimized with 2 different options. No need for additional plugins like Imsanity
35
  * CMYK to RGB conversion
36
+ * **24h <a href="https://wordpress.org/support/plugin/shortpixel-image-optimiser/reviews/?filter=5" target="_blank">stellar support</a>** (24/7) directly from developers.
37
+ * easily **test lossy/lossless** versions of the images with a single click in your Media Library
38
+ * **great for photographers**: <a rel="friend" href="http://blog.shortpixel.com/how-much-smaller-can-be-images-without-exif-icc/" target="_blank">keep or remove EXIF</a> data from your images, compress images with lossless option
 
39
  * works well with both HTTPS and HTTP websites
40
+ * you can run ShortPixel plugin on **multiple websites** or on a **multisite** with a **single API Key**
41
+ * it is **safe to test** and use the plugin: all the original images can be restored with a click
42
+ * 'Bulk' optimize all the existing images in Media Library or in any gallery with one click
43
+ * works great for **eCommerce websites using WooCommerce** or other plugins
44
+ * works great with NextGEN gallery, Foo Gallery and any other galleries and sliders
45
  * compatible with WP Engine hosted websites and all the major hosting providers
46
  * compatible with WPML and WPML Media plugins
47
+ * skip already optimized images
48
  * images that are optimized less that 5% are bonus
49
+ * 40 days optimization report with all image details and overall statistics
50
+ * **free optimization credits for non-profits**, <a href="https://shortpixel.com/contact" target="_blank">contact us</a> for details
51
+
52
+ **Eager to test how it works?**
53
+ Give it a spin on a <a href="https://addendio.com/try-plugin/?slug=shortpixel-image-optimiser
54
+ " target="_blank">test environment</a> (thanks addendio!)
55
+
56
+ **How much it costs?**
57
+ ShortPixel comes with 100 free credits/month and additional credits can be bought with as little as $4.99 for 5,000 image credits.
58
+ Check out <a rel="friend" href="https://shortpixel.com/pricing" target="_blank">our prices</a>
59
+
60
+ > **Testimonials:**
61
+ > ★★★★★ **A Super Plugin works very well 62% reduction overall.**
62
+ > ★★★★★ **The secret sauce for a WordPress website.**
63
+ > ★★★★★ **A must have plugin, great support!**
64
+ > ★★★★★ **Excellent Plugin! Even Better Customer Service!**
65
+ > ★★★★★ **Great image compression, solid plugin, equally great support.**
66
+ > [more testimonials](https://wordpress.org/support/plugin/shortpixel-image-optimiser/reviews/?filter=5)
67
+
68
+ Help us spread a the word by recommending ShortPixel to your friends and collect 100 additional image credits for each referred sign up. Make money by promoting a great plugin with our <a href="https://shortpixel.com/free-sign-up-affiliate" target="_blank">50/50 affiliate program</a>.
 
 
 
 
 
 
 
 
 
 
 
 
69
 
70
  **Get in touch!**
71
 
75
  * Facebook <a href="https://www.facebook.com/ShortPixel" target="_blank">https://www.facebook.com/ShortPixel</a>
76
  * LinkedIn <a href="https://www.linkedin.com/company/shortpixel" target="_blank">https://www.linkedin.com/company/shortpixel</a>
77
 
78
+ **Keywords:** picture, optimization, image editor, pngout, upload speed, shortpixel, compression, nextgen, nextgen gallery optimizer, jpegmini, webp, lossless, cwebp, media, jpegtran, image, image optimisation, image optimization, shrink, picture, photo, optimize photos, compress, performance, tinypng, crunch, pngquant, attachment, optimize, pictures, fast, images, image files, image quality, lossy, upload, kraken, resize, seo, smushit, optipng, kraken image optimizer, ewww, photo optimization, gifsicle, image optimizer, images, krakenio, png, gmagick, image optimize, pdf, pdf optimisation, pdf optimization, optimize pdf, optimise pdf, shrink pdf, jpg, jpeg, jpg optimisation, jpg optimization, optimize jpg, optimise jpg, shrink jpg, gif, animated gif, optimize gif, optimise gif, optimizer, optimiser, compresion, optimization, cruncher, image cruncher, compress png, compress jpg, compress jpeg, compress pdf, faster loading times, image optimiser, improve pagerank, optimise, optimize animated gif, optimise jpeg, optimize jpeg, optimize png, optimise png, optimise pdf, optimize pdf, tinyjpg, short pixel, shortpixel, woocommerce compatible, wpml compatible, smush, imsanity, scale, wp smush, compress images, pdf compression, optimize images, shrink jpeg, compressor, faster website, google pagerank, imagify, prizm, optimus, zara, improve page speed, PageSpeed Insights, sitespeed, smaller images, tinyjpeg, wordpress compression, wordPress image tool, reduce image size, bandwidth, pics, keep exif, remove exif, speed up site, speed up website, compress thumbnails, optimize thumbnails
79
 
80
 
81
  == Installation ==
177
 
178
  == Changelog ==
179
 
180
+ = 4.1.0 =
181
+
182
+ * retina images support - optimize also retina images
183
+ * WebP support - generate also WebP images option
184
+ * optimize other media folders also from the root of the site, not only in wp-content
185
+ * restore and re-optimize other media images
186
+ * resize options - defined rectangle to be contained in the resized image or the resized image to contain the defined rectangle
187
 
188
  = 4.0.2 =
189
 
res/css/short-pixel.css CHANGED
@@ -20,7 +20,8 @@ div.bulk-progress h2 {
20
  margin-top:0;
21
  margin-bottom: 10px;
22
  }
23
- div.bulk-progress .bulk-progress-indicator {
 
24
  display: inline-block;
25
  text-align: center;
26
  padding: 0 10px;
@@ -242,6 +243,9 @@ li.shortpixel-hide {
242
  float:right;
243
  text-align: right;
244
  }
 
 
 
245
  .wp-core-ui .column-wp-shortPixel .button.button-smaller {
246
  font-size: 13px;
247
  padding:0px 5px;
20
  margin-top:0;
21
  margin-bottom: 10px;
22
  }
23
+ div.bulk-progress .bulk-progress-indicator,
24
+ div.sp-quota-exceeded-alert .bulk-progress-indicator {
25
  display: inline-block;
26
  text-align: center;
27
  padding: 0 10px;
243
  float:right;
244
  text-align: right;
245
  }
246
+ .wp-core-ui .column-wp-shortPixel .sp-column-actions .button.button-smaller {
247
+ margin-right: 0px;
248
+ }
249
  .wp-core-ui .column-wp-shortPixel .button.button-smaller {
250
  font-size: 13px;
251
  padding:0px 5px;
res/img/resize-inner.png ADDED
Binary file
res/img/resize-outer.png ADDED
Binary file
res/js/short-pixel.js CHANGED
@@ -76,7 +76,7 @@ var ShortPixel = function() {
76
  }
77
 
78
  function successMsg(id, percent, type, thumbsCount) {
79
- return (percent > 0 ? "<div class='sp-column-info'>Reduced by <span class='percent'>" + percent + "%</span> " : "")
80
  + (percent > 0 && percent < 5 ? "<br>" : '')
81
  + (percent < 5 ? "Bonus processing" : '')
82
  + (type.length > 0 ? " ("+type+")" : "")
@@ -97,15 +97,28 @@ var ShortPixel = function() {
97
  }
98
 
99
  function successActions(id, type, thumbsCount, thumbsTotal, backupEnabled) {
100
- if(backupEnabled == 1) {
101
  var otherType = type.length > 0 ? (type == "lossy" ? "lossless" : "lossy") : "";
102
  return '<div class="sp-column-actions">'
103
  + (thumbsTotal > thumbsCount ? "<a class='button button-smaller button-primary' href=\"javascript:optimizeThumbs(" + id + ");\">Optimize " + (thumbsTotal - thumbsCount) + " thumbnails</a>" : "")
104
  + (otherType.length ? "<a class='button button-smaller' href=\"javascript:reoptimize(" + id + ", '" + otherType + "');\">Re-optimize " + otherType + "</a>" : "")
105
  + "<a class='button button-smaller' href=\"admin.php?action=shortpixel_restore_backup&attachment_ID=" + id + ")\">Restore backup</a>"
106
  + "</div>";
107
- }
108
- return "";
 
 
 
 
 
 
 
 
 
 
 
 
 
109
  }
110
 
111
  function retry(msg) {
@@ -219,6 +232,7 @@ var ShortPixel = function() {
219
  percentDial : percentDial,
220
  successMsg : successMsg,
221
  successActions : successActions,
 
222
  retry : retry,
223
  initFolderSelector : initFolderSelector,
224
  browseContent : browseContent,
@@ -236,7 +250,6 @@ function showToolBarAlert($status, $message) {
236
  case ShortPixel.STATUS_QUOTA_EXCEEDED:
237
  if( window.location.href.search("wp-short-pixel-bulk") > 0
238
  && jQuery(".sp-quota-exceeded-alert").length == 0) { //if we're in bulk and the alert is not displayed reload to see all options
239
- debugger;
240
  location.reload();
241
  return;
242
  }
@@ -372,6 +385,7 @@ function checkBulkProcessingCallApi(){
372
  if(data['Stop'] == false) { //there are other items in the priority list, maybe processed, try those
373
  setTimeout(checkBulkProgress, 5000);
374
  }
 
375
  break;
376
  case ShortPixel.STATUS_FAIL:
377
  setCellMessage(id, data["Message"], "<a class='button button-smaller button-primary' href=\"javascript:manualOptimization('<?php echo($id)?>')\">Retry</a>");
@@ -381,6 +395,7 @@ function checkBulkProcessingCallApi(){
381
  if(data["BulkPercent"]) {
382
  progressUpdate(data["BulkPercent"], data["BulkMsg"]);
383
  }
 
384
  }
385
  console.log(data["Message"]);
386
  setTimeout(checkBulkProgress, 5000);
@@ -413,6 +428,7 @@ function checkBulkProcessingCallApi(){
413
  : ShortPixel.successActions(id, data["Type"], data['ThumbsCount'], data['ThumbsTotal'], data["BackupEnabled"]);
414
 
415
  setCellMessage(id, ShortPixel.successMsg(id, percent, data["Type"], data['ThumbsCount']), successActions);
 
416
  var animator = new PercentageAnimator("#sp-msg-" + id + " span.percent", percent);
417
  animator.animate(percent);
418
  if(isBulkPage && typeof data["Thumb"] !== 'undefined') { // && data["PercentImprovement"] > 0) {
@@ -444,6 +460,7 @@ function checkBulkProcessingCallApi(){
444
  showToolBarAlert(ShortPixel.STATUS_SKIP, data["Message"] + ' Image ID: ' + id);
445
  setCellMessage(id, data["Message"], "");
446
  }
 
447
  //fall through
448
  case ShortPixel.STATUS_RETRY:
449
  console.log('Server response: ' + response);
@@ -479,7 +496,7 @@ function clearBulkProcessor(){
479
  function setCellMessage(id, message, actions){
480
  var msg = jQuery("#sp-msg-" + id);
481
  if(msg.length > 0) {
482
- msg.html("<div class='sp-column-actions' style='width:110px;'>" + actions + "</div>"
483
  + "<div class='sp-column-info'>" + message + "</div>");
484
  msg.css("color", "");
485
  }
76
  }
77
 
78
  function successMsg(id, percent, type, thumbsCount) {
79
+ return (percent > 0 ? "<div class='sp-column-info'>Reduced by <span class='percent'><strong>" + percent + "%</strong></span> " : "")
80
  + (percent > 0 && percent < 5 ? "<br>" : '')
81
  + (percent < 5 ? "Bonus processing" : '')
82
  + (type.length > 0 ? " ("+type+")" : "")
97
  }
98
 
99
  function successActions(id, type, thumbsCount, thumbsTotal, backupEnabled) {
100
+ if(backupEnabled == 1) {
101
  var otherType = type.length > 0 ? (type == "lossy" ? "lossless" : "lossy") : "";
102
  return '<div class="sp-column-actions">'
103
  + (thumbsTotal > thumbsCount ? "<a class='button button-smaller button-primary' href=\"javascript:optimizeThumbs(" + id + ");\">Optimize " + (thumbsTotal - thumbsCount) + " thumbnails</a>" : "")
104
  + (otherType.length ? "<a class='button button-smaller' href=\"javascript:reoptimize(" + id + ", '" + otherType + "');\">Re-optimize " + otherType + "</a>" : "")
105
  + "<a class='button button-smaller' href=\"admin.php?action=shortpixel_restore_backup&attachment_ID=" + id + ")\">Restore backup</a>"
106
  + "</div>";
107
+ }
108
+ return "";
109
+ }
110
+
111
+ function otherMediaUpdateActions(id, actions) {
112
+ id = id.substring(2);
113
+ if(jQuery(".shortpixel-other-media").length) {
114
+ var allActions = ['optimize', 'retry', 'restore','redo', 'quota', 'view'];
115
+ for(var i=0, tot=allActions.length; i < tot; i++) {
116
+ jQuery("#"+allActions[i]+"_"+id).css("display", "none");
117
+ }
118
+ for(var i=0, tot=actions.length; i < tot; i++) {
119
+ jQuery("#"+actions[i]+"_"+id).css("display", "");
120
+ }
121
+ }
122
  }
123
 
124
  function retry(msg) {
232
  percentDial : percentDial,
233
  successMsg : successMsg,
234
  successActions : successActions,
235
+ otherMediaUpdateActions: otherMediaUpdateActions,
236
  retry : retry,
237
  initFolderSelector : initFolderSelector,
238
  browseContent : browseContent,
250
  case ShortPixel.STATUS_QUOTA_EXCEEDED:
251
  if( window.location.href.search("wp-short-pixel-bulk") > 0
252
  && jQuery(".sp-quota-exceeded-alert").length == 0) { //if we're in bulk and the alert is not displayed reload to see all options
 
253
  location.reload();
254
  return;
255
  }
385
  if(data['Stop'] == false) { //there are other items in the priority list, maybe processed, try those
386
  setTimeout(checkBulkProgress, 5000);
387
  }
388
+ ShortPixel.otherMediaUpdateActions(id, ['quota','view']);
389
  break;
390
  case ShortPixel.STATUS_FAIL:
391
  setCellMessage(id, data["Message"], "<a class='button button-smaller button-primary' href=\"javascript:manualOptimization('<?php echo($id)?>')\">Retry</a>");
395
  if(data["BulkPercent"]) {
396
  progressUpdate(data["BulkPercent"], data["BulkMsg"]);
397
  }
398
+ ShortPixel.otherMediaUpdateActions(id, ['retry','view']);
399
  }
400
  console.log(data["Message"]);
401
  setTimeout(checkBulkProgress, 5000);
428
  : ShortPixel.successActions(id, data["Type"], data['ThumbsCount'], data['ThumbsTotal'], data["BackupEnabled"]);
429
 
430
  setCellMessage(id, ShortPixel.successMsg(id, percent, data["Type"], data['ThumbsCount']), successActions);
431
+ ShortPixel.otherMediaUpdateActions(id, ['restore','redo'+(data["Type"] == 'lossy' ? 'lossless': 'lossy'),'view']);
432
  var animator = new PercentageAnimator("#sp-msg-" + id + " span.percent", percent);
433
  animator.animate(percent);
434
  if(isBulkPage && typeof data["Thumb"] !== 'undefined') { // && data["PercentImprovement"] > 0) {
460
  showToolBarAlert(ShortPixel.STATUS_SKIP, data["Message"] + ' Image ID: ' + id);
461
  setCellMessage(id, data["Message"], "");
462
  }
463
+ ShortPixel.otherMediaUpdateActions(id, ['retry','view']);
464
  //fall through
465
  case ShortPixel.STATUS_RETRY:
466
  console.log('Server response: ' + response);
496
  function setCellMessage(id, message, actions){
497
  var msg = jQuery("#sp-msg-" + id);
498
  if(msg.length > 0) {
499
+ msg.html("<div class='sp-column-actions'>" + actions + "</div>"
500
  + "<div class='sp-column-info'>" + message + "</div>");
501
  msg.css("color", "");
502
  }
shortpixel_api.php CHANGED
@@ -45,14 +45,14 @@ class ShortPixelAPI {
45
  * @return response from wp_remote_post or error
46
  */
47
  public function doRequests($URLs, $Blocking, $itemHandler, $compressionType = false) {
48
-
49
  $requestParameters = array(
50
  'plugin_version' => PLUGIN_VERSION,
51
  'key' => $this->_settings->apiKey,
52
  'lossy' => $compressionType === false ? $this->_settings->compressionType : $compressionType,
53
  'cmyk2rgb' => $this->_settings->CMYKtoRGBconversion,
54
  'keep_exif' => ($this->_settings->keepExif ? "1" : "0"),
55
- 'resize' => $this->_settings->resizeImages,
 
56
  'resize_width' => $this->_settings->resizeWidth,
57
  'resize_height' => $this->_settings->resizeHeight,
58
  'urllist' => $URLs
@@ -296,11 +296,15 @@ class ShortPixelAPI {
296
  {
297
  $fileType = "LossyURL";
298
  $fileSize = "LossySize";
 
 
299
  }
300
  else
301
  {
302
  $fileType = "LosslessURL";
303
  $fileSize = "LoselessSize";
 
 
304
  }
305
 
306
  //if there is no improvement in size then we do not download this file
@@ -312,15 +316,19 @@ class ShortPixelAPI {
312
 
313
  $downloadTimeout = max(ini_get('max_execution_time') - 10, 15);
314
  $tempFile = download_url($fileURL, $downloadTimeout);
315
- //var_dump($tempFiles);
316
-
317
  if(is_wp_error( $tempFile ))
318
  { //try to switch the default protocol
319
  $fileURL = $this->setPreferredProtocol(urldecode($fileData->$fileType), true); //force recheck of the protocol
320
  $tempFile = download_url($fileURL, $downloadTimeout);
321
  }
 
 
 
 
 
 
322
  //on success we return this
323
- $returnMessage = array("Status" => self::STATUS_SUCCESS, "Message" => $tempFile);
324
 
325
  if ( is_wp_error( $tempFile ) ) {
326
  @unlink($tempFile);
@@ -368,7 +376,7 @@ class ShortPixelAPI {
368
  }
369
  $downloadResult = $this->handleDownload($fileData,$compressionType);
370
  if ( $downloadResult['Status'] == self::STATUS_SUCCESS ) {
371
- $tempFiles[$counter] = $downloadResult['Message'];
372
  }
373
  //when the status is STATUS_UNCHANGED we just skip the array line for that one
374
  elseif ( $downloadResult['Status'] <> self::STATUS_UNCHANGED ) {
@@ -388,7 +396,7 @@ class ShortPixelAPI {
388
 
389
  //figure out in what SubDir files should land
390
  //#$SubDir = $this->returnSubDir(get_attached_file($ID));
391
- $fullSubDir = str_replace(WP_CONTENT_DIR, "", dirname($itemHandler->getMeta()->getPath())) . DIRECTORY_SEPARATOR;
392
  //die("Uploads base: " . SP_UPLOADS_BASE . " FullSubDir: ". $fullSubDir . " PATH: " . dirname($itemHandler->getMeta()->getPath()));
393
  $SubDir = ShortPixelMetaFacade::returnSubDir($itemHandler->getMeta()->getPath(), $itemHandler->getType());
394
 
@@ -415,8 +423,8 @@ class ShortPixelAPI {
415
  foreach ( $destination as $fileID => $filePATH )
416
  {
417
  if ( !file_exists($filePATH) )
418
- {
419
- if ( !@copy($source[$fileID], $destination[$fileID]) )
420
  {//file couldn't be saved in backup folder
421
  $msg = 'Cannot save file <i>' . self::MB_basename($source[$fileID]) . '</i> in backup directory';
422
  //#ShortPixelAPI::SaveMessageinMetadata($ID, $msg);
@@ -445,10 +453,18 @@ class ShortPixelAPI {
445
  if ( !empty($tempFiles) )
446
  {
447
  //overwrite the original files with the optimized ones
448
- foreach ( $tempFiles as $tempFileID => $tempFilePATH )
449
  {
 
 
 
450
  if ( file_exists($tempFilePATH) && file_exists($PATHs[$tempFileID]) && is_writable($PATHs[$tempFileID]) ) {
451
- copy($tempFilePATH, $PATHs[$tempFileID]);
 
 
 
 
 
452
  if($firstImage) { //this is the main image
453
  $firstImage = false;
454
  if($resize) {
45
  * @return response from wp_remote_post or error
46
  */
47
  public function doRequests($URLs, $Blocking, $itemHandler, $compressionType = false) {
 
48
  $requestParameters = array(
49
  'plugin_version' => PLUGIN_VERSION,
50
  'key' => $this->_settings->apiKey,
51
  'lossy' => $compressionType === false ? $this->_settings->compressionType : $compressionType,
52
  'cmyk2rgb' => $this->_settings->CMYKtoRGBconversion,
53
  'keep_exif' => ($this->_settings->keepExif ? "1" : "0"),
54
+ 'convertto' => ($this->_settings->createWebp ? urlencode("+webp") : ""),
55
+ 'resize' => $this->_settings->resizeImages + 2 * ($this->_settings->resizeType == 'inner' ? 1 : 0),
56
  'resize_width' => $this->_settings->resizeWidth,
57
  'resize_height' => $this->_settings->resizeHeight,
58
  'urllist' => $URLs
296
  {
297
  $fileType = "LossyURL";
298
  $fileSize = "LossySize";
299
+ $webpType = "WebPLossyURL";
300
+ $webpSize = "WebPLossySize";
301
  }
302
  else
303
  {
304
  $fileType = "LosslessURL";
305
  $fileSize = "LoselessSize";
306
+ $webpType = "WebPLosslessURL";
307
+ $webpSize = "WebPLosslessSize";
308
  }
309
 
310
  //if there is no improvement in size then we do not download this file
316
 
317
  $downloadTimeout = max(ini_get('max_execution_time') - 10, 15);
318
  $tempFile = download_url($fileURL, $downloadTimeout);
 
 
319
  if(is_wp_error( $tempFile ))
320
  { //try to switch the default protocol
321
  $fileURL = $this->setPreferredProtocol(urldecode($fileData->$fileType), true); //force recheck of the protocol
322
  $tempFile = download_url($fileURL, $downloadTimeout);
323
  }
324
+
325
+ if($webpType !== "NA") {
326
+ $webpURL = $this->setPreferredProtocol(urldecode($fileData->$webpType));
327
+ $webpTempFile = download_url($webpURL, $downloadTimeout);
328
+ }
329
+
330
  //on success we return this
331
+ $returnMessage = array("Status" => self::STATUS_SUCCESS, "Message" => $tempFile, "WebP" => is_wp_error( $webpTempFile ) ? "NA" : $webpTempFile);
332
 
333
  if ( is_wp_error( $tempFile ) ) {
334
  @unlink($tempFile);
376
  }
377
  $downloadResult = $this->handleDownload($fileData,$compressionType);
378
  if ( $downloadResult['Status'] == self::STATUS_SUCCESS ) {
379
+ $tempFiles[$counter] = $downloadResult;
380
  }
381
  //when the status is STATUS_UNCHANGED we just skip the array line for that one
382
  elseif ( $downloadResult['Status'] <> self::STATUS_UNCHANGED ) {
396
 
397
  //figure out in what SubDir files should land
398
  //#$SubDir = $this->returnSubDir(get_attached_file($ID));
399
+ $fullSubDir = str_replace(get_home_path(), "", dirname($itemHandler->getMeta()->getPath())) . DIRECTORY_SEPARATOR;
400
  //die("Uploads base: " . SP_UPLOADS_BASE . " FullSubDir: ". $fullSubDir . " PATH: " . dirname($itemHandler->getMeta()->getPath()));
401
  $SubDir = ShortPixelMetaFacade::returnSubDir($itemHandler->getMeta()->getPath(), $itemHandler->getType());
402
 
423
  foreach ( $destination as $fileID => $filePATH )
424
  {
425
  if ( !file_exists($filePATH) )
426
+ {
427
+ if ( !@copy($source[$fileID], $filePATH) )
428
  {//file couldn't be saved in backup folder
429
  $msg = 'Cannot save file <i>' . self::MB_basename($source[$fileID]) . '</i> in backup directory';
430
  //#ShortPixelAPI::SaveMessageinMetadata($ID, $msg);
453
  if ( !empty($tempFiles) )
454
  {
455
  //overwrite the original files with the optimized ones
456
+ foreach ( $tempFiles as $tempFileID => $tempFiles )
457
  {
458
+ if(!is_array($tempFiles)) continue;
459
+ $tempFilePATH = $tempFiles["Message"];
460
+ $tempWebpFilePATH = $tempFiles["WebP"];
461
  if ( file_exists($tempFilePATH) && file_exists($PATHs[$tempFileID]) && is_writable($PATHs[$tempFileID]) ) {
462
+ $targetFile = $PATHs[$tempFileID];
463
+ copy($tempFilePATH, $targetFile);
464
+ if(file_exists($tempWebpFilePATH)) {
465
+ $targetWebPFile = dirname($targetFile) . DIRECTORY_SEPARATOR . basename($targetFile, '.' . pathinfo($targetFile, PATHINFO_EXTENSION)) . ".webp";
466
+ copy($tempWebpFilePATH, $targetWebPFile);
467
+ }
468
  if($firstImage) { //this is the main image
469
  $firstImage = false;
470
  if($resize) {
wp-shortpixel-req.php CHANGED
@@ -1,9 +1,9 @@
1
  <?php
2
  require_once('shortpixel-debug.php');
3
 
4
- require_once('wp-shortpixel-settings.php');
5
  require_once('shortpixel_api.php');
6
- require_once('shortpixel_queue.php');
7
  //entities
8
  require_once('class/model/shortpixel-entity.php');
9
  require_once('class/model/shortpixel-meta.php');
1
  <?php
2
  require_once('shortpixel-debug.php');
3
 
4
+ require_once('class/wp-shortpixel-settings.php');
5
  require_once('shortpixel_api.php');
6
+ require_once('class/shortpixel_queue.php');
7
  //entities
8
  require_once('class/model/shortpixel-entity.php');
9
  require_once('class/model/shortpixel-meta.php');
wp-shortpixel.php CHANGED
@@ -3,7 +3,7 @@
3
  * Plugin Name: ShortPixel Image Optimizer
4
  * Plugin URI: https://shortpixel.com/
5
  * Description: ShortPixel optimizes images automatically, while guarding the quality of your images. Check your <a href="options-general.php?page=wp-shortpixel" target="_blank">Settings &gt; ShortPixel</a> page on how to start optimizing your image library and make your website load faster.
6
- * Version: 4.0.2
7
  * Author: ShortPixel
8
  * Author URI: https://shortpixel.com
9
  */
@@ -12,7 +12,7 @@ define('SP_RESET_ON_ACTIVATE', false); //if true TODO set false
12
 
13
  define('SP_AFFILIATE_CODE', '');
14
 
15
- define('PLUGIN_VERSION', "4.0.2");
16
  define('SP_MAX_TIMEOUT', 10);
17
  define('SP_VALIDATE_MAX_TIMEOUT', 15);
18
  define('SP_BACKUP', 'ShortpixelBackups');
@@ -255,7 +255,7 @@ class WPShortPixel {
255
  WP_ADMIN_URL: '<?php echo admin_url(); ?>',
256
  API_KEY: "<?php echo $this->_settings->apiKey; ?>",
257
  MEDIA_ALERT: '<?php echo $this->_settings->mediaAlert ? "done" : "todo"; ?>',
258
- FRONT_BOOTSTRAP: <?php echo $this->_settings->frontBootstrap && (time() - $this->_settings->lastBackAction > 60) ? 1 : 0; ?>,
259
  AJAX_URL: '<?php echo admin_url('admin-ajax.php'); ?>'
260
  };
261
  </script> <?php
@@ -595,9 +595,7 @@ class WPShortPixel {
595
  for($i = 0; $i < min(3, count($ids)); $i++) {
596
  $itemHandler = $ids[$i];
597
  $tmpMeta = $itemHandler->getMeta();
598
- //$compType = (isset($tmpMeta['ShortPixel']['type']) ? ($tmpMeta['ShortPixel']['type'] == 'lossy' ? 1 : 0) : $this->_settings->compressionType);
599
  $compType = ($tmpMeta->getCompressionType() !== null ? $tmpMeta->getCompressionType() : $this->_settings->compressionType);
600
- //$URLsAndPATHs = $this->sendToProcessing($ID, $compType, isset($tmpMeta['ShortPixel']['thumbsTodo']));
601
  $URLsAndPATHs = $this->sendToProcessing($itemHandler, $compType, $tmpMeta->getThumbsTodo());
602
  if($i == 0) { //save for later use
603
  $firstUrlAndPaths = $URLsAndPATHs;
@@ -694,15 +692,15 @@ class WPShortPixel {
694
  }
695
  elseif( is_array($customIds)) { // this item is from custom bulk
696
  foreach($customIds as $customId) {
697
- $contentUrl = network_site_url("/") . "/wp-content";
698
  if($customId->id == $itemHandler->getId()) {
699
  if('pdf' == strtolower(pathinfo($meta->getName(), PATHINFO_EXTENSION))) {
700
  $result["Thumb"] = plugins_url( 'shortpixel-image-optimiser/res/img/logo-pdf.png' );
701
  $result["BkThumb"] = "";
702
  } else {
703
- $result["Thumb"] = $thumb = $contentUrl . "/" . $meta->getWebPath();
704
  if($this->_settings->backupImages) {
705
- $result["BkThumb"] = str_replace($contentUrl, $contentUrl. "/" . SP_UPLOADS_NAME . "/" . SP_BACKUP, $thumb);
706
  }
707
  }
708
  $this->setBulkInfo($itemId, $result);
@@ -747,7 +745,7 @@ class WPShortPixel {
747
  }
748
  $this->advanceBulk($meta->getId(), $result);
749
  if($itemHandler->getType() == ShortPixelMetaFacade::CUSTOM_TYPE) {
750
- $result["CustomImageLink"] = trailingslashit(network_site_url("/")) . "wp-content/" . $meta->getWebPath();
751
  }
752
  }
753
  elseif ($this->prioQ->isPrio($itemId) && $result["Status"] == ShortPixelAPI::STATUS_QUOTA_EXCEEDED) {
@@ -763,7 +761,7 @@ class WPShortPixel {
763
  self::log("HIP: 5 Prio Skipped: ".json_encode($this->prioQ->getSkipped()));
764
  }
765
  elseif($result["Status"] == ShortPixelAPI::STATUS_RETRY && is_array($customIds)) {
766
- $result["CustomImageLink"] = $thumb = trailingslashit(network_site_url("/")) . "wp-content/" . $meta->getWebPath();
767
  }
768
 
769
  if($result["Status"] !== ShortPixelAPI::STATUS_RETRY) {
@@ -909,13 +907,13 @@ class WPShortPixel {
909
  if($bkFolder) {
910
  try {
911
  //main file
912
- @rename($bkFile, $file);
 
913
 
914
  //overwriting thumbnails
915
  foreach($thumbsPaths as $source => $destination) {
916
- @rename($source, $destination);
917
  }
918
-
919
  $duplicates = ShortPixelMetaFacade::getWPMLDuplicates($attachmentID);
920
  foreach($duplicates as $ID) {
921
  $crtMeta = $attachmentID == $ID ? $meta : wp_get_attachment_metadata($ID);
@@ -937,7 +935,31 @@ class WPShortPixel {
937
 
938
  return $meta;
939
  }
 
 
 
 
 
 
 
940
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
941
  public function handleRestoreBackup() {
942
  $attachmentID = intval($_GET['attachment_ID']);
943
 
@@ -953,28 +975,38 @@ class WPShortPixel {
953
  }
954
 
955
  public function handleRedo() {
956
- $ID = $_GET['attachment_ID'];
957
- $mediaType = ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE;
958
- if(strpos($ID, 'C-') === 0) {
959
- die("handleRedo not implemented for Custom media");
960
- $ID = substr($ID, 2);
961
- $mediaType = ShortPixelMetaFacade::CUSTOM_TYPE;
962
- }
963
- $ID = intval($ID);
964
- $compressionType = ($_GET['type'] == 'lossless' ? 'lossless' : 'lossy'); //sanity check
965
-
966
- $meta = $this->doRestore($ID);
967
- //die(var_dump($meta));
968
- if($meta) { //restore succeeded
969
- $meta['ShortPixel'] = array("type" => $compressionType);
970
- wp_update_attachment_metadata($ID, $meta);
971
- $this->prioQ->push($ID);
972
- $this->sendToProcessing(new ShortPixelMetaFacade($ID), $compressionType == 'lossy' ? 1 : 0);
973
- $ret = array("Status" => ShortPixelAPI::STATUS_SUCCESS, "Message" => "");
974
  } else {
975
- $ret = array("Status" => ShortPixelAPI::STATUS_SKIP, "Message" => "Could not restore from backup: " . $ID);
 
 
 
 
 
 
 
 
 
 
 
 
976
  }
977
- die(json_encode($ret));
978
  }
979
 
980
  public function handleOptimizeThumbs() {
@@ -1068,7 +1100,7 @@ class WPShortPixel {
1068
  ?><script>var shortPixelQuotaExceeded = 0;</script><?php
1069
  }
1070
  else {
1071
- $this->view->displayQuotaExceededAlert($quotaData);
1072
  ?><script>var shortPixelQuotaExceeded = 1;</script><?php
1073
  }
1074
  return $quotaData;
@@ -1092,7 +1124,7 @@ class WPShortPixel {
1092
  }
1093
  $customMediaListTable = new ShortPixelListTable($this, $this->spMetaDao, $this->hasNextGen);
1094
  ?>
1095
- <div class="wrap">
1096
  <h2>
1097
  <div style="float:right;">
1098
  <a href="upload.php?page=wp-short-pixel-custom&refresh=1" id="refresh" class="button button-primary" title="Refresh custom folders content">
@@ -1135,7 +1167,9 @@ class WPShortPixel {
1135
  }
1136
 
1137
  $quotaData = $this->checkQuotaAndAlert();
1138
- if($this->_settings->getOpt('wp-short-pixel-quota-exceeded', 0) != 0) return;
 
 
1139
 
1140
  if(isset($_POST['bulkProcessPause']))
1141
  {//pause an ongoing bulk processing, it might be needed sometimes
@@ -1178,10 +1212,6 @@ class WPShortPixel {
1178
  $this->_settings->skipToCustom = true;
1179
  }//resume was clicked
1180
 
1181
- //figure out all the files that could be processed
1182
- $qry = "SELECT count(*) FilesToBeProcessed FROM " . $wpdb->prefix . "postmeta
1183
- WHERE meta_key = '_wp_attached_file' ";
1184
- $allFiles = $wpdb->get_results($qry);
1185
  //figure out the files that are left to be processed
1186
  $qry_left = "SELECT count(*) FilesLeftToBeProcessed FROM " . $wpdb->prefix . "postmeta
1187
  WHERE meta_key = '_wp_attached_file' AND post_id <= " . (0 + $this->prioQ->getStartBulkId());
@@ -1205,10 +1235,6 @@ class WPShortPixel {
1205
  $this->view->displayBulkProcessingRunning($percent, $msg, $quotaData['APICallsRemaining'], $this->getAverageCompression(),
1206
  ($pendingMeta !== null ? ($this->prioQ->bulkRunning() ? 3 : 2) : 1));
1207
 
1208
- // $imagesLeft = $filesLeft[0]->FilesLeftToBeProcessed;
1209
- // $totalImages = $allFiles[0]->FilesToBeProcessed;
1210
- // echo "<p>{$imagesLeft} out of {$totalImages} images left to process.</p>";
1211
- // echo ' <a class="button button-secondary" href="' . get_admin_url() . 'upload.php">Media Library</a> ';
1212
  } else
1213
  {
1214
  if($this->prioQ->bulkRan() && !$this->prioQ->bulkPaused()) {
@@ -1216,15 +1242,13 @@ class WPShortPixel {
1216
  }
1217
 
1218
  //image count
1219
- //$imageCount = $this->countAllProcessableFiles();
1220
- $imageOnlyThumbs = $quotaData['totalFiles'] - $quotaData['mainFiles'];
1221
- $thumbsProcessedCount = $this->_settings->getOpt( 'wp-short-pixel-thumbnail-count', 0);//amount of optimized thumbnails
1222
- $under5PercentCount = $this->_settings->getOpt( 'wp-short-pixel-files-under-5-percent', 0);//amount of under 5% optimized imgs.
1223
 
1224
  //average compression
1225
  $averageCompression = self::getAverageCompression();
1226
  $percent = $this->prioQ->bulkPaused() ? round($quotaData["totalProcessedFiles"] *100.0 / $quotaData["totalFiles"]) : false;
1227
- $this->view->displayBulkProcessingForm($quotaData, $thumbsProcessedCount, $under5PercentCount,
1228
  $this->prioQ->bulkRan(), $averageCompression, $this->_settings->fileCount,
1229
  self::formatBytes($this->_settings->savedSpace), $percent, $pendingMeta);
1230
  }
@@ -1292,7 +1316,7 @@ class WPShortPixel {
1292
 
1293
  // set checkbox if multiSelect set to true
1294
  $checkbox = ( isset($_POST['multiSelect']) && $_POST['multiSelect'] == 'true' ) ? "<input type='checkbox' />" : null;
1295
- $onlyFolders = ( isset($_POST['onlyFolders']) && $_POST['onlyFolders'] == 'true' ) ? true : false;
1296
  $onlyFiles = ( isset($_POST['onlyFiles']) && $_POST['onlyFiles'] == 'true' ) ? true : false;
1297
 
1298
  if( file_exists($postDir) ) {
@@ -1328,7 +1352,8 @@ class WPShortPixel {
1328
 
1329
  public function getCustomFolderBase() {
1330
  if(is_main_site()) {
1331
- return WP_CONTENT_DIR;
 
1332
  } else {
1333
  $up = wp_upload_dir();
1334
  return $up['basedir'];
@@ -1455,6 +1480,7 @@ class WPShortPixel {
1455
  $this->_settings->keepExif = isset($_POST['removeExif']) ? 0 : 1;
1456
  //delete_option('wp-short-pixel-keep-exif');
1457
  $this->_settings->resizeImages = (isset($_POST['resize']) ? 1: 0);
 
1458
  $this->_settings->resizeWidth = (isset($_POST['width']) ? $_POST['width']: $this->_settings->resizeWidth);
1459
  $this->_settings->resizeHeight = (isset($_POST['height']) ? $_POST['height']: $this->_settings->resizeHeight);
1460
  $this->_settings->siteAuthUser = (isset($_POST['siteAuthUser']) ? $_POST['siteAuthUser']: $this->_settings->siteAuthUser);
@@ -1487,6 +1513,7 @@ class WPShortPixel {
1487
  $customFolders = $this->spMetaDao->getFolders();
1488
  $this->_settings->hasCustomFolders = true;
1489
  }
 
1490
  if(isset($_POST['frontBootstrap'])) { $this->_settings->frontBootstrap = 1; } else { $this->_settings->frontBootstrap = 0; }
1491
  }
1492
  if(isset($_POST['removeFolder']) && strlen(($_POST['removeFolder']))) {
@@ -1928,7 +1955,7 @@ class WPShortPixel {
1928
 
1929
  if(file_exists($oldBackupFolder)) { //if old backup folder does not exist then there is nothing to do
1930
 
1931
- if(!file_exists(SP_BACKUP_FOLDER)) {
1932
  //we check that the backup folder exists, if not we create it so we can copy into it
1933
  if(!mkdir(SP_BACKUP_FOLDER, 0777, true)) return;
1934
  }
@@ -1943,7 +1970,8 @@ class WPShortPixel {
1943
  }
1944
  }
1945
  //now if the backup folder does not contain the uploads level, create it
1946
- if(!is_dir(SP_BACKUP_FOLDER.DIRECTORY_SEPARATOR.SP_UPLOADS_NAME)) {
 
1947
  @rename(SP_BACKUP_FOLDER, SP_BACKUP_FOLDER."_tmp");
1948
  @mkdir(SP_BACKUP_FOLDER);
1949
  @rename(SP_BACKUP_FOLDER."_tmp", SP_BACKUP_FOLDER.DIRECTORY_SEPARATOR.SP_UPLOADS_NAME);
@@ -1951,6 +1979,15 @@ class WPShortPixel {
1951
  @rename(SP_BACKUP_FOLDER."_tmp", SP_BACKUP_FOLDER);
1952
  }
1953
  }
 
 
 
 
 
 
 
 
 
1954
  return;
1955
  }
1956
 
3
  * Plugin Name: ShortPixel Image Optimizer
4
  * Plugin URI: https://shortpixel.com/
5
  * Description: ShortPixel optimizes images automatically, while guarding the quality of your images. Check your <a href="options-general.php?page=wp-shortpixel" target="_blank">Settings &gt; ShortPixel</a> page on how to start optimizing your image library and make your website load faster.
6
+ * Version: 4.1.0
7
  * Author: ShortPixel
8
  * Author URI: https://shortpixel.com
9
  */
12
 
13
  define('SP_AFFILIATE_CODE', '');
14
 
15
+ define('PLUGIN_VERSION', "4.1.0");
16
  define('SP_MAX_TIMEOUT', 10);
17
  define('SP_VALIDATE_MAX_TIMEOUT', 15);
18
  define('SP_BACKUP', 'ShortpixelBackups');
255
  WP_ADMIN_URL: '<?php echo admin_url(); ?>',
256
  API_KEY: "<?php echo $this->_settings->apiKey; ?>",
257
  MEDIA_ALERT: '<?php echo $this->_settings->mediaAlert ? "done" : "todo"; ?>',
258
+ FRONT_BOOTSTRAP: <?php echo $this->_settings->frontBootstrap && (time() - $this->_settings->lastBackAction > 600) ? 1 : 0; ?>,
259
  AJAX_URL: '<?php echo admin_url('admin-ajax.php'); ?>'
260
  };
261
  </script> <?php
595
  for($i = 0; $i < min(3, count($ids)); $i++) {
596
  $itemHandler = $ids[$i];
597
  $tmpMeta = $itemHandler->getMeta();
 
598
  $compType = ($tmpMeta->getCompressionType() !== null ? $tmpMeta->getCompressionType() : $this->_settings->compressionType);
 
599
  $URLsAndPATHs = $this->sendToProcessing($itemHandler, $compType, $tmpMeta->getThumbsTodo());
600
  if($i == 0) { //save for later use
601
  $firstUrlAndPaths = $URLsAndPATHs;
692
  }
693
  elseif( is_array($customIds)) { // this item is from custom bulk
694
  foreach($customIds as $customId) {
695
+ $rootUrl = trailingslashit(network_site_url("/"));
696
  if($customId->id == $itemHandler->getId()) {
697
  if('pdf' == strtolower(pathinfo($meta->getName(), PATHINFO_EXTENSION))) {
698
  $result["Thumb"] = plugins_url( 'shortpixel-image-optimiser/res/img/logo-pdf.png' );
699
  $result["BkThumb"] = "";
700
  } else {
701
+ $result["Thumb"] = $thumb = $rootUrl . $meta->getWebPath();
702
  if($this->_settings->backupImages) {
703
+ $result["BkThumb"] = str_replace($rootUrl, $rootUrl. "/" . basename(dirname(dirname(SP_BACKUP_FOLDER))) . "/" . SP_UPLOADS_NAME . "/" . SP_BACKUP . "/", $thumb);
704
  }
705
  }
706
  $this->setBulkInfo($itemId, $result);
745
  }
746
  $this->advanceBulk($meta->getId(), $result);
747
  if($itemHandler->getType() == ShortPixelMetaFacade::CUSTOM_TYPE) {
748
+ $result["CustomImageLink"] = trailingslashit(network_site_url("/")) . $meta->getWebPath();
749
  }
750
  }
751
  elseif ($this->prioQ->isPrio($itemId) && $result["Status"] == ShortPixelAPI::STATUS_QUOTA_EXCEEDED) {
761
  self::log("HIP: 5 Prio Skipped: ".json_encode($this->prioQ->getSkipped()));
762
  }
763
  elseif($result["Status"] == ShortPixelAPI::STATUS_RETRY && is_array($customIds)) {
764
+ $result["CustomImageLink"] = $thumb = trailingslashit(network_site_url("/")) . $meta->getWebPath();
765
  }
766
 
767
  if($result["Status"] !== ShortPixelAPI::STATUS_RETRY) {
907
  if($bkFolder) {
908
  try {
909
  //main file
910
+ $this->renameWithRetina($bkFile, $file);
911
+
912
 
913
  //overwriting thumbnails
914
  foreach($thumbsPaths as $source => $destination) {
915
+ $this->renameWithRetina($source, $destination);
916
  }
 
917
  $duplicates = ShortPixelMetaFacade::getWPMLDuplicates($attachmentID);
918
  foreach($duplicates as $ID) {
919
  $crtMeta = $attachmentID == $ID ? $meta : wp_get_attachment_metadata($ID);
935
 
936
  return $meta;
937
  }
938
+
939
+ protected function renameWithRetina($bkFile, $file) {
940
+ @rename($bkFile, $file);
941
+ $ext = pathinfo($file, PATHINFO_EXTENSION);
942
+ @rename(substr($bkFile, 0, strlen($bkFile) - 1 - strlen($ext)) . "@2x." . $ext, substr($file, 0, strlen($file) - 1 - strlen($ext)) . "@2x." . $ext);
943
+
944
+ }
945
 
946
+ public function doCustomRestore($ID) {
947
+ $meta = $this->spMetaDao->getMeta($ID);
948
+ if(!$meta || $meta->getStatus() != 2) return false;
949
+
950
+ $file = $meta->getPath();
951
+ $fullSubDir = str_replace(get_home_path(), "", dirname($file)) . DIRECTORY_SEPARATOR;
952
+ $bkFile = SP_BACKUP_FOLDER . DIRECTORY_SEPARATOR . $fullSubDir . ShortPixelAPI::MB_basename($file);
953
+
954
+ if(file_exists($bkFile)) {
955
+ @rename($bkFile, $file);
956
+ $meta->setStatus(3);
957
+ $this->spMetaDao->update($meta);
958
+ }
959
+
960
+ return $meta;
961
+ }
962
+
963
  public function handleRestoreBackup() {
964
  $attachmentID = intval($_GET['attachment_ID']);
965
 
975
  }
976
 
977
  public function handleRedo() {
978
+ die(json_encode($this->redo($_GET['attachment_ID'], $_GET['type'])));
979
+ }
980
+
981
+ public function redo($qID, $type = false) {
982
+ if(ShortPixelMetaFacade::isCustomQueuedId($qID)) {
983
+ $ID = ShortPixelMetaFacade::stripQueuedIdType($qID);
984
+ $meta = $this->doCustomRestore($ID);
985
+ if($meta) {
986
+ $meta->setCompressionType(1 - $meta->getCompressionType());
987
+ $meta->setStatus(1);
988
+ $this->spMetaDao->update($meta);
989
+ $this->prioQ->push($qID);
990
+ $ret = array("Status" => ShortPixelAPI::STATUS_SUCCESS, "Message" => "");
991
+ } else {
992
+ $ret = array("Status" => ShortPixelAPI::STATUS_SKIP, "Message" => "Could not restore from backup: " . $qID);
993
+ }
 
 
994
  } else {
995
+ $ID = intval($qID);
996
+ $compressionType = ($type == 'lossless' ? 'lossless' : 'lossy'); //sanity check
997
+
998
+ $meta = $this->doRestore($ID);
999
+ if($meta) { //restore succeeded
1000
+ $meta['ShortPixel'] = array("type" => $compressionType);
1001
+ wp_update_attachment_metadata($ID, $meta);
1002
+ $this->prioQ->push($ID);
1003
+ $this->sendToProcessing(new ShortPixelMetaFacade($ID), $compressionType == 'lossy' ? 1 : 0);
1004
+ $ret = array("Status" => ShortPixelAPI::STATUS_SUCCESS, "Message" => "");
1005
+ } else {
1006
+ $ret = array("Status" => ShortPixelAPI::STATUS_SKIP, "Message" => "Could not restore from backup: " . $ID);
1007
+ }
1008
  }
1009
+ return $ret;
1010
  }
1011
 
1012
  public function handleOptimizeThumbs() {
1100
  ?><script>var shortPixelQuotaExceeded = 0;</script><?php
1101
  }
1102
  else {
1103
+ $this->view->displayQuotaExceededAlert($quotaData, self::getAverageCompression());
1104
  ?><script>var shortPixelQuotaExceeded = 1;</script><?php
1105
  }
1106
  return $quotaData;
1124
  }
1125
  $customMediaListTable = new ShortPixelListTable($this, $this->spMetaDao, $this->hasNextGen);
1126
  ?>
1127
+ <div class="wrap shortpixel-other-media">
1128
  <h2>
1129
  <div style="float:right;">
1130
  <a href="upload.php?page=wp-short-pixel-custom&refresh=1" id="refresh" class="button button-primary" title="Refresh custom folders content">
1167
  }
1168
 
1169
  $quotaData = $this->checkQuotaAndAlert();
1170
+ if($this->_settings->quotaExceeded != 0) {
1171
+ return;
1172
+ }
1173
 
1174
  if(isset($_POST['bulkProcessPause']))
1175
  {//pause an ongoing bulk processing, it might be needed sometimes
1212
  $this->_settings->skipToCustom = true;
1213
  }//resume was clicked
1214
 
 
 
 
 
1215
  //figure out the files that are left to be processed
1216
  $qry_left = "SELECT count(*) FilesLeftToBeProcessed FROM " . $wpdb->prefix . "postmeta
1217
  WHERE meta_key = '_wp_attached_file' AND post_id <= " . (0 + $this->prioQ->getStartBulkId());
1235
  $this->view->displayBulkProcessingRunning($percent, $msg, $quotaData['APICallsRemaining'], $this->getAverageCompression(),
1236
  ($pendingMeta !== null ? ($this->prioQ->bulkRunning() ? 3 : 2) : 1));
1237
 
 
 
 
 
1238
  } else
1239
  {
1240
  if($this->prioQ->bulkRan() && !$this->prioQ->bulkPaused()) {
1242
  }
1243
 
1244
  //image count
1245
+ $thumbsProcessedCount = $this->_settings->thumbsCount;//amount of optimized thumbnails
1246
+ $under5PercentCount = $this->_settings->under5Percent;//amount of under 5% optimized imgs.
 
 
1247
 
1248
  //average compression
1249
  $averageCompression = self::getAverageCompression();
1250
  $percent = $this->prioQ->bulkPaused() ? round($quotaData["totalProcessedFiles"] *100.0 / $quotaData["totalFiles"]) : false;
1251
+ $this->view->displayBulkProcessingForm($quotaData, $thumbsProcessedCount, $under5PercentCount,
1252
  $this->prioQ->bulkRan(), $averageCompression, $this->_settings->fileCount,
1253
  self::formatBytes($this->_settings->savedSpace), $percent, $pendingMeta);
1254
  }
1316
 
1317
  // set checkbox if multiSelect set to true
1318
  $checkbox = ( isset($_POST['multiSelect']) && $_POST['multiSelect'] == 'true' ) ? "<input type='checkbox' />" : null;
1319
+ $onlyFolders = ($_POST['dir'] == '/' || isset($_POST['onlyFolders']) && $_POST['onlyFolders'] == 'true' ) ? true : false;
1320
  $onlyFiles = ( isset($_POST['onlyFiles']) && $_POST['onlyFiles'] == 'true' ) ? true : false;
1321
 
1322
  if( file_exists($postDir) ) {
1352
 
1353
  public function getCustomFolderBase() {
1354
  if(is_main_site()) {
1355
+ $base = get_home_path();
1356
+ return rtrim($base, DIRECTORY_SEPARATOR);
1357
  } else {
1358
  $up = wp_upload_dir();
1359
  return $up['basedir'];
1480
  $this->_settings->keepExif = isset($_POST['removeExif']) ? 0 : 1;
1481
  //delete_option('wp-short-pixel-keep-exif');
1482
  $this->_settings->resizeImages = (isset($_POST['resize']) ? 1: 0);
1483
+ $this->_settings->resizeType = (isset($_POST['resize_type']) ? $_POST['resize_type']: false);
1484
  $this->_settings->resizeWidth = (isset($_POST['width']) ? $_POST['width']: $this->_settings->resizeWidth);
1485
  $this->_settings->resizeHeight = (isset($_POST['height']) ? $_POST['height']: $this->_settings->resizeHeight);
1486
  $this->_settings->siteAuthUser = (isset($_POST['siteAuthUser']) ? $_POST['siteAuthUser']: $this->_settings->siteAuthUser);
1513
  $customFolders = $this->spMetaDao->getFolders();
1514
  $this->_settings->hasCustomFolders = true;
1515
  }
1516
+ if(isset($_POST['createWebp'])) { $this->_settings->createWebp = 1; } else { $this->_settings->createWebp = 0; }
1517
  if(isset($_POST['frontBootstrap'])) { $this->_settings->frontBootstrap = 1; } else { $this->_settings->frontBootstrap = 0; }
1518
  }
1519
  if(isset($_POST['removeFolder']) && strlen(($_POST['removeFolder']))) {
1955
 
1956
  if(file_exists($oldBackupFolder)) { //if old backup folder does not exist then there is nothing to do
1957
 
1958
+ if(!file_exists(SP_BACKUP_FOLDER)) {
1959
  //we check that the backup folder exists, if not we create it so we can copy into it
1960
  if(!mkdir(SP_BACKUP_FOLDER, 0777, true)) return;
1961
  }
1970
  }
1971
  }
1972
  //now if the backup folder does not contain the uploads level, create it
1973
+ if( !is_dir(SP_BACKUP_FOLDER . DIRECTORY_SEPARATOR . SP_UPLOADS_NAME )
1974
+ && !is_dir(SP_BACKUP_FOLDER . DIRECTORY_SEPARATOR . basename(WP_CONTENT_DIR))) {
1975
  @rename(SP_BACKUP_FOLDER, SP_BACKUP_FOLDER."_tmp");
1976
  @mkdir(SP_BACKUP_FOLDER);
1977
  @rename(SP_BACKUP_FOLDER."_tmp", SP_BACKUP_FOLDER.DIRECTORY_SEPARATOR.SP_UPLOADS_NAME);
1979
  @rename(SP_BACKUP_FOLDER."_tmp", SP_BACKUP_FOLDER);
1980
  }
1981
  }
1982
+ //then create the wp-content level if not present
1983
+ if(!is_dir(SP_BACKUP_FOLDER . DIRECTORY_SEPARATOR . basename(WP_CONTENT_DIR))) {
1984
+ @rename(SP_BACKUP_FOLDER, SP_BACKUP_FOLDER."_tmp");
1985
+ @mkdir(SP_BACKUP_FOLDER);
1986
+ @rename(SP_BACKUP_FOLDER."_tmp", SP_BACKUP_FOLDER.DIRECTORY_SEPARATOR . basename(WP_CONTENT_DIR));
1987
+ if(!file_exists(SP_BACKUP_FOLDER)) {//just in case..
1988
+ @rename(SP_BACKUP_FOLDER."_tmp", SP_BACKUP_FOLDER);
1989
+ }
1990
+ }
1991
  return;
1992
  }
1993