Version Description
Release date: 31st October 2018
- Generate WebP <picture> tags - use the output buffer instead of the_content which is not triggered by some themes on all content.
- compatibility of the WebP <picture> tag with lazy loading plugins (that support <picture>)
- Compatibility with Polylang.
- hooks to be used by thumbnail regeneration plugins: 'shortpixel-thumbnails-before-regenerate' and 'shortpixel-thumbnails-regenerated'
- Proper error message when the custom tables cannot be created.
- exclude the PNGs from conversion to JPEG when they match the exclude patterns.
- properly warn when cURL is not enabled that Cloudflare integration won't work.
- send only one url for metadata thumbnails which correspond to the same physical file.
- JavaScript delayed init for cases when some plugins deffer the load of javascript files.
- fix identifying filenames with basename length =
Download this release
Release Info
Developer | ShortPixel |
Plugin | ShortPixel Image Optimizer |
Version | 4.12.0 |
Comparing to | |
See all releases |
Code changes from version 4.11.3 to 4.12.0
- class/db/shortpixel-custom-meta-dao.php +7 -1
- class/db/shortpixel-meta-facade.php +13 -3
- class/db/wp-shortpixel-media-library-adapter.php +3 -1
- class/front/img-to-picture-webp.php +95 -66
- class/model/shortpixel-folder.php +26 -8
- class/shortpixel-png2jpg.php +38 -4
- class/view/shortpixel-feedback.php +35 -29
- class/view/shortpixel_view.php +33 -16
- class/wp-short-pixel.php +107 -43
- class/wp-shortpixel-cloudflare-api.php +2 -0
- class/wp-shortpixel-settings.php +6 -0
- readme.txt +20 -4
- res/css/short-pixel.css +23 -1
- res/css/short-pixel.min.css +1 -1
- shortpixel_api.php +217 -71
- wp-shortpixel.php +14 -7
class/db/shortpixel-custom-meta-dao.php
CHANGED
@@ -216,7 +216,13 @@ class ShortPixelCustomMetaDao {
|
|
216 |
}
|
217 |
$folderMsg = $this->saveFolder($folder);
|
218 |
if(!$folder->getId()) {
|
219 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
220 |
}
|
221 |
//die(var_dump($folder));
|
222 |
if(!$folderMsg) {
|
216 |
}
|
217 |
$folderMsg = $this->saveFolder($folder);
|
218 |
if(!$folder->getId()) {
|
219 |
+
//try again creating the tables first.
|
220 |
+
$this->createUpdateShortPixelTables();
|
221 |
+
$folderMsg = $this->saveFolder($folder);
|
222 |
+
//still no luck - complain... :)
|
223 |
+
if(!$folder->getId()) {
|
224 |
+
return __('The folder could not be saved to the database. Please check that the plugin can create its database tables.', 'shortpixel-image-optimiser') . $folderMsg;
|
225 |
+
}
|
226 |
}
|
227 |
//die(var_dump($folder));
|
228 |
if(!$folderMsg) {
|
class/db/shortpixel-meta-facade.php
CHANGED
@@ -329,7 +329,7 @@ class ShortPixelMetaFacade {
|
|
329 |
throw new Exception("Post metadata is corrupt (No attachment URL)", ShortPixelAPI::ERR_POSTMETA_CORRUPT);
|
330 |
}
|
331 |
if ( !parse_url($attURL, PHP_URL_SCHEME) ) {//no absolute URLs used -> we implement a hack
|
332 |
-
return self::getHomeUrl() . $attURL;//get the file URL
|
333 |
}
|
334 |
else {
|
335 |
return $attURL;//get the file URL
|
@@ -408,6 +408,7 @@ class ShortPixelMetaFacade {
|
|
408 |
}
|
409 |
if (file_exists($tPath)) {
|
410 |
$tUrl = str_replace(ShortPixelAPI::MB_basename($url), $thumbnailInfo['file'], $url);
|
|
|
411 |
$urlList[] = $tUrl;
|
412 |
$filePaths[] = $tPath;
|
413 |
if($addRetina) {
|
@@ -453,7 +454,7 @@ class ShortPixelMetaFacade {
|
|
453 |
|
454 |
public static function isRetina($path) {
|
455 |
$baseName = pathinfo(ShortPixelAPI::MB_basename($path), PATHINFO_FILENAME);
|
456 |
-
return
|
457 |
}
|
458 |
|
459 |
public static function getWPMLDuplicates( $id ) {
|
@@ -468,7 +469,16 @@ class ShortPixelMetaFacade {
|
|
468 |
SELECT pm.post_id FROM {$wpdb->postmeta} pm
|
469 |
WHERE pm.meta_value = %s AND pm.meta_key = '_icl_lang_duplicate_of'
|
470 |
", $id ) );
|
471 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
472 |
if(!in_array($id, $duplicates)) $duplicates[] = $id;
|
473 |
|
474 |
$transTable = $wpdb->get_results("SELECT COUNT(1) hasTransTable FROM information_schema.tables WHERE table_schema='{$wpdb->dbname}' AND table_name='{$wpdb->prefix}icl_translations'");
|
329 |
throw new Exception("Post metadata is corrupt (No attachment URL)", ShortPixelAPI::ERR_POSTMETA_CORRUPT);
|
330 |
}
|
331 |
if ( !parse_url($attURL, PHP_URL_SCHEME) ) {//no absolute URLs used -> we implement a hack
|
332 |
+
return self::getHomeUrl() . ltrim($attURL,'/');//get the file URL
|
333 |
}
|
334 |
else {
|
335 |
return $attURL;//get the file URL
|
408 |
}
|
409 |
if (file_exists($tPath)) {
|
410 |
$tUrl = str_replace(ShortPixelAPI::MB_basename($url), $thumbnailInfo['file'], $url);
|
411 |
+
if(in_array($tUrl, $urlList)) continue;
|
412 |
$urlList[] = $tUrl;
|
413 |
$filePaths[] = $tPath;
|
414 |
if($addRetina) {
|
454 |
|
455 |
public static function isRetina($path) {
|
456 |
$baseName = pathinfo(ShortPixelAPI::MB_basename($path), PATHINFO_FILENAME);
|
457 |
+
return (substr($baseName, -3) === '@2x');
|
458 |
}
|
459 |
|
460 |
public static function getWPMLDuplicates( $id ) {
|
469 |
SELECT pm.post_id FROM {$wpdb->postmeta} pm
|
470 |
WHERE pm.meta_value = %s AND pm.meta_key = '_icl_lang_duplicate_of'
|
471 |
", $id ) );
|
472 |
+
|
473 |
+
//Polylang
|
474 |
+
$moreDuplicates = $wpdb->get_col( $wpdb->prepare( "
|
475 |
+
SELECT p.ID FROM {$wpdb->posts} p
|
476 |
+
INNER JOIN {$wpdb->posts} pbase ON p.guid = pbase.guid
|
477 |
+
WHERE pbase.ID = %s
|
478 |
+
", $id ) );
|
479 |
+
|
480 |
+
$duplicates = array_unique(array_merge($duplicates, $moreDuplicates));
|
481 |
+
|
482 |
if(!in_array($id, $duplicates)) $duplicates[] = $id;
|
483 |
|
484 |
$transTable = $wpdb->get_results("SELECT COUNT(1) hasTransTable FROM information_schema.tables WHERE table_schema='{$wpdb->dbname}' AND table_name='{$wpdb->prefix}icl_translations'");
|
class/db/wp-shortpixel-media-library-adapter.php
CHANGED
@@ -86,7 +86,7 @@ class WpShortPixelMediaLbraryAdapter {
|
|
86 |
{
|
87 |
$foundThumbs = WpShortPixelMediaLbraryAdapter::findThumbs($filePath);
|
88 |
$foundCount = count($foundThumbs);
|
89 |
-
//echo(" <br>> $counter CHECKING FILE THUMBS: FOUND $foundCount "
|
90 |
// . ($foundCount > $sizesCount ? " DIFFERENT ($sizesCount)!" : ""));
|
91 |
if(count($foundThumbs) > $sizesCount) {
|
92 |
$unlisted = array();
|
@@ -248,6 +248,7 @@ class WpShortPixelMediaLbraryAdapter {
|
|
248 |
foreach($sizes as $key => $val) {
|
249 |
if (strpos($key, ShortPixelMeta::WEBP_THUMB_PREFIX) === 0) continue;
|
250 |
if (isset($val['mime-type']) && $val['mime-type'] == "image/webp") continue;
|
|
|
251 |
if (in_array($key, $exclude)) continue;
|
252 |
$uniq[$val['file']] = $key;
|
253 |
}
|
@@ -262,6 +263,7 @@ class WpShortPixelMediaLbraryAdapter {
|
|
262 |
foreach($sizesAll as $key => $size) {
|
263 |
if(strpos($key, ShortPixelMeta::FOUND_THUMB_PREFIX) === 0) continue;
|
264 |
if(in_array($size['file'], $files)) continue;
|
|
|
265 |
$sizes[$key] = $size;
|
266 |
$files[] = $size['file'];
|
267 |
}
|
86 |
{
|
87 |
$foundThumbs = WpShortPixelMediaLbraryAdapter::findThumbs($filePath);
|
88 |
$foundCount = count($foundThumbs);
|
89 |
+
//echo(" <br>> $counter CHECKING FILE THUMBS: FOUND $foundCount "
|
90 |
// . ($foundCount > $sizesCount ? " DIFFERENT ($sizesCount)!" : ""));
|
91 |
if(count($foundThumbs) > $sizesCount) {
|
92 |
$unlisted = array();
|
248 |
foreach($sizes as $key => $val) {
|
249 |
if (strpos($key, ShortPixelMeta::WEBP_THUMB_PREFIX) === 0) continue;
|
250 |
if (isset($val['mime-type']) && $val['mime-type'] == "image/webp") continue;
|
251 |
+
if(!isset($val['file'])) continue;
|
252 |
if (in_array($key, $exclude)) continue;
|
253 |
$uniq[$val['file']] = $key;
|
254 |
}
|
263 |
foreach($sizesAll as $key => $size) {
|
264 |
if(strpos($key, ShortPixelMeta::FOUND_THUMB_PREFIX) === 0) continue;
|
265 |
if(in_array($size['file'], $files)) continue;
|
266 |
+
if(!isset($size['file'])) continue;
|
267 |
$sizes[$key] = $size;
|
268 |
$files[] = $size['file'];
|
269 |
}
|
class/front/img-to-picture-webp.php
CHANGED
@@ -5,84 +5,113 @@
|
|
5 |
*/
|
6 |
|
7 |
class ShortPixelImgToPictureWebp {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
8 |
|
9 |
public static function convert($content) {
|
10 |
// Don't do anything with the RSS feed.
|
11 |
if ( is_feed() || is_admin() ) { return $content; }
|
12 |
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
33 |
$proto = $proto[0];
|
34 |
if(strpos($updir['baseurl'], $proto."://") === false) {
|
35 |
$base = explode("://", $updir['baseurl']);
|
36 |
-
$
|
37 |
-
|
38 |
-
$imageBase = str_replace($updir['baseurl'], SHORTPIXEL_UPLOADS_BASE, $src);
|
39 |
-
if($imageBase == $src) {
|
40 |
-
return $match[0];
|
41 |
-
}
|
42 |
-
$imageBase = dirname($imageBase) . '/';
|
43 |
-
|
44 |
-
// We don't wanna have an src attribute on the <img>
|
45 |
-
unset($img['src']);
|
46 |
-
//unset($img['srcset']);
|
47 |
-
//unset($img['sizes']);
|
48 |
-
|
49 |
-
$srcsetWebP = '';
|
50 |
-
if($srcset) {
|
51 |
-
$defs = explode(",", $srcset);
|
52 |
-
foreach($defs as $item) {
|
53 |
-
$parts = preg_split('/\s+/', trim($item));
|
54 |
-
|
55 |
-
//echo(" file: " . $parts[0] . " ext: " . pathinfo($parts[0], PATHINFO_EXTENSION) . " basename: " . wp_basename($parts[0], '.' . pathinfo($parts[0], PATHINFO_EXTENSION)));
|
56 |
-
|
57 |
-
$fileWebP = $imageBase . wp_basename($parts[0], '.' . pathinfo($parts[0], PATHINFO_EXTENSION)) . '.webp';
|
58 |
-
if(file_exists($fileWebP)) {
|
59 |
-
$srcsetWebP .= (strlen($srcsetWebP) ? ',': '')
|
60 |
-
. preg_replace('/\.[a-zA-Z0-9]+$/', '.webp', $parts[0])
|
61 |
-
. (isset($parts[1]) ? ' ' . $parts[1] : '');
|
62 |
-
}
|
63 |
}
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
71 |
if(file_exists($fileWebP)) {
|
72 |
-
$srcsetWebP
|
|
|
|
|
73 |
}
|
74 |
}
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
86 |
}
|
87 |
|
88 |
public static function get_attributes( $image_node )
|
5 |
*/
|
6 |
|
7 |
class ShortPixelImgToPictureWebp {
|
8 |
+
|
9 |
+
public static function lazyGet($img, $type) {
|
10 |
+
return array(
|
11 |
+
'value' =>
|
12 |
+
(isset($img[$type]) && strlen($img[$type])) ?
|
13 |
+
$img[$type]
|
14 |
+
: (isset($img['data-' . $type]) && strlen($img['data-' . $type]) ?
|
15 |
+
$img['data-' . $type]
|
16 |
+
: (isset($img['data-lazy-' . $type]) && strlen($img['data-lazy-' . $type]) ? $img['data-lazy-' . $type] : false)),
|
17 |
+
'prefix' =>
|
18 |
+
(isset($img[$type]) && strlen($img[$type])) ? ''
|
19 |
+
: (isset($img['data-' . $type]) && strlen($img['data-' . $type]) ? 'data-'
|
20 |
+
: (isset($img['data-lazy-' . $type]) && strlen($img['data-lazy-' . $type]) ? 'data-lazy-' : false))
|
21 |
+
);
|
22 |
+
}
|
23 |
|
24 |
public static function convert($content) {
|
25 |
// Don't do anything with the RSS feed.
|
26 |
if ( is_feed() || is_admin() ) { return $content; }
|
27 |
|
28 |
+
return preg_replace_callback('/<img[^>]*>/', array('ShortPixelImgToPictureWebp', 'convertImage'), $content);
|
29 |
+
}
|
30 |
+
|
31 |
+
public static function convertImage($match) {
|
32 |
+
// Do nothing with images that have the 'sp-no-webp' class.
|
33 |
+
if ( strpos($match[0], 'sp-no-webp') ) { return $match[0]; }
|
34 |
+
|
35 |
+
$img = self::get_attributes($match[0]);
|
36 |
+
|
37 |
+
$srcInfo = self::lazyGet($img, 'src');
|
38 |
+
$src = $srcInfo['value'];
|
39 |
+
$srcPrefix = $srcInfo['prefix'];
|
40 |
+
|
41 |
+
$srcsetInfo = self::lazyGet($img, 'srcset');
|
42 |
+
$srcset = $srcsetInfo['value'];
|
43 |
+
$srcsetPrefix = $srcsetInfo['prefix'];
|
44 |
+
|
45 |
+
$sizesInfo = self::lazyGet($img, 'sizes');
|
46 |
+
$sizes = $sizesInfo['value'];
|
47 |
+
$sizesPrefix = $sizesInfo['prefix'];
|
48 |
+
|
49 |
+
//check if there are webps
|
50 |
+
/*$id = $thisClass::url_to_attachment_id( $src );
|
51 |
+
if(!$id) {
|
52 |
+
return $match[0];
|
53 |
+
}
|
54 |
+
$imageBase = dirname(get_attached_file($id)) . '/';
|
55 |
+
*/
|
56 |
+
$updir = wp_upload_dir();
|
57 |
+
$proto = explode("://", $src);
|
58 |
+
if(count($proto) > 1) {
|
59 |
+
//check that baseurl uses the same http/https proto and if not, change
|
60 |
$proto = $proto[0];
|
61 |
if(strpos($updir['baseurl'], $proto."://") === false) {
|
62 |
$base = explode("://", $updir['baseurl']);
|
63 |
+
if(count($base) > 1) {
|
64 |
+
$updir['baseurl'] = $proto . "://" . $base[1];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
65 |
}
|
66 |
+
}
|
67 |
+
}
|
68 |
+
$imageBase = str_replace($updir['baseurl'], SHORTPIXEL_UPLOADS_BASE, $src);
|
69 |
+
if($imageBase == $src) {
|
70 |
+
return $match[0];
|
71 |
+
}
|
72 |
+
$imageBase = dirname($imageBase) . '/';
|
73 |
+
|
74 |
+
// We don't wanna have an src attribute on the <img>
|
75 |
+
unset($img['src']);
|
76 |
+
//unset($img['srcset']);
|
77 |
+
//unset($img['sizes']);
|
78 |
+
|
79 |
+
$srcsetWebP = '';
|
80 |
+
if($srcset) {
|
81 |
+
$defs = explode(",", $srcset);
|
82 |
+
foreach($defs as $item) {
|
83 |
+
$parts = preg_split('/\s+/', trim($item));
|
84 |
+
|
85 |
+
//echo(" file: " . $parts[0] . " ext: " . pathinfo($parts[0], PATHINFO_EXTENSION) . " basename: " . wp_basename($parts[0], '.' . pathinfo($parts[0], PATHINFO_EXTENSION)));
|
86 |
+
|
87 |
+
$fileWebP = $imageBase . wp_basename($parts[0], '.' . pathinfo($parts[0], PATHINFO_EXTENSION)) . '.webp';
|
88 |
if(file_exists($fileWebP)) {
|
89 |
+
$srcsetWebP .= (strlen($srcsetWebP) ? ',': '')
|
90 |
+
. preg_replace('/\.[a-zA-Z0-9]+$/', '.webp', $parts[0])
|
91 |
+
. (isset($parts[1]) ? ' ' . $parts[1] : '');
|
92 |
}
|
93 |
}
|
94 |
+
//$srcsetWebP = preg_replace('/\.[a-zA-Z0-9]+\s+/', '.webp ', $srcset);
|
95 |
+
} else {
|
96 |
+
$srcset = trim($src);
|
97 |
+
|
98 |
+
// die(var_dump($match));
|
99 |
+
|
100 |
+
$fileWebP = $imageBase . wp_basename($srcset, '.' . pathinfo($srcset, PATHINFO_EXTENSION)) . '.webp';
|
101 |
+
if(file_exists($fileWebP)) {
|
102 |
+
$srcsetWebP = preg_replace('/\.[a-zA-Z0-9]+$/', '.webp', $srcset);
|
103 |
+
}
|
104 |
+
}
|
105 |
+
if(!strlen($srcsetWebP)) { return $match[0]; }
|
106 |
+
|
107 |
+
//add the exclude class so if this content is processed again in other filter, the img is not converted again in picture
|
108 |
+
$img['class'] = (isset($img['class']) ? $img['class'] . " " : "") . "sp-no-webp";
|
109 |
+
|
110 |
+
return '<picture ' . self::create_attributes($img) . '>'
|
111 |
+
.'<source ' . $srcsetPrefix . 'srcset="' . $srcsetWebP . '"' . ($sizes ? ' ' . $sizesPrefix . 'sizes="' . $sizes . '"' : '') . ' type="image/webp">'
|
112 |
+
.'<source ' . $srcsetPrefix . 'srcset="' . $srcset . '"' . ($sizes ? ' ' . $sizesPrefix . 'sizes="' . $sizes . '"' : '') . '>'
|
113 |
+
.'<img ' . $srcPrefix . 'src="' . $src . '" ' . self::create_attributes($img) . '>'
|
114 |
+
.'</picture>';
|
115 |
}
|
116 |
|
117 |
public static function get_attributes( $image_node )
|
class/model/shortpixel-folder.php
CHANGED
@@ -31,11 +31,29 @@ class ShortPixelFolder extends ShortPixelEntity{
|
|
31 |
}
|
32 |
return false;
|
33 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
34 |
|
35 |
/**
|
36 |
* returns the first from parents that is a parent folder of $folder
|
37 |
-
* @param
|
38 |
-
* @param
|
39 |
* @return parent if found, false otherwise
|
40 |
*/
|
41 |
public static function checkFolderIsSubfolder($folder, $parents) {
|
@@ -52,9 +70,9 @@ class ShortPixelFolder extends ShortPixelEntity{
|
|
52 |
|
53 |
/**
|
54 |
* finds the first from the subfolders that has the folder as parent
|
55 |
-
* @param
|
56 |
-
* @param
|
57 |
-
* @return subfolder if found, false otherwise
|
58 |
*/
|
59 |
public static function checkFolderIsParent($folder, $subfolders) {
|
60 |
if(!is_array($subfolders)) {
|
@@ -133,7 +151,7 @@ class ShortPixelFolder extends ShortPixelEntity{
|
|
133 |
if(in_array($t, $ignore)) continue;
|
134 |
$tpath = trailingslashit($path) . $t;
|
135 |
if (is_dir($tpath)) {
|
136 |
-
self::checkFolderContentsRecursive($tpath, $callback);
|
137 |
} elseif( WPShortPixel::_isProcessablePath($tpath, array(), WPShortPixelSettings::getOpt('excludePatterns'))
|
138 |
&& !(in_array($tpath, $reference) && $reference[$tpath]->compressedSize == filesize($tpath))) {
|
139 |
$changed[] = $tpath;
|
@@ -142,7 +160,7 @@ class ShortPixelFolder extends ShortPixelEntity{
|
|
142 |
}
|
143 |
|
144 |
public function getFolderContentsChangeDate() {
|
145 |
-
return self::getFolderContentsChangeDateRecursive($this->getPath(), 0,
|
146 |
}
|
147 |
|
148 |
protected static function getFolderContentsChangeDateRecursive($path, $mtime, $refMtime) {
|
@@ -221,7 +239,7 @@ class ShortPixelFolder extends ShortPixelEntity{
|
|
221 |
|
222 |
/**
|
223 |
* needed as callback
|
224 |
-
* @param
|
225 |
*/
|
226 |
public static function path($item) {
|
227 |
return $item->getPath();
|
31 |
}
|
32 |
return false;
|
33 |
}
|
34 |
+
|
35 |
+
public static function deleteFolder($dirname) {
|
36 |
+
if (is_dir($dirname))
|
37 |
+
$dir_handle = opendir($dirname);
|
38 |
+
if (!$dir_handle)
|
39 |
+
return false;
|
40 |
+
while($file = @readdir($dir_handle)) {
|
41 |
+
if ($file != "." && $file != "..") {
|
42 |
+
if (!is_dir($dirname."/".$file))
|
43 |
+
@unlink($dirname."/".$file);
|
44 |
+
else
|
45 |
+
self::deleteFolder($dirname.'/'.$file);
|
46 |
+
}
|
47 |
+
}
|
48 |
+
closedir($dir_handle);
|
49 |
+
@rmdir($dirname);
|
50 |
+
return true;
|
51 |
+
}
|
52 |
|
53 |
/**
|
54 |
* returns the first from parents that is a parent folder of $folder
|
55 |
+
* @param string $folder
|
56 |
+
* @param array $parents
|
57 |
* @return parent if found, false otherwise
|
58 |
*/
|
59 |
public static function checkFolderIsSubfolder($folder, $parents) {
|
70 |
|
71 |
/**
|
72 |
* finds the first from the subfolders that has the folder as parent
|
73 |
+
* @param string $folder
|
74 |
+
* @param array $subfolders
|
75 |
+
* @return string subfolder if found, false otherwise
|
76 |
*/
|
77 |
public static function checkFolderIsParent($folder, $subfolders) {
|
78 |
if(!is_array($subfolders)) {
|
151 |
if(in_array($t, $ignore)) continue;
|
152 |
$tpath = trailingslashit($path) . $t;
|
153 |
if (is_dir($tpath)) {
|
154 |
+
self::checkFolderContentsRecursive($tpath, $changed, $callback);
|
155 |
} elseif( WPShortPixel::_isProcessablePath($tpath, array(), WPShortPixelSettings::getOpt('excludePatterns'))
|
156 |
&& !(in_array($tpath, $reference) && $reference[$tpath]->compressedSize == filesize($tpath))) {
|
157 |
$changed[] = $tpath;
|
160 |
}
|
161 |
|
162 |
public function getFolderContentsChangeDate() {
|
163 |
+
return self::getFolderContentsChangeDateRecursive($this->getPath(), 0, strtotime($this->getTsUpdated()));
|
164 |
}
|
165 |
|
166 |
protected static function getFolderContentsChangeDateRecursive($path, $mtime, $refMtime) {
|
239 |
|
240 |
/**
|
241 |
* needed as callback
|
242 |
+
* @param ShortPixelFolder $item
|
243 |
*/
|
244 |
public static function path($item) {
|
245 |
return $item->getPath();
|
class/shortpixel-png2jpg.php
CHANGED
@@ -109,6 +109,7 @@ class ShortPixelPng2Jpg {
|
|
109 |
$origSize = filesize($image);
|
110 |
if($newSize > $origSize * 0.95) {
|
111 |
//if the image is not 5% smaller, don't bother.
|
|
|
112 |
unlink($newPath);
|
113 |
return (object)array("params" => $params, "unlink" => false);
|
114 |
}
|
@@ -127,6 +128,7 @@ class ShortPixelPng2Jpg {
|
|
127 |
$image = $imageForBk;
|
128 |
$ret = ShortPixelAPI::backupImage($image, array($image));
|
129 |
if($ret['Status'] !== ShortPixelAPI::STATUS_SUCCESS) {
|
|
|
130 |
unlink($newPath);
|
131 |
return (object)array("params" => $params, "unlink" => false);
|
132 |
}
|
@@ -143,6 +145,21 @@ class ShortPixelPng2Jpg {
|
|
143 |
return (object)array("params" => $params, "unlink" => $image);
|
144 |
}
|
145 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
146 |
/**
|
147 |
* Convert an uploaded image from PNG to JPG
|
148 |
* @param type $params
|
@@ -154,6 +171,7 @@ class ShortPixelPng2Jpg {
|
|
154 |
if(!$this->_settings->png2jpg || strtolower(substr($params['file'], -4)) !== '.png') {
|
155 |
return $params;
|
156 |
}
|
|
|
157 |
|
158 |
$image = $params['file'];
|
159 |
WPShortPixel::log("Convert Media PNG to JPG on upload: {$image}");
|
@@ -199,6 +217,7 @@ class ShortPixelPng2Jpg {
|
|
199 |
if(!$this->_settings->png2jpg || !isset($meta['file']) || strtolower(substr($meta['file'], -4)) !== '.png') {
|
200 |
return ;
|
201 |
}
|
|
|
202 |
|
203 |
WPShortPixel::log("Send to processing: Convert Media PNG to JPG #{$ID} META: " . json_encode($meta));
|
204 |
|
@@ -264,10 +283,21 @@ class ShortPixelPng2Jpg {
|
|
264 |
WPShortPixel::log(" WPML duplicates: " . json_encode($duplicates));
|
265 |
|
266 |
$originalSizes = isset($meta['sizes']) ? $meta['sizes'] : array();
|
|
|
267 |
foreach($meta['sizes'] as $size => $info) {
|
268 |
-
|
269 |
-
|
270 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
271 |
|
272 |
WPShortPixel::log("PNG2JPG doConvert thumb RETURNED " . json_encode($rett));
|
273 |
if ($rett['type'] == 'image/jpeg') {
|
@@ -280,7 +310,10 @@ class ShortPixelPng2Jpg {
|
|
280 |
WPShortPixel::log("PNG2JPG thumb original: " . $originalSizes[$size]['file']);
|
281 |
$toReplace[$baseUrl . $baseRelPath . $info['file']] = $baseUrl . $baseRelPath . wp_basename($rett['file']);
|
282 |
|
|
|
283 |
$this->updateThumbAlsoInWPMLDuplicates($ID, $meta, $duplicates, $size, wp_basename($rett['file']));
|
|
|
|
|
284 |
}
|
285 |
}
|
286 |
$meta['ShortPixelPng2Jpg'] = array('originalFile' => $imagePath, 'originalSizes' => $originalSizes, 'originalSizes2' => $originalSizes,
|
@@ -288,6 +321,7 @@ class ShortPixelPng2Jpg {
|
|
288 |
'optimizationPercent' => round(100.0 * (1.00 - $jpgSize / $pngSize)));
|
289 |
//wp_update_attachment_metadata($ID, $meta);
|
290 |
update_post_meta($ID, '_wp_attachment_metadata', $meta);
|
|
|
291 |
}
|
292 |
|
293 |
self::png2JpgUpdateUrls(array(), $toReplace);
|
@@ -405,7 +439,7 @@ class ShortPixelPng2Jpg {
|
|
405 |
}
|
406 |
|
407 |
public static function removeUrlProtocol($url) {
|
408 |
-
return preg_replace("/^http[s]{0,1}:\/\//", "
|
409 |
}
|
410 |
|
411 |
/**
|
109 |
$origSize = filesize($image);
|
110 |
if($newSize > $origSize * 0.95) {
|
111 |
//if the image is not 5% smaller, don't bother.
|
112 |
+
WPShortPixel::log("PNG2JPG converted image is larger ($newSize vs. $origSize), keeping the PNG");
|
113 |
unlink($newPath);
|
114 |
return (object)array("params" => $params, "unlink" => false);
|
115 |
}
|
128 |
$image = $imageForBk;
|
129 |
$ret = ShortPixelAPI::backupImage($image, array($image));
|
130 |
if($ret['Status'] !== ShortPixelAPI::STATUS_SUCCESS) {
|
131 |
+
WPShortPixel::log("PNG2JPG couldn't backup, keeping the PNG");
|
132 |
unlink($newPath);
|
133 |
return (object)array("params" => $params, "unlink" => false);
|
134 |
}
|
145 |
return (object)array("params" => $params, "unlink" => $image);
|
146 |
}
|
147 |
|
148 |
+
protected function isExcluded($params) {
|
149 |
+
if(is_array($this->_settings->excludePatterns)) {
|
150 |
+
foreach($this->_settings->excludePatterns as $item) {
|
151 |
+
$type = trim($item["type"]);
|
152 |
+
if(in_array($type, array('name', 'path')) && WpShortPixel::matchExcludePattern($params['file'], $item['value'])) {
|
153 |
+
return true; //excluded by name pattern
|
154 |
+
}
|
155 |
+
if(isset($params['width']) && isset($params['height']) && 'size' == $type && WPShortPixel::isProcessableSize($params['width'], $params['height'], $item['value'])){
|
156 |
+
return true;
|
157 |
+
}
|
158 |
+
}
|
159 |
+
}
|
160 |
+
return false;
|
161 |
+
}
|
162 |
+
|
163 |
/**
|
164 |
* Convert an uploaded image from PNG to JPG
|
165 |
* @param type $params
|
171 |
if(!$this->_settings->png2jpg || strtolower(substr($params['file'], -4)) !== '.png') {
|
172 |
return $params;
|
173 |
}
|
174 |
+
if($this->isExcluded($params)) { return $params; }
|
175 |
|
176 |
$image = $params['file'];
|
177 |
WPShortPixel::log("Convert Media PNG to JPG on upload: {$image}");
|
217 |
if(!$this->_settings->png2jpg || !isset($meta['file']) || strtolower(substr($meta['file'], -4)) !== '.png') {
|
218 |
return ;
|
219 |
}
|
220 |
+
if($this->isExcluded($meta)) { return; }
|
221 |
|
222 |
WPShortPixel::log("Send to processing: Convert Media PNG to JPG #{$ID} META: " . json_encode($meta));
|
223 |
|
283 |
WPShortPixel::log(" WPML duplicates: " . json_encode($duplicates));
|
284 |
|
285 |
$originalSizes = isset($meta['sizes']) ? $meta['sizes'] : array();
|
286 |
+
$filesConverted = array();
|
287 |
foreach($meta['sizes'] as $size => $info) {
|
288 |
+
if(isset($filesConverted[$info['file']])) {
|
289 |
+
WPShortPixel::log("PNG2JPG DUPLICATED THUMB: " . $size);
|
290 |
+
if($filesConverted[$info['file']] === false) {
|
291 |
+
WPShortPixel::log("PNG2JPG DUPLICATED THUMB not converted");
|
292 |
+
continue;
|
293 |
+
}
|
294 |
+
WPShortPixel::log("PNG2JPG DUPLICATED THUMB already converted");
|
295 |
+
$rett = $filesConverted[$info['file']];
|
296 |
+
} else {
|
297 |
+
$retThumb = $this->doConvertPng2Jpg(array('file' => $basePath . $baseRelPath . $info['file'], 'url' => false, 'type' => 'image/png'),
|
298 |
+
$this->_settings->backupImages, "[0-9]+x[0-9]+");
|
299 |
+
$rett = $retThumb->params;
|
300 |
+
}
|
301 |
|
302 |
WPShortPixel::log("PNG2JPG doConvert thumb RETURNED " . json_encode($rett));
|
303 |
if ($rett['type'] == 'image/jpeg') {
|
310 |
WPShortPixel::log("PNG2JPG thumb original: " . $originalSizes[$size]['file']);
|
311 |
$toReplace[$baseUrl . $baseRelPath . $info['file']] = $baseUrl . $baseRelPath . wp_basename($rett['file']);
|
312 |
|
313 |
+
$filesConverted[$info['file']] = $rett;
|
314 |
$this->updateThumbAlsoInWPMLDuplicates($ID, $meta, $duplicates, $size, wp_basename($rett['file']));
|
315 |
+
} else {
|
316 |
+
$filesConverted[$info['file']] = false;
|
317 |
}
|
318 |
}
|
319 |
$meta['ShortPixelPng2Jpg'] = array('originalFile' => $imagePath, 'originalSizes' => $originalSizes, 'originalSizes2' => $originalSizes,
|
321 |
'optimizationPercent' => round(100.0 * (1.00 - $jpgSize / $pngSize)));
|
322 |
//wp_update_attachment_metadata($ID, $meta);
|
323 |
update_post_meta($ID, '_wp_attachment_metadata', $meta);
|
324 |
+
WPShortPixel::log("Updated meta: " . json_encode($meta));
|
325 |
}
|
326 |
|
327 |
self::png2JpgUpdateUrls(array(), $toReplace);
|
439 |
}
|
440 |
|
441 |
public static function removeUrlProtocol($url) {
|
442 |
+
return preg_replace("/^http[s]{0,1}:\/\//", "", $url);
|
443 |
}
|
444 |
|
445 |
/**
|
class/view/shortpixel-feedback.php
CHANGED
@@ -62,7 +62,7 @@ class ShortPixelFeedback {
|
|
62 |
. esc_html__( 'Remove the ShortPixel settings on plugin delete.', $this->plugin_name ) . '</label></span><br>';
|
63 |
$html .= '<p><strong>' . esc_html( $form['body'] ) . '</strong></p><p>';
|
64 |
foreach( $form['options'] as $key => $option ) {
|
65 |
-
$html .= '<input type="radio" name="shortpixel-deactivate-reason"
|
66 |
}
|
67 |
$html .= '</p><label id="shortpixel-deactivate-details-label" for="shortpixel-deactivate-reasons"><strong>' . esc_html( $form['details'] ) .'</strong></label><textarea name="shortpixel-deactivate-details" id="shortpixel-deactivate-details" rows="2" style="width:100%"></textarea>';
|
68 |
$html .= '<label for="anonymous" title="'
|
@@ -72,7 +72,7 @@ class ShortPixelFeedback {
|
|
72 |
}
|
73 |
$html .= '</div><!-- .shortpixel-deactivate-form-body -->';
|
74 |
$html .= '<p class="deactivating-spinner"><span class="spinner"></span> ' . __( 'Submitting form', $this->plugin_name ) . '</p>';
|
75 |
-
$html .= '<div class="shortpixel-deactivate-form-footer"><p><a id="shortpixel-deactivate-plugin" href="#">' . __( 'Just Deactivate', $this->plugin_name ) . '</a><a id="shortpixel-deactivate-submit-form" class="button button-primary" href="#">' . __( 'Submit and Deactivate', $this->plugin_name ) . '</a></p></div>'
|
76 |
?>
|
77 |
<div class="shortpixel-deactivate-form-bg"></div>
|
78 |
<style type="text/css">
|
@@ -150,9 +150,10 @@ class ShortPixelFeedback {
|
|
150 |
jQuery(document).ready(function($){
|
151 |
var deactivateURL = $("#shortpixel-deactivate-link-<?php echo esc_attr( $this->plugin_name ); ?>"),
|
152 |
formContainer = $('#shortpixel-deactivate-form-<?php echo esc_attr( $this->plugin_name ); ?>'),
|
|
|
153 |
detailsStrings = {
|
154 |
'setup' : '<?php echo __( 'What was the dificult part ?', $this->plugin_name ) ?>',
|
155 |
-
'
|
156 |
'features' : '<?php echo __( 'How could we improve ?', $this->plugin_name ) ?>',
|
157 |
'better-plugin' : '<?php echo __( 'Can you mention it ?', $this->plugin_name ) ?>',
|
158 |
'incompatibility' : '<?php echo __( 'With what plugin or theme is incompatible ?', $this->plugin_name ) ?>',
|
@@ -176,35 +177,40 @@ class ShortPixelFeedback {
|
|
176 |
var detailsLabel = formContainer.find( '#shortpixel-deactivate-details-label strong' );
|
177 |
var value = formContainer.find( 'input[name="shortpixel-deactivate-reason"]:checked' ).val();
|
178 |
detailsLabel.text( detailsStrings[ value ] );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
179 |
});
|
180 |
|
181 |
formContainer.on('click', '#shortpixel-deactivate-submit-form', function(e){
|
182 |
-
debugger;
|
183 |
-
var data = {
|
184 |
-
'action': 'shortpixel_deactivate_plugin',
|
185 |
-
'security': "<?php echo wp_create_nonce ( 'shortpixel_deactivate_plugin' ); ?>",
|
186 |
-
'dataType': "json"
|
187 |
-
};
|
188 |
e.preventDefault();
|
189 |
-
// As soon as we click, the body of the form should disappear
|
190 |
-
formContainer.addClass( 'process-response' );
|
191 |
-
// Fade in spinner
|
192 |
-
formContainer.find(".deactivating-spinner").fadeIn();
|
193 |
-
|
194 |
-
data['reason'] = formContainer.find( 'input[name="shortpixel-deactivate-reason"]:checked' ).val();
|
195 |
-
data['details'] = formContainer.find('#shortpixel-deactivate-details').val();
|
196 |
-
data['anonymous'] = formContainer.find( '#anonymous:checked' ).length;
|
197 |
-
data['remove-settings'] = formContainer.find( '#shortpixel-remove-settings:checked').length;
|
198 |
-
|
199 |
-
$.post(
|
200 |
-
ajaxurl,
|
201 |
-
data,
|
202 |
-
function(response){
|
203 |
-
// Redirect to original deactivation URL
|
204 |
-
debugger;
|
205 |
-
window.location.href = url;
|
206 |
-
}
|
207 |
-
);
|
208 |
});
|
209 |
|
210 |
formContainer.on('click', '#shortpixel-deactivate-plugin', function(e){
|
@@ -233,7 +239,7 @@ class ShortPixelFeedback {
|
|
233 |
$form['body'] = __( 'Before you deactivate the plugin, would you quickly give us your reason for doing so?', $this->plugin_name );
|
234 |
$form['options'] = array(
|
235 |
'setup' => __( 'Set up is too difficult', $this->plugin_name ),
|
236 |
-
'
|
237 |
'features' => __( 'Not the features I wanted', $this->plugin_name ),
|
238 |
'better-plugin' => __( 'Found a better plugin', $this->plugin_name ),
|
239 |
'incompatibility' => __( 'Incompatible with theme or plugin', $this->plugin_name ),
|
62 |
. esc_html__( 'Remove the ShortPixel settings on plugin delete.', $this->plugin_name ) . '</label></span><br>';
|
63 |
$html .= '<p><strong>' . esc_html( $form['body'] ) . '</strong></p><p>';
|
64 |
foreach( $form['options'] as $key => $option ) {
|
65 |
+
$html .= '<input type="radio" name="shortpixel-deactivate-reason" id="' . esc_attr( $key ) . '" value="' . esc_attr( $key ) . '"> <label for="' . esc_attr( $key ) . '">' . esc_attr( $option ) . '</label><br>';
|
66 |
}
|
67 |
$html .= '</p><label id="shortpixel-deactivate-details-label" for="shortpixel-deactivate-reasons"><strong>' . esc_html( $form['details'] ) .'</strong></label><textarea name="shortpixel-deactivate-details" id="shortpixel-deactivate-details" rows="2" style="width:100%"></textarea>';
|
68 |
$html .= '<label for="anonymous" title="'
|
72 |
}
|
73 |
$html .= '</div><!-- .shortpixel-deactivate-form-body -->';
|
74 |
$html .= '<p class="deactivating-spinner"><span class="spinner"></span> ' . __( 'Submitting form', $this->plugin_name ) . '</p>';
|
75 |
+
$html .= '<div class="shortpixel-deactivate-form-footer"><p><a id="shortpixel-deactivate-plugin" href="#">' . __( 'Just Deactivate', $this->plugin_name ) . '</a><a id="shortpixel-deactivate-submit-form" class="button button-primary" href="#" disabled>' . __( 'Submit and Deactivate', $this->plugin_name ) . '</a></p></div>'
|
76 |
?>
|
77 |
<div class="shortpixel-deactivate-form-bg"></div>
|
78 |
<style type="text/css">
|
150 |
jQuery(document).ready(function($){
|
151 |
var deactivateURL = $("#shortpixel-deactivate-link-<?php echo esc_attr( $this->plugin_name ); ?>"),
|
152 |
formContainer = $('#shortpixel-deactivate-form-<?php echo esc_attr( $this->plugin_name ); ?>'),
|
153 |
+
deactivated = true,
|
154 |
detailsStrings = {
|
155 |
'setup' : '<?php echo __( 'What was the dificult part ?', $this->plugin_name ) ?>',
|
156 |
+
'docs' : '<?php echo __( 'What can we describe more ?', $this->plugin_name ) ?>',
|
157 |
'features' : '<?php echo __( 'How could we improve ?', $this->plugin_name ) ?>',
|
158 |
'better-plugin' : '<?php echo __( 'Can you mention it ?', $this->plugin_name ) ?>',
|
159 |
'incompatibility' : '<?php echo __( 'With what plugin or theme is incompatible ?', $this->plugin_name ) ?>',
|
177 |
var detailsLabel = formContainer.find( '#shortpixel-deactivate-details-label strong' );
|
178 |
var value = formContainer.find( 'input[name="shortpixel-deactivate-reason"]:checked' ).val();
|
179 |
detailsLabel.text( detailsStrings[ value ] );
|
180 |
+
if(deactivated) {
|
181 |
+
deactivated = false;
|
182 |
+
$('#shortpixel-deactivate-submit-form').removeAttr("disabled");
|
183 |
+
formContainer.on('click', '#shortpixel-deactivate-submit-form', function(e){
|
184 |
+
var data = {
|
185 |
+
'action': 'shortpixel_deactivate_plugin',
|
186 |
+
'security': "<?php echo wp_create_nonce ( 'shortpixel_deactivate_plugin' ); ?>",
|
187 |
+
'dataType': "json"
|
188 |
+
};
|
189 |
+
e.preventDefault();
|
190 |
+
// As soon as we click, the body of the form should disappear
|
191 |
+
formContainer.addClass( 'process-response' );
|
192 |
+
// Fade in spinner
|
193 |
+
formContainer.find(".deactivating-spinner").fadeIn();
|
194 |
+
|
195 |
+
data['reason'] = formContainer.find( 'input[name="shortpixel-deactivate-reason"]:checked' ).val();
|
196 |
+
data['details'] = formContainer.find('#shortpixel-deactivate-details').val();
|
197 |
+
data['anonymous'] = formContainer.find( '#anonymous:checked' ).length;
|
198 |
+
data['remove-settings'] = formContainer.find( '#shortpixel-remove-settings:checked').length;
|
199 |
+
|
200 |
+
$.post(
|
201 |
+
ajaxurl,
|
202 |
+
data,
|
203 |
+
function(response){
|
204 |
+
// Redirect to original deactivation URL
|
205 |
+
window.location.href = url;
|
206 |
+
}
|
207 |
+
);
|
208 |
+
});
|
209 |
+
}
|
210 |
});
|
211 |
|
212 |
formContainer.on('click', '#shortpixel-deactivate-submit-form', function(e){
|
|
|
|
|
|
|
|
|
|
|
|
|
213 |
e.preventDefault();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
214 |
});
|
215 |
|
216 |
formContainer.on('click', '#shortpixel-deactivate-plugin', function(e){
|
239 |
$form['body'] = __( 'Before you deactivate the plugin, would you quickly give us your reason for doing so?', $this->plugin_name );
|
240 |
$form['options'] = array(
|
241 |
'setup' => __( 'Set up is too difficult', $this->plugin_name ),
|
242 |
+
'docs' => __( 'Lack of documentation', $this->plugin_name ),
|
243 |
'features' => __( 'Not the features I wanted', $this->plugin_name ),
|
244 |
'better-plugin' => __( 'Found a better plugin', $this->plugin_name ),
|
245 |
'incompatibility' => __( 'Incompatible with theme or plugin', $this->plugin_name ),
|
class/view/shortpixel_view.php
CHANGED
@@ -393,7 +393,7 @@ class ShortPixelView {
|
|
393 |
<?php
|
394 |
$failed = $this->ctrl->getPrioQ()->getFailed();
|
395 |
if(count($failed)) { ?>
|
396 |
-
<div class="bulk-progress" style="margin-bottom: 15px">
|
397 |
<p>
|
398 |
<?php _e('The following images could not be processed because of their limited write rights. This usually happens if you have changed your hosting provider. Please restart the optimization process after you granted write rights to all the files below.','shortpixel-image-optimiser');?>
|
399 |
</p>
|
@@ -421,23 +421,36 @@ class ShortPixelView {
|
|
421 |
_e('','shortpixel-image-optimiser');
|
422 |
if (count($quotaData['filesWithErrors'])) {
|
423 |
echo(' ');
|
424 |
-
_e('Some have errors
|
425 |
-
|
426 |
foreach($quotaData['filesWithErrors'] as $id => $data) {
|
427 |
-
if(!$first) {
|
428 |
-
echo(", ");
|
429 |
-
}
|
430 |
-
$first = false;
|
431 |
if(ShortPixelMetaFacade::isCustomQueuedId($id)) {
|
432 |
-
echo('<a href="'. ShortPixelMetaFacade::getHomeUrl() . ShortPixelMetaFacade::filenameToRootRelative($data['Path']).'"
|
433 |
} else {
|
434 |
-
echo('<a href="post.php?post='.$data['Id'].'&action=edit"
|
435 |
}
|
436 |
}
|
437 |
if(isset($quotaData['moreFilesWithErrors']) && $quotaData['moreFilesWithErrors']) {
|
438 |
-
echo('
|
439 |
}
|
440 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
441 |
</p>
|
442 |
<?php }
|
443 |
$settings = $this->ctrl->getSettings();
|
@@ -680,7 +693,7 @@ class ShortPixelView {
|
|
680 |
|
681 |
public function displayFailed($failed) {
|
682 |
?>
|
683 |
-
<div class="bulk-progress bulk-stats">
|
684 |
<?php foreach($failed as $fail) {
|
685 |
if($fail->type == ShortPixelMetaFacade::CUSTOM_TYPE) {
|
686 |
$meta = $fail->meta;
|
@@ -1145,7 +1158,7 @@ class ShortPixelView {
|
|
1145 |
if(!$gdInstalled) {echo(" <span style='color:red;'>" . __('You need PHP GD for this. Please ask your hosting to install it.','shortpixel-image-optimiser') . "</span>");}
|
1146 |
?>
|
1147 |
<p class="settings-info">
|
1148 |
-
<?php _e('Converts all PNGs that don\'t have transparent pixels to JPEG. This can dramatically reduce the file size, especially if you have camera pictures that are saved in PNG format.
|
1149 |
</p>
|
1150 |
</td>
|
1151 |
</tr>
|
@@ -1289,6 +1302,10 @@ class ShortPixelView {
|
|
1289 |
*/
|
1290 |
function display_cloudflare_settings_form()
|
1291 |
{
|
|
|
|
|
|
|
|
|
1292 |
?>
|
1293 |
<p><?php _e("If you're using Cloudflare on your site then we advise you to fill in the details below. This will allow ShortPixel to work seamlessly with Cloudflare so that any image optimized/restored by ShortPixel will be automatically updated on Cloudflare as well.",'shortpixel-image-optimiser');?></p>
|
1294 |
<form name='wp_shortpixel_cloudflareAPI' action='options-general.php?page=wp-shortpixel&noheader=true'
|
@@ -1300,7 +1317,7 @@ class ShortPixelView {
|
|
1300 |
<label for="cloudflare-email"><?php _e('Cloudflare E-mail:', 'shortpixel-image-optimiser'); ?></label>
|
1301 |
</th>
|
1302 |
<td>
|
1303 |
-
<input name="cloudflare-email" type="text" id="cloudflare-email"
|
1304 |
value="<?php echo($this->ctrl->fetch_cloudflare_api_email()); ?>" class="regular-text">
|
1305 |
<p class="settings-info">
|
1306 |
<?php _e('The e-mail address you use to login to CloudFlare.','shortpixel-image-optimiser');?>
|
@@ -1312,7 +1329,7 @@ class ShortPixelView {
|
|
1312 |
for="cloudflare-auth-key"><?php _e('Global API Key:', 'shortpixel-image-optimiser'); ?></label>
|
1313 |
</th>
|
1314 |
<td>
|
1315 |
-
<input name="cloudflare-auth-key" type="text" id="cloudflare-auth-key"
|
1316 |
value="<?php echo($this->ctrl->fetch_cloudflare_api_key()); ?>" class="regular-text">
|
1317 |
<p class="settings-info">
|
1318 |
<?php _e("This can be found when you're logged into your account, on the My Profile page:",'shortpixel-image-optimiser');?> <a href='https://www.cloudflare.com/a/profile' target='_blank'>https://www.cloudflare.com/a/profile</a>
|
@@ -1324,7 +1341,7 @@ class ShortPixelView {
|
|
1324 |
for="cloudflare-zone-id"><?php _e('Zone ID:', 'shortpixel-image-optimiser'); ?></label>
|
1325 |
</th>
|
1326 |
<td>
|
1327 |
-
<input name="cloudflare-zone-id" type="text" id="cloudflare-zone-id"
|
1328 |
value="<?php echo($this->ctrl->fetch_cloudflare_api_zoneid()); ?>" class="regular-text">
|
1329 |
<p class="settings-info">
|
1330 |
<?php _e('This can be found in your Cloudflare account in the "Overview" section for your domain.','shortpixel-image-optimiser');?>
|
393 |
<?php
|
394 |
$failed = $this->ctrl->getPrioQ()->getFailed();
|
395 |
if(count($failed)) { ?>
|
396 |
+
<div class="bulk-progress sp-notice sp-notice-warning sp-floating-block sp-double-width" style="margin-bottom: 15px">
|
397 |
<p>
|
398 |
<?php _e('The following images could not be processed because of their limited write rights. This usually happens if you have changed your hosting provider. Please restart the optimization process after you granted write rights to all the files below.','shortpixel-image-optimiser');?>
|
399 |
</p>
|
421 |
_e('','shortpixel-image-optimiser');
|
422 |
if (count($quotaData['filesWithErrors'])) {
|
423 |
echo(' ');
|
424 |
+
echo('<strong class="bulk-error-show closed">');_e('Some have errors','shortpixel-image-optimiser'); echo(' <a <span class="dashicons dashicons-arrow-down"></span></strong>');
|
425 |
+
?><div class="bulk-error-list"><ul><?php
|
426 |
foreach($quotaData['filesWithErrors'] as $id => $data) {
|
|
|
|
|
|
|
|
|
427 |
if(ShortPixelMetaFacade::isCustomQueuedId($id)) {
|
428 |
+
echo('<li><a href="'. ShortPixelMetaFacade::getHomeUrl() . ShortPixelMetaFacade::filenameToRootRelative($data['Path']).'" target="_blank">'.$data['Name'].'</a> - '.$data['Message'].'</li>');
|
429 |
} else {
|
430 |
+
echo('<li><a href="post.php?post='.$data['Id'].'&action=edit">'.$data['Name'].'</a> - '.$data['Message'].'</li>');
|
431 |
}
|
432 |
}
|
433 |
if(isset($quotaData['moreFilesWithErrors']) && $quotaData['moreFilesWithErrors']) {
|
434 |
+
echo('<li>');printf(__("(%s more)",'shortpixel-image-optimiser'), $quotaData['moreFilesWithErrors']); echo('</li>');
|
435 |
}
|
436 |
+
?></ul></div>
|
437 |
+
<script>
|
438 |
+
jQuery(function(){
|
439 |
+
jQuery(".sp-notice .bulk-error-show").click(function(e){
|
440 |
+
var elm = e.target;
|
441 |
+
if(jQuery(elm).hasClass("closed")){
|
442 |
+
jQuery(".sp-notice .bulk-error-list").show(400);
|
443 |
+
jQuery(elm).removeClass("closed").addClass("open");
|
444 |
+
jQuery("a.dashicons", elm).removeClass("dashicons-arrow-down").addClass("dashicons-arrow-up");
|
445 |
+
} else {
|
446 |
+
jQuery(".sp-notice .bulk-error-list").hide(400);
|
447 |
+
jQuery(elm).removeClass("open").addClass("closed");
|
448 |
+
jQuery("a.dashicons", elm).removeClass("dashicons-arrow-up").addClass("dashicons-arrow-down");
|
449 |
+
}
|
450 |
+
});
|
451 |
+
});
|
452 |
+
</script>
|
453 |
+
<?php } ?>
|
454 |
</p>
|
455 |
<?php }
|
456 |
$settings = $this->ctrl->getSettings();
|
693 |
|
694 |
public function displayFailed($failed) {
|
695 |
?>
|
696 |
+
<div class="bulk-progress bulk-stats" style="padding-top:5px;">
|
697 |
<?php foreach($failed as $fail) {
|
698 |
if($fail->type == ShortPixelMetaFacade::CUSTOM_TYPE) {
|
699 |
$meta = $fail->meta;
|
1158 |
if(!$gdInstalled) {echo(" <span style='color:red;'>" . __('You need PHP GD for this. Please ask your hosting to install it.','shortpixel-image-optimiser') . "</span>");}
|
1159 |
?>
|
1160 |
<p class="settings-info">
|
1161 |
+
<?php _e('Converts all PNGs that don\'t have transparent pixels to JPEG. This can dramatically reduce the file size, especially if you have camera pictures that are saved in PNG format. The plugin will also search for references of the image in posts and will replace them.','shortpixel-image-optimiser');?>
|
1162 |
</p>
|
1163 |
</td>
|
1164 |
</tr>
|
1302 |
*/
|
1303 |
function display_cloudflare_settings_form()
|
1304 |
{
|
1305 |
+
$noCurl = !function_exists('curl_init');
|
1306 |
+
if($noCurl) {
|
1307 |
+
echo('<p style="font-weight:bold;color:red">' . __("Please enable PHP cURL extension for the Cloudflare integration to work.", 'shortpixel-image-optimiser') . '</p>' );
|
1308 |
+
}
|
1309 |
?>
|
1310 |
<p><?php _e("If you're using Cloudflare on your site then we advise you to fill in the details below. This will allow ShortPixel to work seamlessly with Cloudflare so that any image optimized/restored by ShortPixel will be automatically updated on Cloudflare as well.",'shortpixel-image-optimiser');?></p>
|
1311 |
<form name='wp_shortpixel_cloudflareAPI' action='options-general.php?page=wp-shortpixel&noheader=true'
|
1317 |
<label for="cloudflare-email"><?php _e('Cloudflare E-mail:', 'shortpixel-image-optimiser'); ?></label>
|
1318 |
</th>
|
1319 |
<td>
|
1320 |
+
<input name="cloudflare-email" type="text" id="cloudflare-email" <?php echo($noCurl ? 'disabled' : '');?>
|
1321 |
value="<?php echo($this->ctrl->fetch_cloudflare_api_email()); ?>" class="regular-text">
|
1322 |
<p class="settings-info">
|
1323 |
<?php _e('The e-mail address you use to login to CloudFlare.','shortpixel-image-optimiser');?>
|
1329 |
for="cloudflare-auth-key"><?php _e('Global API Key:', 'shortpixel-image-optimiser'); ?></label>
|
1330 |
</th>
|
1331 |
<td>
|
1332 |
+
<input name="cloudflare-auth-key" type="text" id="cloudflare-auth-key" <?php echo($noCurl ? 'disabled' : '');?>
|
1333 |
value="<?php echo($this->ctrl->fetch_cloudflare_api_key()); ?>" class="regular-text">
|
1334 |
<p class="settings-info">
|
1335 |
<?php _e("This can be found when you're logged into your account, on the My Profile page:",'shortpixel-image-optimiser');?> <a href='https://www.cloudflare.com/a/profile' target='_blank'>https://www.cloudflare.com/a/profile</a>
|
1341 |
for="cloudflare-zone-id"><?php _e('Zone ID:', 'shortpixel-image-optimiser'); ?></label>
|
1342 |
</th>
|
1343 |
<td>
|
1344 |
+
<input name="cloudflare-zone-id" type="text" id="cloudflare-zone-id" <?php echo($noCurl ? 'disabled' : '');?>
|
1345 |
value="<?php echo($this->ctrl->fetch_cloudflare_api_zoneid()); ?>" class="regular-text">
|
1346 |
<p class="settings-info">
|
1347 |
<?php _e('This can be found in your Cloudflare account in the "Overview" section for your domain.','shortpixel-image-optimiser');?>
|
class/wp-short-pixel.php
CHANGED
@@ -39,7 +39,7 @@ class WPShortPixel {
|
|
39 |
|
40 |
define('QUOTA_EXCEEDED', $this->view->getQuotaExceededHTML());
|
41 |
|
42 |
-
if(is_plugin_active('envira-gallery/envira-gallery.php')) {
|
43 |
define('SHORTPIXEL_CUSTOM_THUMB_SUFFIX', '_c');
|
44 |
}
|
45 |
|
@@ -78,7 +78,9 @@ class WPShortPixel {
|
|
78 |
|
79 |
//custom hook
|
80 |
add_action( 'shortpixel-optimize-now', array( &$this, 'optimizeNowHook' ), 10, 1);
|
81 |
-
|
|
|
|
|
82 |
|
83 |
if($isAdminUser) {
|
84 |
//add settings page
|
@@ -109,7 +111,7 @@ class WPShortPixel {
|
|
109 |
//only if the key is not yet valid or the user hasn't bought any credits.
|
110 |
$stats = $this->_settings->currentStats;
|
111 |
$totalCredits = isset($stats["APICallsQuotaNumeric"]) ? $stats['APICallsQuotaNumeric'] + $stats['APICallsQuotaOneTimeNumeric'] : 0;
|
112 |
-
if(!$this->_settings->verifiedKey || $totalCredits < 4000) {
|
113 |
require_once 'view/shortpixel-feedback.php';
|
114 |
new ShortPixelFeedback( SHORTPIXEL_PLUGIN_FILE, 'shortpixel-image-optimiser', $this->_settings->apiKey, $this);
|
115 |
}
|
@@ -369,7 +371,7 @@ class WPShortPixel {
|
|
369 |
array("__SP_FIRST_TYPE__", "__SP_SECOND_TYPE__"), "__SP_CELL_MESSAGE__", 'sp-column-actions-template');
|
370 |
}
|
371 |
}
|
372 |
-
?>
|
373 |
<script type="text/javascript" >
|
374 |
var ShortPixelConstants = {
|
375 |
STATUS_SUCCESS: <?php echo ShortPixelAPI::STATUS_SUCCESS; ?>,
|
@@ -392,9 +394,14 @@ class WPShortPixel {
|
|
392 |
AFFILIATE: '<?php echo(self::getAffiliateSufix());?>'
|
393 |
};
|
394 |
//check after 10 seconds if ShortPixel initialized OK, if not, force the init (could happen if a JS error somewhere else stopped the JS execution).
|
395 |
-
|
396 |
-
ShortPixel
|
397 |
-
|
|
|
|
|
|
|
|
|
|
|
398 |
</script> <?php
|
399 |
wp_enqueue_style('short-pixel.min.css', plugins_url('/res/css/short-pixel.min.css',SHORTPIXEL_PLUGIN_FILE), array(), SHORTPIXEL_IMAGE_OPTIMISER_VERSION);
|
400 |
|
@@ -556,7 +563,7 @@ class WPShortPixel {
|
|
556 |
}
|
557 |
|
558 |
/**
|
559 |
-
*
|
560 |
* @param array $meta - the wordpress postmeta structure
|
561 |
* @param type $ID - the Media Library ID
|
562 |
* @return the meta structure updated with ShortPixel info if case
|
@@ -574,6 +581,11 @@ class WPShortPixel {
|
|
574 |
if(isset($dbMeta['ShortPixelImprovement'])) {
|
575 |
return $meta;
|
576 |
}
|
|
|
|
|
|
|
|
|
|
|
577 |
|
578 |
self::log("Handle Media Library Image Upload #{$ID}");
|
579 |
//self::log("STACK: " . json_encode(debug_backtrace()));
|
@@ -872,10 +884,21 @@ class WPShortPixel {
|
|
872 |
$meta = $item->getMeta();//wp_get_attachment_metadata($crtStartQueryID);
|
873 |
|
874 |
if($meta->getStatus() != 2) {
|
875 |
-
$
|
876 |
-
|
877 |
-
if(
|
878 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
879 |
elseif($meta->getCompressionType() !== null && $meta->getCompressionType() != $this->_settings->compressionType) {//a different type of compression was chosen in settings
|
880 |
if($this->doRestore($crtStartQueryID)) {
|
881 |
$itemList[] = $item = new ShortPixelMetaFacade($crtStartQueryID); //force reload after restore
|
@@ -888,12 +911,14 @@ class WPShortPixel {
|
|
888 |
elseif( $this->_settings->processThumbnails && $meta->getThumbsOpt() !== null
|
889 |
&& ($meta->getThumbsOpt() == 0 && count($meta->getThumbs()) > 0
|
890 |
|| $meta->getThumbsOpt() < WpShortPixelMediaLbraryAdapter::countSizesNotExcluded($meta->getThumbs(), $this->_settings->excludeSizes) && is_array($meta->getThumbsOptList()))) { //thumbs were chosen in settings
|
891 |
-
|
892 |
-
$
|
893 |
-
|
894 |
-
|
895 |
-
|
896 |
-
|
|
|
|
|
897 |
}
|
898 |
elseif($itemMetaData->meta_key == '_wp_attachment_metadata') { //count skipped
|
899 |
$skippedAlreadyProcessed++;
|
@@ -1012,7 +1037,7 @@ class WPShortPixel {
|
|
1012 |
|
1013 |
//self::log("HIP: 0 Bulk ran: " . $this->prioQ->bulkRan());
|
1014 |
$customIds = false;
|
1015 |
-
if(count($ids) <
|
1016 |
&& (!$this->_settings->cancelPointer || $this->_settings->skipToCustom)
|
1017 |
&& !$this->_settings->customBulkPaused)
|
1018 |
{ //take from custom images if any left to optimize - only if bulk was ever started
|
@@ -1032,8 +1057,8 @@ class WPShortPixel {
|
|
1032 |
//self::log("HIP: 1 Ids: ".json_encode($ids));
|
1033 |
if(count($ids)) {$idl='';foreach($ids as $i){$idl.=$i->getId().' ';} self::log("HIP: 1 Selected IDs: $idl");}
|
1034 |
|
1035 |
-
//2: Send up to
|
1036 |
-
for($i = 0, $itemHandler = false; $ids !== false && $i < min(
|
1037 |
$crtItemHandler = $ids[$i];
|
1038 |
$tmpMeta = $crtItemHandler->getMeta();
|
1039 |
$compType = ($tmpMeta->getCompressionType() !== null ? $tmpMeta->getCompressionType() : $this->_settings->compressionType);
|
@@ -1047,7 +1072,9 @@ class WPShortPixel {
|
|
1047 |
$firstUrlAndPaths = $URLsAndPATHs;
|
1048 |
}
|
1049 |
} catch(Exception $e) { // Exception("Post metadata is corrupt (No attachment URL)") or Exception("Image files are missing.")
|
1050 |
-
|
|
|
|
|
1051 |
if(! $this->prioQ->remove($crtItemHandler->getQueuedId()) ){
|
1052 |
$this->advanceBulk($crtItemHandler->getId());
|
1053 |
$res['searching'] = true;
|
@@ -1145,10 +1172,15 @@ class WPShortPixel {
|
|
1145 |
$bkThumb = $backupUrl . $urlBkPath . $thumb;
|
1146 |
}
|
1147 |
if(strlen($thumb)) {
|
1148 |
-
$
|
1149 |
-
|
1150 |
-
|
1151 |
-
|
|
|
|
|
|
|
|
|
|
|
1152 |
}
|
1153 |
}
|
1154 |
|
@@ -1267,7 +1299,7 @@ class WPShortPixel {
|
|
1267 |
|
1268 |
private function sendToProcessing($itemHandler, $compressionType = false, $onlyThumbs = false) {
|
1269 |
|
1270 |
-
//
|
1271 |
if($itemHandler->getType() == ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE) { //currently only for ML
|
1272 |
$rawMeta = $this->checkConvertMediaPng2Jpg($itemHandler);
|
1273 |
|
@@ -1295,7 +1327,9 @@ class WPShortPixel {
|
|
1295 |
if(pathinfo($mainFile, PATHINFO_EXTENSION) !== pathinfo($size['file'], PATHINFO_EXTENSION)){
|
1296 |
continue;
|
1297 |
}
|
1298 |
-
$
|
|
|
|
|
1299 |
if($size['file'] === ShortPixelAPI::MB_basename($found)) {
|
1300 |
$foundThumbs[$id] = false;
|
1301 |
}
|
@@ -1407,6 +1441,17 @@ class WPShortPixel {
|
|
1407 |
die(json_encode($ret));
|
1408 |
}
|
1409 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1410 |
/**
|
1411 |
* to be called by thumbnail regeneration plugins when regenerating the thumbnails for an image
|
1412 |
* @param $postId - the postId of the image
|
@@ -1439,6 +1484,12 @@ class WPShortPixel {
|
|
1439 |
}
|
1440 |
//wp_update_attachment_metadata($postId, $meta);
|
1441 |
update_post_meta($postId, '_wp_attachment_metadata', $meta);
|
|
|
|
|
|
|
|
|
|
|
|
|
1442 |
if(!$bulk) {
|
1443 |
$this->prioQ->push($postId);
|
1444 |
}
|
@@ -1565,7 +1616,9 @@ class WPShortPixel {
|
|
1565 |
$baseRelPath = trailingslashit(dirname($image));
|
1566 |
$toReplace[ShortPixelPng2Jpg::removeUrlProtocol($imageUrl)] = $baseUrl . $baseRelPath . wp_basename($png2jpgMain);
|
1567 |
foreach($sizes as $key => $size) {
|
1568 |
-
|
|
|
|
|
1569 |
}
|
1570 |
$file = $png2jpgMain;
|
1571 |
$sizes = $png2jpgSizes;
|
@@ -1612,7 +1665,7 @@ class WPShortPixel {
|
|
1612 |
$this->throwNotice('generic-err', __("No backup files found. Restore not performed.",'shortpixel-image-optimiser'));
|
1613 |
return false;
|
1614 |
}
|
1615 |
-
//either backups exist, or
|
1616 |
try {
|
1617 |
$width = false;
|
1618 |
if($bkCount) { // backups, if exist
|
@@ -1651,7 +1704,7 @@ class WPShortPixel {
|
|
1651 |
if($png2jpgMain) {
|
1652 |
$crtMeta['file'] = trailingslashit(dirname($crtMeta['file'])) . ShortPixelAPI::MB_basename($file);
|
1653 |
update_attached_file($ID, $crtMeta['file']);
|
1654 |
-
if($png2jpgSizes) {
|
1655 |
$crtMeta['sizes'] = $png2jpgSizes;
|
1656 |
} else {
|
1657 |
//this was an image converted on upload, regenerate the thumbs using the PNG main image BUT deactivate temporarily the filter!!
|
@@ -1662,10 +1715,10 @@ class WPShortPixel {
|
|
1662 |
}
|
1663 |
//wp_update_attachment_metadata($ID, $crtMeta);
|
1664 |
update_post_meta($ID, '_wp_attachment_metadata', $crtMeta);
|
|
|
|
|
|
|
1665 |
}
|
1666 |
-
unset($rawMeta["ShortPixelImprovement"]);
|
1667 |
-
unset($rawMeta['ShortPixel']);
|
1668 |
-
unset($rawMeta['ShortPixelPng2Jpg']);
|
1669 |
|
1670 |
if($png2jpgMain) {
|
1671 |
$spPng2Jpg = new ShortPixelPng2Jpg($this->_settings);
|
@@ -1816,11 +1869,13 @@ class WPShortPixel {
|
|
1816 |
$this->sendToProcessing(new ShortPixelMetaFacade($ID), false, true);
|
1817 |
$ret = array("Status" => ShortPixelAPI::STATUS_SUCCESS, "message" => "");
|
1818 |
} catch(Exception $e) { // Exception("Post metadata is corrupt (No attachment URL)") or Exception("Image files are missing.")
|
1819 |
-
$meta['ShortPixelImprovement']
|
1820 |
-
|
1821 |
-
|
1822 |
-
|
1823 |
-
|
|
|
|
|
1824 |
$ret = array("Status" => ShortPixelAPI::STATUS_FAIL, "Message" => $e->getMessage());
|
1825 |
}
|
1826 |
} else {
|
@@ -2407,6 +2462,10 @@ class WPShortPixel {
|
|
2407 |
}
|
2408 |
$_POST['key'] = SHORTPIXEL_API_KEY;
|
2409 |
}
|
|
|
|
|
|
|
|
|
2410 |
|
2411 |
//check all custom folders and update meta table if files appeared
|
2412 |
$customFolders = $this->refreshCustomFolders($notice, isset($_POST['removeFolder']) ? $_POST['removeFolder'] : null);
|
@@ -2841,7 +2900,7 @@ class WPShortPixel {
|
|
2841 |
if(!is_array($data)) {
|
2842 |
$data = unserialize($data);
|
2843 |
}
|
2844 |
-
//if($extended) {var_dump(wp_get_attachment_url($id));
|
2845 |
$fileExtension = strtolower(pathinfo($file, PATHINFO_EXTENSION));
|
2846 |
$invalidKey = !$this->_settings->verifiedKey;
|
2847 |
$quotaExceeded = $this->_settings->quotaExceeded;
|
@@ -3186,8 +3245,7 @@ class WPShortPixel {
|
|
3186 |
if(in_array($type, array("name", "path"))) {
|
3187 |
$pattern = trim($item["value"]);
|
3188 |
$target = $type == "name" ? ShortPixelAPI::MB_basename($path) : $path;
|
3189 |
-
if(
|
3190 |
-
|| $pattern[0] != '/' && strpos($target, $pattern) !== false) { //search as a substring if not
|
3191 |
return false;
|
3192 |
}
|
3193 |
}
|
@@ -3197,7 +3255,7 @@ class WPShortPixel {
|
|
3197 |
return false;
|
3198 |
}
|
3199 |
}
|
3200 |
-
|
3201 |
static public function isProcessableSize($width, $height, $excludePattern) {
|
3202 |
$ranges = preg_split("/(x|×)/",$excludePattern);
|
3203 |
$widthBounds = explode("-", $ranges[0]);
|
@@ -3212,6 +3270,11 @@ class WPShortPixel {
|
|
3212 |
return true;
|
3213 |
}
|
3214 |
|
|
|
|
|
|
|
|
|
|
|
3215 |
|
3216 |
//return an array with URL(s) and PATH(s) for this file
|
3217 |
public function getURLsAndPATHs($itemHandler, $meta = NULL, $onlyThumbs = false) {
|
@@ -3458,6 +3521,7 @@ class WPShortPixel {
|
|
3458 |
return $this->_settings->resizeHeight;
|
3459 |
}
|
3460 |
public static function getAffiliateSufix() {
|
|
|
3461 |
// return isset($_COOKIE["AffiliateShortPixel"])
|
3462 |
// ? "/affiliate/" . $_COOKIE["AffiliateShortPixel"]
|
3463 |
// : (defined("SHORTPIXEL_AFFILIATE_CODE") && strlen(SHORTPIXEL_AFFILIATE_CODE) ? "/affiliate/" . SHORTPIXEL_AFFILIATE_CODE : "");
|
39 |
|
40 |
define('QUOTA_EXCEEDED', $this->view->getQuotaExceededHTML());
|
41 |
|
42 |
+
if(is_plugin_active('envira-gallery/envira-gallery.php') || is_plugin_active('soliloquy-lite/soliloquy-lite.php')) {
|
43 |
define('SHORTPIXEL_CUSTOM_THUMB_SUFFIX', '_c');
|
44 |
}
|
45 |
|
78 |
|
79 |
//custom hook
|
80 |
add_action( 'shortpixel-optimize-now', array( &$this, 'optimizeNowHook' ), 10, 1);
|
81 |
+
|
82 |
+
add_action( 'shortpixel-thumbnails-before-regenerate', array( &$this, 'thumbnailsBeforeRegenerateHook' ), 10, 1);
|
83 |
+
add_action( 'shortpixel-thumbnails-regenerated', array( &$this, 'thumbnailsRegeneratedHook' ), 10, 4);
|
84 |
|
85 |
if($isAdminUser) {
|
86 |
//add settings page
|
111 |
//only if the key is not yet valid or the user hasn't bought any credits.
|
112 |
$stats = $this->_settings->currentStats;
|
113 |
$totalCredits = isset($stats["APICallsQuotaNumeric"]) ? $stats['APICallsQuotaNumeric'] + $stats['APICallsQuotaOneTimeNumeric'] : 0;
|
114 |
+
if(true || !$this->_settings->verifiedKey || $totalCredits < 4000) {
|
115 |
require_once 'view/shortpixel-feedback.php';
|
116 |
new ShortPixelFeedback( SHORTPIXEL_PLUGIN_FILE, 'shortpixel-image-optimiser', $this->_settings->apiKey, $this);
|
117 |
}
|
371 |
array("__SP_FIRST_TYPE__", "__SP_SECOND_TYPE__"), "__SP_CELL_MESSAGE__", 'sp-column-actions-template');
|
372 |
}
|
373 |
}
|
374 |
+
?><!--SP ARCHIVE is <?php echo($this->_settings->downloadArchive . " CRC: " . crc32(get_site_url())%10); ?> -->
|
375 |
<script type="text/javascript" >
|
376 |
var ShortPixelConstants = {
|
377 |
STATUS_SUCCESS: <?php echo ShortPixelAPI::STATUS_SUCCESS; ?>,
|
394 |
AFFILIATE: '<?php echo(self::getAffiliateSufix());?>'
|
395 |
};
|
396 |
//check after 10 seconds if ShortPixel initialized OK, if not, force the init (could happen if a JS error somewhere else stopped the JS execution).
|
397 |
+
function delayedInit() {
|
398 |
+
if(typeof ShortPixel !== "undefined") {
|
399 |
+
ShortPixel.init();
|
400 |
+
} else {
|
401 |
+
setTimeout(delayedInit, 10000);
|
402 |
+
}
|
403 |
+
}
|
404 |
+
setTimeout(delayedInit, 10000);
|
405 |
</script> <?php
|
406 |
wp_enqueue_style('short-pixel.min.css', plugins_url('/res/css/short-pixel.min.css',SHORTPIXEL_PLUGIN_FILE), array(), SHORTPIXEL_IMAGE_OPTIMISER_VERSION);
|
407 |
|
563 |
}
|
564 |
|
565 |
/**
|
566 |
+
* Optimize a new image - usually uploaded into the Media Library
|
567 |
* @param array $meta - the wordpress postmeta structure
|
568 |
* @param type $ID - the Media Library ID
|
569 |
* @return the meta structure updated with ShortPixel info if case
|
581 |
if(isset($dbMeta['ShortPixelImprovement'])) {
|
582 |
return $meta;
|
583 |
}
|
584 |
+
|
585 |
+
$t = get_transient("wp-short-pixel-regenerating");
|
586 |
+
if(is_array($t) && isset($t[$ID])) {
|
587 |
+
return;
|
588 |
+
}
|
589 |
|
590 |
self::log("Handle Media Library Image Upload #{$ID}");
|
591 |
//self::log("STACK: " . json_encode(debug_backtrace()));
|
884 |
$meta = $item->getMeta();//wp_get_attachment_metadata($crtStartQueryID);
|
885 |
|
886 |
if($meta->getStatus() != 2) {
|
887 |
+
$addIt = (strpos($meta->getMessage(), __('Image files are missing.', 'shortpixel-image-optimiser')) === false);
|
888 |
+
|
889 |
+
if(!$addIt) {
|
890 |
+
//in case the message is "Image files are missing", we only add it if we could do a restore.
|
891 |
+
if ($this->doRestore($crtStartQueryID)) {
|
892 |
+
$addIt = true;
|
893 |
+
$item = new ShortPixelMetaFacade($crtStartQueryID);
|
894 |
+
}
|
895 |
+
}
|
896 |
+
if($addIt) {
|
897 |
+
$itemList[] = $item;
|
898 |
+
$idList[] = $crtStartQueryID;
|
899 |
+
if(count($itemList) > SHORTPIXEL_PRESEND_ITEMS) break;
|
900 |
+
}
|
901 |
+
}
|
902 |
elseif($meta->getCompressionType() !== null && $meta->getCompressionType() != $this->_settings->compressionType) {//a different type of compression was chosen in settings
|
903 |
if($this->doRestore($crtStartQueryID)) {
|
904 |
$itemList[] = $item = new ShortPixelMetaFacade($crtStartQueryID); //force reload after restore
|
911 |
elseif( $this->_settings->processThumbnails && $meta->getThumbsOpt() !== null
|
912 |
&& ($meta->getThumbsOpt() == 0 && count($meta->getThumbs()) > 0
|
913 |
|| $meta->getThumbsOpt() < WpShortPixelMediaLbraryAdapter::countSizesNotExcluded($meta->getThumbs(), $this->_settings->excludeSizes) && is_array($meta->getThumbsOptList()))) { //thumbs were chosen in settings
|
914 |
+
$URLsAndPATHs = $item->getURLsAndPATHs(true, true, $this->_settings->optimizeRetina, $this->_settings->excludeSizes);
|
915 |
+
if(count($URLsAndPATHs["URLs"])) {
|
916 |
+
$meta->setThumbsTodo(true);
|
917 |
+
$item->updateMeta($meta);//wp_update_attachment_metadata($crtStartQueryID, $meta);
|
918 |
+
$itemList[] = $item;
|
919 |
+
$idList[] = $crtStartQueryID;
|
920 |
+
if(count($itemList) > SHORTPIXEL_PRESEND_ITEMS) break;
|
921 |
+
}
|
922 |
}
|
923 |
elseif($itemMetaData->meta_key == '_wp_attachment_metadata') { //count skipped
|
924 |
$skippedAlreadyProcessed++;
|
1037 |
|
1038 |
//self::log("HIP: 0 Bulk ran: " . $this->prioQ->bulkRan());
|
1039 |
$customIds = false;
|
1040 |
+
if(count($ids) < SHORTPIXEL_PRESEND_ITEMS && $this->prioQ->bulkRan() && $this->_settings->hasCustomFolders
|
1041 |
&& (!$this->_settings->cancelPointer || $this->_settings->skipToCustom)
|
1042 |
&& !$this->_settings->customBulkPaused)
|
1043 |
{ //take from custom images if any left to optimize - only if bulk was ever started
|
1057 |
//self::log("HIP: 1 Ids: ".json_encode($ids));
|
1058 |
if(count($ids)) {$idl='';foreach($ids as $i){$idl.=$i->getId().' ';} self::log("HIP: 1 Selected IDs: $idl");}
|
1059 |
|
1060 |
+
//2: Send up to SHORTPIXEL_PRESEND_ITEMS files to the server for processing
|
1061 |
+
for($i = 0, $itemHandler = false; $ids !== false && $i < min(SHORTPIXEL_PRESEND_ITEMS, count($ids)); $i++) {
|
1062 |
$crtItemHandler = $ids[$i];
|
1063 |
$tmpMeta = $crtItemHandler->getMeta();
|
1064 |
$compType = ($tmpMeta->getCompressionType() !== null ? $tmpMeta->getCompressionType() : $this->_settings->compressionType);
|
1072 |
$firstUrlAndPaths = $URLsAndPATHs;
|
1073 |
}
|
1074 |
} catch(Exception $e) { // Exception("Post metadata is corrupt (No attachment URL)") or Exception("Image files are missing.")
|
1075 |
+
if($tmpMeta->getStatus() != 2) {
|
1076 |
+
$crtItemHandler->incrementRetries(1, ($e->getCode() < 0 ? $e->getCode() : ShortPixelAPI::ERR_FILE_NOT_FOUND), $e->getMessage());
|
1077 |
+
}
|
1078 |
if(! $this->prioQ->remove($crtItemHandler->getQueuedId()) ){
|
1079 |
$this->advanceBulk($crtItemHandler->getId());
|
1080 |
$res['searching'] = true;
|
1172 |
$bkThumb = $backupUrl . $urlBkPath . $thumb;
|
1173 |
}
|
1174 |
if(strlen($thumb)) {
|
1175 |
+
if($itemHandler->getType() == ShortPixelMetaFacade::CUSTOM_TYPE) {
|
1176 |
+
$uploadsUrl = ShortPixelMetaFacade::getHomeUrl();
|
1177 |
+
$urlPath = ShortPixelMetaFacade::returnSubDir($meta->getPath());
|
1178 |
+
//$urlPath = implode("/", array_slice($filePath, 0, count($filePath) - 1));
|
1179 |
+
$thumb = $uploadsUrl . $urlPath . $thumb;
|
1180 |
+
} else {
|
1181 |
+
$mainUrl = ShortPixelMetaFacade::safeGetAttachmentUrl($itemHandler->getId());
|
1182 |
+
$thumb = dirname($mainUrl) . '/' . $thumb;
|
1183 |
+
}
|
1184 |
}
|
1185 |
}
|
1186 |
|
1299 |
|
1300 |
private function sendToProcessing($itemHandler, $compressionType = false, $onlyThumbs = false) {
|
1301 |
|
1302 |
+
//conversion of PNG 2 JPG for existing images
|
1303 |
if($itemHandler->getType() == ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE) { //currently only for ML
|
1304 |
$rawMeta = $this->checkConvertMediaPng2Jpg($itemHandler);
|
1305 |
|
1327 |
if(pathinfo($mainFile, PATHINFO_EXTENSION) !== pathinfo($size['file'], PATHINFO_EXTENSION)){
|
1328 |
continue;
|
1329 |
}
|
1330 |
+
if(isset($size['mime-type'])) { //situation from support case #9351 Ramesh Mehay
|
1331 |
+
$mimeType = $size['mime-type'];
|
1332 |
+
}
|
1333 |
if($size['file'] === ShortPixelAPI::MB_basename($found)) {
|
1334 |
$foundThumbs[$id] = false;
|
1335 |
}
|
1441 |
die(json_encode($ret));
|
1442 |
}
|
1443 |
|
1444 |
+
/**
|
1445 |
+
* To be called by thumbnail regeneration plugins before regenerating thumbnails for an image.
|
1446 |
+
* @param $postId
|
1447 |
+
*/
|
1448 |
+
public function thumbnailsBeforeRegenerateHook($postId) {
|
1449 |
+
$t = get_transient("wp-short-pixel-regenerating");
|
1450 |
+
if($t === false) $t = array();
|
1451 |
+
$t[$postId] = true;
|
1452 |
+
set_transient("wp-short-pixel-regenerating" . $t, true, 30);
|
1453 |
+
}
|
1454 |
+
|
1455 |
/**
|
1456 |
* to be called by thumbnail regeneration plugins when regenerating the thumbnails for an image
|
1457 |
* @param $postId - the postId of the image
|
1484 |
}
|
1485 |
//wp_update_attachment_metadata($postId, $meta);
|
1486 |
update_post_meta($postId, '_wp_attachment_metadata', $meta);
|
1487 |
+
$t = get_transient("wp-short-pixel-regenerating");
|
1488 |
+
if(is_array($t) && isset($t[$postId])) {
|
1489 |
+
unset($t[$postId]);
|
1490 |
+
set_transient("wp-short-pixel-regenerating" . $t, true, 30);
|
1491 |
+
}
|
1492 |
+
|
1493 |
if(!$bulk) {
|
1494 |
$this->prioQ->push($postId);
|
1495 |
}
|
1616 |
$baseRelPath = trailingslashit(dirname($image));
|
1617 |
$toReplace[ShortPixelPng2Jpg::removeUrlProtocol($imageUrl)] = $baseUrl . $baseRelPath . wp_basename($png2jpgMain);
|
1618 |
foreach($sizes as $key => $size) {
|
1619 |
+
if(isset($png2jpgSizes[$key])) {
|
1620 |
+
$toReplace[$baseUrl . $baseRelPath . $size['file']] = $baseUrl . $baseRelPath . wp_basename($png2jpgSizes[$key]['file']);
|
1621 |
+
}
|
1622 |
}
|
1623 |
$file = $png2jpgMain;
|
1624 |
$sizes = $png2jpgSizes;
|
1665 |
$this->throwNotice('generic-err', __("No backup files found. Restore not performed.",'shortpixel-image-optimiser'));
|
1666 |
return false;
|
1667 |
}
|
1668 |
+
//either backups exist, or there was an error when trying to optimize, so it's normal no backup is present
|
1669 |
try {
|
1670 |
$width = false;
|
1671 |
if($bkCount) { // backups, if exist
|
1704 |
if($png2jpgMain) {
|
1705 |
$crtMeta['file'] = trailingslashit(dirname($crtMeta['file'])) . ShortPixelAPI::MB_basename($file);
|
1706 |
update_attached_file($ID, $crtMeta['file']);
|
1707 |
+
if($png2jpgSizes && count($png2jpgSizes)) {
|
1708 |
$crtMeta['sizes'] = $png2jpgSizes;
|
1709 |
} else {
|
1710 |
//this was an image converted on upload, regenerate the thumbs using the PNG main image BUT deactivate temporarily the filter!!
|
1715 |
}
|
1716 |
//wp_update_attachment_metadata($ID, $crtMeta);
|
1717 |
update_post_meta($ID, '_wp_attachment_metadata', $crtMeta);
|
1718 |
+
if($attachmentID == $ID) { //copy back the metadata which will be returned.
|
1719 |
+
$rawMeta = $crtMeta;
|
1720 |
+
}
|
1721 |
}
|
|
|
|
|
|
|
1722 |
|
1723 |
if($png2jpgMain) {
|
1724 |
$spPng2Jpg = new ShortPixelPng2Jpg($this->_settings);
|
1869 |
$this->sendToProcessing(new ShortPixelMetaFacade($ID), false, true);
|
1870 |
$ret = array("Status" => ShortPixelAPI::STATUS_SUCCESS, "message" => "");
|
1871 |
} catch(Exception $e) { // Exception("Post metadata is corrupt (No attachment URL)") or Exception("Image files are missing.")
|
1872 |
+
if(!isset($meta['ShortPixelImprovement']) || !is_numeric($meta['ShortPixelImprovement'])) {
|
1873 |
+
$meta['ShortPixelImprovement'] = $e->getMessage();
|
1874 |
+
$meta['ShortPixel']['ErrCode'] = $e->getCode() < 0 ? $e->getCode() : ShortPixelAPI::STATUS_FAIL;
|
1875 |
+
unset($meta['ShortPixel']['WaitingProcessing']);
|
1876 |
+
//wp_update_attachment_metadata($ID, $meta);
|
1877 |
+
update_post_meta($ID, '_wp_attachment_metadata', $meta);
|
1878 |
+
}
|
1879 |
$ret = array("Status" => ShortPixelAPI::STATUS_FAIL, "Message" => $e->getMessage());
|
1880 |
}
|
1881 |
} else {
|
2462 |
}
|
2463 |
$_POST['key'] = SHORTPIXEL_API_KEY;
|
2464 |
}
|
2465 |
+
|
2466 |
+
if(isset($_GET['setsparchive'])) {
|
2467 |
+
$this->_settings->downloadArchive = intval($_GET['setsparchive']);
|
2468 |
+
}
|
2469 |
|
2470 |
//check all custom folders and update meta table if files appeared
|
2471 |
$customFolders = $this->refreshCustomFolders($notice, isset($_POST['removeFolder']) ? $_POST['removeFolder'] : null);
|
2900 |
if(!is_array($data)) {
|
2901 |
$data = unserialize($data);
|
2902 |
}
|
2903 |
+
//if($extended) {var_dump(wp_get_attachment_url($id)); echo(json_encode($data));}
|
2904 |
$fileExtension = strtolower(pathinfo($file, PATHINFO_EXTENSION));
|
2905 |
$invalidKey = !$this->_settings->verifiedKey;
|
2906 |
$quotaExceeded = $this->_settings->quotaExceeded;
|
3245 |
if(in_array($type, array("name", "path"))) {
|
3246 |
$pattern = trim($item["value"]);
|
3247 |
$target = $type == "name" ? ShortPixelAPI::MB_basename($path) : $path;
|
3248 |
+
if( self::matchExcludePattern($target, $pattern) ) { //search as a substring if not
|
|
|
3249 |
return false;
|
3250 |
}
|
3251 |
}
|
3255 |
return false;
|
3256 |
}
|
3257 |
}
|
3258 |
+
|
3259 |
static public function isProcessableSize($width, $height, $excludePattern) {
|
3260 |
$ranges = preg_split("/(x|×)/",$excludePattern);
|
3261 |
$widthBounds = explode("-", $ranges[0]);
|
3270 |
return true;
|
3271 |
}
|
3272 |
|
3273 |
+
static public function matchExcludePattern($target, $pattern) {
|
3274 |
+
return (
|
3275 |
+
$pattern[0] == '/' && @preg_match($pattern, false) !== false && preg_match($pattern, $target) //search as regex pattern if starts with a / and regex is valid
|
3276 |
+
|| $pattern[0] != '/' && strpos($target, $pattern) !== false ); //search as a substring if not
|
3277 |
+
}
|
3278 |
|
3279 |
//return an array with URL(s) and PATH(s) for this file
|
3280 |
public function getURLsAndPATHs($itemHandler, $meta = NULL, $onlyThumbs = false) {
|
3521 |
return $this->_settings->resizeHeight;
|
3522 |
}
|
3523 |
public static function getAffiliateSufix() {
|
3524 |
+
// not allowed anymore by WP as of Sept.27 2018
|
3525 |
// return isset($_COOKIE["AffiliateShortPixel"])
|
3526 |
// ? "/affiliate/" . $_COOKIE["AffiliateShortPixel"]
|
3527 |
// : (defined("SHORTPIXEL_AFFILIATE_CODE") && strlen(SHORTPIXEL_AFFILIATE_CODE) ? "/affiliate/" . SHORTPIXEL_AFFILIATE_CODE : "");
|
class/wp-shortpixel-cloudflare-api.php
CHANGED
@@ -142,6 +142,8 @@ class ShortPixelCloudFlareApi {
|
|
142 |
* @return array|mixed|object - Request response as decoded JSON
|
143 |
*/
|
144 |
private function delete_url_cache_request_action( $request_url = '', $parameters_as_json = '', $request_headers = array() ) {
|
|
|
|
|
145 |
$curl_connection = curl_init();
|
146 |
curl_setopt( $curl_connection, CURLOPT_URL, $request_url );
|
147 |
curl_setopt( $curl_connection, CURLOPT_CUSTOMREQUEST, "DELETE" );
|
142 |
* @return array|mixed|object - Request response as decoded JSON
|
143 |
*/
|
144 |
private function delete_url_cache_request_action( $request_url = '', $parameters_as_json = '', $request_headers = array() ) {
|
145 |
+
if(!function_exists('curl_init')) return false;
|
146 |
+
|
147 |
$curl_connection = curl_init();
|
148 |
curl_setopt( $curl_connection, CURLOPT_URL, $request_url );
|
149 |
curl_setopt( $curl_connection, CURLOPT_CUSTOMREQUEST, "DELETE" );
|
class/wp-shortpixel-settings.php
CHANGED
@@ -68,6 +68,8 @@ class WPShortPixelSettings {
|
|
68 |
'quotaExceeded' => array('key' => 'wp-short-pixel-quota-exceeded', 'default' => 0, 'group' => 'state'),
|
69 |
'httpProto' => array('key' => 'wp-short-pixel-protocol', 'default' => 'https', 'group' => 'state'),
|
70 |
'downloadProto' => array('key' => 'wp-short-pixel-download-protocol', 'default' => null, 'group' => 'state'),
|
|
|
|
|
71 |
'mediaAlert' => array('key' => 'wp-short-pixel-media-alert', 'default' => null, 'group' => 'state'),
|
72 |
'dismissedNotices' => array('key' => 'wp-short-pixel-dismissed-notices', 'default' => array(), 'group' => 'state'),
|
73 |
'activationDate' => array('key' => 'wp-short-pixel-activation-date', 'default' => null, 'group' => 'state'),
|
@@ -121,6 +123,10 @@ class WPShortPixelSettings {
|
|
121 |
foreach(self::$_optionsMap as $opt) {
|
122 |
self::getOpt($opt['key'], $opt['default']);
|
123 |
}
|
|
|
|
|
|
|
|
|
124 |
}
|
125 |
|
126 |
public static function debugResetOptions() {
|
68 |
'quotaExceeded' => array('key' => 'wp-short-pixel-quota-exceeded', 'default' => 0, 'group' => 'state'),
|
69 |
'httpProto' => array('key' => 'wp-short-pixel-protocol', 'default' => 'https', 'group' => 'state'),
|
70 |
'downloadProto' => array('key' => 'wp-short-pixel-download-protocol', 'default' => null, 'group' => 'state'),
|
71 |
+
//TODO downloadArchive initial sa fie 10% - hash pe numele de domeniu
|
72 |
+
'downloadArchive' => array('key' => 'wp-short-pixel-download-archive', 'default' => -1, 'group' => 'state'),
|
73 |
'mediaAlert' => array('key' => 'wp-short-pixel-media-alert', 'default' => null, 'group' => 'state'),
|
74 |
'dismissedNotices' => array('key' => 'wp-short-pixel-dismissed-notices', 'default' => array(), 'group' => 'state'),
|
75 |
'activationDate' => array('key' => 'wp-short-pixel-activation-date', 'default' => null, 'group' => 'state'),
|
123 |
foreach(self::$_optionsMap as $opt) {
|
124 |
self::getOpt($opt['key'], $opt['default']);
|
125 |
}
|
126 |
+
|
127 |
+
if(self::getOpt("downloadArchive") == -1) {
|
128 |
+
self::setOpt(self::$_optionsMap["downloadArchive"]['key'], crc32(get_site_url())%10);
|
129 |
+
}
|
130 |
}
|
131 |
|
132 |
public static function debugResetOptions() {
|
readme.txt
CHANGED
@@ -2,9 +2,9 @@
|
|
2 |
Contributors: ShortPixel
|
3 |
Tags: compressor, image, compression, optimize, image optimizer, image optimiser, image compression, resize, compress pdf, compress jpg, compress png, image compression
|
4 |
Requires at least: 3.2.0
|
5 |
-
Tested up to:
|
6 |
Requires PHP: 5.2
|
7 |
-
Stable tag: 4.
|
8 |
License: GPLv2 or later
|
9 |
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
10 |
|
@@ -63,7 +63,7 @@ Make an instant <a href="http://shortpixel.com/image-compression-test" target="_
|
|
63 |
* **free optimization credits for non-profits**, <a href="https://shortpixel.com/contact" target="_blank">contact us</a> for details
|
64 |
|
65 |
**How much does it cost?**
|
66 |
-
ShortPixel comes with 100 free credits/month and additional credits can be bought
|
67 |
Check out <a href="https://shortpixel.com/pricing" target="_blank">our prices</a>.
|
68 |
|
69 |
> **Testimonials:**
|
@@ -241,6 +241,22 @@ The ShortPixel Image Optimiser plugin calls the following actions and filters:
|
|
241 |
|
242 |
== Changelog ==
|
243 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
244 |
= 4.11.3 =
|
245 |
|
246 |
Release date: 27th September 2018
|
@@ -250,7 +266,7 @@ Release date: 27th September 2018
|
|
250 |
|
251 |
= 4.11.2 =
|
252 |
|
253 |
-
Release date:
|
254 |
|
255 |
* Fix "Image files are missing" warning when thumbails optimization is activated but all the thumbnails are excepted from optimization and the bulk is ran a second time.
|
256 |
* Fix not saving properly the metadata on some situations
|
2 |
Contributors: ShortPixel
|
3 |
Tags: compressor, image, compression, optimize, image optimizer, image optimiser, image compression, resize, compress pdf, compress jpg, compress png, image compression
|
4 |
Requires at least: 3.2.0
|
5 |
+
Tested up to: 5.0
|
6 |
Requires PHP: 5.2
|
7 |
+
Stable tag: 4.12.0
|
8 |
License: GPLv2 or later
|
9 |
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
10 |
|
63 |
* **free optimization credits for non-profits**, <a href="https://shortpixel.com/contact" target="_blank">contact us</a> for details
|
64 |
|
65 |
**How much does it cost?**
|
66 |
+
ShortPixel comes with 100 free credits/month and additional credits can be bought for as little as $4.99 for 5,000 image credits.
|
67 |
Check out <a href="https://shortpixel.com/pricing" target="_blank">our prices</a>.
|
68 |
|
69 |
> **Testimonials:**
|
241 |
|
242 |
== Changelog ==
|
243 |
|
244 |
+
= 4.12.0 =
|
245 |
+
|
246 |
+
Release date: 31st October 2018
|
247 |
+
|
248 |
+
* Generate WebP <picture> tags - use the output buffer instead of the_content which is not triggered by some themes on all content.
|
249 |
+
* compatibility of the WebP <picture> tag with lazy loading plugins (that support <picture>)
|
250 |
+
* Compatibility with Polylang.
|
251 |
+
* hooks to be used by thumbnail regeneration plugins: 'shortpixel-thumbnails-before-regenerate' and 'shortpixel-thumbnails-regenerated'
|
252 |
+
* Proper error message when the custom tables cannot be created.
|
253 |
+
* exclude the PNGs from conversion to JPEG when they match the exclude patterns.
|
254 |
+
* properly warn when cURL is not enabled that Cloudflare integration won't work.
|
255 |
+
* send only one url for metadata thumbnails which correspond to the same physical file.
|
256 |
+
* JavaScript delayed init for cases when some plugins deffer the load of javascript files.
|
257 |
+
* fix identifying filenames with basename length == 3 as retina
|
258 |
+
* display improvements for the bulk errors list
|
259 |
+
|
260 |
= 4.11.3 =
|
261 |
|
262 |
Release date: 27th September 2018
|
266 |
|
267 |
= 4.11.2 =
|
268 |
|
269 |
+
Release date: 30th August 2018
|
270 |
|
271 |
* Fix "Image files are missing" warning when thumbails optimization is activated but all the thumbnails are excepted from optimization and the bulk is ran a second time.
|
272 |
* Fix not saving properly the metadata on some situations
|
res/css/short-pixel.css
CHANGED
@@ -81,6 +81,9 @@ div.fb-like {
|
|
81 |
.sp-notice-success {
|
82 |
border-left-color: #46b450;
|
83 |
}
|
|
|
|
|
|
|
84 |
li.sp-conflict-plugins-list {
|
85 |
line-height: 28px;
|
86 |
list-style: disc;
|
@@ -161,6 +164,24 @@ div.sp-bulk-summary {
|
|
161 |
float:right;
|
162 |
margin:8px 5px 3px 20px;
|
163 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
164 |
input.dial {
|
165 |
box-shadow: none;
|
166 |
}
|
@@ -442,13 +463,14 @@ th.sorted.column-wp-shortPixel a {
|
|
442 |
width: 80px;
|
443 |
text-align: right;
|
444 |
}
|
445 |
-
.progress {
|
446 |
background-color: #ecedee;
|
447 |
height: 30px;
|
448 |
position: relative;
|
449 |
width: 60%;
|
450 |
display: inline-block;
|
451 |
margin-right: 28px;
|
|
|
452 |
}
|
453 |
.progress .progress-img {
|
454 |
position: absolute;
|
81 |
.sp-notice-success {
|
82 |
border-left-color: #46b450;
|
83 |
}
|
84 |
+
.sp-notice-warning {
|
85 |
+
border-left-color: #f1e02a;
|
86 |
+
}
|
87 |
li.sp-conflict-plugins-list {
|
88 |
line-height: 28px;
|
89 |
list-style: disc;
|
164 |
float:right;
|
165 |
margin:8px 5px 3px 20px;
|
166 |
}
|
167 |
+
.sp-notice .bulk-error-show {
|
168 |
+
cursor: pointer;
|
169 |
+
}
|
170 |
+
.sp-notice div.bulk-error-list {
|
171 |
+
background-color: #f1f1f1;
|
172 |
+
padding: 0 10px;
|
173 |
+
display: none;
|
174 |
+
max-height: 200px;
|
175 |
+
overflow-y: scroll;
|
176 |
+
}
|
177 |
+
.sp-notice div.bulk-error-list ul {
|
178 |
+
padding: 3px 0 0;
|
179 |
+
margin-top: 5px;
|
180 |
+
}
|
181 |
+
.sp-notice div.bulk-error-list ul > li:not(:last-child) {
|
182 |
+
border-bottom: 1px solid white;
|
183 |
+
padding-bottom: 4px;
|
184 |
+
}
|
185 |
input.dial {
|
186 |
box-shadow: none;
|
187 |
}
|
463 |
width: 80px;
|
464 |
text-align: right;
|
465 |
}
|
466 |
+
.short-pixel-bulk-page .progress {
|
467 |
background-color: #ecedee;
|
468 |
height: 30px;
|
469 |
position: relative;
|
470 |
width: 60%;
|
471 |
display: inline-block;
|
472 |
margin-right: 28px;
|
473 |
+
overflow: visible;
|
474 |
}
|
475 |
.progress .progress-img {
|
476 |
position: absolute;
|
res/css/short-pixel.min.css
CHANGED
@@ -1 +1 @@
|
|
1 |
-
.sp-dropbtn.button{padding:1px 24px 20px 5px;font-size:20px;cursor:pointer}.sp-dropdown{position:relative;display:inline-block}.sp-dropdown-content{display:none;right:0;position:absolute;background-color:#f9f9f9;min-width:190px;box-shadow:0 8px 16px 0 rgba(0,0,0,0.2);z-index:1}.sp-dropdown-content a{color:black;padding:12px 16px;text-decoration:none;display:block}.sp-dropdown-content a:hover{background-color:#f1f1f1}.sp-dropdown.sp-show .sp-dropdown-content{display:block}div.fb-like{transform:scale(1.3);-ms-transform:scale(1.3);-webkit-transform:scale(1.3);-o-transform:scale(1.3);-moz-transform:scale(1.3);transform-origin:bottom left;-ms-transform-origin:bottom left;-webkit-transform-origin:bottom left;-moz-transform-origin:bottom left;-webkit-transform-origin:bottom left}.wp-core-ui .button.button-alert,.wp-core-ui .button.button-alert:hover{background:#f79797}.wp-core-ui .button.remove-folder-button{min-width:120px}.sp-notice{background:#fff;border-left:4px solid #fff;-webkit-box-shadow:0 1px 1px 0 rgba(0,0,0,.1);box-shadow:0 1px 1px 0 rgba(0,0,0,.1);padding:1px 12px}@media(max-width:1249px){.sp-notice{margin:5px 15px 2px}}.sp-notice-info{border-left-color:#00a0d2}.sp-notice-success{border-left-color:#46b450}li.sp-conflict-plugins-list{line-height:28px;list-style:disc;margin-left:80px}li.sp-conflict-plugins-list a.button{margin-left:10px}div.short-pixel-bulk-page input.dial{font-size:16px !important}div.short-pixel-bulk-page h1{margin-bottom:20px}div.bulk-progress div.sp-h2{margin-top:0;margin-bottom:10px;font-size:23px;font-weight:400;padding:9px 15px 4px 0;line-height:29px}div.bulk-progress-partners{margin-top:20px}div.bulk-progress.bulk-progress-partners a div{display:inline-block;vertical-align:top;line-height:50px;margin-left:30px;font-size:1.2em}div.bulk-progress .bulk-progress-indicator,div.sp-quota-exceeded-alert .bulk-progress-indicator{display:inline-block;text-align:center;padding:0 10px;margin-left:10px;float:left;height:90px;overflow:hidden;border:1px solid #1caecb}div.wrap.short-pixel-bulk-page .bulk-notice-container{margin-top:15px;position:absolute;width:500px}div.wrap.short-pixel-bulk-page .bulk-notice-container .bulk-notice-msg{text-align:center;margin:10px 0 0 32px;overflow:hidden;border:1px solid #1caecb;background-color:#9ddbe0;border-radius:5px;padding:7px 10px 10px;display:none;max-width:600px;margin-right:20px}div.wrap.short-pixel-bulk-page .bulk-notice-container .bulk-notice-msg.bulk-error{border:1px solid #b5914d;background-color:#ffe996;margin-right:20px;position:relative;z-index:10}div.wrap.short-pixel-bulk-page .bulk-notice-container .bulk-notice-msg.bulk-error.bulk-error-fatal{border:1px solid #c32525;background-color:#ff969d}div.wrap.short-pixel-bulk-page .bulk-notice-msg img{float:left;margin-top:3px;margin-right:5px}div.sp-bulk-summary{float:right;margin:8px 5px 3px 20px}input.dial{box-shadow:none}.shortpixel-table .column-filename{max-width:32em;width:40%}.shortpixel-table .column-folder{max-width:20em;width:20%}.shortpixel-table .column-media_type{max-width:8em;width:10%}.shortpixel-table .column-status{max-width:16em;width:15%}.shortpixel-table .column-options{max-width:16em;width:15%}.form-table table.shortpixel-folders-list tr{background-color:#eee}.form-table table.shortpixel-folders-list td{padding:5px 10px}div.shortpixel-rate-us{display:inline-block;margin-left:10px;vertical-align:top;font-weight:bold}div.shortpixel-rate-us>a{vertical-align:middle;padding:1px 5px 0;text-align:center;display:inline-block}div.shortpixel-rate-us>a>span{display:inline-block;vertical-align:top;margin-top:5px}div.shortpixel-rate-us>a>img{padding-top:7px}div.shortpixel-rate-us>a:active,div.shortpixel-rate-us>a:hover,div.shortpixel-rate-us>a:focus{outline:0;border-style:none}.sp-loading-small{margin-top:2px;float:left;margin-right:5px}li.shortpixel-toolbar-processing>a.ab-item>div,#wpadminbar li.shortpixel-toolbar-processing>a.ab-item>div{height:33px;margin-top:-1px;padding:0 3px}li.shortpixel-toolbar-processing>a.ab-item>div>img,#wpadminbar li.shortpixel-toolbar-processing>a.ab-item>div>img{margin-right:2px;margin-top:6px}li.shortpixel-toolbar-processing>a.ab-item>div>span.shp-alert,#wpadminbar li.shortpixel-toolbar-processing>a.ab-item>div>span.shp-alert{display:none}li.shortpixel-toolbar-processing.shortpixel-alert>a.ab-item>div>span.shp-alert,#wpadminbar li.shortpixel-toolbar-processing.shortpixel-alert>a.ab-item>div>span.shp-alert{display:inline;font-size:26px;color:red;font-weight:bold;vertical-align:top}li.shortpixel-toolbar-processing.shortpixel-alert>a.ab-item>div,#wpadminbar li.shortpixel-toolbar-processing.shortpixel-alert>a.ab-item>div{background-image:none}.sp-quota-exceeded-alert{background-color:#fff;border-left:4px solid red;box-shadow:0 1px 1px 0 rgba(0,0,0,0.1);padding:1px 12px}.shortpixel-clearfix{width:100%;float:left}div.sp-modal-shade{display:none;position:fixed;z-index:10;left:0;top:0;width:100%;height:100%;overflow:auto;background-color:#000;background-color:rgba(0,0,0,0.4)}div.shortpixel-modal{background-color:#fefefe;margin:8% auto;padding:20px;border:1px solid #888;width:30%;min-width:300px}div.shortpixel-modal .sp-close-button,div.shortpixel-modal .sp-close-upgrade-button{float:right;margin-top:0;background:transparent;border:0;font-size:22px;line-height:10px;cursor:pointer}.twentytwenty-horizontal .twentytwenty-before-label:before,.twentytwenty-horizontal .twentytwenty-after-label:before{font-family:inherit;font-size:16px}div.sp-modal-title{font-size:22px}div.sp-modal-body{margin-top:20px}.short-pixel-bulk-page p{margin:.6em 0}div.shortpixel-modal .sptw-modal-spinner{background-image:url("../img/spinner2.gif");background-repeat:no-repeat;background-position:center}.short-pixel-bulk-page form.start{display:table;content:" ";width:98%;background-color:white;padding:10px 10px 0;position:relative}.bulk-stats-container{display:inline-block;min-width:450px;width:45%;float:left;padding-right:50px;font-size:1.1em;line-height:1.5em}.bulk-text-container{display:inline-block;min-width:440px;width:45%;float:left;padding-right:50px}.bulk-text-container h3{border-bottom:1px solid #a8a8a8;margin-bottom:.5em;padding-bottom:.5em}.bulk-wide{display:inline-block;width:90%;float:left;margin-top:25px}.bulk-stats-container .bulk-label{width:220px;display:inline-block}.bulk-stats-container .bulk-val{width:50px;display:inline-block;text-align:right}.bulk-stats-container .bulk-total{font-weight:bold;margin-top:10px;margin-bottom:10px}.wp-core-ui .bulk-play{display:inline;width:310px;float:left;margin-bottom:20px}.wp-core-ui .bulk-play.bulk-nothing-optimize{font-weight:bold;color:#0080b2;border:1px solid;border-radius:5px;margin-top:60px;padding:5px 12px}.wp-core-ui .bulk-play a.button{height:60px;margin-top:27px;width:290px;overflow:hidden}.wp-core-ui .column-wp-shortPixel .sp-column-actions{max-width:140px;float:right;text-align:right}.wp-core-ui .column-wp-shortPixel .sp-column-actions .button.button-smaller{margin-right:0}.wp-core-ui .column-wp-shortPixel .button.button-smaller{font-size:13px;padding:0 5px;margin-bottom:4px;height:20px;line-height:16px;float:right}th.sortable.column-wp-shortPixel a,th.sorted.column-wp-shortPixel a{display:inline-block}.column-wp-shortPixel .sorting-indicator{display:inline-block}.wp-core-ui .bulk-play a.button .bulk-btn-img{float:left;display:inline-block;padding-top:6px}.wp-core-ui .bulk-play a.button .bulk-btn-txt{float:left;display:inline-block;text-align:right;line-height:1.3em;margin:11px 10px}.wp-core-ui .bulk-play a.button .bulk-btn-txt span.label{font-size:1.6em}.wp-core-ui .bulk-play a.button .bulk-btn-txt span.total{font-size:1.4em}.short-pixel-notice-icon{float:left;margin:10px 10px 10px 0}.bulk-progress{padding:20px 32px 17px;background-color:#fff}.bulk-progress.bulk-stats>div{display:inline-block}.bulk-progress.bulk-stats>div.label{width:320px}.bulk-progress.bulk-stats>div.stat-value{width:80px;text-align:right}.progress{background-color:#ecedee;height:30px;position:relative;width:60%;display:inline-block;margin-right:28px}.progress .progress-img{position:absolute;top:-10px;z-index:2;margin-left:-35px;line-height:48px;font-size:22px;font-weight:bold}.progress .progress-img span{vertical-align:top;margin-left:-7px}.progress .progress-left{background-color:#1cbecb;bottom:0;left:0;position:absolute;top:0;z-index:1;font-size:22px;font-weight:bold;line-height:28px;text-align:center;color:#fff}.bulk-estimate{font-size:20px;line-height:30px;vertical-align:top;display:inline-block}.wp-core-ui .button-primary.bulk-cancel{float:right;height:30px}.short-pixel-block-title{font-size:22px;font-weight:bold;margin-bottom:15px;text-align:center;margin-bottom:30px}.sp-floating-block.bulk-slider-container{display:none}.sp-floating-block.sp-notice.bulk-notices-parent{padding:0;margin:0;float:right;margin-right:500px !important}.bulk-slider-container{margin-top:20px;min-height:300px;overflow:hidden}.bulk-slider-container h2{margin-bottom:15px}.bulk-slider-container span.filename{font-weight:normal}.bulk-slider{display:table;margin:0 auto}.bulk-slider .bulk-slide{margin:0 auto;padding-left:120px;display:inline-block;font-weight:bold}.bulk-slider .img-original,.bulk-slider .img-optimized{display:inline-block;margin-right:20px;text-align:center}.bulk-slider .img-original div,.bulk-slider .img-optimized div{max-height:450px;overflow:hidden}.bulk-slider .img-original img,.bulk-slider .img-optimized img{max-width:300px}.bulk-slider .img-info{display:inline-block;vertical-align:top;font-size:48px;max-width:150px;padding:10px 0 0 20px}.bulk-slide-images{display:inline-block;border:1px solid #1caecb;padding:15px 0 0 20px}p.settings-info{padding-top:0;color:#818181;font-size:13px !important}p.settings-info.shortpixel-settings-error{color:#c32525}.shortpixel-key-valid{font-weight:bold}.shortpixel-key-valid .dashicons-yes:before{font-size:2em;line-height:25px;color:#3485ba;margin-left:-20px}.shortpixel-compression .shortpixel-compression-options{color:#999}.shortpixel-compression strong{line-height:22px}.shortpixel-compression .shortpixel-compression-options{display:inline-block}.shortpixel-compression label{width:158px;margin:0 -2px;background-color:#e2faff;font-weight:bold;display:inline-block}.shortpixel-compression label span{text-align:center;font-size:18px;padding:8px 0;display:block}.shortpixel-compression label input{display:none}.shortpixel-compression input:checked+span{background-color:#0085ba;color:#f7f7f7}.shortpixel-compression .shortpixel-radio-info{min-height:60px}article.sp-tabs{position:relative;display:block;width:100%;height:1100px;margin:2em auto}article.sp-tabs section{position:absolute;display:block;top:1.8em;left:0;height:1100px;width:94%;padding:10px 20px;background-color:#ddd;box-shadow:0 3px 3px rgba(0,0,0,0.1);z-index:0}article.sp-tabs section:first-child{z-index:1}article.sp-tabs section h2{position:absolute;font-size:1.3em;font-weight:normal;width:180px;height:1.8em;top:-1.8em;left:10px;padding:0;margin:0;color:#999;background-color:#ddd}article.sp-tabs section:nth-child(2) h2{left:192px}article.sp-tabs section:nth-child(3) h2{left:374px}article.sp-tabs section:nth-child(4) h2{left:556px}article.sp-tabs section:nth-child(5) h2{left:738px}article.sp-tabs section h2 a{display:block;width:100%;line-height:1.8em;text-align:center;text-decoration:none;color:#23282d;outline:0 none}article.sp-tabs section h2 a:focus,article.sp-tabs section#tab-resources a:focus{box-shadow:none;outline:0}article.sp-tabs section.sel-tab,article.sp-tabs section.sel-tab h2{color:#333;background-color:#fff;z-index:2}.shortpixel-help-link span.dashicons{text-decoration:none;margin-top:-1px}@media(min-width:1000px){section#tab-resources .col-md-6{display:inline-block;width:45%}}@media(max-width:999px){section#tab-resources .col-sm-12{display:inline-block;width:100%}}section#tab-resources .text-center{text-align:center}section#tab-resources p{font-size:16px}.wrap.short-pixel-bulk-page{margin-right:0}.sp-container{overflow:hidden;display:block;width:100%}.sp-floating-block{overflow:hidden;display:inline-block;float:left;margin-right:1.1% !important}.sp-full-width{width:98.8%;box-sizing:border-box}.sp-double-width{width:65.52%;box-sizing:border-box}.sp-single-width{width:32.23%;box-sizing:border-box}@media(max-width:1759px){.sp-floating-block{margin-right:1.3% !important}.sp-double-width,.sp-full-width{width:98.65%}.sp-single-width{width:48.7%}}@media(max-width:1249px){.sp-floating-block{margin-right:2% !important}.sp-double-width,.sp-full-width,.sp-single-width{width:97%}}.sp-tabs h2:before{content:none}#wpadminbar .shortpixel-toolbar-processing .cssload-container{width:100%;height:24px;text-align:center;position:absolute;top:0;left:-1px}#wpadminbar .shortpixel-toolbar-processing.shortpixel-quota-exceeded .cssload-container,#wpadminbar .shortpixel-toolbar-processing.shortpixel-alert .cssload-container{display:none}#wpadminbar .shortpixel-toolbar-processing .cssload-speeding-wheel{width:24px;height:24px;opacity:.7;margin:0 auto;border:4px solid #1cbfcb;border-radius:50%;border-left-color:transparent;animation:cssload-spin 2000ms infinite linear;-o-animation:cssload-spin 2000ms infinite linear;-ms-animation:cssload-spin 2000ms infinite linear;-webkit-animation:cssload-spin 2000ms infinite linear;-moz-animation:cssload-spin 2000ms infinite linear}@keyframes cssload-spin{100%{transform:rotate(360deg);transform:rotate(360deg)}}@-o-keyframes cssload-spin{100%{-o-transform:rotate(360deg);transform:rotate(360deg)}}@-ms-keyframes cssload-spin{100%{-ms-transform:rotate(360deg);transform:rotate(360deg)}}@-webkit-keyframes cssload-spin{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@-moz-keyframes cssload-spin{100%{-moz-transform:rotate(360deg);transform:rotate(360deg)}}
|
1 |
+
.sp-dropbtn.button{padding:1px 24px 20px 5px;font-size:20px;cursor:pointer}.sp-dropdown{position:relative;display:inline-block}.sp-dropdown-content{display:none;right:0;position:absolute;background-color:#f9f9f9;min-width:190px;box-shadow:0 8px 16px 0 rgba(0,0,0,0.2);z-index:1}.sp-dropdown-content a{color:black;padding:12px 16px;text-decoration:none;display:block}.sp-dropdown-content a:hover{background-color:#f1f1f1}.sp-dropdown.sp-show .sp-dropdown-content{display:block}div.fb-like{transform:scale(1.3);-ms-transform:scale(1.3);-webkit-transform:scale(1.3);-o-transform:scale(1.3);-moz-transform:scale(1.3);transform-origin:bottom left;-ms-transform-origin:bottom left;-webkit-transform-origin:bottom left;-moz-transform-origin:bottom left;-webkit-transform-origin:bottom left}.wp-core-ui .button.button-alert,.wp-core-ui .button.button-alert:hover{background:#f79797}.wp-core-ui .button.remove-folder-button{min-width:120px}.sp-notice{background:#fff;border-left:4px solid #fff;-webkit-box-shadow:0 1px 1px 0 rgba(0,0,0,.1);box-shadow:0 1px 1px 0 rgba(0,0,0,.1);padding:1px 12px}@media(max-width:1249px){.sp-notice{margin:5px 15px 2px}}.sp-notice-info{border-left-color:#00a0d2}.sp-notice-success{border-left-color:#46b450}.sp-notice-warning{border-left-color:#f1e02a}li.sp-conflict-plugins-list{line-height:28px;list-style:disc;margin-left:80px}li.sp-conflict-plugins-list a.button{margin-left:10px}div.short-pixel-bulk-page input.dial{font-size:16px !important}div.short-pixel-bulk-page h1{margin-bottom:20px}div.bulk-progress div.sp-h2{margin-top:0;margin-bottom:10px;font-size:23px;font-weight:400;padding:9px 15px 4px 0;line-height:29px}div.bulk-progress-partners{margin-top:20px}div.bulk-progress.bulk-progress-partners a div{display:inline-block;vertical-align:top;line-height:50px;margin-left:30px;font-size:1.2em}div.bulk-progress .bulk-progress-indicator,div.sp-quota-exceeded-alert .bulk-progress-indicator{display:inline-block;text-align:center;padding:0 10px;margin-left:10px;float:left;height:90px;overflow:hidden;border:1px solid #1caecb}div.wrap.short-pixel-bulk-page .bulk-notice-container{margin-top:15px;position:absolute;width:500px}div.wrap.short-pixel-bulk-page .bulk-notice-container .bulk-notice-msg{text-align:center;margin:10px 0 0 32px;overflow:hidden;border:1px solid #1caecb;background-color:#9ddbe0;border-radius:5px;padding:7px 10px 10px;display:none;max-width:600px;margin-right:20px}div.wrap.short-pixel-bulk-page .bulk-notice-container .bulk-notice-msg.bulk-error{border:1px solid #b5914d;background-color:#ffe996;margin-right:20px;position:relative;z-index:10}div.wrap.short-pixel-bulk-page .bulk-notice-container .bulk-notice-msg.bulk-error.bulk-error-fatal{border:1px solid #c32525;background-color:#ff969d}div.wrap.short-pixel-bulk-page .bulk-notice-msg img{float:left;margin-top:3px;margin-right:5px}div.sp-bulk-summary{float:right;margin:8px 5px 3px 20px}.sp-notice .bulk-error-show{cursor:pointer}.sp-notice div.bulk-error-list{background-color:#f1f1f1;padding:0 10px;display:none;max-height:200px;overflow-y:scroll}.sp-notice div.bulk-error-list ul{padding:3px 0 0;margin-top:5px}.sp-notice div.bulk-error-list ul>li:not(:last-child){border-bottom:1px solid white;padding-bottom:4px}input.dial{box-shadow:none}.shortpixel-table .column-filename{max-width:32em;width:40%}.shortpixel-table .column-folder{max-width:20em;width:20%}.shortpixel-table .column-media_type{max-width:8em;width:10%}.shortpixel-table .column-status{max-width:16em;width:15%}.shortpixel-table .column-options{max-width:16em;width:15%}.form-table table.shortpixel-folders-list tr{background-color:#eee}.form-table table.shortpixel-folders-list td{padding:5px 10px}div.shortpixel-rate-us{display:inline-block;margin-left:10px;vertical-align:top;font-weight:bold}div.shortpixel-rate-us>a{vertical-align:middle;padding:1px 5px 0;text-align:center;display:inline-block}div.shortpixel-rate-us>a>span{display:inline-block;vertical-align:top;margin-top:5px}div.shortpixel-rate-us>a>img{padding-top:7px}div.shortpixel-rate-us>a:active,div.shortpixel-rate-us>a:hover,div.shortpixel-rate-us>a:focus{outline:0;border-style:none}.sp-loading-small{margin-top:2px;float:left;margin-right:5px}li.shortpixel-toolbar-processing>a.ab-item>div,#wpadminbar li.shortpixel-toolbar-processing>a.ab-item>div{height:33px;margin-top:-1px;padding:0 3px}li.shortpixel-toolbar-processing>a.ab-item>div>img,#wpadminbar li.shortpixel-toolbar-processing>a.ab-item>div>img{margin-right:2px;margin-top:6px}li.shortpixel-toolbar-processing>a.ab-item>div>span.shp-alert,#wpadminbar li.shortpixel-toolbar-processing>a.ab-item>div>span.shp-alert{display:none}li.shortpixel-toolbar-processing.shortpixel-alert>a.ab-item>div>span.shp-alert,#wpadminbar li.shortpixel-toolbar-processing.shortpixel-alert>a.ab-item>div>span.shp-alert{display:inline;font-size:26px;color:red;font-weight:bold;vertical-align:top}li.shortpixel-toolbar-processing.shortpixel-alert>a.ab-item>div,#wpadminbar li.shortpixel-toolbar-processing.shortpixel-alert>a.ab-item>div{background-image:none}.sp-quota-exceeded-alert{background-color:#fff;border-left:4px solid red;box-shadow:0 1px 1px 0 rgba(0,0,0,0.1);padding:1px 12px}.shortpixel-clearfix{width:100%;float:left}div.sp-modal-shade{display:none;position:fixed;z-index:10;left:0;top:0;width:100%;height:100%;overflow:auto;background-color:#000;background-color:rgba(0,0,0,0.4)}div.shortpixel-modal{background-color:#fefefe;margin:8% auto;padding:20px;border:1px solid #888;width:30%;min-width:300px}div.shortpixel-modal .sp-close-button,div.shortpixel-modal .sp-close-upgrade-button{float:right;margin-top:0;background:transparent;border:0;font-size:22px;line-height:10px;cursor:pointer}.twentytwenty-horizontal .twentytwenty-before-label:before,.twentytwenty-horizontal .twentytwenty-after-label:before{font-family:inherit;font-size:16px}div.sp-modal-title{font-size:22px}div.sp-modal-body{margin-top:20px}.short-pixel-bulk-page p{margin:.6em 0}div.shortpixel-modal .sptw-modal-spinner{background-image:url("../img/spinner2.gif");background-repeat:no-repeat;background-position:center}.short-pixel-bulk-page form.start{display:table;content:" ";width:98%;background-color:white;padding:10px 10px 0;position:relative}.bulk-stats-container{display:inline-block;min-width:450px;width:45%;float:left;padding-right:50px;font-size:1.1em;line-height:1.5em}.bulk-text-container{display:inline-block;min-width:440px;width:45%;float:left;padding-right:50px}.bulk-text-container h3{border-bottom:1px solid #a8a8a8;margin-bottom:.5em;padding-bottom:.5em}.bulk-wide{display:inline-block;width:90%;float:left;margin-top:25px}.bulk-stats-container .bulk-label{width:220px;display:inline-block}.bulk-stats-container .bulk-val{width:50px;display:inline-block;text-align:right}.bulk-stats-container .bulk-total{font-weight:bold;margin-top:10px;margin-bottom:10px}.wp-core-ui .bulk-play{display:inline;width:310px;float:left;margin-bottom:20px}.wp-core-ui .bulk-play.bulk-nothing-optimize{font-weight:bold;color:#0080b2;border:1px solid;border-radius:5px;margin-top:60px;padding:5px 12px}.wp-core-ui .bulk-play a.button{height:60px;margin-top:27px;width:290px;overflow:hidden}.wp-core-ui .column-wp-shortPixel .sp-column-actions{max-width:140px;float:right;text-align:right}.wp-core-ui .column-wp-shortPixel .sp-column-actions .button.button-smaller{margin-right:0}.wp-core-ui .column-wp-shortPixel .button.button-smaller{font-size:13px;padding:0 5px;margin-bottom:4px;height:20px;line-height:16px;float:right}th.sortable.column-wp-shortPixel a,th.sorted.column-wp-shortPixel a{display:inline-block}.column-wp-shortPixel .sorting-indicator{display:inline-block}.wp-core-ui .bulk-play a.button .bulk-btn-img{float:left;display:inline-block;padding-top:6px}.wp-core-ui .bulk-play a.button .bulk-btn-txt{float:left;display:inline-block;text-align:right;line-height:1.3em;margin:11px 10px}.wp-core-ui .bulk-play a.button .bulk-btn-txt span.label{font-size:1.6em}.wp-core-ui .bulk-play a.button .bulk-btn-txt span.total{font-size:1.4em}.short-pixel-notice-icon{float:left;margin:10px 10px 10px 0}.bulk-progress{padding:20px 32px 17px;background-color:#fff}.bulk-progress.bulk-stats>div{display:inline-block}.bulk-progress.bulk-stats>div.label{width:320px}.bulk-progress.bulk-stats>div.stat-value{width:80px;text-align:right}.short-pixel-bulk-page .progress{background-color:#ecedee;height:30px;position:relative;width:60%;display:inline-block;margin-right:28px;overflow:visible}.progress .progress-img{position:absolute;top:-10px;z-index:2;margin-left:-35px;line-height:48px;font-size:22px;font-weight:bold}.progress .progress-img span{vertical-align:top;margin-left:-7px}.progress .progress-left{background-color:#1cbecb;bottom:0;left:0;position:absolute;top:0;z-index:1;font-size:22px;font-weight:bold;line-height:28px;text-align:center;color:#fff}.bulk-estimate{font-size:20px;line-height:30px;vertical-align:top;display:inline-block}.wp-core-ui .button-primary.bulk-cancel{float:right;height:30px}.short-pixel-block-title{font-size:22px;font-weight:bold;margin-bottom:15px;text-align:center;margin-bottom:30px}.sp-floating-block.bulk-slider-container{display:none}.sp-floating-block.sp-notice.bulk-notices-parent{padding:0;margin:0;float:right;margin-right:500px !important}.bulk-slider-container{margin-top:20px;min-height:300px;overflow:hidden}.bulk-slider-container h2{margin-bottom:15px}.bulk-slider-container span.filename{font-weight:normal}.bulk-slider{display:table;margin:0 auto}.bulk-slider .bulk-slide{margin:0 auto;padding-left:120px;display:inline-block;font-weight:bold}.bulk-slider .img-original,.bulk-slider .img-optimized{display:inline-block;margin-right:20px;text-align:center}.bulk-slider .img-original div,.bulk-slider .img-optimized div{max-height:450px;overflow:hidden}.bulk-slider .img-original img,.bulk-slider .img-optimized img{max-width:300px}.bulk-slider .img-info{display:inline-block;vertical-align:top;font-size:48px;max-width:150px;padding:10px 0 0 20px}.bulk-slide-images{display:inline-block;border:1px solid #1caecb;padding:15px 0 0 20px}p.settings-info{padding-top:0;color:#818181;font-size:13px !important}p.settings-info.shortpixel-settings-error{color:#c32525}.shortpixel-key-valid{font-weight:bold}.shortpixel-key-valid .dashicons-yes:before{font-size:2em;line-height:25px;color:#3485ba;margin-left:-20px}.shortpixel-compression .shortpixel-compression-options{color:#999}.shortpixel-compression strong{line-height:22px}.shortpixel-compression .shortpixel-compression-options{display:inline-block}.shortpixel-compression label{width:158px;margin:0 -2px;background-color:#e2faff;font-weight:bold;display:inline-block}.shortpixel-compression label span{text-align:center;font-size:18px;padding:8px 0;display:block}.shortpixel-compression label input{display:none}.shortpixel-compression input:checked+span{background-color:#0085ba;color:#f7f7f7}.shortpixel-compression .shortpixel-radio-info{min-height:60px}article.sp-tabs{position:relative;display:block;width:100%;height:1100px;margin:2em auto}article.sp-tabs section{position:absolute;display:block;top:1.8em;left:0;height:1100px;width:94%;padding:10px 20px;background-color:#ddd;box-shadow:0 3px 3px rgba(0,0,0,0.1);z-index:0}article.sp-tabs section:first-child{z-index:1}article.sp-tabs section h2{position:absolute;font-size:1.3em;font-weight:normal;width:180px;height:1.8em;top:-1.8em;left:10px;padding:0;margin:0;color:#999;background-color:#ddd}article.sp-tabs section:nth-child(2) h2{left:192px}article.sp-tabs section:nth-child(3) h2{left:374px}article.sp-tabs section:nth-child(4) h2{left:556px}article.sp-tabs section:nth-child(5) h2{left:738px}article.sp-tabs section h2 a{display:block;width:100%;line-height:1.8em;text-align:center;text-decoration:none;color:#23282d;outline:0 none}article.sp-tabs section h2 a:focus,article.sp-tabs section#tab-resources a:focus{box-shadow:none;outline:0}article.sp-tabs section.sel-tab,article.sp-tabs section.sel-tab h2{color:#333;background-color:#fff;z-index:2}.shortpixel-help-link span.dashicons{text-decoration:none;margin-top:-1px}@media(min-width:1000px){section#tab-resources .col-md-6{display:inline-block;width:45%}}@media(max-width:999px){section#tab-resources .col-sm-12{display:inline-block;width:100%}}section#tab-resources .text-center{text-align:center}section#tab-resources p{font-size:16px}.wrap.short-pixel-bulk-page{margin-right:0}.sp-container{overflow:hidden;display:block;width:100%}.sp-floating-block{overflow:hidden;display:inline-block;float:left;margin-right:1.1% !important}.sp-full-width{width:98.8%;box-sizing:border-box}.sp-double-width{width:65.52%;box-sizing:border-box}.sp-single-width{width:32.23%;box-sizing:border-box}@media(max-width:1759px){.sp-floating-block{margin-right:1.3% !important}.sp-double-width,.sp-full-width{width:98.65%}.sp-single-width{width:48.7%}}@media(max-width:1249px){.sp-floating-block{margin-right:2% !important}.sp-double-width,.sp-full-width,.sp-single-width{width:97%}}.sp-tabs h2:before{content:none}#wpadminbar .shortpixel-toolbar-processing .cssload-container{width:100%;height:24px;text-align:center;position:absolute;top:0;left:-1px}#wpadminbar .shortpixel-toolbar-processing.shortpixel-quota-exceeded .cssload-container,#wpadminbar .shortpixel-toolbar-processing.shortpixel-alert .cssload-container{display:none}#wpadminbar .shortpixel-toolbar-processing .cssload-speeding-wheel{width:24px;height:24px;opacity:.7;margin:0 auto;border:4px solid #1cbfcb;border-radius:50%;border-left-color:transparent;animation:cssload-spin 2000ms infinite linear;-o-animation:cssload-spin 2000ms infinite linear;-ms-animation:cssload-spin 2000ms infinite linear;-webkit-animation:cssload-spin 2000ms infinite linear;-moz-animation:cssload-spin 2000ms infinite linear}@keyframes cssload-spin{100%{transform:rotate(360deg);transform:rotate(360deg)}}@-o-keyframes cssload-spin{100%{-o-transform:rotate(360deg);transform:rotate(360deg)}}@-ms-keyframes cssload-spin{100%{-ms-transform:rotate(360deg);transform:rotate(360deg)}}@-webkit-keyframes cssload-spin{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@-moz-keyframes cssload-spin{100%{-moz-transform:rotate(360deg);transform:rotate(360deg)}}
|
shortpixel_api.php
CHANGED
@@ -28,7 +28,6 @@ class ShortPixelAPI {
|
|
28 |
const ERR_UNKNOWN = -999;
|
29 |
|
30 |
private $_settings;
|
31 |
-
private $_maxAttempts = 10;
|
32 |
private $_apiEndPoint;
|
33 |
private $_apiDumpEndPoint;
|
34 |
|
@@ -76,23 +75,26 @@ class ShortPixelAPI {
|
|
76 |
* @param array $URLs - list of urls to send to API
|
77 |
* @param Boolean $Blocking - true means it will wait for an answer
|
78 |
* @param ShortPixelMetaFacade $itemHandler - the Facade that manages different types of image metadatas: MediaLibrary (postmeta table), ShortPixel custom (shortpixel_meta table)
|
79 |
-
* @param int $compressionType 1 - lossy, 2 - glossy, 0 - lossless
|
80 |
-
* @
|
|
|
|
|
81 |
*/
|
82 |
public function doRequests($URLs, $Blocking, $itemHandler, $compressionType = false, $refresh = false) {
|
83 |
|
84 |
if(!count($URLs)) {
|
85 |
$meta = $itemHandler->getMeta();
|
86 |
-
$files = " (";
|
87 |
if(count($meta->getThumbsMissing())) {
|
|
|
88 |
foreach ($meta->getThumbsMissing() as $miss) {
|
89 |
$files .= $miss . ", ";
|
90 |
}
|
91 |
if(strrpos($files, ', ')) {
|
92 |
$files = substr_replace($files , ')', strrpos($files , ', '));
|
93 |
}
|
|
|
94 |
}
|
95 |
-
throw new Exception(__('Image files are missing.'
|
96 |
}
|
97 |
|
98 |
//WpShortPixel::log("DO REQUESTS for META: " . json_encode($itemHandler->getRawMeta()) . " STACK: " . json_encode(debug_backtrace()));
|
@@ -107,9 +109,11 @@ class ShortPixelAPI {
|
|
107 |
'resize' => $this->_settings->resizeImages ? 1 + 2 * ($this->_settings->resizeType == 'inner' ? 1 : 0) : 0,
|
108 |
'resize_width' => $this->_settings->resizeWidth,
|
109 |
'resize_height' => $this->_settings->resizeHeight,
|
110 |
-
'group_id' => $itemHandler->getId(),
|
111 |
'urllist' => $URLs
|
112 |
);
|
|
|
|
|
|
|
113 |
if($refresh) {
|
114 |
$requestParameters['refresh'] = 1;
|
115 |
}
|
@@ -125,7 +129,7 @@ class ShortPixelAPI {
|
|
125 |
{
|
126 |
//WpShortPixel::log("API response : " . json_encode($response));
|
127 |
|
128 |
-
//die(var_dump(array('URL: ' => $this->_apiEndPoint, '<br><br>REQUEST:' => $
|
129 |
//there was an error, save this error inside file's SP optimization field
|
130 |
if ( is_object($response) && get_class($response) == 'WP_Error' )
|
131 |
{
|
@@ -153,7 +157,7 @@ class ShortPixelAPI {
|
|
153 |
/**
|
154 |
* parse the JSON response
|
155 |
* @param $response
|
156 |
-
* @return parsed
|
157 |
*/
|
158 |
public function parseResponse($response) {
|
159 |
$data = $response['body'];
|
@@ -166,7 +170,7 @@ class ShortPixelAPI {
|
|
166 |
* @param array $URLs - list of urls to send to API
|
167 |
* @param array $PATHs - list of local paths for the images
|
168 |
* @param ShortPixelMetaFacade $itemHandler - the Facade that manages different types of image metadatas: MediaLibrary (postmeta table), ShortPixel custom (shortpixel_meta table)
|
169 |
-
* @return status/message array
|
170 |
*/
|
171 |
public function processImage($URLs, $PATHs, $itemHandler = null) {
|
172 |
return $this->processImageRecursive($URLs, $PATHs, $itemHandler, 0);
|
@@ -177,8 +181,8 @@ class ShortPixelAPI {
|
|
177 |
* @param array $URLs - list of urls to send to API
|
178 |
* @param array $PATHs - list of local paths for the images
|
179 |
* @param ShortPixelMetaFacade $itemHandler - the Facade that manages different types of image metadatas: MediaLibrary (postmeta table), ShortPixel custom (shortpixel_meta table)
|
180 |
-
* @param
|
181 |
-
* @return status/message array
|
182 |
*/
|
183 |
private function processImageRecursive($URLs, $PATHs, $itemHandler = null, $startTime = 0)
|
184 |
{
|
@@ -227,7 +231,7 @@ class ShortPixelAPI {
|
|
227 |
$compressionType = $meta->getCompressionType() !== null ? $meta->getCompressionType() : $this->_settings->compressionType;
|
228 |
$response = $this->doRequests($URLs, true, $itemHandler, $compressionType);//send requests to API
|
229 |
|
230 |
-
//die(
|
231 |
|
232 |
if($response['response']['code'] != 200) {//response <> 200 -> there was an error apparently?
|
233 |
return array("Status" => self::STATUS_FAIL, "Message" => __('There was an error and your request was not processed.', 'shortpixel-image-optimiser')
|
@@ -235,16 +239,16 @@ class ShortPixelAPI {
|
|
235 |
}
|
236 |
|
237 |
$APIresponse = $this->parseResponse($response);//get the actual response from API, its an array
|
238 |
-
|
239 |
if ( isset($APIresponse[0]) ) //API returned image details
|
240 |
{
|
241 |
foreach ( $APIresponse as $imageObject ) {//this part makes sure that all the sizes were processed and ready to be downloaded
|
242 |
-
if ( $imageObject->Status->Code == 0 || $imageObject->Status->Code == 1
|
243 |
sleep(1);
|
244 |
return $this->processImageRecursive($URLs, $PATHs, $itemHandler, $startTime);
|
245 |
}
|
246 |
}
|
247 |
-
|
248 |
$firstImage = $APIresponse[0];//extract as object first image
|
249 |
switch($firstImage->Status->Code)
|
250 |
{
|
@@ -317,7 +321,7 @@ class ShortPixelAPI {
|
|
317 |
* If http works then it's http, otherwise sets https
|
318 |
* @param string $url
|
319 |
* @param bool $reset - forces recheck even if preferred protocol is already set
|
320 |
-
* @return url with the preferred protocol
|
321 |
*/
|
322 |
public function setPreferredProtocol($url, $reset = false) {
|
323 |
//switch protocol based on the formerly detected working protocol
|
@@ -334,53 +338,71 @@ class ShortPixelAPI {
|
|
334 |
|
335 |
}
|
336 |
|
337 |
-
function
|
338 |
-
|
339 |
-
|
340 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
341 |
}
|
342 |
|
343 |
/**
|
344 |
* handles the download of an optimized image from ShortPixel API
|
345 |
-
* @param
|
346 |
-
* @param int $
|
347 |
-
* @
|
|
|
|
|
348 |
*/
|
349 |
-
private function handleDownload($
|
350 |
-
|
351 |
-
if($compressionType)
|
352 |
-
{
|
353 |
-
$fileType = "LossyURL";
|
354 |
-
$fileSize = "LossySize";
|
355 |
-
$webpType = "WebPLossyURL";
|
356 |
-
}
|
357 |
-
else
|
358 |
-
{
|
359 |
-
$fileType = "LosslessURL";
|
360 |
-
$fileSize = "LoselessSize";
|
361 |
-
$webpType = "WebPLosslessURL";
|
362 |
-
}
|
363 |
-
|
364 |
-
$downloadTimeout = max(ini_get('max_execution_time') - 10, 15);
|
365 |
|
366 |
$webpTempFile = "NA";
|
367 |
-
if(
|
368 |
-
$webpURL = $this->setPreferredProtocol(urldecode($
|
369 |
$webpTempFile = download_url($webpURL, $downloadTimeout);
|
370 |
$webpTempFile = is_wp_error( $webpTempFile ) ? "NA" : $webpTempFile;
|
371 |
}
|
372 |
|
373 |
//if there is no improvement in size then we do not download this file
|
374 |
-
if ( $
|
375 |
return array("Status" => self::STATUS_UNCHANGED, "Message" => "File wasn't optimized so we do not download it.", "WebP" => $webpTempFile);
|
376 |
|
377 |
-
$correctFileSize = $
|
378 |
-
$fileURL = $this->setPreferredProtocol(urldecode($
|
379 |
|
380 |
$tempFile = download_url($fileURL, $downloadTimeout);
|
381 |
if(is_wp_error( $tempFile ))
|
382 |
{ //try to switch the default protocol
|
383 |
-
$fileURL = $this->setPreferredProtocol(urldecode($
|
384 |
$tempFile = download_url($fileURL, $downloadTimeout);
|
385 |
}
|
386 |
|
@@ -389,10 +411,11 @@ class ShortPixelAPI {
|
|
389 |
|
390 |
if ( is_wp_error( $tempFile ) ) {
|
391 |
@unlink($tempFile);
|
|
|
392 |
$returnMessage = array(
|
393 |
"Status" => self::STATUS_ERROR,
|
394 |
"Code" => self::ERR_DOWNLOAD,
|
395 |
-
"Message" => __('Error downloading file','shortpixel-image-optimiser') . " ({$
|
396 |
}
|
397 |
//check response so that download is OK
|
398 |
elseif (!file_exists($tempFile)) {
|
@@ -403,6 +426,7 @@ class ShortPixelAPI {
|
|
403 |
elseif( filesize($tempFile) != $correctFileSize) {
|
404 |
$size = filesize($tempFile);
|
405 |
@unlink($tempFile);
|
|
|
406 |
$returnMessage = array(
|
407 |
"Status" => self::STATUS_ERROR,
|
408 |
"Code" => self::ERR_INCORRECT_FILE_SIZE,
|
@@ -451,23 +475,105 @@ class ShortPixelAPI {
|
|
451 |
}
|
452 |
}
|
453 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
454 |
/**
|
455 |
* handles a successful optimization, setting metadata and handling download for each file in the set
|
456 |
-
* @param
|
457 |
-
* @param
|
458 |
* @param ShortPixelMetaFacade $itemHandler - the Facade that manages different types of image metadatas: MediaLibrary (postmeta table), ShortPixel custom (shortpixel_meta table)
|
459 |
* @param int $compressionType - 1 - lossy, 2 - glossy, 0 - lossless
|
460 |
-
* @return status/message
|
461 |
*/
|
462 |
private function handleSuccess($APIresponse, $PATHs, $itemHandler, $compressionType) {
|
463 |
$counter = $savedSpace = $originalSpace = $optimizedSpace = $averageCompression = 0;
|
464 |
$NoBackup = true;
|
465 |
|
466 |
-
|
467 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
468 |
//download each file from array and process it
|
469 |
foreach ( $APIresponse as $fileData )
|
470 |
{
|
|
|
|
|
471 |
if ( $fileData->Status->Code == 2 ) //file was processed OK
|
472 |
{
|
473 |
if ( $counter == 0 ) { //save percent improvement for main file
|
@@ -475,19 +581,25 @@ class ShortPixelAPI {
|
|
475 |
} else { //count thumbnails only
|
476 |
$this->_settings->thumbsCount = $this->_settings->thumbsCount + 1;
|
477 |
}
|
478 |
-
|
479 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
480 |
if ( $downloadResult['Status'] == self::STATUS_SUCCESS ) {
|
481 |
-
|
482 |
}
|
483 |
//when the status is STATUS_UNCHANGED we just skip the array line for that one
|
484 |
elseif( $downloadResult['Status'] == self::STATUS_UNCHANGED ) {
|
485 |
//this image is unchanged so won't be copied below, only the optimization stats need to be computed
|
486 |
$originalSpace += $fileData->OriginalSize;
|
487 |
-
$optimizedSpace += $fileData->$
|
488 |
-
$tempFiles[$counter] = $downloadResult;
|
489 |
}
|
490 |
-
else {
|
|
|
491 |
return array("Status" => $downloadResult['Status'], "Code" => $downloadResult['Code'], "Message" => $downloadResult['Message']);
|
492 |
}
|
493 |
|
@@ -497,7 +609,7 @@ class ShortPixelAPI {
|
|
497 |
}
|
498 |
$counter++;
|
499 |
}
|
500 |
-
|
501 |
//figure out in what SubDir files should land
|
502 |
$mainPath = $itemHandler->getMeta()->getPath();
|
503 |
|
@@ -507,7 +619,8 @@ class ShortPixelAPI {
|
|
507 |
$backupStatus = self::backupImage($mainPath, $PATHs);
|
508 |
if($backupStatus == self::STATUS_FAIL) {
|
509 |
$itemHandler->incrementRetries(1, self::ERR_SAVE_BKP, $backupStatus["Message"]);
|
510 |
-
|
|
|
511 |
}
|
512 |
$NoBackup = false;
|
513 |
}//end backup section
|
@@ -518,8 +631,7 @@ class ShortPixelAPI {
|
|
518 |
$retinas = 0;
|
519 |
$thumbsOpt = 0;
|
520 |
$thumbsOptList = array();
|
521 |
-
|
522 |
-
|
523 |
if ( !empty($tempFiles) )
|
524 |
{
|
525 |
//overwrite the original files with the optimized ones
|
@@ -529,7 +641,7 @@ class ShortPixelAPI {
|
|
529 |
|
530 |
$targetFile = $PATHs[$tempFileID];
|
531 |
$isRetina = ShortPixelMetaFacade::isRetina($targetFile);
|
532 |
-
|
533 |
if( ($tempFile['Status'] == self::STATUS_UNCHANGED || $tempFile['Status'] == self::STATUS_SUCCESS) && !$isRetina
|
534 |
&& $targetFile !== $mainPath) {
|
535 |
$thumbsOpt++;
|
@@ -538,7 +650,7 @@ class ShortPixelAPI {
|
|
538 |
|
539 |
if($tempFile['Status'] == self::STATUS_SUCCESS) { //if it's unchanged it will still be in the array but only for WebP (handled below)
|
540 |
$tempFilePATH = $tempFile["Message"];
|
541 |
-
if ( file_exists($tempFilePATH) && file_exists($
|
542 |
copy($tempFilePATH, $targetFile);
|
543 |
if(ShortPixelMetaFacade::isRetina($targetFile)) {
|
544 |
$retinas ++;
|
@@ -550,18 +662,27 @@ class ShortPixelAPI {
|
|
550 |
}
|
551 |
//Calculate the saved space
|
552 |
$fileData = $APIresponse[$tempFileID];
|
553 |
-
$savedSpace += $fileData->OriginalSize - $fileData->$
|
554 |
$originalSpace += $fileData->OriginalSize;
|
555 |
-
$optimizedSpace += $fileData->$
|
556 |
$averageCompression += $fileData->PercentImprovement;
|
557 |
-
WPShortPixel::log("HANDLE SUCCESS: Image " . $PATHs[$tempFileID] . " original size: ".$fileData->OriginalSize . " optimized: " . $fileData->$
|
558 |
|
559 |
//add the number of files with < 5% optimization
|
560 |
-
if ( ( ( 1 - $APIresponse[$tempFileID]->$
|
561 |
$this->_settings->under5Percent++;
|
562 |
}
|
563 |
}
|
564 |
else {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
565 |
$writeFailed++;
|
566 |
}
|
567 |
@unlink($tempFilePATH);
|
@@ -574,9 +695,16 @@ class ShortPixelAPI {
|
|
574 |
@unlink($tempWebpFilePATH);
|
575 |
}
|
576 |
}
|
577 |
-
|
|
|
578 |
if ( $writeFailed > 0 )//there was an error
|
579 |
{
|
|
|
|
|
|
|
|
|
|
|
|
|
580 |
$msg = sprintf(__('Optimized version of %s file(s) couldn\'t be updated.','shortpixel-image-optimiser'),$writeFailed);
|
581 |
$itemHandler->incrementRetries(1, self::ERR_SAVE, $msg);
|
582 |
$this->_settings->bulkProcessingStatus = "error";
|
@@ -628,7 +756,8 @@ class ShortPixelAPI {
|
|
628 |
|
629 |
$itemHandler->updateMeta($meta);
|
630 |
$itemHandler->optimizationSucceeded();
|
631 |
-
|
|
|
632 |
if(!$originalSpace) { //das kann nicht sein, alles klar?!
|
633 |
throw new Exception("OriginalSpace = 0. APIResponse" . json_encode($APIresponse));
|
634 |
}
|
@@ -641,7 +770,24 @@ class ShortPixelAPI {
|
|
641 |
? number_format(100.0 * (1.0 - (1.0 - $png2jpg / 100.0) * $optimizedSpace / $originalSpace), 2)
|
642 |
: "Couldn't compute thumbs optimization percent. Main image: " . $percentImprovement);
|
643 |
}//end handleSuccess
|
644 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
645 |
/**
|
646 |
* a basename alternative that deals OK with multibyte charsets (e.g. Arabic)
|
647 |
* @param string $Path
|
@@ -666,7 +812,7 @@ class ShortPixelAPI {
|
|
666 |
|
667 |
/**
|
668 |
* sometimes, the paths to the files as defined in metadata are wrong, we try to automatically correct them
|
669 |
-
* @param
|
670 |
* @return boolean|string
|
671 |
*/
|
672 |
static public function CheckAndFixImagePaths($PATHs){
|
28 |
const ERR_UNKNOWN = -999;
|
29 |
|
30 |
private $_settings;
|
|
|
31 |
private $_apiEndPoint;
|
32 |
private $_apiDumpEndPoint;
|
33 |
|
75 |
* @param array $URLs - list of urls to send to API
|
76 |
* @param Boolean $Blocking - true means it will wait for an answer
|
77 |
* @param ShortPixelMetaFacade $itemHandler - the Facade that manages different types of image metadatas: MediaLibrary (postmeta table), ShortPixel custom (shortpixel_meta table)
|
78 |
+
* @param bool|int $compressionType 1 - lossy, 2 - glossy, 0 - lossless
|
79 |
+
* @param bool $refresh
|
80 |
+
* @return Array response from wp_remote_post or error
|
81 |
+
* @throws Exception
|
82 |
*/
|
83 |
public function doRequests($URLs, $Blocking, $itemHandler, $compressionType = false, $refresh = false) {
|
84 |
|
85 |
if(!count($URLs)) {
|
86 |
$meta = $itemHandler->getMeta();
|
|
|
87 |
if(count($meta->getThumbsMissing())) {
|
88 |
+
$files = " (";
|
89 |
foreach ($meta->getThumbsMissing() as $miss) {
|
90 |
$files .= $miss . ", ";
|
91 |
}
|
92 |
if(strrpos($files, ', ')) {
|
93 |
$files = substr_replace($files , ')', strrpos($files , ', '));
|
94 |
}
|
95 |
+
throw new Exception(__('Image files are missing.', 'shortpixel-image-optimiser') . (strlen($files) > 1 ? $files : ''));
|
96 |
}
|
97 |
+
else throw new Exception(__('Image files are missing.', 'shortpixel-image-optimiser'));
|
98 |
}
|
99 |
|
100 |
//WpShortPixel::log("DO REQUESTS for META: " . json_encode($itemHandler->getRawMeta()) . " STACK: " . json_encode(debug_backtrace()));
|
109 |
'resize' => $this->_settings->resizeImages ? 1 + 2 * ($this->_settings->resizeType == 'inner' ? 1 : 0) : 0,
|
110 |
'resize_width' => $this->_settings->resizeWidth,
|
111 |
'resize_height' => $this->_settings->resizeHeight,
|
|
|
112 |
'urllist' => $URLs
|
113 |
);
|
114 |
+
if(/*false &&*/ $this->_settings->downloadArchive == 7 && class_exists('PharData')) {
|
115 |
+
$requestParameters['group'] = $itemHandler->getId();
|
116 |
+
}
|
117 |
if($refresh) {
|
118 |
$requestParameters['refresh'] = 1;
|
119 |
}
|
129 |
{
|
130 |
//WpShortPixel::log("API response : " . json_encode($response));
|
131 |
|
132 |
+
//die(var_dump(array('URL: ' => $this->_apiEndPoint, '<br><br>REQUEST:' => $requestParameters, '<br><br>RESPONSE: ' => $response, '<br><br>BODY: ' => isset($response['body']) ? $response['body'] : '' )));
|
133 |
//there was an error, save this error inside file's SP optimization field
|
134 |
if ( is_object($response) && get_class($response) == 'WP_Error' )
|
135 |
{
|
157 |
/**
|
158 |
* parse the JSON response
|
159 |
* @param $response
|
160 |
+
* @return array parsed
|
161 |
*/
|
162 |
public function parseResponse($response) {
|
163 |
$data = $response['body'];
|
170 |
* @param array $URLs - list of urls to send to API
|
171 |
* @param array $PATHs - list of local paths for the images
|
172 |
* @param ShortPixelMetaFacade $itemHandler - the Facade that manages different types of image metadatas: MediaLibrary (postmeta table), ShortPixel custom (shortpixel_meta table)
|
173 |
+
* @return array status/message array
|
174 |
*/
|
175 |
public function processImage($URLs, $PATHs, $itemHandler = null) {
|
176 |
return $this->processImageRecursive($URLs, $PATHs, $itemHandler, 0);
|
181 |
* @param array $URLs - list of urls to send to API
|
182 |
* @param array $PATHs - list of local paths for the images
|
183 |
* @param ShortPixelMetaFacade $itemHandler - the Facade that manages different types of image metadatas: MediaLibrary (postmeta table), ShortPixel custom (shortpixel_meta table)
|
184 |
+
* @param int $startTime - time of the first call
|
185 |
+
* @return array status/message array
|
186 |
*/
|
187 |
private function processImageRecursive($URLs, $PATHs, $itemHandler = null, $startTime = 0)
|
188 |
{
|
231 |
$compressionType = $meta->getCompressionType() !== null ? $meta->getCompressionType() : $this->_settings->compressionType;
|
232 |
$response = $this->doRequests($URLs, true, $itemHandler, $compressionType);//send requests to API
|
233 |
|
234 |
+
//die($response['body']);
|
235 |
|
236 |
if($response['response']['code'] != 200) {//response <> 200 -> there was an error apparently?
|
237 |
return array("Status" => self::STATUS_FAIL, "Message" => __('There was an error and your request was not processed.', 'shortpixel-image-optimiser')
|
239 |
}
|
240 |
|
241 |
$APIresponse = $this->parseResponse($response);//get the actual response from API, its an array
|
242 |
+
|
243 |
if ( isset($APIresponse[0]) ) //API returned image details
|
244 |
{
|
245 |
foreach ( $APIresponse as $imageObject ) {//this part makes sure that all the sizes were processed and ready to be downloaded
|
246 |
+
if ( isset($imageObject->Status) && ( $imageObject->Status->Code == 0 || $imageObject->Status->Code == 1 ) ) {
|
247 |
sleep(1);
|
248 |
return $this->processImageRecursive($URLs, $PATHs, $itemHandler, $startTime);
|
249 |
}
|
250 |
}
|
251 |
+
|
252 |
$firstImage = $APIresponse[0];//extract as object first image
|
253 |
switch($firstImage->Status->Code)
|
254 |
{
|
321 |
* If http works then it's http, otherwise sets https
|
322 |
* @param string $url
|
323 |
* @param bool $reset - forces recheck even if preferred protocol is already set
|
324 |
+
* @return string url with the preferred protocol
|
325 |
*/
|
326 |
public function setPreferredProtocol($url, $reset = false) {
|
327 |
//switch protocol based on the formerly detected working protocol
|
338 |
|
339 |
}
|
340 |
|
341 |
+
function fromArchive($path, $optimizedUrl, $optimizedSize, $originalSize, $webpUrl) {
|
342 |
+
$webpTempFile = "NA";
|
343 |
+
if($webpUrl !== "NA") {
|
344 |
+
$webpTempFile = $path . '/' . wp_basename($webpUrl);
|
345 |
+
$webpTempFile = file_exists($webpTempFile) ? $webpTempFile : 'NA';
|
346 |
+
}
|
347 |
+
|
348 |
+
//if there is no improvement in size then we do not download this file
|
349 |
+
if ( $originalSize == $optimizedSize )
|
350 |
+
return array("Status" => self::STATUS_UNCHANGED, "Message" => "File wasn't optimized so we do not download it.", "WebP" => $webpTempFile);
|
351 |
+
|
352 |
+
$correctFileSize = $optimizedSize;
|
353 |
+
$tempFile = $path . '/' . wp_basename($optimizedUrl);
|
354 |
+
|
355 |
+
if(file_exists($tempFile)) {
|
356 |
+
//on success we return this
|
357 |
+
if( filesize($tempFile) != $correctFileSize) {
|
358 |
+
$size = filesize($tempFile);
|
359 |
+
@unlink($tempFile);
|
360 |
+
@unlink($webpTempFile);
|
361 |
+
$returnMessage = array(
|
362 |
+
"Status" => self::STATUS_ERROR,
|
363 |
+
"Code" => self::ERR_INCORRECT_FILE_SIZE,
|
364 |
+
"Message" => sprintf(__('Error in archive - incorrect file size (downloaded: %s, correct: %s )','shortpixel-image-optimiser'),$size, $correctFileSize));
|
365 |
+
} else {
|
366 |
+
$returnMessage = array("Status" => self::STATUS_SUCCESS, "Message" => $tempFile, "WebP" => $webpTempFile);
|
367 |
+
}
|
368 |
+
} else {
|
369 |
+
$returnMessage = array("Status" => self::STATUS_ERROR,
|
370 |
+
"Code" => self::ERR_FILE_NOT_FOUND,
|
371 |
+
"Message" => __('Unable to locate downloaded file','shortpixel-image-optimiser') . " " . $tempFile);
|
372 |
+
}
|
373 |
+
|
374 |
+
return $returnMessage;
|
375 |
}
|
376 |
|
377 |
/**
|
378 |
* handles the download of an optimized image from ShortPixel API
|
379 |
+
* @param string $optimizedUrl
|
380 |
+
* @param int $optimizedSize
|
381 |
+
* @param int $originalSize
|
382 |
+
* @param string $webpUrl
|
383 |
+
* @return array status /message array
|
384 |
*/
|
385 |
+
private function handleDownload($optimizedUrl, $optimizedSize, $originalSize, $webpUrl){
|
386 |
+
$downloadTimeout = max(ini_get('max_execution_time') - 10, 15);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
387 |
|
388 |
$webpTempFile = "NA";
|
389 |
+
if($webpUrl !== "NA") {
|
390 |
+
$webpURL = $this->setPreferredProtocol(urldecode($webpUrl));
|
391 |
$webpTempFile = download_url($webpURL, $downloadTimeout);
|
392 |
$webpTempFile = is_wp_error( $webpTempFile ) ? "NA" : $webpTempFile;
|
393 |
}
|
394 |
|
395 |
//if there is no improvement in size then we do not download this file
|
396 |
+
if ( $originalSize == $optimizedSize )
|
397 |
return array("Status" => self::STATUS_UNCHANGED, "Message" => "File wasn't optimized so we do not download it.", "WebP" => $webpTempFile);
|
398 |
|
399 |
+
$correctFileSize = $optimizedSize;
|
400 |
+
$fileURL = $this->setPreferredProtocol(urldecode($optimizedUrl));
|
401 |
|
402 |
$tempFile = download_url($fileURL, $downloadTimeout);
|
403 |
if(is_wp_error( $tempFile ))
|
404 |
{ //try to switch the default protocol
|
405 |
+
$fileURL = $this->setPreferredProtocol(urldecode($optimizedUrl), true); //force recheck of the protocol
|
406 |
$tempFile = download_url($fileURL, $downloadTimeout);
|
407 |
}
|
408 |
|
411 |
|
412 |
if ( is_wp_error( $tempFile ) ) {
|
413 |
@unlink($tempFile);
|
414 |
+
@unlink($webpTempFile);
|
415 |
$returnMessage = array(
|
416 |
"Status" => self::STATUS_ERROR,
|
417 |
"Code" => self::ERR_DOWNLOAD,
|
418 |
+
"Message" => __('Error downloading file','shortpixel-image-optimiser') . " ({$optimizedUrl}) " . $tempFile->get_error_message());
|
419 |
}
|
420 |
//check response so that download is OK
|
421 |
elseif (!file_exists($tempFile)) {
|
426 |
elseif( filesize($tempFile) != $correctFileSize) {
|
427 |
$size = filesize($tempFile);
|
428 |
@unlink($tempFile);
|
429 |
+
@unlink($webpTempFile);
|
430 |
$returnMessage = array(
|
431 |
"Status" => self::STATUS_ERROR,
|
432 |
"Code" => self::ERR_INCORRECT_FILE_SIZE,
|
475 |
}
|
476 |
}
|
477 |
|
478 |
+
private function createArchiveTempFolder($archiveBasename) {
|
479 |
+
$archiveTempDir = get_temp_dir() . '/' . $archiveBasename;
|
480 |
+
if(file_exists($archiveTempDir) && is_dir($archiveTempDir) && (time() - filemtime($archiveTempDir) < max(30, SHORTPIXEL_MAX_EXECUTION_TIME) + 10)) {
|
481 |
+
WPShortPixel::log("CONFLICT. Folder already exists and is modified in the last minute. Current IP:" . $_SERVER['REMOTE_ADDR']);
|
482 |
+
return array("Status" => self::STATUS_RETRY, "Code" => 1, "Message" => "Pending");
|
483 |
+
}
|
484 |
+
if( !file_exists($archiveTempDir) && !@mkdir($archiveTempDir) ) {
|
485 |
+
return array("Status" => self::STATUS_ERROR, "Code" => self::ERR_SAVE, "Message" => "Could not create temporary folder.");
|
486 |
+
}
|
487 |
+
return array("Status" => self::STATUS_SUCCESS, "Dir" => $archiveTempDir);
|
488 |
+
}
|
489 |
+
|
490 |
+
private function downloadArchive($archive, $compressionType, $first = true) {
|
491 |
+
if($archive->ArchiveStatus->Code == 1 || $archive->ArchiveStatus->Code == 0) {
|
492 |
+
return array("Status" => self::STATUS_RETRY, "Code" => 1, "Message" => "Pending");
|
493 |
+
} elseif($archive->ArchiveStatus->Code == 2) {
|
494 |
+
|
495 |
+
$suffix = ($compressionType == 0 ? "-lossless" : "");
|
496 |
+
$archiveURL = "Archive" . ($compressionType == 0 ? "Lossless" : "") . "URL";
|
497 |
+
$archiveSize = "Archive" . ($compressionType == 0 ? "Lossless" : "") . "Size";
|
498 |
+
|
499 |
+
$archiveTemp = $this->createArchiveTempFolder(wp_basename($archive->$archiveURL, '.tar'));
|
500 |
+
if($archiveTemp["Status"] == self::STATUS_SUCCESS) { $archiveTempDir = $archiveTemp["Dir"]; }
|
501 |
+
else { return $archiveTemp; }
|
502 |
+
|
503 |
+
$downloadResult = $this->handleDownload($archive->$archiveURL, $archive->$archiveSize, 0, 'NA');
|
504 |
+
|
505 |
+
if ( $downloadResult['Status'] == self::STATUS_SUCCESS ) {
|
506 |
+
$archiveFile = $downloadResult['Message'];
|
507 |
+
if(filesize($archiveFile) !== $archive->$archiveSize) {
|
508 |
+
@unlink($archiveFile);
|
509 |
+
ShortpixelFolder::deleteFolder($archiveTempDir);
|
510 |
+
return array("Status" => self::STATUS_RETRY, "Code" => 1, "Message" => "Pending");
|
511 |
+
}
|
512 |
+
$pharData = new PharData($archiveFile);
|
513 |
+
try {
|
514 |
+
if (SHORTPIXEL_DEBUG === true) {
|
515 |
+
$info = "Current IP:" . $_SERVER['REMOTE_ADDR'] . "ARCHIVE CONTENTS: COUNT " . $pharData->count() . ", ";
|
516 |
+
foreach($pharData as $file) {
|
517 |
+
$info .= $file . ", ";
|
518 |
+
}
|
519 |
+
WPShortPixel::log($info);
|
520 |
+
}
|
521 |
+
$pharData->extractTo($archiveTempDir, null, true);
|
522 |
+
WPShortPixel::log("ARCHIVE EXTRACTED " . json_encode(scandir($archiveTempDir)));
|
523 |
+
@unlink($archiveFile);
|
524 |
+
} catch (Exception $ex) {
|
525 |
+
@unlink($archiveFile);
|
526 |
+
ShortpixelFolder::deleteFolder($archiveTempDir);
|
527 |
+
return array("Status" => self::STATUS_ERROR, "Code" => $ex->getCode(), "Message" => $ex->getMessage());
|
528 |
+
}
|
529 |
+
return array("Status" => self::STATUS_SUCCESS, "Code" => 2, "Message" => "Success", "Path" => $archiveTempDir);
|
530 |
+
|
531 |
+
} else {
|
532 |
+
WPShortPixel::log("ARCHIVE ERROR (" . $archive->$archiveURL . "): " . json_encode($downloadResult));
|
533 |
+
if($first && $downloadResult['Code'] == self::ERR_INCORRECT_FILE_SIZE) {
|
534 |
+
WPShortPixel::log("RETRYING AFTER ARCHIVE ERROR");
|
535 |
+
return $this->downloadArchive($archive, $compressionType, false); // try again, maybe the archive was flushing...
|
536 |
+
}
|
537 |
+
@rmdir($archiveTempDir); //in the case it was just created and it's empty...
|
538 |
+
return array("Status" => $downloadResult['Status'], "Code" => $downloadResult['Code'], "Message" => $downloadResult['Message']);
|
539 |
+
}
|
540 |
+
}
|
541 |
+
return false;
|
542 |
+
}
|
543 |
+
|
544 |
/**
|
545 |
* handles a successful optimization, setting metadata and handling download for each file in the set
|
546 |
+
* @param array $APIresponse - the response from the API - contains the optimized images URLs to download
|
547 |
+
* @param array $PATHs - list of local paths for the files
|
548 |
* @param ShortPixelMetaFacade $itemHandler - the Facade that manages different types of image metadatas: MediaLibrary (postmeta table), ShortPixel custom (shortpixel_meta table)
|
549 |
* @param int $compressionType - 1 - lossy, 2 - glossy, 0 - lossless
|
550 |
+
* @return array status/message
|
551 |
*/
|
552 |
private function handleSuccess($APIresponse, $PATHs, $itemHandler, $compressionType) {
|
553 |
$counter = $savedSpace = $originalSpace = $optimizedSpace = $averageCompression = 0;
|
554 |
$NoBackup = true;
|
555 |
|
556 |
+
if($compressionType) {
|
557 |
+
$fileType = "LossyURL";
|
558 |
+
$fileSize = "LossySize";
|
559 |
+
} else {
|
560 |
+
$fileType = "LosslessURL";
|
561 |
+
$fileSize = "LoselessSize";
|
562 |
+
}
|
563 |
+
$webpType = "WebP" . $fileType;
|
564 |
+
|
565 |
+
$archive = /*false &&*/
|
566 |
+
($this->_settings->downloadArchive == 7 && class_exists('PharData') && isset($APIresponse[count($APIresponse) - 1]->ArchiveStatus))
|
567 |
+
? $this->downloadArchive($APIresponse[count($APIresponse) - 1], $compressionType) : false;
|
568 |
+
if($archive !== false && $archive['Status'] !== self::STATUS_SUCCESS) {
|
569 |
+
return $archive;
|
570 |
+
}
|
571 |
+
|
572 |
//download each file from array and process it
|
573 |
foreach ( $APIresponse as $fileData )
|
574 |
{
|
575 |
+
if(!isset($fileData->Status)) continue; //if optimized images archive is activated, last entry of APIResponse if the Archive data.
|
576 |
+
|
577 |
if ( $fileData->Status->Code == 2 ) //file was processed OK
|
578 |
{
|
579 |
if ( $counter == 0 ) { //save percent improvement for main file
|
581 |
} else { //count thumbnails only
|
582 |
$this->_settings->thumbsCount = $this->_settings->thumbsCount + 1;
|
583 |
}
|
584 |
+
//TODO la sfarsit sa faca fallback la handleDownload
|
585 |
+
if($archive) {
|
586 |
+
$downloadResult = $this->fromArchive($archive['Path'], $fileData->$fileType, $fileData->$fileSize, $fileData->OriginalSize, isset($fileData->$webpType) ? $fileData->$webpType : 'NA');
|
587 |
+
} else {
|
588 |
+
$downloadResult = $this->handleDownload($fileData->$fileType, $fileData->$fileSize, $fileData->OriginalSize, isset($fileData->$webpType) ? $fileData->$webpType : 'NA');
|
589 |
+
}
|
590 |
+
|
591 |
+
$tempFiles[$counter] = $downloadResult;
|
592 |
if ( $downloadResult['Status'] == self::STATUS_SUCCESS ) {
|
593 |
+
//nothing to do
|
594 |
}
|
595 |
//when the status is STATUS_UNCHANGED we just skip the array line for that one
|
596 |
elseif( $downloadResult['Status'] == self::STATUS_UNCHANGED ) {
|
597 |
//this image is unchanged so won't be copied below, only the optimization stats need to be computed
|
598 |
$originalSpace += $fileData->OriginalSize;
|
599 |
+
$optimizedSpace += $fileData->$fileSize;
|
|
|
600 |
}
|
601 |
+
else {
|
602 |
+
self::cleanupTemporaryFiles($archive, $tempFiles);
|
603 |
return array("Status" => $downloadResult['Status'], "Code" => $downloadResult['Code'], "Message" => $downloadResult['Message']);
|
604 |
}
|
605 |
|
609 |
}
|
610 |
$counter++;
|
611 |
}
|
612 |
+
|
613 |
//figure out in what SubDir files should land
|
614 |
$mainPath = $itemHandler->getMeta()->getPath();
|
615 |
|
619 |
$backupStatus = self::backupImage($mainPath, $PATHs);
|
620 |
if($backupStatus == self::STATUS_FAIL) {
|
621 |
$itemHandler->incrementRetries(1, self::ERR_SAVE_BKP, $backupStatus["Message"]);
|
622 |
+
self::cleanupTemporaryFiles($archive, empty($tempFiles) ? array() : $tempFiles);
|
623 |
+
return array("Status" => self::STATUS_FAIL, "Code" =>"backup-fail", "Message" => "Failed to back the image up.");
|
624 |
}
|
625 |
$NoBackup = false;
|
626 |
}//end backup section
|
631 |
$retinas = 0;
|
632 |
$thumbsOpt = 0;
|
633 |
$thumbsOptList = array();
|
634 |
+
|
|
|
635 |
if ( !empty($tempFiles) )
|
636 |
{
|
637 |
//overwrite the original files with the optimized ones
|
641 |
|
642 |
$targetFile = $PATHs[$tempFileID];
|
643 |
$isRetina = ShortPixelMetaFacade::isRetina($targetFile);
|
644 |
+
|
645 |
if( ($tempFile['Status'] == self::STATUS_UNCHANGED || $tempFile['Status'] == self::STATUS_SUCCESS) && !$isRetina
|
646 |
&& $targetFile !== $mainPath) {
|
647 |
$thumbsOpt++;
|
650 |
|
651 |
if($tempFile['Status'] == self::STATUS_SUCCESS) { //if it's unchanged it will still be in the array but only for WebP (handled below)
|
652 |
$tempFilePATH = $tempFile["Message"];
|
653 |
+
if ( file_exists($tempFilePATH) && file_exists($targetFile) && is_writable($targetFile) ) {
|
654 |
copy($tempFilePATH, $targetFile);
|
655 |
if(ShortPixelMetaFacade::isRetina($targetFile)) {
|
656 |
$retinas ++;
|
662 |
}
|
663 |
//Calculate the saved space
|
664 |
$fileData = $APIresponse[$tempFileID];
|
665 |
+
$savedSpace += $fileData->OriginalSize - $fileData->$fileSize;
|
666 |
$originalSpace += $fileData->OriginalSize;
|
667 |
+
$optimizedSpace += $fileData->$fileSize;
|
668 |
$averageCompression += $fileData->PercentImprovement;
|
669 |
+
WPShortPixel::log("HANDLE SUCCESS: Image " . $PATHs[$tempFileID] . " original size: ".$fileData->OriginalSize . " optimized: " . $fileData->$fileSize);
|
670 |
|
671 |
//add the number of files with < 5% optimization
|
672 |
+
if ( ( ( 1 - $APIresponse[$tempFileID]->$fileSize/$APIresponse[$tempFileID]->OriginalSize ) * 100 ) < 5 ) {
|
673 |
$this->_settings->under5Percent++;
|
674 |
}
|
675 |
}
|
676 |
else {
|
677 |
+
if($archive && SHORTPIXEL_DEBUG === true) {
|
678 |
+
if(!file_exists($tempFilePATH)) {
|
679 |
+
WPShortPixel::log("MISSING FROM ARCHIVE. tempFilePath: $tempFilePATH with ID: $tempFileID");
|
680 |
+
} elseif(!file_exists($targetFile)){
|
681 |
+
WPShortPixel::log("MISSING TARGET: $targetFile");
|
682 |
+
} elseif(!is_writable($targetFile)){
|
683 |
+
WPShortPixel::log("TARGET NOT WRITABLE: $targetFile");
|
684 |
+
}
|
685 |
+
}
|
686 |
$writeFailed++;
|
687 |
}
|
688 |
@unlink($tempFilePATH);
|
695 |
@unlink($tempWebpFilePATH);
|
696 |
}
|
697 |
}
|
698 |
+
self::cleanupTemporaryFiles($archive, $tempFiles);
|
699 |
+
|
700 |
if ( $writeFailed > 0 )//there was an error
|
701 |
{
|
702 |
+
if($archive && SHORTPIXEL_DEBUG === true) {
|
703 |
+
WPShortPixel::log("ARCHIVE HAS MISSING FILES. EXPECTED: " . json_encode($PATHs)
|
704 |
+
. " AND: " . json_encode($APIresponse)
|
705 |
+
. " GOT ARCHIVE: " . $APIresponse[count($APIresponse) - 1]->ArchiveURL . " LOSSLESS: " . $APIresponse[count($APIresponse) - 1]->ArchiveLosslessURL
|
706 |
+
. " CONTAINING: " . json_encode(scandir($archive['Path'])));
|
707 |
+
}
|
708 |
$msg = sprintf(__('Optimized version of %s file(s) couldn\'t be updated.','shortpixel-image-optimiser'),$writeFailed);
|
709 |
$itemHandler->incrementRetries(1, self::ERR_SAVE, $msg);
|
710 |
$this->_settings->bulkProcessingStatus = "error";
|
756 |
|
757 |
$itemHandler->updateMeta($meta);
|
758 |
$itemHandler->optimizationSucceeded();
|
759 |
+
WPShortPixel::log("HANDLE SUCCESS: Metadata saved.");
|
760 |
+
|
761 |
if(!$originalSpace) { //das kann nicht sein, alles klar?!
|
762 |
throw new Exception("OriginalSpace = 0. APIResponse" . json_encode($APIresponse));
|
763 |
}
|
770 |
? number_format(100.0 * (1.0 - (1.0 - $png2jpg / 100.0) * $optimizedSpace / $originalSpace), 2)
|
771 |
: "Couldn't compute thumbs optimization percent. Main image: " . $percentImprovement);
|
772 |
}//end handleSuccess
|
773 |
+
|
774 |
+
/**
|
775 |
+
* @param $archive
|
776 |
+
* @param $tempFiles
|
777 |
+
*/
|
778 |
+
protected static function cleanupTemporaryFiles($archive, $tempFiles)
|
779 |
+
{
|
780 |
+
if ($archive) {
|
781 |
+
ShortpixelFolder::deleteFolder($archive['Path']);
|
782 |
+
} else {
|
783 |
+
if (!empty($tempFiles) && is_array($tempFiles)) {
|
784 |
+
foreach ($tempFiles as $tmpFile) {
|
785 |
+
@unlink($tmpFile["Message"]);
|
786 |
+
}
|
787 |
+
}
|
788 |
+
}
|
789 |
+
}
|
790 |
+
|
791 |
/**
|
792 |
* a basename alternative that deals OK with multibyte charsets (e.g. Arabic)
|
793 |
* @param string $Path
|
812 |
|
813 |
/**
|
814 |
* sometimes, the paths to the files as defined in metadata are wrong, we try to automatically correct them
|
815 |
+
* @param array $PATHs
|
816 |
* @return boolean|string
|
817 |
*/
|
818 |
static public function CheckAndFixImagePaths($PATHs){
|
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 > ShortPixel</a> page on how to start optimizing your image library and make your website load faster.
|
6 |
-
* Version: 4.
|
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.
|
22 |
define('SHORTPIXEL_MAX_TIMEOUT', 10);
|
23 |
define('SHORTPIXEL_VALIDATE_MAX_TIMEOUT', 15);
|
24 |
define('SHORTPIXEL_BACKUP', 'ShortpixelBackups');
|
@@ -80,8 +80,14 @@ function shortpixelInit() {
|
|
80 |
require_once('wp-shortpixel-req.php');
|
81 |
$shortPixelPluginInstance = new WPShortPixel;
|
82 |
}
|
83 |
-
}
|
84 |
|
|
|
|
|
|
|
|
|
|
|
|
|
85 |
function shortPixelHandleImageUploadHook($meta, $ID = null) {
|
86 |
global $shortPixelPluginInstance;
|
87 |
if(!isset($shortPixelPluginInstance)) {
|
@@ -174,8 +180,9 @@ function shortPixelGravityForms( $value, $lead, $field, $form ) {
|
|
174 |
}
|
175 |
|
176 |
if ( get_option('wp-short-pixel-create-webp-markup')) {
|
177 |
-
add_filter( 'the_content', 'shortPixelConvertImgToPictureAddWebp', 10000 ); // priority big, so it will be executed last
|
178 |
-
add_filter( 'post_thumbnail_html', 'shortPixelConvertImgToPictureAddWebp');
|
|
|
179 |
add_action( 'wp_head', 'shortPixelAddPictureJs');
|
180 |
// add_action( 'wp_enqueue_scripts', 'spAddPicturefillJs' );
|
181 |
}
|
@@ -185,12 +192,12 @@ if ( !function_exists( 'vc_action' ) || vc_action() !== 'vc_inline' ) { //handle
|
|
185 |
add_action('ngg_added_new_image', 'shortPixelNggAdd');
|
186 |
|
187 |
$autoPng2Jpg = get_option('wp-short-pixel-png2jpg');
|
188 |
-
|
|
|
189 |
add_action( 'wp_handle_upload', 'shortPixelPng2JpgHook');
|
190 |
add_action( 'mpp_handle_upload', 'shortPixelPng2JpgHook');
|
191 |
}
|
192 |
add_action('wp_handle_replace', 'shortPixelReplaceHook');
|
193 |
-
$autoMediaLibrary = get_option('wp-short-pixel-auto-media-library');
|
194 |
if($autoMediaLibrary) {
|
195 |
add_filter( 'wp_generate_attachment_metadata', 'shortPixelHandleImageUploadHook', 10, 2 );
|
196 |
add_filter( 'mpp_generate_metadata', 'shortPixelHandleImageUploadHook', 10, 2 );
|
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 > ShortPixel</a> page on how to start optimizing your image library and make your website load faster.
|
6 |
+
* Version: 4.12.0
|
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.12.0");
|
22 |
define('SHORTPIXEL_MAX_TIMEOUT', 10);
|
23 |
define('SHORTPIXEL_VALIDATE_MAX_TIMEOUT', 15);
|
24 |
define('SHORTPIXEL_BACKUP', 'ShortpixelBackups');
|
80 |
require_once('wp-shortpixel-req.php');
|
81 |
$shortPixelPluginInstance = new WPShortPixel;
|
82 |
}
|
83 |
+
}
|
84 |
|
85 |
+
/**
|
86 |
+
* this is hooked into wp_generate_attachment_metadata
|
87 |
+
* @param $meta
|
88 |
+
* @param null $ID
|
89 |
+
* @return WPShortPixel the instance
|
90 |
+
*/
|
91 |
function shortPixelHandleImageUploadHook($meta, $ID = null) {
|
92 |
global $shortPixelPluginInstance;
|
93 |
if(!isset($shortPixelPluginInstance)) {
|
180 |
}
|
181 |
|
182 |
if ( get_option('wp-short-pixel-create-webp-markup')) {
|
183 |
+
//add_filter( 'the_content', 'shortPixelConvertImgToPictureAddWebp', 10000 ); // priority big, so it will be executed last
|
184 |
+
//add_filter( 'post_thumbnail_html', 'shortPixelConvertImgToPictureAddWebp');
|
185 |
+
ob_start( 'shortPixelConvertImgToPictureAddWebp');
|
186 |
add_action( 'wp_head', 'shortPixelAddPictureJs');
|
187 |
// add_action( 'wp_enqueue_scripts', 'spAddPicturefillJs' );
|
188 |
}
|
192 |
add_action('ngg_added_new_image', 'shortPixelNggAdd');
|
193 |
|
194 |
$autoPng2Jpg = get_option('wp-short-pixel-png2jpg');
|
195 |
+
$autoMediaLibrary = get_option('wp-short-pixel-auto-media-library');
|
196 |
+
if($autoPng2Jpg && $autoMediaLibrary) {
|
197 |
add_action( 'wp_handle_upload', 'shortPixelPng2JpgHook');
|
198 |
add_action( 'mpp_handle_upload', 'shortPixelPng2JpgHook');
|
199 |
}
|
200 |
add_action('wp_handle_replace', 'shortPixelReplaceHook');
|
|
|
201 |
if($autoMediaLibrary) {
|
202 |
add_filter( 'wp_generate_attachment_metadata', 'shortPixelHandleImageUploadHook', 10, 2 );
|
203 |
add_filter( 'mpp_generate_metadata', 'shortPixelHandleImageUploadHook', 10, 2 );
|