ShortPixel Image Optimizer - Version 4.10.3

Version Description

  • improvements to context help beacon
  • performance improvements to PNG to JPG conversion
Download this release

Release Info

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

Code changes from version 4.10.2 to 4.10.3

class/db/wp-shortpixel-media-library-adapter.php CHANGED
@@ -54,7 +54,7 @@ class WpShortPixelMediaLbraryAdapter {
54
  if ( $file->meta_key == "_wp_attached_file" )
55
  {//count pdf files only
56
  $extension = substr($file->meta_value, strrpos($file->meta_value,".") + 1 );
57
- if ( $extension == "pdf" && !isset($filesMap[$file->meta_value]))
58
  {
59
  $totalFiles++;
60
  $totalFilesThis++;
54
  if ( $file->meta_key == "_wp_attached_file" )
55
  {//count pdf files only
56
  $extension = substr($file->meta_value, strrpos($file->meta_value,".") + 1 );
57
+ if ( $extension == "pdf" && $settings->optimizePdfs && !isset($filesMap[$file->meta_value]))
58
  {
59
  $totalFiles++;
60
  $totalFilesThis++;
class/shortpixel-png2jpg.php CHANGED
@@ -18,37 +18,44 @@ class ShortPixelPng2Jpg {
18
 
19
  protected function canConvertPng2Jpg($image) {
20
  $transparent = 0;
21
- if (ord(file_get_contents($image, false, null, 25, 1)) & 4) {
22
- $transparent = 1;
23
- }
24
- $contents = file_get_contents($image);
25
- if (stripos($contents, 'PLTE') !== false && stripos($contents, 'tRNS') !== false) {
26
- $transparent = 1;
27
- }
28
  $transparent_pixel = $img = $bg = false;
29
- if (!$transparent) {
30
- $is = getimagesize($image);
31
- WPShortPixel::log("PNG2JPG Image size: " . round($is[0]*$is[1]*5/1024/1024) . "M memory limit: " . ini_get('memory_limit') . " USED: " . memory_get_usage());
32
- WPShortPixel::log("PNG2JPG create from png $image");
33
- $img = @imagecreatefrompng($image);
34
- if(!$img) {
35
- $transparent = true; //it's not a PNG, can't convert it
36
- } else {
37
- $w = imagesx($img); // Get the width of the image
38
- $h = imagesy($img); // Get the height of the image
39
- //run through pixels until transparent pixel is found:
40
- for ($i = 0; $i < $w; $i++) {
41
- for ($j = 0; $j < $h; $j++) {
42
- $rgba = imagecolorat($img, $i, $j);
43
- if (($rgba & 0x7F000000) >> 24) {
44
- $transparent_pixel = true;
45
- break;
 
 
 
 
 
 
 
 
 
 
 
 
 
46
  }
47
  }
48
  }
49
  }
50
  }
51
 
 
52
  //pass on the img too, if it was already loaded from PNG, matter of performance
53
  return array('notTransparent' => !$transparent && !$transparent_pixel, 'img' => $img);
54
  }
@@ -64,17 +71,23 @@ class ShortPixelPng2Jpg {
64
 
65
  protected function doConvertPng2Jpg($params, $backup, $suffixRegex = false, $img = false) {
66
  $image = $params['file'];
 
67
  if(!$img) {
68
- $img = imagecreatefrompng($image);
 
69
  if(!$img) {
70
- return $params; //actually not a PNG.
 
71
  }
72
  }
73
 
 
74
  $x = imagesx($img);
75
  $y = imagesy($img);
 
76
  $bg = imagecreatetruecolor($x, $y);
77
- if(!$bg) return $params;
 
78
  imagefill($bg, 0, 0, imagecolorallocate($bg, 255, 255, 255));
79
  imagealphablending($bg, 1);
80
  imagecopy($bg, $img, 0, 0, 0, 0, $x, $y);
@@ -89,29 +102,33 @@ class ShortPixelPng2Jpg {
89
  }
90
  }
91
  if (imagejpeg($bg, $newPath, 90)) {
 
92
  $newSize = filesize($newPath);
93
  $origSize = filesize($image);
94
  if($newSize > $origSize * 0.95) {
95
  //if the image is not 5% smaller, don't bother.
96
  unlink($newPath);
97
- return $params;
98
  }
99
  //backup?
100
  if($backup) {
101
  $imageForBk = trailingslashit(dirname($image)) . ShortPixelAPI::MB_basename($newPath, '.jpg') . '.png';
102
- @rename($image, $imageForBk);
 
 
 
103
  if(!file_exists($imageForBk)) {
104
  unlink($newPath);
105
- return $params;
106
  }
107
  $image = $imageForBk;
108
  $ret = ShortPixelAPI::backupImage($image, array($image));
109
  if($ret['Status'] !== ShortPixelAPI::STATUS_SUCCESS) {
110
  unlink($newPath);
111
- return $params;
112
  }
113
  }
114
- unlink($image);
115
  $params['file'] = $newPath;
116
  $params['original_file'] = $image;
117
  $params['url'] = $newUrl;
@@ -119,7 +136,7 @@ class ShortPixelPng2Jpg {
119
  $params['png_size'] = $origSize;
120
  $params['jpg_size'] = $newSize;
121
  }
122
- return $params;
123
  }
124
 
125
  /**
@@ -139,7 +156,9 @@ class ShortPixelPng2Jpg {
139
 
140
  $ret = $this->canConvertPng2Jpg($image);
141
  if ($ret['notTransparent']) {
142
- $paramsC = $this->doConvertPng2Jpg($params, $this->_settings->backupImages, false, $ret['img']);
 
 
143
  if($paramsC['type'] == 'image/jpeg') {
144
  // we don't have metadata, so save the information in a temporary map
145
  $conv = $this->_settings->convertedPng2Jpg;
@@ -192,12 +211,17 @@ class ShortPixelPng2Jpg {
192
  $meta['ShortPixel']['ErrCode'] = ShortPixelAPI::ERR_PNG2JPG_MEMORY;
193
  wp_update_attachment_metadata($ID, $meta);
194
 
195
- $ret = $this->canConvertPng2Jpg($imagePath);
196
- if (!$ret['notTransparent']) {
 
197
  return $meta; //cannot convert it
198
  }
199
 
200
- $ret = $this->doConvertPng2Jpg(array('file' => $imagePath, 'url' => false, 'type' => 'image/png'), $this->_settings->backupImages, false, $ret['img']);
 
 
 
 
201
 
202
  //unset the temporary error
203
  unset($meta['ShortPixelImprovement']);
@@ -206,9 +230,11 @@ class ShortPixelPng2Jpg {
206
  wp_update_attachment_metadata($ID, $meta);
207
 
208
  if ($ret['type'] == 'image/jpeg') {
 
209
  //convert to the new URLs the urls in the existing posts.
210
  $baseRelPath = trailingslashit(dirname($image));
211
- $this->png2JpgUpdateUrls(array(), $imageUrl, $baseUrl . $baseRelPath . wp_basename($ret['file']));
 
212
  $pngSize = $ret['png_size'];
213
  $jpgSize = $ret['jpg_size'];
214
  $imagePath = isset($ret['original_file']) ? $ret['original_file'] : $imagePath;
@@ -216,27 +242,45 @@ class ShortPixelPng2Jpg {
216
  //conversion succeeded for the main image, update meta and proceed to thumbs. (It could also not succeed if the converted file is not smaller)
217
  $meta['file'] = str_replace($basePath, '', $ret['file']);
218
  $meta['type'] = 'image/jpeg';
 
 
219
 
220
  $originalSizes = isset($meta['sizes']) ? $meta['sizes'] : array();
221
  foreach($meta['sizes'] as $size => $info) {
222
- $rett = $this->doConvertPng2Jpg(array('file' => $basePath . $baseRelPath . $info['file'], 'url' => false, 'type' => 'image/png'),
223
  $this->_settings->backupImages, "[0-9]+x[0-9]+");
 
 
 
224
  if ($rett['type'] == 'image/jpeg') {
 
 
225
  $meta['sizes'][$size]['file'] = wp_basename($rett['file']);
226
  $meta['sizes'][$size]['mime-type'] = 'image/jpeg';
227
- $pngSize += $ret['png_size'];
228
- $jpgSize += $ret['jpg_size'];
 
229
  $originalSizes[$size]['file'] = wp_basename($rett['file'], '.jpg') . '.png';
230
- $this->png2JpgUpdateUrls(array(), $baseUrl . $baseRelPath . $info['file'], $baseUrl . $baseRelPath . wp_basename($rett['file']));
 
 
231
  }
232
  }
233
  $meta['ShortPixelPng2Jpg'] = array('originalFile' => $imagePath, 'originalSizes' => $originalSizes,
234
  'backup' => $this->_settings->backupImages,
235
  'optimizationPercent' => round(100.0 * (1.00 - $jpgSize / $pngSize)));
236
- update_attached_file($ID, $meta['file']);
237
  wp_update_attachment_metadata($ID, $meta);
238
  }
239
 
 
 
 
 
 
 
 
 
 
240
  return $meta;
241
  }
242
 
@@ -247,21 +291,23 @@ class ShortPixelPng2Jpg {
247
  * @param $newurl
248
  * @return array
249
  */
250
- protected function png2JpgUpdateUrls($options,$oldurl,$newurl){
251
  global $wpdb;
 
252
  $results = array();
253
  $queries = array(
254
- 'content' => array("UPDATE $wpdb->posts SET post_content = replace(post_content, %s, %s)", __('Content Items (Posts, Pages, Custom Post Types, Revisions)','hortpixel-image-optimiser') ),
255
- 'excerpts' => array("UPDATE $wpdb->posts SET post_excerpt = replace(post_excerpt, %s, %s)", __('Excerpts','hortpixel-image-optimiser') ),
256
- 'attachments' => array("UPDATE $wpdb->posts SET guid = replace(guid, %s, %s) WHERE post_type = 'attachment'", __('Attachments','hortpixel-image-optimiser') ),
257
- 'links' => array("UPDATE $wpdb->links SET link_url = replace(link_url, %s, %s)", __('Links','hortpixel-image-optimiser') ),
258
- 'custom' => array("UPDATE $wpdb->postmeta SET meta_value = replace(meta_value, %s, %s)", __('Custom Fields','hortpixel-image-optimiser') ),
259
- 'guids' => array("UPDATE $wpdb->posts SET guid = replace(guid, %s, %s)", __('GUIDs','hortpixel-image-optimiser') )
260
  );
261
  if(count($options) == 0) {
262
  $options = array_keys($queries);
263
  }
264
  foreach($options as $option){
 
265
  if( $option == 'custom' ){
266
  $n = 0;
267
  $row_count = $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->postmeta" );
@@ -269,20 +315,24 @@ class ShortPixelPng2Jpg {
269
  $pages = ceil( $row_count / $page_size );
270
 
271
  for( $page = 0; $page < $pages; $page++ ) {
272
- $current_row = 0;
273
  $start = $page * $page_size;
274
- $end = $start + $page_size;
275
- $pmquery = "SELECT * FROM $wpdb->postmeta WHERE meta_value <> ''";
276
  $items = $wpdb->get_results( $pmquery );
277
  foreach( $items as $item ){
278
  $value = $item->meta_value;
279
  if( trim($value) == '' )
280
  continue;
281
 
282
- $edited = $this->png2JpgUnserializeReplace( $oldurl, $newurl, $value );
283
-
284
- if( $edited != $value ){
285
- $fix = $wpdb->query("UPDATE $wpdb->postmeta SET meta_value = '".$edited."' WHERE meta_id = ".$item->meta_id );
 
 
 
 
 
 
286
  if( $fix )
287
  $n++;
288
  }
@@ -290,9 +340,13 @@ class ShortPixelPng2Jpg {
290
  }
291
  $results[$option] = array($n, $queries[$option][1]);
292
  }
293
- else{
294
- $result = $wpdb->query( $wpdb->prepare( $queries[$option][0], $oldurl, $newurl) );
295
- $results[$option] = array($result, $queries[$option][1]);
 
 
 
 
296
  }
297
  }
298
  return $results;
@@ -307,27 +361,53 @@ class ShortPixelPng2Jpg {
307
  * @return array|mixed|string
308
  */
309
  function png2JpgUnserializeReplace( $from = '', $to = '', $data = '', $serialised = false ) {
 
310
  try {
311
  if ( false !== is_serialized( $data ) ) {
 
 
 
 
 
312
  $unserialized = unserialize( $data );
313
- $data = $this->png2JpgUnserializeReplace( $from, $to, $unserialized, true );
 
 
314
  }
315
  elseif ( is_array( $data ) ) {
316
  $_tmp = array( );
317
  foreach ( $data as $key => $value ) {
318
- $_tmp[ $key ] = $this->png2JpgUnserializeReplace( $from, $to, $value, false );
 
 
319
  }
320
  $data = $_tmp;
321
  unset( $_tmp );
322
  }
323
- else {
324
- if ( is_string( $data ) )
 
 
 
 
 
 
 
 
 
325
  $data = str_replace( $from, $to, $data );
 
 
 
 
 
 
 
 
 
326
  }
327
- if ( $serialised )
328
- return serialize( $data );
329
  } catch( Exception $error ) {
330
  }
331
- return $data;
332
  }
333
  }
18
 
19
  protected function canConvertPng2Jpg($image) {
20
  $transparent = 0;
 
 
 
 
 
 
 
21
  $transparent_pixel = $img = $bg = false;
22
+
23
+ if (!file_exists($image) || ord(file_get_contents($image, false, null, 25, 1)) & 4) {
24
+ $transparent = 1;
25
+ } else {
26
+ $contents = file_get_contents($image);
27
+ if (stripos($contents, 'PLTE') !== false && stripos($contents, 'tRNS') !== false) {
28
+ $transparent = 1;
29
+ }
30
+ if (!$transparent) {
31
+ $is = getimagesize($image);
32
+ WPShortPixel::log("PNG2JPG Image width: " . $is[0] . " height: " . $is[1] . " aprox. size: " . round($is[0]*$is[1]*5/1024/1024) . "M memory limit: " . ini_get('memory_limit') . " USED: " . memory_get_usage());
33
+ WPShortPixel::log("PNG2JPG create from png $image");
34
+ $img = @imagecreatefrompng($image);
35
+ WPShortPixel::log("PNG2JPG created from png");
36
+ if(!$img) {
37
+ WPShortPixel::log("PNG2JPG not a PNG");
38
+ $transparent = true; //it's not a PNG, can't convert it
39
+ } else {
40
+ WPShortPixel::log("PNG2JPG is PNG");
41
+ $w = imagesx($img); // Get the width of the image
42
+ $h = imagesy($img); // Get the height of the image
43
+ WPShortPixel::log("PNG2JPG width $w height $h. Now checking pixels.");
44
+ //run through pixels until transparent pixel is found:
45
+ for ($i = 0; $i < $w; $i++) {
46
+ for ($j = 0; $j < $h; $j++) {
47
+ $rgba = imagecolorat($img, $i, $j);
48
+ if (($rgba & 0x7F000000) >> 24) {
49
+ $transparent_pixel = true;
50
+ break;
51
+ }
52
  }
53
  }
54
  }
55
  }
56
  }
57
 
58
+ WPShortPixel::log("PNG2JPG is " . (!$transparent && !$transparent_pixel ? " not" : "") . " transparent");
59
  //pass on the img too, if it was already loaded from PNG, matter of performance
60
  return array('notTransparent' => !$transparent && !$transparent_pixel, 'img' => $img);
61
  }
71
 
72
  protected function doConvertPng2Jpg($params, $backup, $suffixRegex = false, $img = false) {
73
  $image = $params['file'];
74
+ WPShortPixel::log("PNG2JPG doConvert $image");
75
  if(!$img) {
76
+ WPShortPixel::log("PNG2JPG doConvert create from PNG");
77
+ $img = (file_exists($image) ? imagecreatefrompng($image) : false);
78
  if(!$img) {
79
+ WPShortPixel::log("PNG2JPG doConvert image cannot be created.");
80
+ return (object)array("params" => $params, "unlink" => false); //actually not a PNG.
81
  }
82
  }
83
 
84
+ WPShortPixel::log("PNG2JPG doConvert img ready");
85
  $x = imagesx($img);
86
  $y = imagesy($img);
87
+ WPShortPixel::log("PNG2JPG doConvert width $x height $y");
88
  $bg = imagecreatetruecolor($x, $y);
89
+ WPShortPixel::log("PNG2JPG doConvert img created truecolor");
90
+ if(!$bg) return (object)array("params" => $params, "unlink" => false);
91
  imagefill($bg, 0, 0, imagecolorallocate($bg, 255, 255, 255));
92
  imagealphablending($bg, 1);
93
  imagecopy($bg, $img, 0, 0, 0, 0, $x, $y);
102
  }
103
  }
104
  if (imagejpeg($bg, $newPath, 90)) {
105
+ WPShortPixel::log("PNG2JPG doConvert created JPEG at $newPath");
106
  $newSize = filesize($newPath);
107
  $origSize = filesize($image);
108
  if($newSize > $origSize * 0.95) {
109
  //if the image is not 5% smaller, don't bother.
110
  unlink($newPath);
111
+ return (object)array("params" => $params, "unlink" => false);
112
  }
113
  //backup?
114
  if($backup) {
115
  $imageForBk = trailingslashit(dirname($image)) . ShortPixelAPI::MB_basename($newPath, '.jpg') . '.png';
116
+ if($image != $imageForBk) {
117
+ WPShortPixel::log("PNG2JPG doConvert rename $image to $imageForBk");
118
+ @rename($image, $imageForBk);
119
+ }
120
  if(!file_exists($imageForBk)) {
121
  unlink($newPath);
122
+ return (object)array("params" => $params, "unlink" => false);
123
  }
124
  $image = $imageForBk;
125
  $ret = ShortPixelAPI::backupImage($image, array($image));
126
  if($ret['Status'] !== ShortPixelAPI::STATUS_SUCCESS) {
127
  unlink($newPath);
128
+ return (object)array("params" => $params, "unlink" => false);
129
  }
130
  }
131
+ //unlink($image);
132
  $params['file'] = $newPath;
133
  $params['original_file'] = $image;
134
  $params['url'] = $newUrl;
136
  $params['png_size'] = $origSize;
137
  $params['jpg_size'] = $newSize;
138
  }
139
+ return (object)array("params" => $params, "unlink" => $image);
140
  }
141
 
142
  /**
156
 
157
  $ret = $this->canConvertPng2Jpg($image);
158
  if ($ret['notTransparent']) {
159
+ $ret = $this->doConvertPng2Jpg($params, $this->_settings->backupImages, false, $ret['img']);
160
+ if($ret->unlink) @unlink($ret->unlink);
161
+ $paramsC = $ret->params;
162
  if($paramsC['type'] == 'image/jpeg') {
163
  // we don't have metadata, so save the information in a temporary map
164
  $conv = $this->_settings->convertedPng2Jpg;
211
  $meta['ShortPixel']['ErrCode'] = ShortPixelAPI::ERR_PNG2JPG_MEMORY;
212
  wp_update_attachment_metadata($ID, $meta);
213
 
214
+ $retC = $this->canConvertPng2Jpg($imagePath);
215
+ if (!$retC['notTransparent']) {
216
+ WPShortPixel::log("PNG2JPG not a PNG");
217
  return $meta; //cannot convert it
218
  }
219
 
220
+ $retMain = $this->doConvertPng2Jpg(array('file' => $imagePath, 'url' => false, 'type' => 'image/png'), $this->_settings->backupImages, false, $retC['img']);
221
+ WPShortPixel::log("PNG2JPG doConvert Main RETURNED " . json_encode($retMain));
222
+ $ret = $retMain->params;
223
+ $toUnlink = array();
224
+ $toReplace = array();
225
 
226
  //unset the temporary error
227
  unset($meta['ShortPixelImprovement']);
230
  wp_update_attachment_metadata($ID, $meta);
231
 
232
  if ($ret['type'] == 'image/jpeg') {
233
+ $toUnlink[] = $retMain->unlink;
234
  //convert to the new URLs the urls in the existing posts.
235
  $baseRelPath = trailingslashit(dirname($image));
236
+ $toReplace[$imageUrl] = $baseUrl . $baseRelPath . wp_basename($ret['file']);
237
+ //$this->png2JpgUpdateUrls(array(), $imageUrl, $baseUrl . $baseRelPath . wp_basename($ret['file']));
238
  $pngSize = $ret['png_size'];
239
  $jpgSize = $ret['jpg_size'];
240
  $imagePath = isset($ret['original_file']) ? $ret['original_file'] : $imagePath;
242
  //conversion succeeded for the main image, update meta and proceed to thumbs. (It could also not succeed if the converted file is not smaller)
243
  $meta['file'] = str_replace($basePath, '', $ret['file']);
244
  $meta['type'] = 'image/jpeg';
245
+ update_attached_file($ID, $meta['file']);
246
+ wp_update_attachment_metadata($ID, $meta);
247
 
248
  $originalSizes = isset($meta['sizes']) ? $meta['sizes'] : array();
249
  foreach($meta['sizes'] as $size => $info) {
250
+ $retThumb = $this->doConvertPng2Jpg(array('file' => $basePath . $baseRelPath . $info['file'], 'url' => false, 'type' => 'image/png'),
251
  $this->_settings->backupImages, "[0-9]+x[0-9]+");
252
+ $rett = $retThumb->params;
253
+
254
+ WPShortPixel::log("PNG2JPG doConvert thumb RETURNED " . json_encode($rett));
255
  if ($rett['type'] == 'image/jpeg') {
256
+ $toUnlink[] = $retThumb->unlink;
257
+ WPShortPixel::log("PNG2JPG thumb is jpg");
258
  $meta['sizes'][$size]['file'] = wp_basename($rett['file']);
259
  $meta['sizes'][$size]['mime-type'] = 'image/jpeg';
260
+ $pngSize += $rett['png_size'];
261
+ $jpgSize += $rett['jpg_size'];
262
+ WPShortPixel::log("PNG2JPG total PNG size: $pngSize total JPG size: $jpgSize");
263
  $originalSizes[$size]['file'] = wp_basename($rett['file'], '.jpg') . '.png';
264
+ $toReplace[$baseUrl . $baseRelPath . $info['file']] = $baseUrl . $baseRelPath . wp_basename($rett['file']);
265
+ //$this->png2JpgUpdateUrls(array(), $baseUrl . $baseRelPath . $info['file'], $baseUrl . $baseRelPath . wp_basename($rett['file']));
266
+ wp_update_attachment_metadata($ID, $meta);
267
  }
268
  }
269
  $meta['ShortPixelPng2Jpg'] = array('originalFile' => $imagePath, 'originalSizes' => $originalSizes,
270
  'backup' => $this->_settings->backupImages,
271
  'optimizationPercent' => round(100.0 * (1.00 - $jpgSize / $pngSize)));
 
272
  wp_update_attachment_metadata($ID, $meta);
273
  }
274
 
275
+ $this->png2JpgUpdateUrls(array(), $toReplace);
276
+ foreach($toUnlink as $unlink) {
277
+ if($unlink) {
278
+ WPShortPixel::log("PNG2JPG unlink $unlink");
279
+ @unlink($unlink);
280
+ }
281
+ }
282
+ WPShortPixel::log("PNG2JPG done. Return: " . json_encode($meta));
283
+
284
  return $meta;
285
  }
286
 
291
  * @param $newurl
292
  * @return array
293
  */
294
+ protected function png2JpgUpdateUrls($options, $map){
295
  global $wpdb;
296
+ WPShortPixel::log("PNG2JPG update URLS " . json_encode($map));
297
  $results = array();
298
  $queries = array(
299
+ 'content' => array("UPDATE $wpdb->posts SET post_content = replace(post_content, %s, %s)", __('Content Items (Posts, Pages, Custom Post Types, Revisions)','shortpixel-image-optimiser') ),
300
+ 'excerpts' => array("UPDATE $wpdb->posts SET post_excerpt = replace(post_excerpt, %s, %s)", __('Excerpts','shortpixel-image-optimiser') ),
301
+ 'attachments' => array("UPDATE $wpdb->posts SET guid = replace(guid, %s, %s) WHERE post_type = 'attachment'", __('Attachments','shortpixel-image-optimiser') ),
302
+ 'links' => array("UPDATE $wpdb->links SET link_url = replace(link_url, %s, %s)", __('Links','shortpixel-image-optimiser') ),
303
+ 'custom' => array("UPDATE $wpdb->postmeta SET meta_value = replace(meta_value, %s, %s)", __('Custom Fields','shortpixel-image-optimiser') ),
304
+ 'guids' => array("UPDATE $wpdb->posts SET guid = replace(guid, %s, %s)", __('GUIDs','shortpixel-image-optimiser') )
305
  );
306
  if(count($options) == 0) {
307
  $options = array_keys($queries);
308
  }
309
  foreach($options as $option){
310
+ WPShortPixel::log("PNG2JPG update URLS on $option ");
311
  if( $option == 'custom' ){
312
  $n = 0;
313
  $row_count = $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->postmeta" );
315
  $pages = ceil( $row_count / $page_size );
316
 
317
  for( $page = 0; $page < $pages; $page++ ) {
 
318
  $start = $page * $page_size;
319
+ $pmquery = "SELECT * FROM $wpdb->postmeta WHERE meta_value <> '' AND meta_value <> '_wp_attachment_metadata' AND meta_value <> '_wp_attached_file' LIMIT $start, $page_size";
 
320
  $items = $wpdb->get_results( $pmquery );
321
  foreach( $items as $item ){
322
  $value = $item->meta_value;
323
  if( trim($value) == '' )
324
  continue;
325
 
326
+ $edited = (object)array('data' => $value, 'replaced' => false);
327
+ foreach($map as $oldurl => $newurl) {
328
+ if (strlen($newurl)) {
329
+ $editedOne = $this->png2JpgUnserializeReplace($oldurl, $newurl, $edited->data);
330
+ $edited->data = $editedOne->data;
331
+ $edited->replaced = $edited->replaced || $editedOne->replaced;
332
+ }
333
+ }
334
+ if( $edited->replaced ){
335
+ $fix = $wpdb->query("UPDATE $wpdb->postmeta SET meta_value = '".$edited->data."' WHERE meta_id = ".$item->meta_id );
336
  if( $fix )
337
  $n++;
338
  }
340
  }
341
  $results[$option] = array($n, $queries[$option][1]);
342
  }
343
+ else {
344
+ foreach($map as $oldurl => $newurl) {
345
+ if(strlen($newurl)) {
346
+ $result = $wpdb->query( $wpdb->prepare( $queries[$option][0], $oldurl, $newurl) );
347
+ $results[$option] = array($result, $queries[$option][1]);
348
+ }
349
+ }
350
  }
351
  }
352
  return $results;
361
  * @return array|mixed|string
362
  */
363
  function png2JpgUnserializeReplace( $from = '', $to = '', $data = '', $serialised = false ) {
364
+ $replaced = false;
365
  try {
366
  if ( false !== is_serialized( $data ) ) {
367
+
368
+ if(false === strpos($data, wp_basename($from))) {
369
+ return (object)array('data' => $data, 'replaced' => false); //quick pre-screening
370
+ }
371
+
372
  $unserialized = unserialize( $data );
373
+ $ret = $this->png2JpgUnserializeReplace( $from, $to, $unserialized, true );
374
+ $data = $ret->data;
375
+ $replaced = $replaced || $ret->replaced;
376
  }
377
  elseif ( is_array( $data ) ) {
378
  $_tmp = array( );
379
  foreach ( $data as $key => $value ) {
380
+ $ret = $this->png2JpgUnserializeReplace( $from, $to, $value, false );
381
+ $_tmp[ $key ] = $ret->data;
382
+ $replaced = $replaced || $ret->replaced;
383
  }
384
  $data = $_tmp;
385
  unset( $_tmp );
386
  }
387
+ elseif(is_object( $data )) {
388
+ foreach(get_object_vars($data) as $key => $value) {
389
+ $ret = $this->png2JpgUnserializeReplace( $from, $to, $value, false );
390
+ $_tmp[ $key ] = $ret->data;
391
+ $replaced = $replaced || $ret->replaced;
392
+ }
393
+ $data = (object)$_tmp;
394
+ }
395
+ elseif ( is_string( $data )) {
396
+ if(false !== strpos($data, $from)) {
397
+ $replaced = true;
398
  $data = str_replace( $from, $to, $data );
399
+ } elseif( strlen($from) > strlen($data) //data is shorter than the url to be replaced - could be a relative path?
400
+ && strlen($data) >= strlen(wp_basename($from)) //but should at least contain the file name
401
+ && strpos($from, $data) == strlen($from) - strlen($data)) {
402
+ $replaced = true;
403
+ $data = substr($to, strlen($from) - strlen($data));
404
+ }
405
+ }
406
+ if ( $serialised ) {
407
+ return (object)array('data' => serialize($data), 'replaced' => $replaced);
408
  }
 
 
409
  } catch( Exception $error ) {
410
  }
411
+ return (object)array('data' => $data, 'replaced' => $replaced);
412
  }
413
  }
class/view/shortpixel_view.php CHANGED
@@ -386,9 +386,9 @@ class ShortPixelView {
386
  <?php $this->displayBulkStats($quotaData['totalProcessedFiles'], $quotaData['mainProcessedFiles'], $under5PercentCount, $averageCompression, $savedSpace);?>
387
  </div>
388
  </div>
389
- <p><?php printf(__('Go to the ShortPixel <a href="%soptions-general.php?page=wp-shortpixel#stats">Stats</a> '
390
- . 'and see all your websites\' optimized stats. Download your detailed <a href="https://%s/v2/report.php?key=%s">Optimization Report</a> '
391
- . 'to check your image optimization statistics for the last 40 days.','shortpixel-image-optimiser'),
392
  SHORTPIXEL_API,
393
  get_admin_url(), (defined("SHORTPIXEL_HIDE_API_KEY") ? '' : $this->ctrl->getApiKey()) );?></p>
394
  <?php
@@ -703,7 +703,7 @@ class ShortPixelView {
703
  <h1><?php _e('ShortPixel Plugin Settings','shortpixel-image-optimiser');?></h1>
704
  <p style="font-size:18px">
705
  <a href="https://shortpixel.com/<?php
706
- echo($this->ctrl->getVerifiedKey() ? "login/".(defined("SHORTPIXEL_HIDE_API_KEY") ? '' : $this->ctrl->getApiKey()) : "pricing" . WPShortPixel::getAffiliateSufix());
707
  ?>" target="_blank" style="font-size:18px">
708
  <?php _e('Upgrade now','shortpixel-image-optimiser');?>
709
  </a> | <a href="https://shortpixel.com/pricing<?php echo(WPShortPixel::getAffiliateSufix()); ?>#faq" target="_blank" style="font-size:18px"><?php _e('FAQ','shortpixel-image-optimiser');?> </a> |
@@ -902,7 +902,7 @@ class ShortPixelView {
902
  <th scope="row"><label for="thumbnails"><?php _e('Also include thumbnails:','shortpixel-image-optimiser');?></label></th>
903
  <td><input name="thumbnails" type="checkbox" id="thumbnails" <?php echo( $checked );?>> <?php
904
  _e('Apply compression also to <strong>image thumbnails.</strong> ','shortpixel-image-optimiser');?>
905
- <?php echo($thumbnailsToProcess ? "(" . number_format($thumbnailsToProcess) . " " . __('thumbnails to optimize','shortpixel-image-optimiser') . ")" : "");?>
906
  <p class="settings-info">
907
  <?php _e('It is highly recommended that you optimize the thumbnails as they are usually the images most viewed by end users and can generate most traffic.<br>Please note that thumbnails count up to your total quota.','shortpixel-image-optimiser');?>
908
  </p>
@@ -1181,16 +1181,16 @@ class ShortPixelView {
1181
  _e('name:keepbig, path:/ignore_regex/i, size:1000x2000','shortpixel-image-optimiser');?>">
1182
  <?php _e('Exclude certain images from being optimized, based on patterns.','shortpixel-image-optimiser');?>
1183
  <p class="settings-info">
1184
- <?php _e('Add patterns separated by comma. A pattern consist of a <strong>type:value</strong> pair; the accepted types are '
1185
- . '<strong>"name"</strong>, <strong>"path"</strong> and <strong>"size"</strong>. '
1186
- . 'A file will be excluded if it matches any of the patterns. '
1187
- . '<br>For a <strong>"name"</strong> pattern only the filename will be matched but for a <strong>"path"</strong>, '
1188
- . 'all the path will be matched (useful for excluding certain subdirectories altoghether).'
1189
- . 'For these you can also use regular expressions accepted by preg_match, but without "," or ":". '
1190
- . 'A pattern will be considered a regex if it starts with a "/" and is valid. '
1191
- . '<br>For the <strong>"size"</strong> type, '
1192
- . 'which applies only to Media Library images, <strong>the main images (not thumbnails)</strong> that have the size in the specified range will be excluded. '
1193
- . 'The format for the "size" exclude is: <strong>minWidth</strong>-<strong>maxWidth</strong>x<strong>minHeight</strong>-<strong>maxHeight</strong>, for example <strong>size:1000-1100x2000-2200</strong>. You can also specify a precise size, as <strong>1000x2000</strong>.','shortpixel-image-optimiser');?>
1194
  </p>
1195
  </td>
1196
  </tr>
@@ -1455,16 +1455,15 @@ class ShortPixelView {
1455
  case 'imgOptimized':
1456
  $excluded = (isset($data['excludeSizes']) ? count($data['excludeSizes']) : 0);
1457
  $successText = $this->getSuccessText($data['percent'],$data['bonus'],$data['type'],$data['thumbsOpt'],$data['thumbsTotal'], $data['retinasOpt'], $data['excludeSizes']);
 
1458
  if($extended) {
1459
- $excludeSizes = '';
1460
  if(isset($data['excludeSizes'])) {
1461
  $excludeSizes .= "<br><span> <span style='font-weight: bold;'>" . __("Excluded thumbnails:", 'shortpixel-image-optimiser') . "</span>";
1462
- foreach($data['excludeSizes'] as $excluded) {
1463
- $excludeSizes .= "<br> &#8226; " . $excluded;
1464
  }
1465
  $excludeSizes .= '</span>';
1466
  }
1467
- $missingThumbs = '';
1468
  if(count($data['thumbsMissing'])) {
1469
  $missingThumbs .= "<br><span> <span style='font-weight: bold;'>" . __("Missing thumbnails:", 'shortpixel-image-optimiser') . "</span>";
1470
  foreach($data['thumbsMissing'] as $miss) {
386
  <?php $this->displayBulkStats($quotaData['totalProcessedFiles'], $quotaData['mainProcessedFiles'], $under5PercentCount, $averageCompression, $savedSpace);?>
387
  </div>
388
  </div>
389
+ <p><?php printf(__('Go to the ShortPixel <a href="%soptions-general.php?page=wp-shortpixel#stats">Stats</a>
390
+ and see all your websites\' optimized stats. Download your detailed <a href="https://%s/v2/report.php?key=%s">Optimization Report</a>
391
+ to check your image optimization statistics for the last 40 days.','shortpixel-image-optimiser'),
392
  SHORTPIXEL_API,
393
  get_admin_url(), (defined("SHORTPIXEL_HIDE_API_KEY") ? '' : $this->ctrl->getApiKey()) );?></p>
394
  <?php
703
  <h1><?php _e('ShortPixel Plugin Settings','shortpixel-image-optimiser');?></h1>
704
  <p style="font-size:18px">
705
  <a href="https://shortpixel.com/<?php
706
+ echo(($this->ctrl->getVerifiedKey() ? "login/".(defined("SHORTPIXEL_HIDE_API_KEY") ? '' : $this->ctrl->getApiKey()) : "pricing") . WPShortPixel::getAffiliateSufix());
707
  ?>" target="_blank" style="font-size:18px">
708
  <?php _e('Upgrade now','shortpixel-image-optimiser');?>
709
  </a> | <a href="https://shortpixel.com/pricing<?php echo(WPShortPixel::getAffiliateSufix()); ?>#faq" target="_blank" style="font-size:18px"><?php _e('FAQ','shortpixel-image-optimiser');?> </a> |
902
  <th scope="row"><label for="thumbnails"><?php _e('Also include thumbnails:','shortpixel-image-optimiser');?></label></th>
903
  <td><input name="thumbnails" type="checkbox" id="thumbnails" <?php echo( $checked );?>> <?php
904
  _e('Apply compression also to <strong>image thumbnails.</strong> ','shortpixel-image-optimiser');?>
905
+ <?php echo($thumbnailsToProcess > 0 ? "(" . number_format($thumbnailsToProcess) . " " . __('thumbnails to optimize','shortpixel-image-optimiser') . ")" : "");?>
906
  <p class="settings-info">
907
  <?php _e('It is highly recommended that you optimize the thumbnails as they are usually the images most viewed by end users and can generate most traffic.<br>Please note that thumbnails count up to your total quota.','shortpixel-image-optimiser');?>
908
  </p>
1181
  _e('name:keepbig, path:/ignore_regex/i, size:1000x2000','shortpixel-image-optimiser');?>">
1182
  <?php _e('Exclude certain images from being optimized, based on patterns.','shortpixel-image-optimiser');?>
1183
  <p class="settings-info">
1184
+ <?php _e('Add patterns separated by comma. A pattern consists of a <strong>type:value</strong> pair; the accepted types are
1185
+ <strong>"name"</strong>, <strong>"path"</strong> and <strong>"size"</strong>.
1186
+ A file will be excluded if it matches any of the patterns.
1187
+ <br>For a <strong>"name"</strong> pattern only the filename will be matched but for a <strong>"path"</strong>,
1188
+ all the path will be matched (useful for excluding certain subdirectories altoghether).
1189
+ For these you can also use regular expressions accepted by preg_match, but without "," or ":".
1190
+ A pattern will be considered a regex if it starts with a "/" and is valid.
1191
+ <br>For the <strong>"size"</strong> type,
1192
+ which applies only to Media Library images, <strong>the main images (not thumbnails)</strong> that have the size in the specified range will be excluded.
1193
+ The format for the "size" exclude is: <strong>minWidth</strong>-<strong>maxWidth</strong>x<strong>minHeight</strong>-<strong>maxHeight</strong>, for example <strong>size:1000-1100x2000-2200</strong>. You can also specify a precise size, as <strong>1000x2000</strong>.','shortpixel-image-optimiser');?>
1194
  </p>
1195
  </td>
1196
  </tr>
1455
  case 'imgOptimized':
1456
  $excluded = (isset($data['excludeSizes']) ? count($data['excludeSizes']) : 0);
1457
  $successText = $this->getSuccessText($data['percent'],$data['bonus'],$data['type'],$data['thumbsOpt'],$data['thumbsTotal'], $data['retinasOpt'], $data['excludeSizes']);
1458
+ $missingThumbs = $excludeSizes = '';
1459
  if($extended) {
 
1460
  if(isset($data['excludeSizes'])) {
1461
  $excludeSizes .= "<br><span> <span style='font-weight: bold;'>" . __("Excluded thumbnails:", 'shortpixel-image-optimiser') . "</span>";
1462
+ foreach($data['excludeSizes'] as $excludedItem) {
1463
+ $excludeSizes .= "<br> &#8226; " . $excludedItem;
1464
  }
1465
  $excludeSizes .= '</span>';
1466
  }
 
1467
  if(count($data['thumbsMissing'])) {
1468
  $missingThumbs .= "<br><span> <span style='font-weight: bold;'>" . __("Missing thumbnails:", 'shortpixel-image-optimiser') . "</span>";
1469
  foreach($data['thumbsMissing'] as $miss) {
class/wp-short-pixel.php CHANGED
@@ -3123,6 +3123,27 @@ class WPShortPixel {
3123
  email: "<?php $u = wp_get_current_user(); echo($u->user_email); ?>",
3124
  apiKey: "<?php echo($this->getApiKey());?>"
3125
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3126
  });
3127
  </script><?php
3128
  }
3123
  email: "<?php $u = wp_get_current_user(); echo($u->user_email); ?>",
3124
  apiKey: "<?php echo($this->getApiKey());?>"
3125
  });
3126
+ HS.beacon.suggest([<?php
3127
+ $screen = get_current_screen();
3128
+ if($screen) {
3129
+ switch($screen->id) {
3130
+ case 'media_page_wp-short-pixel-bulk':
3131
+ echo(" '5a5de2782c7d3a19436843af', '5a5de6902c7d3a19436843e9', '5a5de5c42c7d3a19436843d0', '5a9945e42c7d3a75495145d0', '5a5de1c2042863193801047c',
3132
+ '5a5de66f2c7d3a19436843e0', '5a9946e62c7d3a75495145d8', '5a5de4f02c7d3a19436843c8', '5a5de65f042863193801049f', '5a5de2df0428631938010485' ");
3133
+ break;
3134
+ case 'settings_page_wp-shortpixel':
3135
+ echo(" '5a5de1de2c7d3a19436843a8', '5a6612032c7d3a39e6263a1d', '5a5de1c2042863193801047c', '5a5de2782c7d3a19436843af', '5a6610c62c7d3a39e6263a02',
3136
+ '5a9945e42c7d3a75495145d0', '5a5de66f2c7d3a19436843e0', '5a6597e80428632faf620487', '5a5de5c42c7d3a19436843d0', '5a5de5642c7d3a19436843cc' ");
3137
+ break;
3138
+ case 'media_page_wp-short-pixel-custom':
3139
+ echo(" '5a9946e62c7d3a75495145d8', '5a5de1c2042863193801047c', '5a5de2782c7d3a19436843af', '5a5de6902c7d3a19436843e9', '5a5de4f02c7d3a19436843c8',
3140
+ '5a6610c62c7d3a39e6263a02', '5a9945e42c7d3a75495145d0', '5a5de46c2c7d3a19436843c1', '5a5de1de2c7d3a19436843a8', '5a5de25c2c7d3a19436843ad' ");
3141
+ break;
3142
+ default:
3143
+ die($screen->id);
3144
+ }
3145
+ }
3146
+ ?>]);
3147
  });
3148
  </script><?php
3149
  }
readme.txt CHANGED
@@ -4,7 +4,7 @@ Tags: compress, image, compression, optimize, image optimizer, image optimiser,
4
  Requires at least: 3.2.0
5
  Tested up to: 4.9
6
  Requires PHP: 5.2
7
- Stable tag: 4.10.2
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
@@ -228,6 +228,10 @@ The ShortPixel team is here to help. <a href="https://shortpixel.com/contact">Co
228
 
229
  == Changelog ==
230
 
 
 
 
 
231
  = 4.10.2 =
232
  * fix error when listing Other media in some circumstances
233
 
4
  Requires at least: 3.2.0
5
  Tested up to: 4.9
6
  Requires PHP: 5.2
7
+ Stable tag: 4.10.3
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
228
 
229
  == Changelog ==
230
 
231
+ = 4.10.3 =
232
+ * improvements to context help beacon
233
+ * performance improvements to PNG to JPG conversion
234
+
235
  = 4.10.2 =
236
  * fix error when listing Other media in some circumstances
237
 
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.10.2
7
  * Author: ShortPixel
8
  * Author URI: https://shortpixel.com
9
  * Text Domain: shortpixel-image-optimiser
@@ -18,7 +18,7 @@ define('SHORTPIXEL_PLUGIN_FILE', __FILE__);
18
 
19
  //define('SHORTPIXEL_AFFILIATE_CODE', '');
20
 
21
- define('SHORTPIXEL_IMAGE_OPTIMISER_VERSION', "4.10.2");
22
  define('SHORTPIXEL_MAX_TIMEOUT', 10);
23
  define('SHORTPIXEL_VALIDATE_MAX_TIMEOUT', 15);
24
  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" target="_blank">Settings &gt; ShortPixel</a> page on how to start optimizing your image library and make your website load faster.
6
+ * Version: 4.10.3
7
  * Author: ShortPixel
8
  * Author URI: https://shortpixel.com
9
  * Text Domain: shortpixel-image-optimiser
18
 
19
  //define('SHORTPIXEL_AFFILIATE_CODE', '');
20
 
21
+ define('SHORTPIXEL_IMAGE_OPTIMISER_VERSION', "4.10.3");
22
  define('SHORTPIXEL_MAX_TIMEOUT', 10);
23
  define('SHORTPIXEL_VALIDATE_MAX_TIMEOUT', 15);
24
  define('SHORTPIXEL_BACKUP', 'ShortpixelBackups');