Version Description
- add the webp files as thumbs to the sizes array in metadata so they are automatically used by themes that use srcset.
- add option to optimize PDFs or not.
- seamless integration with WP/LR Sync plugin.
- gracefully ignore missing thumbs on disk when doing the optimization - just mark them as missing in the metadata.
- gracefully add Media Library files that are present on disk but not present in the image metadata (sizes array).
- option to dismiss the top toolbar ShortPixel alert when quota expired.
- compute the backup folder size asynchronously in order to speed up the settings page.
- editors/authors now are able to optimize/restore images from the Media Library list.
- handle internationalized domain names (punycode encoded).
- reset failed images from Custom Media when user launches a reprocessing of the images from Bulk.
- bugfixes
Download this release
Release Info
Developer | ShortPixel |
Plugin | ShortPixel Image Optimizer |
Version | 4.2.6 |
Comparing to | |
See all releases |
Code changes from version 4.2.5 to 4.2.6
- class/db/shortpixel-custom-meta-dao.php +7 -2
- class/db/shortpixel-meta-facade.php +176 -39
- class/db/wp-shortpixel-media-library-adapter.php +18 -24
- class/model/shortpixel-meta.php +17 -2
- class/shortpixel-tools.php +16 -1
- class/shortpixel_queue.php +14 -1
- class/view/shortpixel-list-table.php +2 -2
- class/view/shortpixel_view.php +61 -17
- class/wp-shortpixel-settings.php +8 -0
- readme.txt +93 -54
- res/css/short-pixel.css +23 -1
- res/js/punycode.js +448 -0
- res/js/short-pixel.js +86 -9
- shortpixel_api.php +55 -20
- wp-shortpixel.php +319 -71
class/db/shortpixel-custom-meta-dao.php
CHANGED
@@ -306,6 +306,11 @@ class ShortPixelCustomMetaDao {
|
|
306 |
return $inserted;
|
307 |
}
|
308 |
|
|
|
|
|
|
|
|
|
|
|
309 |
public function getPaginatedMetas($hasNextGen, $count, $page, $orderby = false, $order = false) {
|
310 |
$sql = "SELECT sm.id, sm.name, sm.path folder, "
|
311 |
. ($hasNextGen ? "CASE WHEN ng.gid IS NOT NULL THEN 'NextGen' ELSE 'Custom' END media_type, " : "'Custom' media_type, ")
|
@@ -340,14 +345,14 @@ class ShortPixelCustomMetaDao {
|
|
340 |
public function getPendingMetaCount() {
|
341 |
$res = $this->db->query("SELECT COUNT(sm.id) recCount from {$this->db->getPrefix()}shortpixel_meta sm "
|
342 |
. "INNER JOIN {$this->db->getPrefix()}shortpixel_folders sf on sm.folder_id = sf.id "
|
343 |
-
. "WHERE sf.status <> -1 AND ( sm.status = 0 OR sm.status = 1 )");
|
344 |
return isset($res[0]->recCount) ? $res[0]->recCount : null;
|
345 |
}
|
346 |
|
347 |
public function getCustomMetaCount() {
|
348 |
$sql = "SELECT COUNT(sm.id) recCount FROM {$this->db->getPrefix()}shortpixel_meta sm "
|
349 |
. "INNER JOIN {$this->db->getPrefix()}shortpixel_folders sf on sm.folder_id = sf.id "
|
350 |
-
. "WHERE sf.status <> -1";
|
351 |
$res = $this->db->query($sql);
|
352 |
return isset($res[0]->recCount) ? $res[0]->recCount : 0;
|
353 |
}
|
306 |
return $inserted;
|
307 |
}
|
308 |
|
309 |
+
public function resetFailed() {
|
310 |
+
$sql = "UPDATE {$this->db->getPrefix()}shortpixel_meta SET status = 0, retries = 0 WHERE status < 0";
|
311 |
+
$this->db->query($sql);
|
312 |
+
}
|
313 |
+
|
314 |
public function getPaginatedMetas($hasNextGen, $count, $page, $orderby = false, $order = false) {
|
315 |
$sql = "SELECT sm.id, sm.name, sm.path folder, "
|
316 |
. ($hasNextGen ? "CASE WHEN ng.gid IS NOT NULL THEN 'NextGen' ELSE 'Custom' END media_type, " : "'Custom' media_type, ")
|
345 |
public function getPendingMetaCount() {
|
346 |
$res = $this->db->query("SELECT COUNT(sm.id) recCount from {$this->db->getPrefix()}shortpixel_meta sm "
|
347 |
. "INNER JOIN {$this->db->getPrefix()}shortpixel_folders sf on sm.folder_id = sf.id "
|
348 |
+
. "WHERE sf.status <> -1 AND sm.status <> 3 AND ( sm.status = 0 OR sm.status = 1 OR (sm.status < 0 AND sm.retries < 3))");
|
349 |
return isset($res[0]->recCount) ? $res[0]->recCount : null;
|
350 |
}
|
351 |
|
352 |
public function getCustomMetaCount() {
|
353 |
$sql = "SELECT COUNT(sm.id) recCount FROM {$this->db->getPrefix()}shortpixel_meta sm "
|
354 |
. "INNER JOIN {$this->db->getPrefix()}shortpixel_folders sf on sm.folder_id = sf.id "
|
355 |
+
. "WHERE sf.status <> -1 AND sm.status <> 3";
|
356 |
$res = $this->db->query($sql);
|
357 |
return isset($res[0]->recCount) ? $res[0]->recCount : 0;
|
358 |
}
|
class/db/shortpixel-meta-facade.php
CHANGED
@@ -46,21 +46,24 @@ class ShortPixelMetaFacade {
|
|
46 |
}
|
47 |
|
48 |
private static function rawMetaToMeta($ID, $rawMeta) {
|
|
|
49 |
return new ShortPixelMeta(array(
|
50 |
"id" => $ID,
|
51 |
-
"
|
|
|
52 |
"webPath" => (isset($rawMeta["file"]) ? $rawMeta["file"] : null),
|
53 |
"thumbs" => (isset($rawMeta["sizes"]) ? $rawMeta["sizes"] : array()),
|
54 |
"message" =>(isset($rawMeta["ShortPixelImprovement"]) ? $rawMeta["ShortPixelImprovement"] : null),
|
55 |
"compressionType" =>(isset($rawMeta["ShortPixel"]["type"]) ? ($rawMeta["ShortPixel"]["type"] == "lossy" ? 1 : 0) : null),
|
56 |
"thumbsOpt" =>(isset($rawMeta["ShortPixel"]["thumbsOpt"]) ? $rawMeta["ShortPixel"]["thumbsOpt"] : null),
|
|
|
57 |
"retinasOpt" =>(isset($rawMeta["ShortPixel"]["retinasOpt"]) ? $rawMeta["ShortPixel"]["retinasOpt"] : null),
|
58 |
"thumbsTodo" =>(isset($rawMeta["ShortPixel"]["thumbsTodo"]) ? $rawMeta["ShortPixel"]["thumbsTodo"] : false),
|
59 |
"backup" => !isset($rawMeta['ShortPixel']['NoBackup']),
|
60 |
"status" => (!isset($rawMeta["ShortPixel"]) ? 0
|
61 |
: (isset($rawMeta["ShortPixelImprovement"]) && is_numeric($rawMeta["ShortPixelImprovement"]) ? 2
|
62 |
: (isset($rawMeta["ShortPixel"]["WaitingProcessing"]) ? 1
|
63 |
-
: -500))),
|
64 |
"retries" =>(isset($rawMeta["ShortPixel"]["Retries"]) ? $rawMeta["ShortPixel"]["Retries"] : 0),
|
65 |
));
|
66 |
}
|
@@ -96,18 +99,55 @@ class ShortPixelMetaFacade {
|
|
96 |
foreach($duplicates as $_ID) {
|
97 |
$rawMeta = $this->sanitizeMeta(wp_get_attachment_metadata($_ID));
|
98 |
|
99 |
-
$rawMeta['
|
100 |
-
|
101 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
102 |
//thumbs were processed if settings or if they were explicitely requested
|
103 |
-
|
104 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
105 |
//if thumbsTodo - this means there was an explicit request to process thumbs for an image that was previously processed without
|
106 |
// don't update the ShortPixelImprovement ratio as this is only calculated based on main image
|
107 |
if($this->meta->getThumbsTodo()) {
|
108 |
$rawMeta['ShortPixel']['thumbsTodo'] = true;
|
109 |
} else {
|
110 |
-
|
|
|
|
|
111 |
unset($rawMeta['ShortPixel']['thumbsTodo']);
|
112 |
}
|
113 |
if($this->meta->getActualWidth() && $this->meta->getActualHeight()) {
|
@@ -120,6 +160,10 @@ class ShortPixelMetaFacade {
|
|
120 |
if($this->meta->getStatus() !== 1) {
|
121 |
unset($rawMeta['ShortPixel']['WaitingProcessing']);
|
122 |
}
|
|
|
|
|
|
|
|
|
123 |
wp_update_attachment_metadata($this->ID, $rawMeta);
|
124 |
$this->rawMeta = $rawMeta;
|
125 |
}
|
@@ -156,6 +200,7 @@ class ShortPixelMetaFacade {
|
|
156 |
} else {
|
157 |
if($status) {
|
158 |
$this->rawMeta['ShortPixel']['WaitingProcessing'] = true;
|
|
|
159 |
} else {
|
160 |
unset($this->rawMeta['ShortPixel']['WaitingProcessing']);
|
161 |
}
|
@@ -174,6 +219,7 @@ class ShortPixelMetaFacade {
|
|
174 |
}
|
175 |
} else {
|
176 |
$this->rawMeta['ShortPixelImprovement'] = $this->meta->getMessage();
|
|
|
177 |
unset($this->rawMeta['ShortPixel']['WaitingProcessing']);
|
178 |
wp_update_attachment_metadata($this->ID, $this->rawMeta);
|
179 |
}
|
@@ -195,7 +241,27 @@ class ShortPixelMetaFacade {
|
|
195 |
return trailingslashit((function_exists("is_multisite") && is_multisite()) ? network_site_url("/") : home_url());
|
196 |
}
|
197 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
198 |
public function getURLsAndPATHs($processThumbnails, $onlyThumbs = false, $addRetina = true) {
|
|
|
|
|
199 |
if($this->type == self::CUSTOM_TYPE) {
|
200 |
$meta = $this->getMeta();
|
201 |
|
@@ -205,55 +271,73 @@ class ShortPixelMetaFacade {
|
|
205 |
|
206 |
$filePaths[] = $meta->getPath();
|
207 |
} else {
|
208 |
-
$attURL = wp_get_attachment_url($this->ID);
|
209 |
-
if(!$attURL || !strlen($attURL)) {
|
210 |
-
throw new Exception("Post metadata is corrupt (No attachment URL)");
|
211 |
-
}
|
212 |
-
if ( !parse_url(WP_CONTENT_URL, PHP_URL_SCHEME) ) {//no absolute URLs used -> we implement a hack
|
213 |
-
$url = get_site_url() . $attURL;//get the file URL
|
214 |
-
}
|
215 |
-
else {
|
216 |
-
$url = $attURL;//get the file URL
|
217 |
-
}
|
218 |
-
$urlList[] = $url;
|
219 |
$path = get_attached_file($this->ID);//get the full file PATH
|
220 |
-
$
|
221 |
-
|
222 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
223 |
}
|
224 |
|
225 |
$meta = $this->getMeta();
|
226 |
$sizes = $meta->getThumbs();
|
227 |
|
228 |
//it is NOT a PDF file and thumbs are processable
|
229 |
-
if ( strtolower(substr($
|
230 |
&& ($processThumbnails || $onlyThumbs)
|
231 |
-
&& count($sizes))
|
232 |
{
|
233 |
-
|
234 |
-
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
|
|
|
|
|
|
|
|
|
|
|
240 |
}
|
241 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
242 |
}
|
243 |
if(!count($sizes)) {
|
244 |
WPShortPixel::log("getURLsAndPATHs: no meta sizes for ID " . $this->ID . " : " . json_encode($this->rawMeta));
|
245 |
}
|
246 |
|
247 |
-
if($onlyThumbs) { //remove the main image
|
248 |
array_shift($urlList);
|
249 |
array_shift($filePaths);
|
250 |
-
}
|
251 |
}
|
252 |
|
253 |
//convert the + which are replaced with spaces by wp_remote_post
|
254 |
array_walk($urlList, array( &$this, 'replacePlusChar') );
|
255 |
|
256 |
-
|
|
|
|
|
|
|
257 |
}
|
258 |
|
259 |
protected function replacePlusChar(&$url) {
|
@@ -326,6 +410,32 @@ class ShortPixelMetaFacade {
|
|
326 |
}
|
327 |
}
|
328 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
329 |
public static function getMaxMediaId() {
|
330 |
global $wpdb;
|
331 |
$queryMax = "SELECT max(post_id) as QueryID FROM " . $wpdb->prefix . "postmeta";
|
@@ -382,18 +492,45 @@ class ShortPixelMetaFacade {
|
|
382 |
* @param type $file
|
383 |
* @return string
|
384 |
*/
|
385 |
-
static public function
|
386 |
{
|
387 |
if(strstr($file, get_home_path())) {
|
388 |
$path = str_replace( get_home_path(), "", $file);
|
389 |
} else {
|
390 |
-
$path =
|
391 |
}
|
392 |
$pathArr = explode('/', $path);
|
393 |
unset($pathArr[count($pathArr) - 1]);
|
394 |
return implode('/', $pathArr) . '/';
|
395 |
-
}
|
396 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
397 |
public static function isMediaSubfolder($path) {
|
398 |
$uploadDir = wp_upload_dir();
|
399 |
$uploadBase = $uploadDir["basedir"];
|
46 |
}
|
47 |
|
48 |
private static function rawMetaToMeta($ID, $rawMeta) {
|
49 |
+
$path = get_attached_file($ID);
|
50 |
return new ShortPixelMeta(array(
|
51 |
"id" => $ID,
|
52 |
+
"name" => basename($path),
|
53 |
+
"path" => $path,
|
54 |
"webPath" => (isset($rawMeta["file"]) ? $rawMeta["file"] : null),
|
55 |
"thumbs" => (isset($rawMeta["sizes"]) ? $rawMeta["sizes"] : array()),
|
56 |
"message" =>(isset($rawMeta["ShortPixelImprovement"]) ? $rawMeta["ShortPixelImprovement"] : null),
|
57 |
"compressionType" =>(isset($rawMeta["ShortPixel"]["type"]) ? ($rawMeta["ShortPixel"]["type"] == "lossy" ? 1 : 0) : null),
|
58 |
"thumbsOpt" =>(isset($rawMeta["ShortPixel"]["thumbsOpt"]) ? $rawMeta["ShortPixel"]["thumbsOpt"] : null),
|
59 |
+
"thumbsMissing" =>(isset($rawMeta["ShortPixel"]["thumbsMissing"]) ? $rawMeta["ShortPixel"]["thumbsMissing"] : null),
|
60 |
"retinasOpt" =>(isset($rawMeta["ShortPixel"]["retinasOpt"]) ? $rawMeta["ShortPixel"]["retinasOpt"] : null),
|
61 |
"thumbsTodo" =>(isset($rawMeta["ShortPixel"]["thumbsTodo"]) ? $rawMeta["ShortPixel"]["thumbsTodo"] : false),
|
62 |
"backup" => !isset($rawMeta['ShortPixel']['NoBackup']),
|
63 |
"status" => (!isset($rawMeta["ShortPixel"]) ? 0
|
64 |
: (isset($rawMeta["ShortPixelImprovement"]) && is_numeric($rawMeta["ShortPixelImprovement"]) ? 2
|
65 |
: (isset($rawMeta["ShortPixel"]["WaitingProcessing"]) ? 1
|
66 |
+
: (isset($rawMeta["ShortPixel"]['ErrCode']) ? $rawMeta["ShortPixel"]['ErrCode'] : -500)))),
|
67 |
"retries" =>(isset($rawMeta["ShortPixel"]["Retries"]) ? $rawMeta["ShortPixel"]["Retries"] : 0),
|
68 |
));
|
69 |
}
|
99 |
foreach($duplicates as $_ID) {
|
100 |
$rawMeta = $this->sanitizeMeta(wp_get_attachment_metadata($_ID));
|
101 |
|
102 |
+
if(is_array($rawMeta['sizes'])) {
|
103 |
+
$rawMeta['sizes'] = array_merge($rawMeta['sizes'], $this->meta->getThumbs());
|
104 |
+
}
|
105 |
+
|
106 |
+
if(null === $this->meta->getCompressionType()) {
|
107 |
+
unset($rawMeta['ShortPixel']['type']);
|
108 |
+
} else {
|
109 |
+
$rawMeta['ShortPixel']['type'] = ($this->meta->getCompressionType() == 1 ? "lossy" : "lossless");
|
110 |
+
}
|
111 |
+
|
112 |
+
if(null === $this->meta->getKeepExif()) {
|
113 |
+
unset($rawMeta['ShortPixel']['exifKept']);
|
114 |
+
} else {
|
115 |
+
$rawMeta['ShortPixel']['exifKept'] = $this->meta->getKeepExif();
|
116 |
+
}
|
117 |
+
|
118 |
+
if(null === $this->meta->getTsOptimized()) {
|
119 |
+
unset($rawMeta['ShortPixel']['date']);
|
120 |
+
} else {
|
121 |
+
$rawMeta['ShortPixel']['date'] = date("Y-m-d", strtotime($this->meta->getTsOptimized()));
|
122 |
+
}
|
123 |
+
|
124 |
//thumbs were processed if settings or if they were explicitely requested
|
125 |
+
if(null === $this->meta->getThumbsOpt()) {
|
126 |
+
unset($rawMeta['ShortPixel']['thumbsOpt']);
|
127 |
+
} else {
|
128 |
+
$rawMeta['ShortPixel']['thumbsOpt'] = $this->meta->getThumbsOpt();
|
129 |
+
}
|
130 |
+
|
131 |
+
$thumbsMissing = $this->meta->getThumbsMissing();
|
132 |
+
if(count($thumbsMissing)) {
|
133 |
+
$rawMeta['ShortPixel']['thumbsMissing'] = $this->meta->getThumbsMissing();
|
134 |
+
} else {
|
135 |
+
unset($rawMeta['ShortPixel']['thumbsMissing']);
|
136 |
+
}
|
137 |
+
|
138 |
+
if(null === $this->meta->getRetinasOpt()) {
|
139 |
+
unset($rawMeta['ShortPixel']['retinasOpt']);
|
140 |
+
} else {
|
141 |
+
$rawMeta['ShortPixel']['retinasOpt'] = $this->meta->getRetinasOpt();
|
142 |
+
}
|
143 |
//if thumbsTodo - this means there was an explicit request to process thumbs for an image that was previously processed without
|
144 |
// don't update the ShortPixelImprovement ratio as this is only calculated based on main image
|
145 |
if($this->meta->getThumbsTodo()) {
|
146 |
$rawMeta['ShortPixel']['thumbsTodo'] = true;
|
147 |
} else {
|
148 |
+
if($this->meta->getStatus() > 0) {
|
149 |
+
$rawMeta['ShortPixelImprovement'] = "".round($this->meta->getImprovementPercent(),2);
|
150 |
+
}
|
151 |
unset($rawMeta['ShortPixel']['thumbsTodo']);
|
152 |
}
|
153 |
if($this->meta->getActualWidth() && $this->meta->getActualHeight()) {
|
160 |
if($this->meta->getStatus() !== 1) {
|
161 |
unset($rawMeta['ShortPixel']['WaitingProcessing']);
|
162 |
}
|
163 |
+
if($this->meta->getStatus() >= 0) {
|
164 |
+
unset($rawMeta['ShortPixel']['ErrCode']);
|
165 |
+
}
|
166 |
+
|
167 |
wp_update_attachment_metadata($this->ID, $rawMeta);
|
168 |
$this->rawMeta = $rawMeta;
|
169 |
}
|
200 |
} else {
|
201 |
if($status) {
|
202 |
$this->rawMeta['ShortPixel']['WaitingProcessing'] = true;
|
203 |
+
unset($this->rawMeta['ShortPixel']['ErrCode']);
|
204 |
} else {
|
205 |
unset($this->rawMeta['ShortPixel']['WaitingProcessing']);
|
206 |
}
|
219 |
}
|
220 |
} else {
|
221 |
$this->rawMeta['ShortPixelImprovement'] = $this->meta->getMessage();
|
222 |
+
$this->rawMeta['ShortPixel']['ErrCode'] = $errorCode;
|
223 |
unset($this->rawMeta['ShortPixel']['WaitingProcessing']);
|
224 |
wp_update_attachment_metadata($this->ID, $this->rawMeta);
|
225 |
}
|
241 |
return trailingslashit((function_exists("is_multisite") && is_multisite()) ? network_site_url("/") : home_url());
|
242 |
}
|
243 |
|
244 |
+
//this is in test
|
245 |
+
public static function getHomeUrl2() {
|
246 |
+
return trailingslashit(ShortPixelTools::commonPrefix(self::getHomeUrl(), content_url()));
|
247 |
+
}
|
248 |
+
|
249 |
+
public static function safeGetAttachmentUrl($id) {
|
250 |
+
$attURL = wp_get_attachment_url($id);
|
251 |
+
if(!$attURL || !strlen($attURL)) {
|
252 |
+
throw new Exception("Post metadata is corrupt (No attachment URL)");
|
253 |
+
}
|
254 |
+
if ( !parse_url(WP_CONTENT_URL, PHP_URL_SCHEME) ) {//no absolute URLs used -> we implement a hack
|
255 |
+
return get_site_url() . $attURL;//get the file URL
|
256 |
+
}
|
257 |
+
else {
|
258 |
+
return $attURL;//get the file URL
|
259 |
+
}
|
260 |
+
}
|
261 |
+
|
262 |
public function getURLsAndPATHs($processThumbnails, $onlyThumbs = false, $addRetina = true) {
|
263 |
+
$sizesMissing = array();
|
264 |
+
|
265 |
if($this->type == self::CUSTOM_TYPE) {
|
266 |
$meta = $this->getMeta();
|
267 |
|
271 |
|
272 |
$filePaths[] = $meta->getPath();
|
273 |
} else {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
274 |
$path = get_attached_file($this->ID);//get the full file PATH
|
275 |
+
$mainExists = file_exists($path);
|
276 |
+
$url = self::safeGetAttachmentUrl($this->ID);
|
277 |
+
$urlList = array(); $filePaths = array();
|
278 |
+
|
279 |
+
if($mainExists) {
|
280 |
+
$urlList[] = $url;
|
281 |
+
$filePaths[] = $path;
|
282 |
+
if($addRetina) {
|
283 |
+
$this->addRetina($path, $url, $filePaths, $urlList);
|
284 |
+
}
|
285 |
}
|
286 |
|
287 |
$meta = $this->getMeta();
|
288 |
$sizes = $meta->getThumbs();
|
289 |
|
290 |
//it is NOT a PDF file and thumbs are processable
|
291 |
+
if ( strtolower(substr($path,strrpos($path, ".")+1)) != "pdf"
|
292 |
&& ($processThumbnails || $onlyThumbs)
|
293 |
+
&& count($sizes))
|
294 |
{
|
295 |
+
$uploadDir = wp_upload_dir();
|
296 |
+
$Tmp = explode("/", $uploadDir['basedir']);
|
297 |
+
$TmpCount = count($Tmp);
|
298 |
+
$StichString = $Tmp[$TmpCount-2] . "/" . $Tmp[$TmpCount-1];
|
299 |
+
|
300 |
+
foreach( $sizes as $thumbnailName => $thumbnailInfo ) {
|
301 |
+
if(strpos($thumbnailName, ShortPixelMeta::WEBP_THUMB_PREFIX) === 0) {
|
302 |
+
continue;
|
303 |
+
}
|
304 |
+
$origPath = $tPath = str_replace(ShortPixelAPI::MB_basename($path), $thumbnailInfo['file'], $path);
|
305 |
+
if ( !file_exists($tPath) ) {
|
306 |
+
$tPath = $uploadDir['basedir'] . substr($tPath, strpos($tPath, $StichString) + strlen($StichString));
|
307 |
}
|
308 |
+
if ( !file_exists($tPath) ) {
|
309 |
+
$tPath = trailingslashit($uploadDir['basedir']) . $origPath;
|
310 |
+
}
|
311 |
+
if (file_exists($tPath)) {
|
312 |
+
$tUrl = str_replace(ShortPixelAPI::MB_basename($url), $thumbnailInfo['file'], $url);
|
313 |
+
$urlList[] = $tUrl;
|
314 |
+
$filePaths[] = $tPath;
|
315 |
+
if($addRetina) {
|
316 |
+
$this->addRetina($tPath, $tUrl, $filePaths, $urlList);
|
317 |
+
}
|
318 |
+
}
|
319 |
+
else {
|
320 |
+
$sizesMissing[$thumbnailName] = ShortPixelAPI::MB_basename($tPath);
|
321 |
+
}
|
322 |
+
}
|
323 |
}
|
324 |
if(!count($sizes)) {
|
325 |
WPShortPixel::log("getURLsAndPATHs: no meta sizes for ID " . $this->ID . " : " . json_encode($this->rawMeta));
|
326 |
}
|
327 |
|
328 |
+
if($onlyThumbs && $mainExists) { //remove the main image
|
329 |
array_shift($urlList);
|
330 |
array_shift($filePaths);
|
331 |
+
}
|
332 |
}
|
333 |
|
334 |
//convert the + which are replaced with spaces by wp_remote_post
|
335 |
array_walk($urlList, array( &$this, 'replacePlusChar') );
|
336 |
|
337 |
+
$filePaths = ShortPixelAPI::CheckAndFixImagePaths($filePaths);//check for images to make sure they exist on disk
|
338 |
+
|
339 |
+
//die(var_dump(array("URLs" => $urlList, "PATHs" => $filePaths)));
|
340 |
+
return array("URLs" => $urlList, "PATHs" => $filePaths, "sizesMissing" => $sizesMissing);
|
341 |
}
|
342 |
|
343 |
protected function replacePlusChar(&$url) {
|
410 |
}
|
411 |
}
|
412 |
|
413 |
+
public function getWebpSizeMeta($path) {
|
414 |
+
$meta = $this->getMeta();
|
415 |
+
foreach($meta->getThumbs() as $thumbKey => $thumbMeta) {
|
416 |
+
if(isset($thumbMeta['file']) && strpos($path, $thumbMeta['file']) !== false) {
|
417 |
+
$thumbMeta['file'] = preg_replace( '/\.' . pathinfo($path, PATHINFO_EXTENSION) . '$/', '.webp', $thumbMeta['file']);
|
418 |
+
$thumbMeta['mime-type'] = 'image/webp';
|
419 |
+
return array('key' => ShortPixelMeta::WEBP_THUMB_PREFIX . $thumbKey, 'val' => $thumbMeta);
|
420 |
+
}
|
421 |
+
}
|
422 |
+
$name = $meta->getName();
|
423 |
+
if(strpos($path, $name) !== false) {
|
424 |
+
if(!file_exists($path)) {
|
425 |
+
return false;
|
426 |
+
}
|
427 |
+
$size = getimagesize($path);
|
428 |
+
return array('key' => ShortPixelMeta::WEBP_THUMB_PREFIX . 'main',
|
429 |
+
'val' => array( // it's a file that has no corresponding thumb so it's the WEBP for the main file
|
430 |
+
'file' => pathinfo(ShortPixelAPI::MB_basename($path), PATHINFO_FILENAME) . '.webp',
|
431 |
+
'width' => $size[0],
|
432 |
+
'height' => $size[1],
|
433 |
+
'mime-type' => 'image/webp'
|
434 |
+
));
|
435 |
+
}
|
436 |
+
return false;
|
437 |
+
}
|
438 |
+
|
439 |
public static function getMaxMediaId() {
|
440 |
global $wpdb;
|
441 |
$queryMax = "SELECT max(post_id) as QueryID FROM " . $wpdb->prefix . "postmeta";
|
492 |
* @param type $file
|
493 |
* @return string
|
494 |
*/
|
495 |
+
static public function returnSubDirOld($file, $type)
|
496 |
{
|
497 |
if(strstr($file, get_home_path())) {
|
498 |
$path = str_replace( get_home_path(), "", $file);
|
499 |
} else {
|
500 |
+
$path = (substr($file, 1));
|
501 |
}
|
502 |
$pathArr = explode('/', $path);
|
503 |
unset($pathArr[count($pathArr) - 1]);
|
504 |
return implode('/', $pathArr) . '/';
|
505 |
+
}
|
506 |
+
|
507 |
+
/**
|
508 |
+
* return subdir for that particular attached file - if it's media library then last 3 path items, otherwise substract the uploads path
|
509 |
+
* Has trailing directory separator (/)
|
510 |
+
* @param type $file
|
511 |
+
* @return string
|
512 |
+
*/
|
513 |
+
static public function returnSubDir($file, $type)
|
514 |
+
{
|
515 |
+
$hp = wp_normalize_path(get_home_path());
|
516 |
+
$file = wp_normalize_path($file);
|
517 |
+
$sp__uploads = wp_upload_dir();
|
518 |
+
if(strstr($file, $hp)) {
|
519 |
+
$path = str_replace( $hp, "", $file);
|
520 |
+
} elseif( strstr($file, dirname( WP_CONTENT_DIR ))) { //in some situations the content dir is not inside the root, check this also (ex. single.shortpixel.com)
|
521 |
+
$path = str_replace( trailingslashit(dirname( WP_CONTENT_DIR )), "", $file);
|
522 |
+
} elseif( (strstr(realpath($file), realpath($hp)))) {
|
523 |
+
$path = str_replace( realpath($hp), "", realpath($file));
|
524 |
+
} elseif( strstr($file, trailingslashit(dirname(dirname( $sp__uploads['basedir'] )))) ) {
|
525 |
+
$path = str_replace( trailingslashit(dirname(dirname( $sp__uploads['basedir'] ))), "", $file);
|
526 |
+
} else {
|
527 |
+
$path = (substr($file, 1));
|
528 |
+
}
|
529 |
+
$pathArr = explode('/', $path);
|
530 |
+
unset($pathArr[count($pathArr) - 1]);
|
531 |
+
return implode('/', $pathArr) . '/';
|
532 |
+
}
|
533 |
+
|
534 |
public static function isMediaSubfolder($path) {
|
535 |
$uploadDir = wp_upload_dir();
|
536 |
$uploadBase = $uploadDir["basedir"];
|
class/db/wp-shortpixel-media-library-adapter.php
CHANGED
@@ -3,7 +3,7 @@
|
|
3 |
class WpShortPixelMediaLbraryAdapter {
|
4 |
|
5 |
//count all the processable files in media library (while limiting the results to max 10000)
|
6 |
-
public static function countAllProcessableFiles($maxId = PHP_INT_MAX, $minId = 0){
|
7 |
global $wpdb;
|
8 |
|
9 |
$totalFiles = $mainFiles = $processedMainFiles = $processedTotalFiles =
|
@@ -43,12 +43,13 @@ class WpShortPixelMediaLbraryAdapter {
|
|
43 |
else //_wp_attachment_metadata
|
44 |
{
|
45 |
$attachment = unserialize($file->meta_value);
|
|
|
46 |
//processable
|
47 |
$isProcessable = false;
|
48 |
if(isset($attachment['file']) && !isset($filesMap[$attachment['file']]) && WPShortPixel::isProcessablePath($attachment['file'])){
|
49 |
$isProcessable = true;
|
50 |
if ( isset($attachment['sizes']) ) {
|
51 |
-
$totalFiles +=
|
52 |
}
|
53 |
if ( isset($attachment['file']) )
|
54 |
{
|
@@ -84,9 +85,11 @@ class WpShortPixelMediaLbraryAdapter {
|
|
84 |
$thumbs = $attachment['ShortPixel']['thumbsOpt'];
|
85 |
}
|
86 |
elseif ( isset($attachment['sizes']) ) {
|
87 |
-
$thumbs =
|
88 |
}
|
89 |
-
|
|
|
|
|
90 |
$mainUnprocessedThumbs++;
|
91 |
}
|
92 |
|
@@ -129,27 +132,18 @@ class WpShortPixelMediaLbraryAdapter {
|
|
129 |
);
|
130 |
}
|
131 |
|
132 |
-
public static function
|
133 |
-
$
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
$missing = array();
|
139 |
-
//it is NOT a PDF file and thumbs are processable
|
140 |
-
if ( strtolower(substr($filePath[0],strrpos($filePath[0], ".")+1)) != "pdf"
|
141 |
-
&& count($meta['sizes']))
|
142 |
-
{
|
143 |
-
foreach( $meta['sizes'] as $size => $thumbnailInfo ) {
|
144 |
-
if(!file_exists(str_replace(ShortPixelAPI::MB_basename($filePath[0]), $thumbnailInfo['file'], $path))) {
|
145 |
-
$missing[] = $size;
|
146 |
-
}
|
147 |
-
}
|
148 |
-
foreach($missing as $size) {
|
149 |
-
unset($meta['sizes'][$size]);
|
150 |
-
}
|
151 |
}
|
152 |
-
|
|
|
|
|
|
|
|
|
|
|
153 |
}
|
154 |
|
155 |
protected static function getOptimalChunkSize() {
|
3 |
class WpShortPixelMediaLbraryAdapter {
|
4 |
|
5 |
//count all the processable files in media library (while limiting the results to max 10000)
|
6 |
+
public static function countAllProcessableFiles($includePdfs = true, $maxId = PHP_INT_MAX, $minId = 0){
|
7 |
global $wpdb;
|
8 |
|
9 |
$totalFiles = $mainFiles = $processedMainFiles = $processedTotalFiles =
|
43 |
else //_wp_attachment_metadata
|
44 |
{
|
45 |
$attachment = unserialize($file->meta_value);
|
46 |
+
$sizesCount = isset($attachment['sizes']) ? WpShortPixelMediaLbraryAdapter::countNonWebpSizes($attachment['sizes']) : 0;
|
47 |
//processable
|
48 |
$isProcessable = false;
|
49 |
if(isset($attachment['file']) && !isset($filesMap[$attachment['file']]) && WPShortPixel::isProcessablePath($attachment['file'])){
|
50 |
$isProcessable = true;
|
51 |
if ( isset($attachment['sizes']) ) {
|
52 |
+
$totalFiles += $sizesCount;
|
53 |
}
|
54 |
if ( isset($attachment['file']) )
|
55 |
{
|
85 |
$thumbs = $attachment['ShortPixel']['thumbsOpt'];
|
86 |
}
|
87 |
elseif ( isset($attachment['sizes']) ) {
|
88 |
+
$thumbs = $sizesCount;
|
89 |
}
|
90 |
+
$thumbsMissing = isset($attachment['ShortPixel']['thumbsMissing']) ? $attachment['ShortPixel']['thumbsMissing'] : array();
|
91 |
+
|
92 |
+
if ( isset($attachment['sizes']) && $sizesCount > $thumbs + count($thumbsMissing)) {
|
93 |
$mainUnprocessedThumbs++;
|
94 |
}
|
95 |
|
132 |
);
|
133 |
}
|
134 |
|
135 |
+
public static function countNonWebpSizes($sizes) {
|
136 |
+
$count = 0;
|
137 |
+
foreach($sizes as $key => $val) {
|
138 |
+
if (strpos($key, ShortPixelMeta::WEBP_THUMB_PREFIX) === 0) continue;
|
139 |
+
$count++;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
140 |
}
|
141 |
+
return $count;
|
142 |
+
}
|
143 |
+
|
144 |
+
public static function thumbsSearchPattern($mainFile) {
|
145 |
+
$ext = pathinfo($mainFile, PATHINFO_EXTENSION);
|
146 |
+
return substr($mainFile, 0, strlen($mainFile) - strlen($ext) - 1) . "*[0-9]x*[0-9]." . $ext;
|
147 |
}
|
148 |
|
149 |
protected static function getOptimalChunkSize() {
|
class/model/shortpixel-meta.php
CHANGED
@@ -12,6 +12,7 @@ class ShortPixelMeta extends ShortPixelEntity{
|
|
12 |
protected $compressionType;
|
13 |
protected $compressedSize;
|
14 |
protected $thumbsOpt;
|
|
|
15 |
protected $retinasOpt;
|
16 |
protected $thumbsTodo;
|
17 |
protected $keepExif;
|
@@ -30,6 +31,8 @@ class ShortPixelMeta extends ShortPixelEntity{
|
|
30 |
protected $thumbs;
|
31 |
|
32 |
const TABLE_SUFFIX = 'meta';
|
|
|
|
|
33 |
|
34 |
public function __construct($data = array()) {
|
35 |
parent::__construct($data);
|
@@ -136,6 +139,15 @@ class ShortPixelMeta extends ShortPixelEntity{
|
|
136 |
function setThumbsOpt($thumbsOpt) {
|
137 |
$this->thumbsOpt = $thumbsOpt;
|
138 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
139 |
function getRetinasOpt() {
|
140 |
return $this->retinasOpt;
|
141 |
}
|
@@ -254,6 +266,9 @@ class ShortPixelMeta extends ShortPixelEntity{
|
|
254 |
|
255 |
function setThumbs($thumbs) {
|
256 |
$this->thumbs = $thumbs;
|
257 |
-
}
|
258 |
-
|
|
|
|
|
|
|
259 |
}
|
12 |
protected $compressionType;
|
13 |
protected $compressedSize;
|
14 |
protected $thumbsOpt;
|
15 |
+
protected $thumbsMissing;
|
16 |
protected $retinasOpt;
|
17 |
protected $thumbsTodo;
|
18 |
protected $keepExif;
|
31 |
protected $thumbs;
|
32 |
|
33 |
const TABLE_SUFFIX = 'meta';
|
34 |
+
const WEBP_THUMB_PREFIX = 'sp-webp-';
|
35 |
+
const FOUND_THUMB_PREFIX = 'sp-found-';
|
36 |
|
37 |
public function __construct($data = array()) {
|
38 |
parent::__construct($data);
|
139 |
function setThumbsOpt($thumbsOpt) {
|
140 |
$this->thumbsOpt = $thumbsOpt;
|
141 |
}
|
142 |
+
|
143 |
+
function getThumbsMissing() {
|
144 |
+
return $this->thumbsMissing;
|
145 |
+
}
|
146 |
+
|
147 |
+
function setThumbsMissing($thumbsMissing) {
|
148 |
+
$this->thumbsMissing = $thumbsMissing;
|
149 |
+
}
|
150 |
+
|
151 |
function getRetinasOpt() {
|
152 |
return $this->retinasOpt;
|
153 |
}
|
266 |
|
267 |
function setThumbs($thumbs) {
|
268 |
$this->thumbs = $thumbs;
|
269 |
+
}
|
270 |
+
|
271 |
+
function addThumbs($thumbs) {
|
272 |
+
$this->thumbs = array_merge($this->thumbs, $thumbs);
|
273 |
+
}
|
274 |
}
|
class/shortpixel-tools.php
CHANGED
@@ -38,5 +38,20 @@ class ShortPixelTools {
|
|
38 |
|
39 |
//If no checks triggered, we end up here - not an AJAX request.
|
40 |
return false;
|
41 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
42 |
}
|
38 |
|
39 |
//If no checks triggered, we end up here - not an AJAX request.
|
40 |
return false;
|
41 |
+
}
|
42 |
+
|
43 |
+
public static function commonPrefix($str1, $str2) {
|
44 |
+
$limit = min(strlen($str1), strlen($str2));
|
45 |
+
for ($i = 0; $i < $limit && $str1[$i] === $str2[$i]; $i++);
|
46 |
+
return substr($str1, 0, $i);
|
47 |
+
}
|
48 |
+
|
49 |
+
/**
|
50 |
+
* This is a simplified wp_send_json made compatible with WP 3.2.x to 3.4.x
|
51 |
+
* @param type $response
|
52 |
+
*/
|
53 |
+
public static function sendJSON($response) {
|
54 |
+
@header( 'Content-Type: application/json; charset=' . get_option( 'blog_charset' ) );
|
55 |
+
die(json_encode($response));
|
56 |
+
}
|
57 |
}
|
class/shortpixel_queue.php
CHANGED
@@ -97,6 +97,19 @@ class ShortPixelQueue {
|
|
97 |
WPShortPixel::log("PUSH: Updated: ".json_encode($_SESSION["wp-short-pixel-priorityQueue"]));//get_option("wp-short-pixel-priorityQueue")));
|
98 |
}
|
99 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
100 |
public function getFirst($count = 1)//return the first values added to priority queue
|
101 |
{
|
102 |
$priorityQueue = $_SESSION["wp-short-pixel-priorityQueue"];//self::getOpt("wp-short-pixel-priorityQueue", array());
|
@@ -230,7 +243,7 @@ class ShortPixelQueue {
|
|
230 |
|
231 |
public function setBulkPreviousPercent() {
|
232 |
//processable and already processed
|
233 |
-
$res = WpShortPixelMediaLbraryAdapter::countAllProcessableFiles($this->getFlagBulkId(), $this->settings->stopBulkId);
|
234 |
$this->settings->bulkCount = $res["mainFiles"];
|
235 |
|
236 |
//if compression type changed, add also the images with the other compression type
|
97 |
WPShortPixel::log("PUSH: Updated: ".json_encode($_SESSION["wp-short-pixel-priorityQueue"]));//get_option("wp-short-pixel-priorityQueue")));
|
98 |
}
|
99 |
|
100 |
+
public function enqueue($ID)//add an ID to priority queue as LAST
|
101 |
+
{
|
102 |
+
$priorityQueue = $_SESSION["wp-short-pixel-priorityQueue"]; //get_option("wp-short-pixel-priorityQueue");
|
103 |
+
WPShortPixel::log("PUSH: Push ID $ID into queue ".json_encode($priorityQueue));
|
104 |
+
array_unshift($priorityQueue, $ID);
|
105 |
+
$prioQ = array_unique($priorityQueue);
|
106 |
+
$_SESSION["wp-short-pixel-priorityQueue"] = $prioQ;
|
107 |
+
//push also to the options queue, in case the session gets killed retrieve from there
|
108 |
+
$this->settings->priorityQueue = $prioQ;
|
109 |
+
|
110 |
+
WPShortPixel::log("ENQUEUE: Updated: ".json_encode($_SESSION["wp-short-pixel-priorityQueue"]));//get_option("wp-short-pixel-priorityQueue")));
|
111 |
+
}
|
112 |
+
|
113 |
public function getFirst($count = 1)//return the first values added to priority queue
|
114 |
{
|
115 |
$priorityQueue = $_SESSION["wp-short-pixel-priorityQueue"];//self::getOpt("wp-short-pixel-priorityQueue", array());
|
243 |
|
244 |
public function setBulkPreviousPercent() {
|
245 |
//processable and already processed
|
246 |
+
$res = WpShortPixelMediaLbraryAdapter::countAllProcessableFiles($this->settings->optimizePdfs, $this->getFlagBulkId(), $this->settings->stopBulkId);
|
247 |
$this->settings->bulkCount = $res["mainFiles"];
|
248 |
|
249 |
//if compression type changed, add also the images with the other compression type
|
class/view/shortpixel-list-table.php
CHANGED
@@ -43,7 +43,7 @@ class ShortPixelListTable extends WP_List_Table {
|
|
43 |
function column_default( $item, $column_name ) {
|
44 |
switch( $column_name ) {
|
45 |
case 'name':
|
46 |
-
$title = '<a href="" title="'.$item->folder.'"><strong>' . $item->name . '</strong></a>';
|
47 |
|
48 |
$url = ShortPixelMetaFacade::pathToWebPath($item->folder);
|
49 |
$actions = array(
|
@@ -102,7 +102,7 @@ class ShortPixelListTable extends WP_List_Table {
|
|
102 |
if($item->status < 0) {
|
103 |
$msg = $item->message . "(" . __('code','shortpixel-image-optimiser') . ": " . $item->status . ")";
|
104 |
} else {
|
105 |
-
$msg = "";
|
106 |
}
|
107 |
}
|
108 |
return "<div id='sp-cust-msg-C-" . $item->id . "'>" . $msg . "</div>";
|
43 |
function column_default( $item, $column_name ) {
|
44 |
switch( $column_name ) {
|
45 |
case 'name':
|
46 |
+
$title = '<a href="' . ShortPixelMetaFacade::pathToWebPath($item->folder) . '" title="'.$item->folder.'" target="_blank"><strong>' . $item->name . '</strong></a>';
|
47 |
|
48 |
$url = ShortPixelMetaFacade::pathToWebPath($item->folder);
|
49 |
$actions = array(
|
102 |
if($item->status < 0) {
|
103 |
$msg = $item->message . "(" . __('code','shortpixel-image-optimiser') . ": " . $item->status . ")";
|
104 |
} else {
|
105 |
+
$msg = "<span style='display:none;'>" . $item->status . "</span>";
|
106 |
}
|
107 |
}
|
108 |
return "<div id='sp-cust-msg-C-" . $item->id . "'>" . $msg . "</div>";
|
class/view/shortpixel_view.php
CHANGED
@@ -16,11 +16,11 @@ class ShortPixelView {
|
|
16 |
public function displayQuotaExceededAlert($quotaData, $averageCompression = false, $recheck = false)
|
17 |
{ ?>
|
18 |
<br/>
|
19 |
-
<div class="wrap sp-quota-exceeded-alert">
|
20 |
<?php if($averageCompression) { ?>
|
21 |
<div style="float:right; margin-top: 10px">
|
22 |
-
<div class="bulk-progress-indicator">
|
23 |
-
<div style="margin-bottom:5px"><?php _e('Average reduction','shortpixel-image-optimiser');?></div>
|
24 |
<div id="sp-avg-optimization"><input type="text" id="sp-avg-optimization-dial" value="<?php echo("" . round($averageCompression))?>" class="dial"></div>
|
25 |
<script>
|
26 |
jQuery(function() {
|
@@ -36,12 +36,12 @@ class ShortPixelView {
|
|
36 |
echo('<span style="color: red">' . __('You have no available image credits. If you just bought a package, please note that sometimes it takes a few minutes for the payment confirmation to be sent to us by the payment processor.','shortpixel-image-optimiser') . '</span><br>');
|
37 |
}
|
38 |
printf(__('The plugin has optimized <strong>%s images</strong> and stopped because it reached the available quota limit.','shortpixel-image-optimiser'),
|
39 |
-
number_format($quotaData['APICallsMadeNumeric'] + $quotaData['APICallsMadeOneTimeNumeric']));?>
|
40 |
<?php if($quotaData['totalProcessedFiles'] < $quotaData['totalFiles']) { ?>
|
41 |
<?php
|
42 |
printf(__('<strong>%s images and %s thumbnails</strong> are not yet optimized by ShortPixel.','shortpixel-image-optimiser'),
|
43 |
-
number_format($quotaData['mainFiles'] - $quotaData['mainProcessedFiles']),
|
44 |
-
number_format(($quotaData['totalFiles'] - $quotaData['mainFiles']) - ($quotaData['totalProcessedFiles'] - $quotaData['mainProcessedFiles']))); ?>
|
45 |
<?php } ?></p>
|
46 |
<div> <!-- style='float:right;margin-top:20px;'> -->
|
47 |
<a class='button button-primary' href='https://shortpixel.com/login/<?php echo($this->ctrl->getApiKey());?>' target='_blank'><?php _e('Upgrade','shortpixel-image-optimiser');?></a>
|
@@ -68,12 +68,16 @@ class ShortPixelView {
|
|
68 |
<?php
|
69 |
}
|
70 |
|
71 |
-
public static function displayActivationNotice($when = 'activate') {
|
72 |
-
|
|
|
|
|
73 |
<?php if($when != 'activate') { ?>
|
74 |
<div style="float:right;"><a href="javascript:dismissShortPixelNotice('<?php echo($when);?>')" class="button" style="margin-top:10px;"><?php _e('Dismiss','shortpixel-image-optimiser');?></a></div>
|
75 |
<?php } ?>
|
76 |
-
<h3><?php
|
|
|
|
|
77 |
switch($when) {
|
78 |
case '2h' :
|
79 |
_e("Action needed. Please <a href='https://shortpixel.com/wp-apikey' target='_blank'>get your API key</a> to activate your ShortPixel plugin.",'shortpixel-image-optimiser') . "<BR><BR>";
|
@@ -84,6 +88,16 @@ class ShortPixelView {
|
|
84 |
case 'activate':
|
85 |
self::displayApiKeyAlert();
|
86 |
break;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
87 |
}
|
88 |
?>
|
89 |
</div>
|
@@ -288,8 +302,8 @@ class ShortPixelView {
|
|
288 |
$todo = $reopt = false;
|
289 |
if($quotaData['totalProcessedFiles'] < $quotaData['totalFiles']) {
|
290 |
$todo = true;
|
291 |
-
$mainNotProcessed = $quotaData['mainFiles'] - $quotaData['mainProcessedFiles'];
|
292 |
-
$thumbsNotProcessed = ($quotaData['totalFiles'] - $quotaData['mainFiles']) - ($quotaData['totalProcessedFiles'] - $quotaData['mainProcessedFiles']);
|
293 |
?>
|
294 |
<p>
|
295 |
<?php
|
@@ -380,13 +394,21 @@ class ShortPixelView {
|
|
380 |
</div>
|
381 |
<?php } ?>
|
382 |
|
383 |
-
<div class="sp-floating-block notice bulk-notices-parent">
|
384 |
<div class="bulk-notice-container">
|
385 |
<div class="bulk-notice-msg bulk-lengthy">
|
386 |
<img src="<?php echo(plugins_url( 'shortpixel-image-optimiser/res/img/loading-dark-big.gif' ));?>">
|
387 |
<?php _e('Lengthy operation in progress:','shortpixel-image-optimiser');?><br>
|
388 |
<?php _e('Optimizing image','shortpixel-image-optimiser');?> <a href="#" data-href="<?php echo(get_admin_url());?>/post.php?post=__ID__&action=edit" target="_blank">placeholder.png</a>
|
389 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
390 |
<div class="bulk-notice-msg bulk-error" id="bulk-error-template">
|
391 |
<div style="float: right; margin-top: -4px; margin-right: -8px;">
|
392 |
<a href="javascript:void(0);" onclick="ShortPixel.removeBulkMsg(this)" style='color: #c32525;'>✖</a>
|
@@ -760,6 +782,7 @@ class ShortPixelView {
|
|
760 |
$createWebp = ($settings->createWebp ? 'checked' : '');
|
761 |
$autoMediaLibrary = ($settings->autoMediaLibrary ? 'checked' : '');
|
762 |
$optimizeRetina = ($settings->optimizeRetina ? 'checked' : '');
|
|
|
763 |
?>
|
764 |
<div class="wp-shortpixel-options">
|
765 |
<?php if(!$this->ctrl->getVerifiedKey()) { ?>
|
@@ -881,6 +904,12 @@ class ShortPixelView {
|
|
881 |
</p>
|
882 |
</td>
|
883 |
</tr>
|
|
|
|
|
|
|
|
|
|
|
|
|
884 |
<tr>
|
885 |
<th scope="row"><label for="authentication"><?php _e('HTTP AUTH credentials','shortpixel-image-optimiser');?></label></th>
|
886 |
<td>
|
@@ -951,9 +980,13 @@ class ShortPixelView {
|
|
951 |
<tr>
|
952 |
<th scope="row" bgcolor="#ffffff"><label for="apiQuota"><?php _e('Your monthly plan','shortpixel-image-optimiser');?>:</label></th>
|
953 |
<td bgcolor="#ffffff">
|
954 |
-
<?php
|
955 |
-
|
956 |
-
|
|
|
|
|
|
|
|
|
957 |
<?php printf(__('<a href="https://shortpixel.com/login/%s/tell-a-friend" target="_blank">Join our friend referral system</a> to win more credits. For each user that joins, you receive +100 images credits/month.','shortpixel-image-optimiser'),
|
958 |
$this->ctrl->getApiKey());?>
|
959 |
</td>
|
@@ -992,7 +1025,9 @@ class ShortPixelView {
|
|
992 |
<th scope="row"><label for="sizeBackup"><?php _e('Original images are stored in a backup folder. Your backup folder size is now:','shortpixel-image-optimiser');?></label></th>
|
993 |
<td>
|
994 |
<form action="" method="POST">
|
995 |
-
<?php
|
|
|
|
|
996 |
<input type="submit" style="margin-left: 15px; vertical-align: middle;" class="button button-secondary" name="emptyBackup" value="<?php _e('Empty backups','shortpixel-image-optimiser');?>"/>
|
997 |
</form>
|
998 |
</td>
|
@@ -1053,9 +1088,18 @@ class ShortPixelView {
|
|
1053 |
case 'imgOptimized':
|
1054 |
$successText = $this->getSuccessText($data['percent'],$data['bonus'],$data['type'],$data['thumbsOpt'],$data['thumbsTotal'], $data['retinasOpt']);
|
1055 |
if($extended) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1056 |
$successText .= ($data['webpCount'] ? "<br>+" . $data['webpCount'] . __(" WebP images", 'shortpixel-image-optimiser') : "")
|
1057 |
. "<br>EXIF: " . ($data['exifKept'] ? __('kept','shortpixel-image-optimiser') : __('removed','shortpixel-image-optimiser'))
|
1058 |
-
. "<br>" . __("Optimized on", 'shortpixel-image-optimiser') . ": " . $data['date']
|
|
|
1059 |
}
|
1060 |
$this->renderListCell($id, $data['showActions'],
|
1061 |
!$data['thumbsOpt'] && $data['thumbsTotal'], $data['thumbsTotal'], $data['backup'], $data['type'], $successText);
|
16 |
public function displayQuotaExceededAlert($quotaData, $averageCompression = false, $recheck = false)
|
17 |
{ ?>
|
18 |
<br/>
|
19 |
+
<div class="wrap sp-quota-exceeded-alert" id="short-pixel-notice-exceed">
|
20 |
<?php if($averageCompression) { ?>
|
21 |
<div style="float:right; margin-top: 10px">
|
22 |
+
<div class="bulk-progress-indicator" style="height: 110px">
|
23 |
+
<div style="margin-bottom:5px"><?php _e('Average image<br>reduction so far:','shortpixel-image-optimiser');?></div>
|
24 |
<div id="sp-avg-optimization"><input type="text" id="sp-avg-optimization-dial" value="<?php echo("" . round($averageCompression))?>" class="dial"></div>
|
25 |
<script>
|
26 |
jQuery(function() {
|
36 |
echo('<span style="color: red">' . __('You have no available image credits. If you just bought a package, please note that sometimes it takes a few minutes for the payment confirmation to be sent to us by the payment processor.','shortpixel-image-optimiser') . '</span><br>');
|
37 |
}
|
38 |
printf(__('The plugin has optimized <strong>%s images</strong> and stopped because it reached the available quota limit.','shortpixel-image-optimiser'),
|
39 |
+
number_format(max(0, $quotaData['APICallsMadeNumeric'] + $quotaData['APICallsMadeOneTimeNumeric'])));?>
|
40 |
<?php if($quotaData['totalProcessedFiles'] < $quotaData['totalFiles']) { ?>
|
41 |
<?php
|
42 |
printf(__('<strong>%s images and %s thumbnails</strong> are not yet optimized by ShortPixel.','shortpixel-image-optimiser'),
|
43 |
+
number_format(max(0, $quotaData['mainFiles'] - $quotaData['mainProcessedFiles'])),
|
44 |
+
number_format(max(0, ($quotaData['totalFiles'] - $quotaData['mainFiles']) - ($quotaData['totalProcessedFiles'] - $quotaData['mainProcessedFiles'])))); ?>
|
45 |
<?php } ?></p>
|
46 |
<div> <!-- style='float:right;margin-top:20px;'> -->
|
47 |
<a class='button button-primary' href='https://shortpixel.com/login/<?php echo($this->ctrl->getApiKey());?>' target='_blank'><?php _e('Upgrade','shortpixel-image-optimiser');?></a>
|
68 |
<?php
|
69 |
}
|
70 |
|
71 |
+
public static function displayActivationNotice($when = 'activate', $extra = '') {
|
72 |
+
$extraStyle = $when == 'compat' ? "style='border-left: 4px solid#ff0000;'" : '';
|
73 |
+
?>
|
74 |
+
<div class='notice notice-warning' id='short-pixel-notice-<?php echo($when);?>' <?php echo($extraStyle);?>>
|
75 |
<?php if($when != 'activate') { ?>
|
76 |
<div style="float:right;"><a href="javascript:dismissShortPixelNotice('<?php echo($when);?>')" class="button" style="margin-top:10px;"><?php _e('Dismiss','shortpixel-image-optimiser');?></a></div>
|
77 |
<?php } ?>
|
78 |
+
<h3><?php
|
79 |
+
if($when == 'compat') {_e('Warning','shortpixel-image-optimiser'); echo(' - ');}
|
80 |
+
_e('ShortPixel Image Optimizer','shortpixel-image-optimiser');?></h3> <?php
|
81 |
switch($when) {
|
82 |
case '2h' :
|
83 |
_e("Action needed. Please <a href='https://shortpixel.com/wp-apikey' target='_blank'>get your API key</a> to activate your ShortPixel plugin.",'shortpixel-image-optimiser') . "<BR><BR>";
|
88 |
case 'activate':
|
89 |
self::displayApiKeyAlert();
|
90 |
break;
|
91 |
+
case 'compat' :
|
92 |
+
_e("Using ShortPixel while other image optimization plugins are active can lead to unpredictable results. We recommend to deactivate the following plugin(s): ",'shortpixel-image-optimiser');
|
93 |
+
echo('<ul>');
|
94 |
+
foreach($extra as $plugin) {
|
95 |
+
echo('<li class="sp-conflict-plugins-list"><strong>' . $plugin['name'] . '</strong>');
|
96 |
+
echo('<a href="' . wp_nonce_url( admin_url( 'admin-post.php?action=shortpixel_deactivate_plugin&plugin=' . urlencode( $plugin['path'] ) ), 'sp_deactivate_plugin_nonce' ) . '" class="button">'
|
97 |
+
. __( 'Deactivate', 'shortpixel_image_optimiser' ) . '</a>');
|
98 |
+
}
|
99 |
+
echo("</ul>");
|
100 |
+
break;
|
101 |
}
|
102 |
?>
|
103 |
</div>
|
302 |
$todo = $reopt = false;
|
303 |
if($quotaData['totalProcessedFiles'] < $quotaData['totalFiles']) {
|
304 |
$todo = true;
|
305 |
+
$mainNotProcessed = max(0, $quotaData['mainFiles'] - $quotaData['mainProcessedFiles']);
|
306 |
+
$thumbsNotProcessed = max(0, ($quotaData['totalFiles'] - $quotaData['mainFiles']) - ($quotaData['totalProcessedFiles'] - $quotaData['mainProcessedFiles']));
|
307 |
?>
|
308 |
<p>
|
309 |
<?php
|
394 |
</div>
|
395 |
<?php } ?>
|
396 |
|
397 |
+
<div class="sp-floating-block sp-notice bulk-notices-parent">
|
398 |
<div class="bulk-notice-container">
|
399 |
<div class="bulk-notice-msg bulk-lengthy">
|
400 |
<img src="<?php echo(plugins_url( 'shortpixel-image-optimiser/res/img/loading-dark-big.gif' ));?>">
|
401 |
<?php _e('Lengthy operation in progress:','shortpixel-image-optimiser');?><br>
|
402 |
<?php _e('Optimizing image','shortpixel-image-optimiser');?> <a href="#" data-href="<?php echo(get_admin_url());?>/post.php?post=__ID__&action=edit" target="_blank">placeholder.png</a>
|
403 |
</div>
|
404 |
+
<div class="bulk-notice-msg bulk-maintenance">
|
405 |
+
<img src="<?php echo(plugins_url( 'shortpixel-image-optimiser/res/img/loading-dark-big.gif' ));?>">
|
406 |
+
<?php _e("The ShortPixel API is in maintenance mode. Please don't close this window. The bulk will resume automatically as soon as the API is back online.",'shortpixel-image-optimiser');?>
|
407 |
+
</div>
|
408 |
+
<div class="bulk-notice-msg bulk-queue-full">
|
409 |
+
<img src="<?php echo(plugins_url( 'shortpixel-image-optimiser/res/img/loading-dark-big.gif' ));?>">
|
410 |
+
<?php _e("Too many images processing simultaneously for your site, automatically retrying in 1 min. Please don't close this window.",'shortpixel-image-optimiser');?>
|
411 |
+
</div>
|
412 |
<div class="bulk-notice-msg bulk-error" id="bulk-error-template">
|
413 |
<div style="float: right; margin-top: -4px; margin-right: -8px;">
|
414 |
<a href="javascript:void(0);" onclick="ShortPixel.removeBulkMsg(this)" style='color: #c32525;'>✖</a>
|
782 |
$createWebp = ($settings->createWebp ? 'checked' : '');
|
783 |
$autoMediaLibrary = ($settings->autoMediaLibrary ? 'checked' : '');
|
784 |
$optimizeRetina = ($settings->optimizeRetina ? 'checked' : '');
|
785 |
+
$optimizePdfs = ($settings->optimizePdfs ? 'checked' : '');
|
786 |
?>
|
787 |
<div class="wp-shortpixel-options">
|
788 |
<?php if(!$this->ctrl->getVerifiedKey()) { ?>
|
904 |
</p>
|
905 |
</td>
|
906 |
</tr>
|
907 |
+
<tr>
|
908 |
+
<th scope="row"><label for="optimizePdfs"><?php _e('Optimize PDFs','shortpixel-image-optimiser');?></label></th>
|
909 |
+
<td>
|
910 |
+
<input name="optimizePdfs" type="checkbox" id="optimizePdfs" <?php echo( $optimizePdfs );?>> <?php _e('Optimize PDF documents.','shortpixel-image-optimiser');?>
|
911 |
+
</td>
|
912 |
+
</tr>
|
913 |
<tr>
|
914 |
<th scope="row"><label for="authentication"><?php _e('HTTP AUTH credentials','shortpixel-image-optimiser');?></label></th>
|
915 |
<td>
|
980 |
<tr>
|
981 |
<th scope="row" bgcolor="#ffffff"><label for="apiQuota"><?php _e('Your monthly plan','shortpixel-image-optimiser');?>:</label></th>
|
982 |
<td bgcolor="#ffffff">
|
983 |
+
<?php
|
984 |
+
$DateNow = time();
|
985 |
+
$DateSubscription = strtotime($quotaData['APILastRenewalDate']);
|
986 |
+
$DaysToReset = 30 - ((($DateNow - $DateSubscription) / 84600) % 30);
|
987 |
+
printf(__('%s/month, renews in %s days, on %s ( <a href="https://shortpixel.com/login/%s" target="_blank">Need More? See the options available</a> )','shortpixel-image-optimiser'),
|
988 |
+
$quotaData['APICallsQuota'], $DaysToReset,
|
989 |
+
date('M d, Y', strtotime(date('M d, Y') . ' + ' . $DaysToReset . ' days')), $this->ctrl->getApiKey());?><br/>
|
990 |
<?php printf(__('<a href="https://shortpixel.com/login/%s/tell-a-friend" target="_blank">Join our friend referral system</a> to win more credits. For each user that joins, you receive +100 images credits/month.','shortpixel-image-optimiser'),
|
991 |
$this->ctrl->getApiKey());?>
|
992 |
</td>
|
1025 |
<th scope="row"><label for="sizeBackup"><?php _e('Original images are stored in a backup folder. Your backup folder size is now:','shortpixel-image-optimiser');?></label></th>
|
1026 |
<td>
|
1027 |
<form action="" method="POST">
|
1028 |
+
<?php if ($backupFolderSize === null) { ?>
|
1029 |
+
<span id='backup-folder-size'>Calculating...</span>
|
1030 |
+
<?php } else { echo($backupFolderSize); }?>
|
1031 |
<input type="submit" style="margin-left: 15px; vertical-align: middle;" class="button button-secondary" name="emptyBackup" value="<?php _e('Empty backups','shortpixel-image-optimiser');?>"/>
|
1032 |
</form>
|
1033 |
</td>
|
1088 |
case 'imgOptimized':
|
1089 |
$successText = $this->getSuccessText($data['percent'],$data['bonus'],$data['type'],$data['thumbsOpt'],$data['thumbsTotal'], $data['retinasOpt']);
|
1090 |
if($extended) {
|
1091 |
+
$missingThumbs = '';
|
1092 |
+
if(count($data['thumbsMissing'])) {
|
1093 |
+
$missingThumbs .= "<br><span style='font-weight: bold;'>" . __("Missing thumbs:", 'shortpixel-image-optimiser');
|
1094 |
+
foreach($data['thumbsMissing'] as $miss) {
|
1095 |
+
$missingThumbs .= "<br> • " . $miss;
|
1096 |
+
}
|
1097 |
+
$missingThumbs .= '</span>';
|
1098 |
+
}
|
1099 |
$successText .= ($data['webpCount'] ? "<br>+" . $data['webpCount'] . __(" WebP images", 'shortpixel-image-optimiser') : "")
|
1100 |
. "<br>EXIF: " . ($data['exifKept'] ? __('kept','shortpixel-image-optimiser') : __('removed','shortpixel-image-optimiser'))
|
1101 |
+
. "<br>" . __("Optimized on", 'shortpixel-image-optimiser') . ": " . $data['date']
|
1102 |
+
. $missingThumbs;
|
1103 |
}
|
1104 |
$this->renderListCell($id, $data['showActions'],
|
1105 |
!$data['thumbsOpt'] && $data['thumbsTotal'], $data['thumbsTotal'], $data['backup'], $data['type'], $successText);
|
class/wp-shortpixel-settings.php
CHANGED
@@ -35,6 +35,7 @@ class WPShortPixelSettings {
|
|
35 |
'siteAuthUser' => 'wp-short-pixel-site-auth-user',
|
36 |
'siteAuthPass' => 'wp-short-pixel-site-auth-pass',
|
37 |
'autoMediaLibrary' => 'wp-short-pixel-auto-media-library',
|
|
|
38 |
|
39 |
//optimize other images than the ones in Media Library
|
40 |
'includeNextGen' => 'wp-short-pixel-include-next-gen',
|
@@ -100,6 +101,7 @@ class WPShortPixelSettings {
|
|
100 |
// the following lines practically set defaults for options if they're not set
|
101 |
self::getOpt('wp-short-pixel-auto-media-library', 1);
|
102 |
self::getOpt('wp-short-pixel-optimize-retina', 1);
|
|
|
103 |
self::getOpt( 'wp-short-pixel-fileCount', 0);
|
104 |
self::getOpt( 'wp-short-pixel-thumbnail-count', 0);//amount of optimized thumbnails
|
105 |
self::getOpt( 'wp-short-pixel-files-under-5-percent', 0);//amount of optimized thumbnails
|
@@ -131,6 +133,12 @@ class WPShortPixelSettings {
|
|
131 |
}
|
132 |
update_option( 'wp-short-pixel-activation-date', time());
|
133 |
delete_option( 'wp-short-pixel-bulk-last-status');
|
|
|
|
|
|
|
|
|
|
|
|
|
134 |
}
|
135 |
|
136 |
public static function onDeactivate() {
|
35 |
'siteAuthUser' => 'wp-short-pixel-site-auth-user',
|
36 |
'siteAuthPass' => 'wp-short-pixel-site-auth-pass',
|
37 |
'autoMediaLibrary' => 'wp-short-pixel-auto-media-library',
|
38 |
+
'optimizePdfs' => 'wp-short-pixel-optimize-pdfs',
|
39 |
|
40 |
//optimize other images than the ones in Media Library
|
41 |
'includeNextGen' => 'wp-short-pixel-include-next-gen',
|
101 |
// the following lines practically set defaults for options if they're not set
|
102 |
self::getOpt('wp-short-pixel-auto-media-library', 1);
|
103 |
self::getOpt('wp-short-pixel-optimize-retina', 1);
|
104 |
+
self::getOpt('wp-short-pixel-optimize-pdfs', 1);
|
105 |
self::getOpt( 'wp-short-pixel-fileCount', 0);
|
106 |
self::getOpt( 'wp-short-pixel-thumbnail-count', 0);//amount of optimized thumbnails
|
107 |
self::getOpt( 'wp-short-pixel-files-under-5-percent', 0);//amount of optimized thumbnails
|
133 |
}
|
134 |
update_option( 'wp-short-pixel-activation-date', time());
|
135 |
delete_option( 'wp-short-pixel-bulk-last-status');
|
136 |
+
$dismissed = get_option('wp-short-pixel-dismissed-notices', array());
|
137 |
+
if(isset($dismissed['compat'])) {
|
138 |
+
unset($dismissed['compat']);
|
139 |
+
update_option('wp-short-pixel-dismissed-notices', $dismissed);
|
140 |
+
}
|
141 |
+
|
142 |
}
|
143 |
|
144 |
public static function onDeactivate() {
|
readme.txt
CHANGED
@@ -1,11 +1,11 @@
|
|
1 |
=== ShortPixel Image Optimizer ===
|
2 |
|
3 |
-
Contributors:
|
4 |
Tags: image optimizer, image optimization, compress pdf, compress jpeg, compress png, image compression, wp smush, compress images, optimize images, shrink jpeg, optimize photos, tinypng
|
5 |
|
6 |
Requires at least: 3.2.0
|
7 |
Tested up to: 4.7
|
8 |
-
Stable tag: 4.2.
|
9 |
License: GPLv2 or later
|
10 |
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
11 |
|
@@ -18,6 +18,8 @@ Speed up your website and boost your SEO by compressing old & new images and PDF
|
|
18 |
Increase your website's SEO ranking, number of visitors and ultimately your sales by optimizing any image or PDF document on your website.
|
19 |
ShortPixel is an easy to use, lightweight, install-and-forget-about-it <a rel="friend" href="https://shortpixel.com" target="_blank">image optimization</a> plugin that can compress all your past images and PDF documents with a single click. New images are automatically resized/rescaled and optimized on the fly, in the background.
|
20 |
|
|
|
|
|
21 |
This plugin uses minimal resources and works well with any shared, cloud, VPS or dedicated web hosting. It can optimize any image you have on your website even the images that aren't listed in Media Library like those in galleries like NextGEN or added directly via FTP!
|
22 |
|
23 |
Both lossy and lossless image compression is available for the most common image types (JPG, PNG, GIF and WebP) plus PDF files. Optimized images mean better user experience, better PageSpeed Insights or GTmetrix results, better Google PageRank and more visitors.
|
@@ -53,10 +55,6 @@ Make an instant <a rel="friend" href="http://shortpixel.com/image-compression-te
|
|
53 |
* 40 days optimization report with all image details and overall statistics
|
54 |
* **free optimization credits for non-profits**, <a href="https://shortpixel.com/contact" target="_blank">contact us</a> for details
|
55 |
|
56 |
-
**Eager to test how it works?**
|
57 |
-
Give it a spin on a <a href="https://addendio.com/try-plugin/?slug=shortpixel-image-optimiser
|
58 |
-
" target="_blank">test environment</a> (thanks addendio!)
|
59 |
-
|
60 |
**How much it costs?**
|
61 |
ShortPixel comes with 100 free credits/month and additional credits can be bought with as little as $4.99 for 5,000 image credits.
|
62 |
Check out <a rel="friend" href="https://shortpixel.com/pricing" target="_blank">our prices</a>
|
@@ -98,73 +96,100 @@ Let's get ShortPixel plugin running on your WordPress website:
|
|
98 |
|
99 |
== Frequently Asked Questions ==
|
100 |
|
101 |
-
=
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
* Go to **Media Library**, and select which of the existing images you want to optimize.
|
106 |
|
107 |
-
|
|
|
|
|
108 |
|
109 |
-
|
|
|
|
|
110 |
|
111 |
-
=
|
|
|
|
|
112 |
|
113 |
-
|
|
|
|
|
114 |
|
115 |
-
|
|
|
|
|
116 |
|
117 |
-
|
118 |
-
|
119 |
-
= Why do I need an API key? =
|
120 |
|
121 |
-
|
|
|
|
|
122 |
|
123 |
-
=
|
|
|
|
|
124 |
|
125 |
-
|
|
|
126 |
|
127 |
-
=
|
|
|
128 |
|
129 |
-
|
|
|
130 |
|
131 |
= How do I activate the API key on a multisite? =
|
|
|
|
|
|
|
|
|
|
|
132 |
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
define('SHORTPIXEL_API_KEY', 'APIKEY')
|
137 |
-
where 'APIKEY' is the API Key received upon sign up.
|
138 |
-
|
139 |
-
If configured that way, the API key will be used for all the sites of the multisite but will only be visible on the main site's Settings page, being hidden for the rest of the sites.
|
140 |
|
141 |
-
=
|
|
|
|
|
142 |
|
143 |
-
|
|
|
144 |
|
145 |
-
|
|
|
|
|
146 |
|
147 |
-
=
|
|
|
|
|
148 |
|
149 |
-
|
|
|
|
|
150 |
|
151 |
-
=
|
|
|
152 |
|
153 |
-
|
|
|
|
|
|
|
154 |
|
155 |
-
|
|
|
|
|
|
|
|
|
156 |
|
157 |
-
|
|
|
|
|
158 |
|
159 |
-
|
160 |
-
|
161 |
-
= What types of formats can be optimized? =
|
162 |
-
|
163 |
-
For now, ShortPixel supports JPEG, PNG, PDF and GIF formats. Animated GIFs and thumbnails are also optimized. Additional formats are scheduled for optimization in the future.
|
164 |
-
|
165 |
-
= Will ShortPixel work if my website is using CloudFare? =
|
166 |
-
|
167 |
-
Yes, the image processing happens without interfering with the CloudFare protection. The ShortPixel and CloudFare plugins are also compatible.
|
168 |
|
169 |
= I’m stuck. What do I do? =
|
170 |
|
@@ -172,15 +197,15 @@ The ShortPixel team is here to help. <a href="https://shortpixel.com/contact">Co
|
|
172 |
|
173 |
== Screenshots ==
|
174 |
|
175 |
-
1.
|
176 |
|
177 |
-
2.
|
178 |
|
179 |
-
3.
|
180 |
|
181 |
-
4.
|
182 |
|
183 |
-
5.
|
184 |
|
185 |
6. Check your stats: number of processed files, saved space, average compression, saved bandwidth, remaining images. (Settings>ShortPixel)
|
186 |
|
@@ -192,6 +217,20 @@ The ShortPixel team is here to help. <a href="https://shortpixel.com/contact">Co
|
|
192 |
|
193 |
== Changelog ==
|
194 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
195 |
= 4.2.5 =
|
196 |
|
197 |
* fix for PHP7.1 fatal error when encountering corrupt metadata (wp_get_attachment_metadata returning empty string)
|
1 |
=== ShortPixel Image Optimizer ===
|
2 |
|
3 |
+
Contributors: ShortPixel
|
4 |
Tags: image optimizer, image optimization, compress pdf, compress jpeg, compress png, image compression, wp smush, compress images, optimize images, shrink jpeg, optimize photos, tinypng
|
5 |
|
6 |
Requires at least: 3.2.0
|
7 |
Tested up to: 4.7
|
8 |
+
Stable tag: 4.2.6
|
9 |
License: GPLv2 or later
|
10 |
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
11 |
|
18 |
Increase your website's SEO ranking, number of visitors and ultimately your sales by optimizing any image or PDF document on your website.
|
19 |
ShortPixel is an easy to use, lightweight, install-and-forget-about-it <a rel="friend" href="https://shortpixel.com" target="_blank">image optimization</a> plugin that can compress all your past images and PDF documents with a single click. New images are automatically resized/rescaled and optimized on the fly, in the background.
|
20 |
|
21 |
+
**Ready for a quick DEMO? <a href="https://addendio.com/try-plugin/?slug=shortpixel-image-optimiser" target="_blank">Test here.</a>**
|
22 |
+
|
23 |
This plugin uses minimal resources and works well with any shared, cloud, VPS or dedicated web hosting. It can optimize any image you have on your website even the images that aren't listed in Media Library like those in galleries like NextGEN or added directly via FTP!
|
24 |
|
25 |
Both lossy and lossless image compression is available for the most common image types (JPG, PNG, GIF and WebP) plus PDF files. Optimized images mean better user experience, better PageSpeed Insights or GTmetrix results, better Google PageRank and more visitors.
|
55 |
* 40 days optimization report with all image details and overall statistics
|
56 |
* **free optimization credits for non-profits**, <a href="https://shortpixel.com/contact" target="_blank">contact us</a> for details
|
57 |
|
|
|
|
|
|
|
|
|
58 |
**How much it costs?**
|
59 |
ShortPixel comes with 100 free credits/month and additional credits can be bought with as little as $4.99 for 5,000 image credits.
|
60 |
Check out <a rel="friend" href="https://shortpixel.com/pricing" target="_blank">our prices</a>
|
96 |
|
97 |
== Frequently Asked Questions ==
|
98 |
|
99 |
+
= Can I use the same API Key on multiple web sites? =
|
100 |
+
Yes, you can.
|
101 |
+
As long as you have available credits you can use a single API Key on as many websites as you wish!
|
|
|
|
|
102 |
|
103 |
+
= Can I test/use the plugin for free? =
|
104 |
+
Yes you can.
|
105 |
+
We offer 100 free image optimization credits each month. Exceeding the monthly free quota will pause the optimization process till the quota is reset or extended by buying one of our plans.
|
106 |
|
107 |
+
= Can I optimize images that aren't in Media Library? =
|
108 |
+
Absolutely.
|
109 |
+
You can actually optimize any image you have on your site regardless of its place. You just need to add - in the Advanced section of the ShortPixel Settings - the folders where the images you want to optimize are located and ShortPixel will work its magic and do the rest.
|
110 |
|
111 |
+
= Can I optimize both past and new images? =
|
112 |
+
Sure!
|
113 |
+
You can optimize all your past/current images using our "Bulk ShortPixel" page in your Media with a single click.
|
114 |
|
115 |
+
= A credit = an optimized image? =
|
116 |
+
Yes, that is correct.
|
117 |
+
But please note that usually an image in Media Library has 3, 5 or more associated thumbs. Each optimized thumb requires a credit. In the rare cases when ShortPixel does not optimize the image (lossy) with at least 5%, the credit will not be consumed, though.
|
118 |
|
119 |
+
= Can I restore my images? What happens with the originals? =
|
120 |
+
If you choose the "Image backup" option in Settings/ShortPixel then the original version of any optimized image or PDF will be saved in the backup folder.
|
121 |
+
The original image is necessary if you want to restore an image or if you want to convert an image from lossy to lossless or viceversa.
|
122 |
|
123 |
+
= What types of formats can be optimized? =
|
124 |
+
ShortPixel optimizes JPEG, PNG, GIF and PDF type of files.
|
|
|
125 |
|
126 |
+
= Do you have one-time plans? =
|
127 |
+
Yes we do.
|
128 |
+
The credits that come with our <a href="https://shortpixel.com/plans" rel="friend">one-time plans</a> never expire. Yummy! :-)
|
129 |
|
130 |
+
= What happens to my existing images? =
|
131 |
+
Your existing images are replaced with the optimized ones.
|
132 |
+
If you choose the backup option then the originals will be saved in a separate folder so you can restore them should you ever need/want to do that.
|
133 |
|
134 |
+
= How does the plugin work? =
|
135 |
+
Our light-weight plugin sends the original images to our Image Optimization Cloud where they are compressed. ShortPixel then downloads the optimized images and the unoptimized originals are replaced with the optimized versions.
|
136 |
|
137 |
+
= Do you optimize the images in cloud? =
|
138 |
+
Yes, all the images processsed by ShortPixel are optimized in the Cloud. This takes the load off of your server and allows us to produce the best results.
|
139 |
|
140 |
+
= What payment methods are accepted? =
|
141 |
+
We accept payments via PayPal and card.
|
142 |
|
143 |
= How do I activate the API key on a multisite? =
|
144 |
+
You have to activate the plugin in the network admin and then activate it manually on each individual site in the multisite. Once you have done that, the Settings menu appears and you can add the API key for each individual site.
|
145 |
+
As an alternative, you can edit wp-config.php and add this line
|
146 |
+
define(‘SHORTPIXEL_API_KEY’, ‘APIKEY’)
|
147 |
+
where ‘APIKEY’ is the API Key received upon sign up.
|
148 |
+
If configured that way, the API key will be used for all the sites of the multisite but will only be visible on the main site’s Settings page, being hidden for the rest of the sites.
|
149 |
|
150 |
+
= How much is a credit? =
|
151 |
+
A credit is used each time ShortPixel optimizes an image or thumbnail by at least 5%. If we're not able to optimize an image or thumbnail by at least 5% then no credit will be used :-)
|
152 |
+
Please also note that usually images in your Media Library have 3-5 thumbs associated and a credit will be used for each featured image or associated thumbnail that is optimized.
|
|
|
|
|
|
|
|
|
153 |
|
154 |
+
= Why shall I use a wordpress plugin and not an offline tool? =
|
155 |
+
Because ShortPixel algorithms were perfected while optimizing over a hundred million real-life images.
|
156 |
+
ShortPixel not only offers the best compression for JPEG, PNG, GIF and PDF files but it also saves you a lot of time. You just install it on your site and then ShortPixel will take care that all the images on your site are immediately optimized after upload.
|
157 |
|
158 |
+
= Does optimizing images affect my ALT tags? =
|
159 |
+
No, ShortPixel only optimizes images, it won't touch anything else like your HTML/CSS.
|
160 |
|
161 |
+
= If I stop using ShortPixel will my images remain optimized? =
|
162 |
+
Absolutely!
|
163 |
+
Once optimized the images will remain optimized unless you explicitly choose to restore them. But why would you do that? :-)
|
164 |
|
165 |
+
= Do I have to pay monthly or one time? =
|
166 |
+
We have both options available.
|
167 |
+
One-time credits never expire are a bit more expensive. Check out our prices <a href="https://shortpixel.com/pricing" rel="friend">here</a>
|
168 |
|
169 |
+
= When can I cancel a monthly plan? =
|
170 |
+
Whenever you want.
|
171 |
+
The credits you still have available for the current billing period will still be available until the end of the billing period. At the end of it, you won't be billed again and the plan will be reset to the free plan.
|
172 |
|
173 |
+
= When credits expire? =
|
174 |
+
Monthly credits expire after 30 days while one-time credits never expire.
|
175 |
|
176 |
+
= Do you have an API? =
|
177 |
+
Yes, we have several APIs and tools.
|
178 |
+
You can learn more about it here:
|
179 |
+
<a href="https://shortpixel.com/api-tools">https://shortpixel.com/api-tools</a>
|
180 |
|
181 |
+
= Can I use ShortPixel WP plugin on a localhost installation? =
|
182 |
+
Unfortunately not :-(
|
183 |
+
But you can use either our command line tool or our web tool
|
184 |
+
<a href="https://shortpixel.com/web-tool-docs">https://shortpixel.com/web-tool-docs</a>
|
185 |
+
<a href="https://shortpixel.com/cli-docs">https://shortpixel.com/cli-docs</a>
|
186 |
|
187 |
+
= How does resizing work? =
|
188 |
+
If you choose the option to resize your images then the featured image can be resized to a predefined size while keeping its aspect and proportions intact. The associated thumbs won't be resized
|
189 |
+
Using this option you can safely upload original images safely without needing to apply any pre-processing to make them smaller.
|
190 |
|
191 |
+
= Will ShortPixel work if my website is using CloudFare? =
|
192 |
+
Absolutely! Sometimes you'll need to make sure you whitelist some IPs, just <a href="http://shortpixel.com/contact">contact us</a> and we'll assist you with that.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
193 |
|
194 |
= I’m stuck. What do I do? =
|
195 |
|
197 |
|
198 |
== Screenshots ==
|
199 |
|
200 |
+
1. Bulk optimization running. (Media>Bulk ShortPixel)
|
201 |
|
202 |
+
2. Activate your API key in the plugin Settings. (Settings>ShortPixel)
|
203 |
|
204 |
+
3. Check out the main settings after API key activated. (Settings>ShortPixel)
|
205 |
|
206 |
+
4. Tweak it using Advanced settings. (Settings>ShortPixel)
|
207 |
|
208 |
+
5. Compress all your past images with one click. (Media>Bulk ShortPixel)
|
209 |
|
210 |
6. Check your stats: number of processed files, saved space, average compression, saved bandwidth, remaining images. (Settings>ShortPixel)
|
211 |
|
217 |
|
218 |
== Changelog ==
|
219 |
|
220 |
+
= 4.2.6 =
|
221 |
+
|
222 |
+
* add the webp files as thumbs to the sizes array in metadata so they are automatically used by themes that use srcset.
|
223 |
+
* add option to optimize PDFs or not.
|
224 |
+
* seamless integration with WP/LR Sync plugin.
|
225 |
+
* gracefully ignore missing thumbs on disk when doing the optimization - just mark them as missing in the metadata.
|
226 |
+
* gracefully add Media Library files that are present on disk but not present in the image metadata (sizes array).
|
227 |
+
* option to dismiss the top toolbar ShortPixel alert when quota expired.
|
228 |
+
* compute the backup folder size asynchronously in order to speed up the settings page.
|
229 |
+
* editors/authors now are able to optimize/restore images from the Media Library list.
|
230 |
+
* handle internationalized domain names (punycode encoded).
|
231 |
+
* reset failed images from Custom Media when user launches a reprocessing of the images from Bulk.
|
232 |
+
* bugfixes
|
233 |
+
|
234 |
= 4.2.5 =
|
235 |
|
236 |
* fix for PHP7.1 fatal error when encountering corrupt metadata (wp_get_attachment_metadata returning empty string)
|
res/css/short-pixel.css
CHANGED
@@ -34,6 +34,14 @@ div.fb-like {
|
|
34 |
.sp-notice-success {
|
35 |
border-left-color: #46b450;
|
36 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
37 |
div.short-pixel-bulk-page input.dial {
|
38 |
font-size: 16px !important;
|
39 |
}
|
@@ -72,6 +80,7 @@ div.sp-quota-exceeded-alert .bulk-progress-indicator {
|
|
72 |
div.wrap.short-pixel-bulk-page .bulk-notice-container {
|
73 |
margin-top: 15px;
|
74 |
position: absolute;
|
|
|
75 |
}
|
76 |
div.wrap.short-pixel-bulk-page .bulk-notice-container .bulk-notice-msg {
|
77 |
text-align: center;
|
@@ -83,8 +92,14 @@ div.wrap.short-pixel-bulk-page .bulk-notice-container .bulk-notice-msg {
|
|
83 |
padding: 7px 10px 10px;
|
84 |
display: none;
|
85 |
max-width: 600px;
|
|
|
86 |
}
|
87 |
div.wrap.short-pixel-bulk-page .bulk-notice-container .bulk-notice-msg.bulk-error {
|
|
|
|
|
|
|
|
|
|
|
88 |
border: 1px solid #c32525;
|
89 |
background-color: #ff969d;
|
90 |
}
|
@@ -379,9 +394,11 @@ li.shortpixel-hide {
|
|
379 |
.sp-floating-block.bulk-slider-container {
|
380 |
display: none;
|
381 |
}
|
382 |
-
.sp-floating-block.notice.bulk-notices-parent {
|
383 |
padding: 0;
|
384 |
margin: 0;
|
|
|
|
|
385 |
}
|
386 |
.bulk-slider-container {
|
387 |
margin-top: 20px;
|
@@ -580,3 +597,8 @@ section#tab-resources p {
|
|
580 |
width: 97%;
|
581 |
}
|
582 |
}
|
|
|
|
|
|
|
|
|
|
34 |
.sp-notice-success {
|
35 |
border-left-color: #46b450;
|
36 |
}
|
37 |
+
li.sp-conflict-plugins-list {
|
38 |
+
line-height: 28px;
|
39 |
+
list-style: disc;
|
40 |
+
margin-left: 20px;
|
41 |
+
}
|
42 |
+
li.sp-conflict-plugins-list a.button {
|
43 |
+
margin-left: 10px;
|
44 |
+
}
|
45 |
div.short-pixel-bulk-page input.dial {
|
46 |
font-size: 16px !important;
|
47 |
}
|
80 |
div.wrap.short-pixel-bulk-page .bulk-notice-container {
|
81 |
margin-top: 15px;
|
82 |
position: absolute;
|
83 |
+
width: 500px;
|
84 |
}
|
85 |
div.wrap.short-pixel-bulk-page .bulk-notice-container .bulk-notice-msg {
|
86 |
text-align: center;
|
92 |
padding: 7px 10px 10px;
|
93 |
display: none;
|
94 |
max-width: 600px;
|
95 |
+
margin-right:20px;
|
96 |
}
|
97 |
div.wrap.short-pixel-bulk-page .bulk-notice-container .bulk-notice-msg.bulk-error {
|
98 |
+
border: 1px solid #b5914d;
|
99 |
+
background-color: #ffe996;
|
100 |
+
margin-right:20px;
|
101 |
+
}
|
102 |
+
div.wrap.short-pixel-bulk-page .bulk-notice-container .bulk-notice-msg.bulk-error.bulk-error-fatal {
|
103 |
border: 1px solid #c32525;
|
104 |
background-color: #ff969d;
|
105 |
}
|
394 |
.sp-floating-block.bulk-slider-container {
|
395 |
display: none;
|
396 |
}
|
397 |
+
.sp-floating-block.sp-notice.bulk-notices-parent {
|
398 |
padding: 0;
|
399 |
margin: 0;
|
400 |
+
float: right;
|
401 |
+
margin-right: 500px !important;
|
402 |
}
|
403 |
.bulk-slider-container {
|
404 |
margin-top: 20px;
|
597 |
width: 97%;
|
598 |
}
|
599 |
}
|
600 |
+
|
601 |
+
/*workaround for bad style inline css in the plugin <<WooCommerce Remove /product & /product-category>> that's causing conflict*/
|
602 |
+
.sp-tabs h2:before{
|
603 |
+
content:none;
|
604 |
+
}
|
res/js/punycode.js
ADDED
@@ -0,0 +1,448 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
'use strict';
|
2 |
+
|
3 |
+
/** ShortPixel: Changed punycode to sp_punycode in order to prevent possible conflicts with other WP plugins that use punycode
|
4 |
+
* Also moved all the functions inside the sp_punycode const for the same reason and changed const's to let's */
|
5 |
+
|
6 |
+
var sp_punycode = function(){
|
7 |
+
|
8 |
+
/** Highest positive signed 32-bit float value */
|
9 |
+
var maxInt = 2147483647; // aka. 0x7FFFFFFF or 2^31-1
|
10 |
+
|
11 |
+
/** Bootstring parameters */
|
12 |
+
var base = 36;
|
13 |
+
var tMin = 1;
|
14 |
+
var tMax = 26;
|
15 |
+
var skew = 38;
|
16 |
+
var damp = 700;
|
17 |
+
var initialBias = 72;
|
18 |
+
var initialN = 128; // 0x80
|
19 |
+
var delimiter = '-'; // '\x2D'
|
20 |
+
|
21 |
+
/** Regular expressions */
|
22 |
+
var regexPunycode = /^xn--/;
|
23 |
+
var regexNonASCII = /[^\0-\x7E]/; // non-ASCII chars
|
24 |
+
var regexSeparators = /[\x2E\u3002\uFF0E\uFF61]/g; // RFC 3490 separators
|
25 |
+
|
26 |
+
/** Error messages */
|
27 |
+
var errors = {
|
28 |
+
'overflow': 'Overflow: input needs wider integers to process',
|
29 |
+
'not-basic': 'Illegal input >= 0x80 (not a basic code point)',
|
30 |
+
'invalid-input': 'Invalid input'
|
31 |
+
};
|
32 |
+
|
33 |
+
/** Convenience shortcuts */
|
34 |
+
var baseMinusTMin = base - tMin;
|
35 |
+
var floor = Math.floor;
|
36 |
+
var stringFromCharCode = String.fromCharCode;
|
37 |
+
|
38 |
+
/*--------------------------------------------------------------------------*/
|
39 |
+
|
40 |
+
/**
|
41 |
+
* A generic error utility function.
|
42 |
+
* @private
|
43 |
+
* @param {String} type The error type.
|
44 |
+
* @returns {Error} Throws a `RangeError` with the applicable error message.
|
45 |
+
*/
|
46 |
+
function error(type) {
|
47 |
+
throw new RangeError(errors[type]);
|
48 |
+
}
|
49 |
+
|
50 |
+
/**
|
51 |
+
* A generic `Array#map` utility function.
|
52 |
+
* @private
|
53 |
+
* @param {Array} array The array to iterate over.
|
54 |
+
* @param {Function} callback The function that gets called for every array
|
55 |
+
* item.
|
56 |
+
* @returns {Array} A new array of values returned by the callback function.
|
57 |
+
*/
|
58 |
+
function map(array, fn) {
|
59 |
+
var result = [];
|
60 |
+
var length = array.length;
|
61 |
+
while (length--) {
|
62 |
+
result[length] = fn(array[length]);
|
63 |
+
}
|
64 |
+
return result;
|
65 |
+
}
|
66 |
+
|
67 |
+
/**
|
68 |
+
* A simple `Array#map`-like wrapper to work with domain name strings or email
|
69 |
+
* addresses.
|
70 |
+
* @private
|
71 |
+
* @param {String} domain The domain name or email address.
|
72 |
+
* @param {Function} callback The function that gets called for every
|
73 |
+
* character.
|
74 |
+
* @returns {Array} A new string of characters returned by the callback
|
75 |
+
* function.
|
76 |
+
*/
|
77 |
+
function mapDomain(string, fn) {
|
78 |
+
var parts = string.split('@');
|
79 |
+
var result = '';
|
80 |
+
if (parts.length > 1) {
|
81 |
+
// In email addresses, only the domain name should be punycoded. Leave
|
82 |
+
// the local part (i.e. everything up to `@`) intact.
|
83 |
+
result = parts[0] + '@';
|
84 |
+
string = parts[1];
|
85 |
+
}
|
86 |
+
// Avoid `split(regex)` for IE8 compatibility. See #17.
|
87 |
+
string = string.replace(regexSeparators, '\x2E');
|
88 |
+
var labels = string.split('.');
|
89 |
+
var encoded = map(labels, fn).join('.');
|
90 |
+
return result + encoded;
|
91 |
+
}
|
92 |
+
|
93 |
+
/**
|
94 |
+
* Creates an array containing the numeric code points of each Unicode
|
95 |
+
* character in the string. While JavaScript uses UCS-2 internally,
|
96 |
+
* this function will convert a pair of surrogate halves (each of which
|
97 |
+
* UCS-2 exposes as separate characters) into a single code point,
|
98 |
+
* matching UTF-16.
|
99 |
+
* @see `punycode.ucs2.encode`
|
100 |
+
* @see <https://mathiasbynens.be/notes/javascript-encoding>
|
101 |
+
* @memberOf punycode.ucs2
|
102 |
+
* @name decode
|
103 |
+
* @param {String} string The Unicode input string (UCS-2).
|
104 |
+
* @returns {Array} The new array of code points.
|
105 |
+
*/
|
106 |
+
function ucs2decode(string) {
|
107 |
+
var output = [];
|
108 |
+
var counter = 0;
|
109 |
+
var length = string.length;
|
110 |
+
while (counter < length) {
|
111 |
+
var value = string.charCodeAt(counter++);
|
112 |
+
if (value >= 0xD800 && value <= 0xDBFF && counter < length) {
|
113 |
+
// It's a high surrogate, and there is a next character.
|
114 |
+
var extra = string.charCodeAt(counter++);
|
115 |
+
if ((extra & 0xFC00) == 0xDC00) { // Low surrogate.
|
116 |
+
output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000);
|
117 |
+
} else {
|
118 |
+
// It's an unmatched surrogate; only append this code unit, in case the
|
119 |
+
// next code unit is the high surrogate of a surrogate pair.
|
120 |
+
output.push(value);
|
121 |
+
counter--;
|
122 |
+
}
|
123 |
+
} else {
|
124 |
+
output.push(value);
|
125 |
+
}
|
126 |
+
}
|
127 |
+
return output;
|
128 |
+
}
|
129 |
+
|
130 |
+
/**
|
131 |
+
* Creates a string based on an array of numeric code points.
|
132 |
+
* @see `punycode.ucs2.decode`
|
133 |
+
* @memberOf punycode.ucs2
|
134 |
+
* @name encode
|
135 |
+
* @param {Array} codePoints The array of numeric code points.
|
136 |
+
* @returns {String} The new Unicode string (UCS-2).
|
137 |
+
*/
|
138 |
+
//const ucs2encode = array => String.fromCodePoint(...array);
|
139 |
+
var ucs2encode = array => String.fromCodePoint.prototype.apply(null, array);
|
140 |
+
|
141 |
+
/**
|
142 |
+
* Converts a basic code point into a digit/integer.
|
143 |
+
* @see `digitToBasic()`
|
144 |
+
* @private
|
145 |
+
* @param {Number} codePoint The basic numeric code point value.
|
146 |
+
* @returns {Number} The numeric value of a basic code point (for use in
|
147 |
+
* representing integers) in the range `0` to `base - 1`, or `base` if
|
148 |
+
* the code point does not represent a value.
|
149 |
+
*/
|
150 |
+
var basicToDigit = function(codePoint) {
|
151 |
+
if (codePoint - 0x30 < 0x0A) {
|
152 |
+
return codePoint - 0x16;
|
153 |
+
}
|
154 |
+
if (codePoint - 0x41 < 0x1A) {
|
155 |
+
return codePoint - 0x41;
|
156 |
+
}
|
157 |
+
if (codePoint - 0x61 < 0x1A) {
|
158 |
+
return codePoint - 0x61;
|
159 |
+
}
|
160 |
+
return base;
|
161 |
+
};
|
162 |
+
|
163 |
+
/**
|
164 |
+
* Converts a digit/integer into a basic code point.
|
165 |
+
* @see `basicToDigit()`
|
166 |
+
* @private
|
167 |
+
* @param {Number} digit The numeric value of a basic code point.
|
168 |
+
* @returns {Number} The basic code point whose value (when used for
|
169 |
+
* representing integers) is `digit`, which needs to be in the range
|
170 |
+
* `0` to `base - 1`. If `flag` is non-zero, the uppercase form is
|
171 |
+
* used; else, the lowercase form is used. The behavior is undefined
|
172 |
+
* if `flag` is non-zero and `digit` has no uppercase form.
|
173 |
+
*/
|
174 |
+
var digitToBasic = function(digit, flag) {
|
175 |
+
// 0..25 map to ASCII a..z or A..Z
|
176 |
+
// 26..35 map to ASCII 0..9
|
177 |
+
return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5);
|
178 |
+
};
|
179 |
+
|
180 |
+
/**
|
181 |
+
* Bias adaptation function as per section 3.4 of RFC 3492.
|
182 |
+
* https://tools.ietf.org/html/rfc3492#section-3.4
|
183 |
+
* @private
|
184 |
+
*/
|
185 |
+
var adapt = function(delta, numPoints, firstTime) {
|
186 |
+
var k = 0;
|
187 |
+
delta = firstTime ? floor(delta / damp) : delta >> 1;
|
188 |
+
delta += floor(delta / numPoints);
|
189 |
+
for (/* no initialization */; delta > baseMinusTMin * tMax >> 1; k += base) {
|
190 |
+
delta = floor(delta / baseMinusTMin);
|
191 |
+
}
|
192 |
+
return floor(k + (baseMinusTMin + 1) * delta / (delta + skew));
|
193 |
+
};
|
194 |
+
|
195 |
+
/**
|
196 |
+
* Converts a Punycode string of ASCII-only symbols to a string of Unicode
|
197 |
+
* symbols.
|
198 |
+
* @memberOf punycode
|
199 |
+
* @param {String} input The Punycode string of ASCII-only symbols.
|
200 |
+
* @returns {String} The resulting string of Unicode symbols.
|
201 |
+
*/
|
202 |
+
var decode = function(input) {
|
203 |
+
// Don't use UCS-2.
|
204 |
+
var output = [];
|
205 |
+
var inputLength = input.length;
|
206 |
+
var i = 0;
|
207 |
+
var n = initialN;
|
208 |
+
var bias = initialBias;
|
209 |
+
|
210 |
+
// Handle the basic code points: let `basic` be the number of input code
|
211 |
+
// points before the last delimiter, or `0` if there is none, then copy
|
212 |
+
// the first basic code points to the output.
|
213 |
+
|
214 |
+
var basic = input.lastIndexOf(delimiter);
|
215 |
+
if (basic < 0) {
|
216 |
+
basic = 0;
|
217 |
+
}
|
218 |
+
|
219 |
+
for (var j = 0; j < basic; ++j) {
|
220 |
+
// if it's not a basic code point
|
221 |
+
if (input.charCodeAt(j) >= 0x80) {
|
222 |
+
error('not-basic');
|
223 |
+
}
|
224 |
+
output.push(input.charCodeAt(j));
|
225 |
+
}
|
226 |
+
|
227 |
+
// Main decoding loop: start just after the last delimiter if any basic code
|
228 |
+
// points were copied; start at the beginning otherwise.
|
229 |
+
|
230 |
+
for (var index = basic > 0 ? basic + 1 : 0; index < inputLength; /* no final expression */) {
|
231 |
+
|
232 |
+
// `index` is the index of the next character to be consumed.
|
233 |
+
// Decode a generalized variable-length integer into `delta`,
|
234 |
+
// which gets added to `i`. The overflow checking is easier
|
235 |
+
// if we increase `i` as we go, then subtract off its starting
|
236 |
+
// value at the end to obtain `delta`.
|
237 |
+
var oldi = i;
|
238 |
+
for (var w = 1, k = base; /* no condition */; k += base) {
|
239 |
+
|
240 |
+
if (index >= inputLength) {
|
241 |
+
error('invalid-input');
|
242 |
+
}
|
243 |
+
|
244 |
+
var digit = basicToDigit(input.charCodeAt(index++));
|
245 |
+
|
246 |
+
if (digit >= base || digit > floor((maxInt - i) / w)) {
|
247 |
+
error('overflow');
|
248 |
+
}
|
249 |
+
|
250 |
+
i += digit * w;
|
251 |
+
var t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
|
252 |
+
|
253 |
+
if (digit < t) {
|
254 |
+
break;
|
255 |
+
}
|
256 |
+
|
257 |
+
var baseMinusT = base - t;
|
258 |
+
if (w > floor(maxInt / baseMinusT)) {
|
259 |
+
error('overflow');
|
260 |
+
}
|
261 |
+
|
262 |
+
w *= baseMinusT;
|
263 |
+
|
264 |
+
}
|
265 |
+
|
266 |
+
var out = output.length + 1;
|
267 |
+
bias = adapt(i - oldi, out, oldi == 0);
|
268 |
+
|
269 |
+
// `i` was supposed to wrap around from `out` to `0`,
|
270 |
+
// incrementing `n` each time, so we'll fix that now:
|
271 |
+
if (floor(i / out) > maxInt - n) {
|
272 |
+
error('overflow');
|
273 |
+
}
|
274 |
+
|
275 |
+
n += floor(i / out);
|
276 |
+
i %= out;
|
277 |
+
|
278 |
+
// Insert `n` at position `i` of the output.
|
279 |
+
output.splice(i++, 0, n);
|
280 |
+
|
281 |
+
}
|
282 |
+
|
283 |
+
//return String.fromCodePoint(...output);
|
284 |
+
return String.fromCodePoint.prototype.apply(null, output);
|
285 |
+
};
|
286 |
+
|
287 |
+
/**
|
288 |
+
* Converts a string of Unicode symbols (e.g. a domain name label) to a
|
289 |
+
* Punycode string of ASCII-only symbols.
|
290 |
+
* @memberOf punycode
|
291 |
+
* @param {String} input The string of Unicode symbols.
|
292 |
+
* @returns {String} The resulting Punycode string of ASCII-only symbols.
|
293 |
+
*/
|
294 |
+
const encode = function(input) {
|
295 |
+
var output = [];
|
296 |
+
|
297 |
+
// Convert the input in UCS-2 to an array of Unicode code points.
|
298 |
+
input = ucs2decode(input);
|
299 |
+
|
300 |
+
// Cache the length.
|
301 |
+
var inputLength = input.length;
|
302 |
+
|
303 |
+
// Initialize the state.
|
304 |
+
var n = initialN;
|
305 |
+
var delta = 0;
|
306 |
+
var bias = initialBias;
|
307 |
+
|
308 |
+
// Handle the basic code points.
|
309 |
+
for (var currentValue of input) {
|
310 |
+
if (currentValue < 0x80) {
|
311 |
+
output.push(stringFromCharCode(currentValue));
|
312 |
+
}
|
313 |
+
}
|
314 |
+
|
315 |
+
var basicLength = output.length;
|
316 |
+
var handledCPCount = basicLength;
|
317 |
+
|
318 |
+
// `handledCPCount` is the number of code points that have been handled;
|
319 |
+
// `basicLength` is the number of basic code points.
|
320 |
+
|
321 |
+
// Finish the basic string with a delimiter unless it's empty.
|
322 |
+
if (basicLength) {
|
323 |
+
output.push(delimiter);
|
324 |
+
}
|
325 |
+
|
326 |
+
// Main encoding loop:
|
327 |
+
while (handledCPCount < inputLength) {
|
328 |
+
|
329 |
+
// All non-basic code points < n have been handled already. Find the next
|
330 |
+
// larger one:
|
331 |
+
var m = maxInt;
|
332 |
+
for (var currentValue of input) {
|
333 |
+
if (currentValue >= n && currentValue < m) {
|
334 |
+
m = currentValue;
|
335 |
+
}
|
336 |
+
}
|
337 |
+
|
338 |
+
// Increase `delta` enough to advance the decoder's <n,i> state to <m,0>,
|
339 |
+
// but guard against overflow.
|
340 |
+
var handledCPCountPlusOne = handledCPCount + 1;
|
341 |
+
if (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) {
|
342 |
+
error('overflow');
|
343 |
+
}
|
344 |
+
|
345 |
+
delta += (m - n) * handledCPCountPlusOne;
|
346 |
+
n = m;
|
347 |
+
|
348 |
+
for (var currentValue of input) {
|
349 |
+
if (currentValue < n && ++delta > maxInt) {
|
350 |
+
error('overflow');
|
351 |
+
}
|
352 |
+
if (currentValue == n) {
|
353 |
+
// Represent delta as a generalized variable-length integer.
|
354 |
+
var q = delta;
|
355 |
+
for (var k = base; /* no condition */; k += base) {
|
356 |
+
var t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
|
357 |
+
if (q < t) {
|
358 |
+
break;
|
359 |
+
}
|
360 |
+
var qMinusT = q - t;
|
361 |
+
var baseMinusT = base - t;
|
362 |
+
output.push(
|
363 |
+
stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0))
|
364 |
+
);
|
365 |
+
q = floor(qMinusT / baseMinusT);
|
366 |
+
}
|
367 |
+
|
368 |
+
output.push(stringFromCharCode(digitToBasic(q, 0)));
|
369 |
+
bias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength);
|
370 |
+
delta = 0;
|
371 |
+
++handledCPCount;
|
372 |
+
}
|
373 |
+
}
|
374 |
+
|
375 |
+
++delta;
|
376 |
+
++n;
|
377 |
+
|
378 |
+
}
|
379 |
+
return output.join('');
|
380 |
+
};
|
381 |
+
|
382 |
+
/**
|
383 |
+
* Converts a Punycode string representing a domain name or an email address
|
384 |
+
* to Unicode. Only the Punycoded parts of the input will be converted, i.e.
|
385 |
+
* it doesn't matter if you call it on a string that has already been
|
386 |
+
* converted to Unicode.
|
387 |
+
* @memberOf punycode
|
388 |
+
* @param {String} input The Punycoded domain name or email address to
|
389 |
+
* convert to Unicode.
|
390 |
+
* @returns {String} The Unicode representation of the given Punycode
|
391 |
+
* string.
|
392 |
+
*/
|
393 |
+
var toUnicode = function(input) {
|
394 |
+
return mapDomain(input, function(string) {
|
395 |
+
return regexPunycode.test(string)
|
396 |
+
? decode(string.slice(4).toLowerCase())
|
397 |
+
: string;
|
398 |
+
});
|
399 |
+
};
|
400 |
+
|
401 |
+
/**
|
402 |
+
* Converts a Unicode string representing a domain name or an email address to
|
403 |
+
* Punycode. Only the non-ASCII parts of the domain name will be converted,
|
404 |
+
* i.e. it doesn't matter if you call it with a domain that's already in
|
405 |
+
* ASCII.
|
406 |
+
* @memberOf punycode
|
407 |
+
* @param {String} input The domain name or email address to convert, as a
|
408 |
+
* Unicode string.
|
409 |
+
* @returns {String} The Punycode representation of the given domain name or
|
410 |
+
* email address.
|
411 |
+
*/
|
412 |
+
var toASCII = function(input) {
|
413 |
+
return mapDomain(input, function(string) {
|
414 |
+
return regexNonASCII.test(string)
|
415 |
+
? 'xn--' + encode(string)
|
416 |
+
: string;
|
417 |
+
});
|
418 |
+
};
|
419 |
+
|
420 |
+
/*--------------------------------------------------------------------------*/
|
421 |
+
|
422 |
+
/** Define the public API */
|
423 |
+
return {
|
424 |
+
/**
|
425 |
+
* A string representing the current Punycode.js version number.
|
426 |
+
* @memberOf punycode
|
427 |
+
* @type String
|
428 |
+
*/
|
429 |
+
version: '2.1.0',
|
430 |
+
/**
|
431 |
+
* An object of methods to convert from JavaScript's internal character
|
432 |
+
* representation (UCS-2) to Unicode code points, and back.
|
433 |
+
* @see <https://mathiasbynens.be/notes/javascript-encoding>
|
434 |
+
* @memberOf punycode
|
435 |
+
* @type Object
|
436 |
+
*/
|
437 |
+
ucs2: {
|
438 |
+
'decode': ucs2decode,
|
439 |
+
'encode': ucs2encode
|
440 |
+
},
|
441 |
+
decode: decode,
|
442 |
+
encode: encode,
|
443 |
+
toASCII: toASCII,
|
444 |
+
toUnicode: toUnicode
|
445 |
+
}
|
446 |
+
}();
|
447 |
+
|
448 |
+
//module.exports = sp_punycode;
|
res/js/short-pixel.js
CHANGED
@@ -11,6 +11,10 @@ jQuery(document).ready(function($){
|
|
11 |
|
12 |
ShortPixel.setOptions(ShortPixelConstants);
|
13 |
|
|
|
|
|
|
|
|
|
14 |
if( ShortPixel.MEDIA_ALERT == 'todo' && jQuery('div.media-frame.mode-grid').length > 0) {
|
15 |
//the media table is not in the list mode, alert the user
|
16 |
jQuery('div.media-frame.mode-grid').before('<div id="short-pixel-media-alert" class="notice notice-warning"><p>'
|
@@ -135,7 +139,7 @@ var ShortPixel = function() {
|
|
135 |
}
|
136 |
|
137 |
function adjustSettingsTabsHeight(){
|
138 |
-
var sectionHeight = jQuery('section#tab-settings .wp-shortpixel-options').height() +
|
139 |
sectionHeight = Math.max(sectionHeight, jQuery('section#tab-adv-settings .wp-shortpixel-options').height() + 20);
|
140 |
sectionHeight = Math.max(sectionHeight, jQuery('section#tab-resources .area1').height() + 60);
|
141 |
jQuery('#shortpixel-settings-tabs').css('height', sectionHeight);
|
@@ -164,7 +168,7 @@ var ShortPixel = function() {
|
|
164 |
}
|
165 |
|
166 |
function successMsg(id, percent, type, thumbsCount, retinasCount) {
|
167 |
-
return (percent > 0 ? "<div class='sp-column-info'>" + _spTr.reducedBy + " <span class='percent'
|
168 |
+ (percent > 0 && percent < 5 ? "<br>" : '')
|
169 |
+ (percent < 5 ? _spTr.bonusProcessing : '')
|
170 |
+ (type.length > 0 ? " ("+type+")" : "")
|
@@ -218,7 +222,7 @@ var ShortPixel = function() {
|
|
218 |
console.log("Invalid response from server (Error: " + msg + "). Retrying pass " + (ShortPixel.retries + 1) + "...");
|
219 |
setTimeout(checkBulkProgress, 5000);
|
220 |
} else {
|
221 |
-
ShortPixel.bulkShowError(-1,"Invalid response from server received 6 times. Please retry later by reloading this page, or contact support
|
222 |
console.log("Invalid response from server 6 times. Giving up.");
|
223 |
}
|
224 |
}
|
@@ -238,6 +242,21 @@ var ShortPixel = function() {
|
|
238 |
return browseResponse;
|
239 |
}
|
240 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
241 |
function initFolderSelector() {
|
242 |
jQuery(".select-folder-button").click(function(){
|
243 |
jQuery(".sp-folder-picker-shade").css("display", "block");
|
@@ -277,13 +296,22 @@ var ShortPixel = function() {
|
|
277 |
}
|
278 |
|
279 |
notice.css("display", "block");
|
280 |
-
|
281 |
}
|
282 |
|
283 |
function bulkHideLengthyMsg(){
|
284 |
jQuery(".bulk-notice-msg.bulk-lengthy").css("display", "none");
|
285 |
}
|
286 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
287 |
function bulkShowError(id, msg, fileName, customLink) {
|
288 |
var noticeTpl = jQuery("#bulk-error-template");
|
289 |
if(noticeTpl.length == 0) return;
|
@@ -291,8 +319,12 @@ var ShortPixel = function() {
|
|
291 |
notice.attr("id", "bulk-error-" + id);
|
292 |
if(id == -1) {
|
293 |
jQuery("span.sp-err-title", notice).remove();
|
|
|
|
|
|
|
|
|
294 |
}
|
295 |
-
jQuery("span.sp-err-content", notice).
|
296 |
var link = jQuery("a.sp-post-link", notice);
|
297 |
if(customLink) {
|
298 |
link.attr("href", customLink);
|
@@ -335,8 +367,11 @@ var ShortPixel = function() {
|
|
335 |
retry : retry,
|
336 |
initFolderSelector : initFolderSelector,
|
337 |
browseContent : browseContent,
|
|
|
338 |
bulkShowLengthyMsg : bulkShowLengthyMsg,
|
339 |
bulkHideLengthyMsg : bulkHideLengthyMsg,
|
|
|
|
|
340 |
bulkShowError : bulkShowError,
|
341 |
removeBulkMsg : removeBulkMsg,
|
342 |
isCustomImageId : isCustomImageId,
|
@@ -407,9 +442,29 @@ function checkQuotaExceededAlert() {
|
|
407 |
* calls itself until receives an Empty queue message
|
408 |
*/
|
409 |
function checkBulkProgress() {
|
410 |
-
//the replace stands for malformed urls on some sites, like wp-admin//upload.php which are accepted by the browser.
|
411 |
-
|
412 |
-
var
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
413 |
if( url.search(adminUrl + "upload.php") < 0
|
414 |
&& url.search(adminUrl + "edit.php") < 0
|
415 |
&& url.search(adminUrl + "edit-tags.php") < 0
|
@@ -517,6 +572,7 @@ function checkBulkProcessingCallApi(){
|
|
517 |
case ShortPixel.STATUS_SUCCESS:
|
518 |
if(isBulkPage) {
|
519 |
ShortPixel.bulkHideLengthyMsg();
|
|
|
520 |
}
|
521 |
var percent = data["PercentImprovement"];
|
522 |
|
@@ -572,8 +628,16 @@ function checkBulkProcessingCallApi(){
|
|
572 |
}
|
573 |
setTimeout(checkBulkProgress, 5000);
|
574 |
break;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
575 |
default:
|
576 |
-
ShortPixel.retry(
|
577 |
break;
|
578 |
}
|
579 |
}
|
@@ -657,6 +721,19 @@ function optimizeThumbs(id) {
|
|
657 |
});
|
658 |
}
|
659 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
660 |
function dismissShortPixelNotice(id) {
|
661 |
jQuery("#short-pixel-notice-" + id).hide();
|
662 |
var data = { action : 'shortpixel_dismiss_notice',
|
11 |
|
12 |
ShortPixel.setOptions(ShortPixelConstants);
|
13 |
|
14 |
+
if(jQuery('#backup-folder-size').length) {
|
15 |
+
jQuery('#backup-folder-size').html(ShortPixel.getBackupSize());
|
16 |
+
}
|
17 |
+
|
18 |
if( ShortPixel.MEDIA_ALERT == 'todo' && jQuery('div.media-frame.mode-grid').length > 0) {
|
19 |
//the media table is not in the list mode, alert the user
|
20 |
jQuery('div.media-frame.mode-grid').before('<div id="short-pixel-media-alert" class="notice notice-warning"><p>'
|
139 |
}
|
140 |
|
141 |
function adjustSettingsTabsHeight(){
|
142 |
+
var sectionHeight = jQuery('section#tab-settings .wp-shortpixel-options').height() + 90;
|
143 |
sectionHeight = Math.max(sectionHeight, jQuery('section#tab-adv-settings .wp-shortpixel-options').height() + 20);
|
144 |
sectionHeight = Math.max(sectionHeight, jQuery('section#tab-resources .area1').height() + 60);
|
145 |
jQuery('#shortpixel-settings-tabs').css('height', sectionHeight);
|
168 |
}
|
169 |
|
170 |
function successMsg(id, percent, type, thumbsCount, retinasCount) {
|
171 |
+
return (percent > 0 ? "<div class='sp-column-info'>" + _spTr.reducedBy + " <strong><span class='percent'>" + percent + "%</span></strong> " : "")
|
172 |
+ (percent > 0 && percent < 5 ? "<br>" : '')
|
173 |
+ (percent < 5 ? _spTr.bonusProcessing : '')
|
174 |
+ (type.length > 0 ? " ("+type+")" : "")
|
222 |
console.log("Invalid response from server (Error: " + msg + "). Retrying pass " + (ShortPixel.retries + 1) + "...");
|
223 |
setTimeout(checkBulkProgress, 5000);
|
224 |
} else {
|
225 |
+
ShortPixel.bulkShowError(-1,"Invalid response from server received 6 times. Please retry later by reloading this page, or <a href='https://shortpixel.com/contact' target='_blank'>contact support</a>. (Error: " + msg + ")", "");
|
226 |
console.log("Invalid response from server 6 times. Giving up.");
|
227 |
}
|
228 |
}
|
242 |
return browseResponse;
|
243 |
}
|
244 |
|
245 |
+
function getBackupSize() {
|
246 |
+
var browseData = { 'action': 'shortpixel_get_backup_size'};
|
247 |
+
var browseResponse = "";
|
248 |
+
jQuery.ajax({
|
249 |
+
type: "POST",
|
250 |
+
url: ShortPixel.AJAX_URL,
|
251 |
+
data: browseData,
|
252 |
+
success: function(response) {
|
253 |
+
browseResponse = response;
|
254 |
+
},
|
255 |
+
async: false
|
256 |
+
});
|
257 |
+
return browseResponse;
|
258 |
+
}
|
259 |
+
|
260 |
function initFolderSelector() {
|
261 |
jQuery(".select-folder-button").click(function(){
|
262 |
jQuery(".sp-folder-picker-shade").css("display", "block");
|
296 |
}
|
297 |
|
298 |
notice.css("display", "block");
|
|
|
299 |
}
|
300 |
|
301 |
function bulkHideLengthyMsg(){
|
302 |
jQuery(".bulk-notice-msg.bulk-lengthy").css("display", "none");
|
303 |
}
|
304 |
|
305 |
+
function bulkShowMaintenanceMsg(type){
|
306 |
+
var notice = jQuery(".bulk-notice-msg.bulk-" + type);
|
307 |
+
if(notice.length == 0) return;
|
308 |
+
notice.css("display", "block");
|
309 |
+
}
|
310 |
+
|
311 |
+
function bulkHideMaintenanceMsg(type){
|
312 |
+
jQuery(".bulk-notice-msg.bulk-" + type).css("display", "none");
|
313 |
+
}
|
314 |
+
|
315 |
function bulkShowError(id, msg, fileName, customLink) {
|
316 |
var noticeTpl = jQuery("#bulk-error-template");
|
317 |
if(noticeTpl.length == 0) return;
|
319 |
notice.attr("id", "bulk-error-" + id);
|
320 |
if(id == -1) {
|
321 |
jQuery("span.sp-err-title", notice).remove();
|
322 |
+
notice.addClass("bulk-error-fatal");
|
323 |
+
} else {
|
324 |
+
jQuery("img", notice).remove();
|
325 |
+
jQuery("#bulk-error-" . id).remove();
|
326 |
}
|
327 |
+
jQuery("span.sp-err-content", notice).html(msg);
|
328 |
var link = jQuery("a.sp-post-link", notice);
|
329 |
if(customLink) {
|
330 |
link.attr("href", customLink);
|
367 |
retry : retry,
|
368 |
initFolderSelector : initFolderSelector,
|
369 |
browseContent : browseContent,
|
370 |
+
getBackupSize : getBackupSize,
|
371 |
bulkShowLengthyMsg : bulkShowLengthyMsg,
|
372 |
bulkHideLengthyMsg : bulkHideLengthyMsg,
|
373 |
+
bulkShowMaintenanceMsg : bulkShowMaintenanceMsg,
|
374 |
+
bulkHideMaintenanceMsg : bulkHideMaintenanceMsg,
|
375 |
bulkShowError : bulkShowError,
|
376 |
removeBulkMsg : removeBulkMsg,
|
377 |
isCustomImageId : isCustomImageId,
|
442 |
* calls itself until receives an Empty queue message
|
443 |
*/
|
444 |
function checkBulkProgress() {
|
445 |
+
//the replace stands for malformed urls on some sites, like wp-admin//upload.php which are accepted by the browser.
|
446 |
+
//using a replacer function to avoid replacing the first occurence (https:// ...)
|
447 |
+
var replacer = function(match) {
|
448 |
+
if(!first) {
|
449 |
+
first = true;
|
450 |
+
return match;
|
451 |
+
}
|
452 |
+
return '/';
|
453 |
+
};
|
454 |
+
|
455 |
+
var first = false; //arm replacer
|
456 |
+
var url = window.location.href.toLowerCase().replace(/\/\//g , replacer);
|
457 |
+
|
458 |
+
first = false; //rearm replacer
|
459 |
+
var adminUrl = ShortPixel.WP_ADMIN_URL.toLowerCase().replace(/\/\//g , replacer);
|
460 |
+
|
461 |
+
//handle possible Punycode domain names.
|
462 |
+
if(url.search(adminUrl) < 0) {
|
463 |
+
var parser = document.createElement('a');
|
464 |
+
parser.href = url;
|
465 |
+
url = url.replace(parser.protocol + '//' + parser.hostname, parser.protocol + '//' + parser.hostname.split('.').map(function(part) {return sp_punycode.toASCII(part)}).join('.'));
|
466 |
+
}
|
467 |
+
|
468 |
if( url.search(adminUrl + "upload.php") < 0
|
469 |
&& url.search(adminUrl + "edit.php") < 0
|
470 |
&& url.search(adminUrl + "edit-tags.php") < 0
|
572 |
case ShortPixel.STATUS_SUCCESS:
|
573 |
if(isBulkPage) {
|
574 |
ShortPixel.bulkHideLengthyMsg();
|
575 |
+
ShortPixel.bulkHideMaintenanceMsg();
|
576 |
}
|
577 |
var percent = data["PercentImprovement"];
|
578 |
|
628 |
}
|
629 |
setTimeout(checkBulkProgress, 5000);
|
630 |
break;
|
631 |
+
case ShortPixel.STATUS_MAINTENANCE:
|
632 |
+
ShortPixel.bulkShowMaintenanceMsg('maintenance');
|
633 |
+
setTimeout(checkBulkProgress, 60000);
|
634 |
+
break;
|
635 |
+
case ShortPixel.STATUS_QUEUE_FULL:
|
636 |
+
ShortPixel.bulkShowMaintenanceMsg('queue-full');
|
637 |
+
setTimeout(checkBulkProgress, 60000);
|
638 |
+
break;
|
639 |
default:
|
640 |
+
ShortPixel.retry("Unknown status " + data["Status"] + ". Retrying...");
|
641 |
break;
|
642 |
}
|
643 |
}
|
721 |
});
|
722 |
}
|
723 |
|
724 |
+
function dismissShortPixelNoticeExceed(e) {
|
725 |
+
jQuery("#wp-admin-bar-shortpixel_processing").hide();
|
726 |
+
var data = { action : 'shortpixel_dismiss_notice',
|
727 |
+
notice_id: 'exceed'};
|
728 |
+
jQuery.get(ShortPixel.AJAX_URL, data, function(response) {
|
729 |
+
data = JSON.parse(response);
|
730 |
+
if(data["Status"] == ShortPixel.STATUS_SUCCESS) {
|
731 |
+
console.log("dismissed");
|
732 |
+
}
|
733 |
+
});
|
734 |
+
e.preventDefault();
|
735 |
+
}
|
736 |
+
|
737 |
function dismissShortPixelNotice(id) {
|
738 |
jQuery("#short-pixel-notice-" + id).hide();
|
739 |
var data = { action : 'shortpixel_dismiss_notice',
|
shortpixel_api.php
CHANGED
@@ -14,12 +14,15 @@ class ShortPixelAPI {
|
|
14 |
const STATUS_NOT_FOUND = -5;
|
15 |
const STATUS_NO_KEY = -6;
|
16 |
const STATUS_RETRY = -7;
|
|
|
|
|
17 |
|
18 |
const ERR_FILE_NOT_FOUND = -2;
|
19 |
const ERR_TIMEOUT = -3;
|
20 |
const ERR_SAVE = -4;
|
21 |
const ERR_SAVE_BKP = -5;
|
22 |
const ERR_INCORRECT_FILE_SIZE = -6;
|
|
|
23 |
|
24 |
private $_settings;
|
25 |
private $_maxAttempts = 10;
|
@@ -66,19 +69,19 @@ class ShortPixelAPI {
|
|
66 |
'body' => json_encode($requestParameters),
|
67 |
'cookies' => array()
|
68 |
);
|
|
|
69 |
//add this explicitely only for https, otherwise (for http) it slows down the request
|
70 |
if($this->_settings->httpProto !== 'https') {
|
71 |
unset($arguments['sslverify']);
|
72 |
}
|
73 |
-
|
74 |
-
WpShortPixel::log("Calling API with params : " . json_encode($arguments));
|
75 |
|
76 |
$response = wp_remote_post($this->_apiEndPoint, $arguments );
|
77 |
|
78 |
//only if $Blocking is true analyze the response
|
79 |
if ( $Blocking )
|
80 |
{
|
81 |
-
WpShortPixel::log("API response : " . json_encode($response));
|
82 |
|
83 |
//die(var_dump(array('URL: ' => $this->_apiEndPoint, '<br><br>REQUEST:' => $arguments, '<br><br>RESPONSE: ' => $response )));
|
84 |
//there was an error, save this error inside file's SP optimization field
|
@@ -138,7 +141,7 @@ class ShortPixelAPI {
|
|
138 |
*/
|
139 |
private function processImageRecursive($URLs, $PATHs, $itemHandler = null, $startTime = 0)
|
140 |
{
|
141 |
-
|
142 |
|
143 |
$PATHs = self::CheckAndFixImagePaths($PATHs);//check for images to make sure they exist on disk
|
144 |
if ( $PATHs === false || isset($PATHs['error'])) {
|
@@ -183,7 +186,9 @@ class ShortPixelAPI {
|
|
183 |
$meta = $itemHandler->getMeta();
|
184 |
$compressionType = $meta->getCompressionType() !== null ? $meta->getCompressionType() : $this->_settings->compressionType;
|
185 |
$response = $this->doRequests($URLs, true, $itemHandler, $compressionType);//send requests to API
|
186 |
-
|
|
|
|
|
187 |
if($response['response']['code'] != 200)//response <> 200 -> there was an error apparently?
|
188 |
return array("Status" => self::STATUS_FAIL, "Message" => __('There was an error and your request was not processed.','shortpixel-image-optimiser'));
|
189 |
|
@@ -237,7 +242,7 @@ class ShortPixelAPI {
|
|
237 |
|
238 |
if(!isset($APIresponse['Status'])) {
|
239 |
WpShortPixel::log("API Response Status unfound : " . json_encode($APIresponse));
|
240 |
-
return array("Status" => self::STATUS_FAIL, "Message" => __('
|
241 |
} else {
|
242 |
switch($APIresponse['Status']->Code)
|
243 |
{
|
@@ -246,6 +251,10 @@ class ShortPixelAPI {
|
|
246 |
$this->_settings->quotaExceeded = 1;
|
247 |
return array("Status" => self::STATUS_QUOTA_EXCEEDED, "Message" => __('Quota exceeded.','shortpixel-image-optimiser'));
|
248 |
break;
|
|
|
|
|
|
|
|
|
249 |
}
|
250 |
|
251 |
//sometimes the response array can be different
|
@@ -333,6 +342,7 @@ class ShortPixelAPI {
|
|
333 |
@unlink($tempFile);
|
334 |
$returnMessage = array(
|
335 |
"Status" => self::STATUS_ERROR,
|
|
|
336 |
"Message" => __('Error downloading file','shortpixel-image-optimiser') . " ({$fileData->$fileType}) " . $tempFile->get_error_message());
|
337 |
}
|
338 |
//check response so that download is OK
|
@@ -341,10 +351,13 @@ class ShortPixelAPI {
|
|
341 |
@unlink($tempFile);
|
342 |
$returnMessage = array(
|
343 |
"Status" => self::STATUS_ERROR,
|
|
|
344 |
"Message" => sprintf(__('Error downloading file - incorrect file size (downloaded: %s, correct: %s )','shortpixel-image-optimiser'),$size, $correctFileSize));
|
345 |
}
|
346 |
elseif (!file_exists($tempFile)) {
|
347 |
-
$returnMessage = array("Status" => self::STATUS_ERROR,
|
|
|
|
|
348 |
}
|
349 |
return $returnMessage;
|
350 |
}
|
@@ -386,7 +399,7 @@ class ShortPixelAPI {
|
|
386 |
$tempFiles[$counter] = $downloadResult;
|
387 |
}
|
388 |
else {
|
389 |
-
return array("Status" => $downloadResult['Status'], "Message" => $downloadResult['Message']);
|
390 |
}
|
391 |
|
392 |
}
|
@@ -397,9 +410,11 @@ class ShortPixelAPI {
|
|
397 |
}
|
398 |
|
399 |
//figure out in what SubDir files should land
|
400 |
-
|
401 |
-
|
402 |
-
|
|
|
|
|
403 |
//if backup is enabled - we try to save the images
|
404 |
if( $this->_settings->backupImages )
|
405 |
{
|
@@ -423,7 +438,7 @@ class ShortPixelAPI {
|
|
423 |
foreach ( $destination as $fileID => $filePATH )
|
424 |
{
|
425 |
if ( !file_exists($filePATH) )
|
426 |
-
{
|
427 |
if ( !@copy($source[$fileID], $filePATH) )
|
428 |
{//file couldn't be saved in backup folder
|
429 |
$msg = sprintf(__('Cannot save file <i>%s</i> in backup directory','shortpixel-image-optimiser'),self::MB_basename($source[$fileID]));
|
@@ -447,6 +462,8 @@ class ShortPixelAPI {
|
|
447 |
$width = $height = null;
|
448 |
$resize = $this->_settings->resizeImages;
|
449 |
$retinas = 0;
|
|
|
|
|
450 |
|
451 |
if ( !empty($tempFiles) )
|
452 |
{
|
@@ -456,12 +473,20 @@ class ShortPixelAPI {
|
|
456 |
if(!is_array($tempFile)) continue;
|
457 |
|
458 |
$targetFile = $PATHs[$tempFileID];
|
459 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
460 |
if($tempFile['Status'] == self::STATUS_SUCCESS) { //if it's unchanged it will still be in the array but only for WebP (handled below)
|
461 |
$tempFilePATH = $tempFile["Message"];
|
462 |
if ( file_exists($tempFilePATH) && file_exists($PATHs[$tempFileID]) && is_writable($PATHs[$tempFileID]) ) {
|
463 |
copy($tempFilePATH, $targetFile);
|
464 |
-
|
|
|
|
|
465 |
if($resize && $itemHandler->getMeta()->getPath() == $targetFile) { //this is the main image
|
466 |
$size = getimagesize($PATHs[$tempFileID]);
|
467 |
$width = $size[0];
|
@@ -490,6 +515,10 @@ class ShortPixelAPI {
|
|
490 |
if(file_exists($tempWebpFilePATH)) {
|
491 |
$targetWebPFile = dirname($targetFile) . '/' . basename($targetFile, '.' . pathinfo($targetFile, PATHINFO_EXTENSION)) . ".webp";
|
492 |
copy($tempWebpFilePATH, $targetWebPFile);
|
|
|
|
|
|
|
|
|
493 |
}
|
494 |
@unlink($tempWebpFilePATH);
|
495 |
}
|
@@ -526,12 +555,13 @@ class ShortPixelAPI {
|
|
526 |
: "Couldn't compute thumbs optimization percent. Main image: " . $percentImprovement);
|
527 |
WPShortPixel::log("HANDLE SUCCESS: Image optimization: ".$meta->getMessage());
|
528 |
$meta->setCompressionType($compressionType);
|
529 |
-
$meta->setCompressedSize(filesize($meta->getPath()));
|
530 |
$meta->setKeepExif($this->_settings->keepExif);
|
531 |
$meta->setTsOptimized(date("Y-m-d H:i:s"));
|
532 |
-
$meta->setThumbsOpt(($meta->getThumbsTodo() || $this->_settings->processThumbnails) ?
|
533 |
$meta->setRetinasOpt($retinas);
|
534 |
$meta->setThumbsTodo(false);
|
|
|
535 |
if($width && $height) {
|
536 |
$meta->setActualWidth($width);
|
537 |
$meta->setActualHeight($height);
|
@@ -556,10 +586,10 @@ class ShortPixelAPI {
|
|
556 |
* @param string $Path
|
557 |
* @return string
|
558 |
*/
|
559 |
-
static public function MB_basename($Path){
|
560 |
$Separator = " qq ";
|
561 |
$Path = preg_replace("/[^ ]/u", $Separator."\$0".$Separator, $Path);
|
562 |
-
$Base = basename($Path);
|
563 |
$Base = str_replace($Separator, "", $Base);
|
564 |
return $Base;
|
565 |
}
|
@@ -587,8 +617,13 @@ class ShortPixelAPI {
|
|
587 |
if (file_exists($NewFile)) {
|
588 |
$PATHs[$Id] = $NewFile;
|
589 |
} else {
|
590 |
-
|
591 |
-
$
|
|
|
|
|
|
|
|
|
|
|
592 |
}
|
593 |
}
|
594 |
}
|
14 |
const STATUS_NOT_FOUND = -5;
|
15 |
const STATUS_NO_KEY = -6;
|
16 |
const STATUS_RETRY = -7;
|
17 |
+
const STATUS_QUEUE_FULL = -404;
|
18 |
+
const STATUS_MAINTENANCE = -500;
|
19 |
|
20 |
const ERR_FILE_NOT_FOUND = -2;
|
21 |
const ERR_TIMEOUT = -3;
|
22 |
const ERR_SAVE = -4;
|
23 |
const ERR_SAVE_BKP = -5;
|
24 |
const ERR_INCORRECT_FILE_SIZE = -6;
|
25 |
+
const ERR_DOWNLOAD = -7;
|
26 |
|
27 |
private $_settings;
|
28 |
private $_maxAttempts = 10;
|
69 |
'body' => json_encode($requestParameters),
|
70 |
'cookies' => array()
|
71 |
);
|
72 |
+
//die(var_dump($requestParameters));
|
73 |
//add this explicitely only for https, otherwise (for http) it slows down the request
|
74 |
if($this->_settings->httpProto !== 'https') {
|
75 |
unset($arguments['sslverify']);
|
76 |
}
|
77 |
+
//WpShortPixel::log("Calling API with params : " . json_encode($arguments));
|
|
|
78 |
|
79 |
$response = wp_remote_post($this->_apiEndPoint, $arguments );
|
80 |
|
81 |
//only if $Blocking is true analyze the response
|
82 |
if ( $Blocking )
|
83 |
{
|
84 |
+
//WpShortPixel::log("API response : " . json_encode($response));
|
85 |
|
86 |
//die(var_dump(array('URL: ' => $this->_apiEndPoint, '<br><br>REQUEST:' => $arguments, '<br><br>RESPONSE: ' => $response )));
|
87 |
//there was an error, save this error inside file's SP optimization field
|
141 |
*/
|
142 |
private function processImageRecursive($URLs, $PATHs, $itemHandler = null, $startTime = 0)
|
143 |
{
|
144 |
+
//WPShortPixel::log("processImageRecursive ID: " . $itemHandler->getId() . " PATHs: " . json_encode($PATHs));
|
145 |
|
146 |
$PATHs = self::CheckAndFixImagePaths($PATHs);//check for images to make sure they exist on disk
|
147 |
if ( $PATHs === false || isset($PATHs['error'])) {
|
186 |
$meta = $itemHandler->getMeta();
|
187 |
$compressionType = $meta->getCompressionType() !== null ? $meta->getCompressionType() : $this->_settings->compressionType;
|
188 |
$response = $this->doRequests($URLs, true, $itemHandler, $compressionType);//send requests to API
|
189 |
+
|
190 |
+
//die(var_dump($response));
|
191 |
+
|
192 |
if($response['response']['code'] != 200)//response <> 200 -> there was an error apparently?
|
193 |
return array("Status" => self::STATUS_FAIL, "Message" => __('There was an error and your request was not processed.','shortpixel-image-optimiser'));
|
194 |
|
242 |
|
243 |
if(!isset($APIresponse['Status'])) {
|
244 |
WpShortPixel::log("API Response Status unfound : " . json_encode($APIresponse));
|
245 |
+
return array("Status" => self::STATUS_FAIL, "Message" => __('Unrecognized API response. Please contact support.','shortpixel-image-optimiser'));
|
246 |
} else {
|
247 |
switch($APIresponse['Status']->Code)
|
248 |
{
|
251 |
$this->_settings->quotaExceeded = 1;
|
252 |
return array("Status" => self::STATUS_QUOTA_EXCEEDED, "Message" => __('Quota exceeded.','shortpixel-image-optimiser'));
|
253 |
break;
|
254 |
+
case -404:
|
255 |
+
return array("Status" => self::STATUS_QUEUE_FULL, "Message" => $APIresponse['Status']->Message);
|
256 |
+
case -500:
|
257 |
+
return array("Status" => self::STATUS_MAINTENANCE, "Message" => $APIresponse['Status']->Message);
|
258 |
}
|
259 |
|
260 |
//sometimes the response array can be different
|
342 |
@unlink($tempFile);
|
343 |
$returnMessage = array(
|
344 |
"Status" => self::STATUS_ERROR,
|
345 |
+
"Code" => self::ERR_DOWNLOAD,
|
346 |
"Message" => __('Error downloading file','shortpixel-image-optimiser') . " ({$fileData->$fileType}) " . $tempFile->get_error_message());
|
347 |
}
|
348 |
//check response so that download is OK
|
351 |
@unlink($tempFile);
|
352 |
$returnMessage = array(
|
353 |
"Status" => self::STATUS_ERROR,
|
354 |
+
"Code" => self::ERR_INCORRECT_FILE_SIZE,
|
355 |
"Message" => sprintf(__('Error downloading file - incorrect file size (downloaded: %s, correct: %s )','shortpixel-image-optimiser'),$size, $correctFileSize));
|
356 |
}
|
357 |
elseif (!file_exists($tempFile)) {
|
358 |
+
$returnMessage = array("Status" => self::STATUS_ERROR,
|
359 |
+
"Code" => self::ERR_FILE_NOT_FOUND,
|
360 |
+
"Message" => __('Unable to locate downloaded file','shortpixel-image-optimiser') . " " . $tempFile);
|
361 |
}
|
362 |
return $returnMessage;
|
363 |
}
|
399 |
$tempFiles[$counter] = $downloadResult;
|
400 |
}
|
401 |
else {
|
402 |
+
return array("Status" => $downloadResult['Status'], "Code" => $downloadResult['Code'], "Message" => $downloadResult['Message']);
|
403 |
}
|
404 |
|
405 |
}
|
410 |
}
|
411 |
|
412 |
//figure out in what SubDir files should land
|
413 |
+
//$fullSubDir = str_replace(wp_normalize_path(get_home_path()), "", wp_normalize_path(dirname($itemHandler->getMeta()->getPath()))) . '/';
|
414 |
+
//$SubDir = ShortPixelMetaFacade::returnSubDir($itemHandler->getMeta()->getPath(), $itemHandler->getType());
|
415 |
+
$mainPath = $itemHandler->getMeta()->getPath();
|
416 |
+
$fullSubDir = ShortPixelMetaFacade::returnSubDir($mainPath, $itemHandler->getType());
|
417 |
+
|
418 |
//if backup is enabled - we try to save the images
|
419 |
if( $this->_settings->backupImages )
|
420 |
{
|
438 |
foreach ( $destination as $fileID => $filePATH )
|
439 |
{
|
440 |
if ( !file_exists($filePATH) )
|
441 |
+
{
|
442 |
if ( !@copy($source[$fileID], $filePATH) )
|
443 |
{//file couldn't be saved in backup folder
|
444 |
$msg = sprintf(__('Cannot save file <i>%s</i> in backup directory','shortpixel-image-optimiser'),self::MB_basename($source[$fileID]));
|
462 |
$width = $height = null;
|
463 |
$resize = $this->_settings->resizeImages;
|
464 |
$retinas = 0;
|
465 |
+
$thumbsOpt = 0;
|
466 |
+
$webpSizes = array();
|
467 |
|
468 |
if ( !empty($tempFiles) )
|
469 |
{
|
473 |
if(!is_array($tempFile)) continue;
|
474 |
|
475 |
$targetFile = $PATHs[$tempFileID];
|
476 |
+
$isRetina = ShortPixelMetaFacade::isRetina($targetFile);
|
477 |
+
|
478 |
+
if( ($tempFile['Status'] == self::STATUS_UNCHANGED || $tempFile['Status'] == self::STATUS_SUCCESS) && !$isRetina
|
479 |
+
&& $targetFile !== $mainPath) {
|
480 |
+
$thumbsOpt++;
|
481 |
+
}
|
482 |
+
|
483 |
if($tempFile['Status'] == self::STATUS_SUCCESS) { //if it's unchanged it will still be in the array but only for WebP (handled below)
|
484 |
$tempFilePATH = $tempFile["Message"];
|
485 |
if ( file_exists($tempFilePATH) && file_exists($PATHs[$tempFileID]) && is_writable($PATHs[$tempFileID]) ) {
|
486 |
copy($tempFilePATH, $targetFile);
|
487 |
+
if(ShortPixelMetaFacade::isRetina($targetFile)) {
|
488 |
+
$retinas ++;
|
489 |
+
}
|
490 |
if($resize && $itemHandler->getMeta()->getPath() == $targetFile) { //this is the main image
|
491 |
$size = getimagesize($PATHs[$tempFileID]);
|
492 |
$width = $size[0];
|
515 |
if(file_exists($tempWebpFilePATH)) {
|
516 |
$targetWebPFile = dirname($targetFile) . '/' . basename($targetFile, '.' . pathinfo($targetFile, PATHINFO_EXTENSION)) . ".webp";
|
517 |
copy($tempWebpFilePATH, $targetWebPFile);
|
518 |
+
$webpSize = $itemHandler->getWebpSizeMeta($targetFile);
|
519 |
+
if($webpSize) {
|
520 |
+
$webpSizes[$webpSize['key']] = $webpSize['val'];
|
521 |
+
}
|
522 |
}
|
523 |
@unlink($tempWebpFilePATH);
|
524 |
}
|
555 |
: "Couldn't compute thumbs optimization percent. Main image: " . $percentImprovement);
|
556 |
WPShortPixel::log("HANDLE SUCCESS: Image optimization: ".$meta->getMessage());
|
557 |
$meta->setCompressionType($compressionType);
|
558 |
+
$meta->setCompressedSize(@filesize($meta->getPath()));
|
559 |
$meta->setKeepExif($this->_settings->keepExif);
|
560 |
$meta->setTsOptimized(date("Y-m-d H:i:s"));
|
561 |
+
$meta->setThumbsOpt(($meta->getThumbsTodo() || $this->_settings->processThumbnails) ? $thumbsOpt : 0);
|
562 |
$meta->setRetinasOpt($retinas);
|
563 |
$meta->setThumbsTodo(false);
|
564 |
+
//* Not yet as it doesn't seem to work... */$meta->addThumbs($webpSizes);
|
565 |
if($width && $height) {
|
566 |
$meta->setActualWidth($width);
|
567 |
$meta->setActualHeight($height);
|
586 |
* @param string $Path
|
587 |
* @return string
|
588 |
*/
|
589 |
+
static public function MB_basename($Path, $suffix = false){
|
590 |
$Separator = " qq ";
|
591 |
$Path = preg_replace("/[^ ]/u", $Separator."\$0".$Separator, $Path);
|
592 |
+
$Base = basename($Path, $suffix);
|
593 |
$Base = str_replace($Separator, "", $Base);
|
594 |
return $Base;
|
595 |
}
|
617 |
if (file_exists($NewFile)) {
|
618 |
$PATHs[$Id] = $NewFile;
|
619 |
} else {
|
620 |
+
$NewFile = $uploadDir['basedir'] . "/" . $File;
|
621 |
+
if (file_exists($NewFile)) {
|
622 |
+
$PATHs[$Id] = $NewFile;
|
623 |
+
} else {
|
624 |
+
$missingFiles[] = $File;
|
625 |
+
$ErrorCount++;
|
626 |
+
}
|
627 |
}
|
628 |
}
|
629 |
}
|
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.2.
|
7 |
* Author: ShortPixel
|
8 |
* Author URI: https://shortpixel.com
|
9 |
* Text Domain: shortpixel-image-optimiser
|
@@ -12,9 +12,11 @@
|
|
12 |
|
13 |
define('SP_RESET_ON_ACTIVATE', false); //if true TODO set false
|
14 |
|
|
|
|
|
15 |
define('SP_AFFILIATE_CODE', '');
|
16 |
|
17 |
-
define('PLUGIN_VERSION', "4.2.
|
18 |
define('SP_MAX_TIMEOUT', 10);
|
19 |
define('SP_VALIDATE_MAX_TIMEOUT', 15);
|
20 |
define('SP_BACKUP', 'ShortpixelBackups');
|
@@ -76,6 +78,10 @@ class WPShortPixel {
|
|
76 |
$this->prioQ = new ShortPixelQueue($this, $this->_settings);
|
77 |
$this->view = new ShortPixelView($this);
|
78 |
|
|
|
|
|
|
|
|
|
79 |
define('QUOTA_EXCEEDED', $this->view->getQuotaExceededHTML());
|
80 |
|
81 |
$this->setDefaultViewModeList();//set default mode as list. only @ first run
|
@@ -103,6 +109,9 @@ class WPShortPixel {
|
|
103 |
// hook on the NextGen gallery list update
|
104 |
add_action('ngg_update_addgallery_page', array( &$this, 'addNextGenGalleriesToCustom'));
|
105 |
}
|
|
|
|
|
|
|
106 |
|
107 |
//custom hook
|
108 |
add_action( 'shortpixel-optimize-now', array( &$this, 'optimizeNowHook' ), 10, 1);
|
@@ -113,6 +122,7 @@ class WPShortPixel {
|
|
113 |
add_action( 'admin_menu', array( &$this, 'registerAdminPage' ) );
|
114 |
|
115 |
add_action('wp_ajax_shortpixel_browse_content', array(&$this, 'browseContent'));
|
|
|
116 |
|
117 |
add_action( 'delete_attachment', array( &$this, 'handleDeleteAttachmentInBackup' ) );
|
118 |
add_action( 'load-upload.php', array( &$this, 'handleCustomBulk'));
|
@@ -126,6 +136,8 @@ class WPShortPixel {
|
|
126 |
|
127 |
//toolbar notifications
|
128 |
add_action( 'admin_bar_menu', array( &$this, 'toolbar_shortpixel_processing'), 999 );
|
|
|
|
|
129 |
}
|
130 |
|
131 |
//automatic optimization
|
@@ -139,7 +151,7 @@ class WPShortPixel {
|
|
139 |
add_action('admin_action_shortpixel_check_quota', array(&$this, 'handleCheckQuota'));
|
140 |
//This adds the constants used in PHP to be available also in JS
|
141 |
add_action( 'admin_footer', array( &$this, 'shortPixelJS') );
|
142 |
-
|
143 |
if($this->_settings->frontBootstrap) {
|
144 |
//also need to have it in the front footer then
|
145 |
add_action( 'wp_footer', array( &$this, 'shortPixelJS') );
|
@@ -195,11 +207,34 @@ class WPShortPixel {
|
|
195 |
ShortPixelQueue::resetBulk();
|
196 |
ShortPixelQueue::resetPrio();
|
197 |
WPShortPixelSettings::onDeactivate();
|
198 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
199 |
|
200 |
public function displayAdminNotices() {
|
|
|
201 |
if(!$this->_settings->verifiedKey) {
|
202 |
-
$dismissed = $this->_settings->dismissedNotices ? $this->_settings->dismissedNotices : array();
|
203 |
$now = time();
|
204 |
$act = $this->_settings->activationDate ? $this->_settings->activationDate : $now;
|
205 |
if($this->_settings->activationNotice && $this->_settings->redirectedSettings >= 2) {
|
@@ -212,6 +247,12 @@ class WPShortPixel {
|
|
212 |
ShortPixelView::displayActivationNotice('3d');
|
213 |
}
|
214 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
215 |
}
|
216 |
|
217 |
public function dismissAdminNotice() {
|
@@ -264,6 +305,8 @@ class WPShortPixel {
|
|
264 |
STATUS_SKIP: <?php echo ShortPixelAPI::STATUS_SKIP; ?>,
|
265 |
STATUS_NO_KEY: <?php echo ShortPixelAPI::STATUS_NO_KEY; ?>,
|
266 |
STATUS_RETRY: <?php echo ShortPixelAPI::STATUS_RETRY; ?>,
|
|
|
|
|
267 |
WP_PLUGIN_URL: '<?php echo plugins_url( '', __FILE__ ); ?>',
|
268 |
WP_ADMIN_URL: '<?php echo admin_url(); ?>',
|
269 |
API_KEY: "<?php echo $this->_settings->apiKey; ?>",
|
@@ -278,7 +321,7 @@ class WPShortPixel {
|
|
278 |
$jsTranslation = array(
|
279 |
'optimizeWithSP' => __( 'Optimize with ShortPixel', 'shortpixel-image-optimiser' ),
|
280 |
'changeMLToListMode' => __( 'In order to access the ShortPixel Optimization actions and info, please change to {0}List View{1}List View{2}Dismiss{3}', 'shortpixel-image-optimiser' ),
|
281 |
-
'alertOnlyAppliesToNewImages' => __( 'This type of optimization will apply to new uploaded images
|
282 |
'areYouSureStopOptimizing' => __( 'Are you sure you want to stop optimizing the folder {0}?', 'shortpixel-image-optimiser' ),
|
283 |
'reducedBy' => __( 'Reduced by', 'shortpixel-image-optimiser' ),
|
284 |
'bonusProcessing' => __( 'Bonus processing', 'shortpixel-image-optimiser' ),
|
@@ -301,12 +344,14 @@ class WPShortPixel {
|
|
301 |
|
302 |
wp_enqueue_script('jquery.knob.js', plugins_url('/res/js/jquery.knob.js',__FILE__) );
|
303 |
wp_enqueue_script('jquery.tooltip.js', plugins_url('/res/js/jquery.tooltip.js',__FILE__) );
|
|
|
304 |
}
|
305 |
|
306 |
function toolbar_shortpixel_processing( $wp_admin_bar ) {
|
307 |
|
308 |
$extraClasses = " shortpixel-hide";
|
309 |
/*translators: toolbar icon tooltip*/
|
|
|
310 |
$tooltip = __('ShortPixel optimizing...','shortpixel-image-optimiser');
|
311 |
$icon = "shortpixel.png";
|
312 |
$successLink = $link = current_user_can( 'edit_others_posts')? 'upload.php?page=wp-short-pixel-bulk' : 'upload.php';
|
@@ -314,10 +359,12 @@ class WPShortPixel {
|
|
314 |
if($this->prioQ->processing()) {
|
315 |
$extraClasses = " shortpixel-processing";
|
316 |
}
|
317 |
-
if($this->_settings->quotaExceeded) {
|
318 |
$extraClasses = " shortpixel-alert shortpixel-quota-exceeded";
|
319 |
/*translators: toolbar icon tooltip*/
|
320 |
-
$
|
|
|
|
|
321 |
//$link = "http://shortpixel.com/login/" . $this->_settings->apiKey;
|
322 |
$link = "options-general.php?page=wp-shortpixel";
|
323 |
//$blank = '_blank';
|
@@ -331,12 +378,27 @@ class WPShortPixel {
|
|
331 |
|
332 |
$args = array(
|
333 |
'id' => 'shortpixel_processing',
|
334 |
-
'title' => '<div title="' . $tooltip . '" ><img src="'
|
335 |
. plugins_url( 'res/img/'.$icon, __FILE__ ) . '" success-url="' . $successLink . '"><span class="shp-alert">!</span></div>',
|
336 |
'href' => $link,
|
337 |
'meta' => array('target'=> $blank, 'class' => 'shortpixel-toolbar-processing' . $extraClasses)
|
338 |
);
|
339 |
$wp_admin_bar->add_node( $args );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
340 |
}
|
341 |
|
342 |
public function handleCustomBulk() {
|
@@ -432,7 +494,7 @@ class WPShortPixel {
|
|
432 |
$folder = new ShortPixelFolder(array("path" => $galleryPath));
|
433 |
$folderMsg = $this->spMetaDao->saveFolder($folder);
|
434 |
$folderId = $folder->getId();
|
435 |
-
self::log("NG Image Upload: created folder from path $galleryPath : Folder info: " . json_encode($folder));
|
436 |
}
|
437 |
$pathParts = explode('/', trim($imageFsPath));
|
438 |
//Add the main image
|
@@ -550,7 +612,7 @@ class WPShortPixel {
|
|
550 |
//daca n-am adaugat niciuna pana acum, n-are sens sa mai selectez zona asta de id-uri in bulk-ul asta.
|
551 |
$leapStart = $this->prioQ->getStartBulkId();
|
552 |
$crtStartQueryID = $startQueryID = $itemMetaData->post_id - 1; //decrement it so we don't select it again
|
553 |
-
$res = WpShortPixelMediaLbraryAdapter::countAllProcessableFiles($leapStart, $crtStartQueryID);
|
554 |
$skippedAlreadyProcessed += $res["mainProcessedFiles"] - $res["mainProc".($this->getCompressionType() == 1 ? "Lossy" : "Lossless")."Files"];
|
555 |
$this->prioQ->setStartBulkId($startQueryID);
|
556 |
} else {
|
@@ -595,7 +657,7 @@ class WPShortPixel {
|
|
595 |
}
|
596 |
|
597 |
self::log("HIP: 0 Priority Queue: ".json_encode($this->prioQ->get()));
|
598 |
-
self::log("HIP: 0
|
599 |
|
600 |
//1: get 3 ids to process. Take them with priority from the queue
|
601 |
$ids = $this->getFromPrioAndCheck();
|
@@ -603,8 +665,17 @@ class WPShortPixel {
|
|
603 |
if($this->prioQ->bulkRunning()) {
|
604 |
$res = $this->getBulkItemsFromDb();
|
605 |
$bulkItems = $res['items'];
|
|
|
606 |
if($bulkItems){
|
607 |
-
$
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
608 |
}
|
609 |
}
|
610 |
}
|
@@ -620,8 +691,8 @@ class WPShortPixel {
|
|
620 |
$ids = array_merge($ids, array_map(array('ShortPixelMetaFacade', 'getNewFromRow'), $customIds));
|
621 |
}
|
622 |
}
|
623 |
-
//
|
624 |
-
//
|
625 |
|
626 |
self::log("HIP: 1 Prio Queue: ".json_encode($this->prioQ->get()));
|
627 |
self::log("HIP: 1 Selected IDs count: ".count($ids));
|
@@ -631,8 +702,14 @@ class WPShortPixel {
|
|
631 |
$itemHandler = $ids[$i];
|
632 |
$tmpMeta = $itemHandler->getMeta();
|
633 |
$compType = ($tmpMeta->getCompressionType() !== null ? $tmpMeta->getCompressionType() : $this->_settings->compressionType);
|
634 |
-
try {
|
|
|
635 |
$URLsAndPATHs = $this->sendToProcessing($itemHandler, $compType, $tmpMeta->getThumbsTodo());
|
|
|
|
|
|
|
|
|
|
|
636 |
} catch(Exception $e) { // Exception("Post metadata is corrupt (No attachment URL)")
|
637 |
$meta = $itemHandler->setError(ShortPixelAPI::ERR_FILE_NOT_FOUND, $e->getMessage());
|
638 |
unset($ids[$i]);
|
@@ -646,9 +723,11 @@ class WPShortPixel {
|
|
646 |
if ($ids === false || count( $ids ) == 0 ){
|
647 |
//if searching, than the script is searching for not processed items and found none yet, should be relaunced
|
648 |
if(isset($res['searching']) && $res['searching']) {
|
649 |
-
die(json_encode(array("Status" => ShortPixelAPI::STATUS_RETRY,
|
|
|
650 |
}
|
651 |
//in this case the queue is really empty
|
|
|
652 |
$bulkEverRan = $this->prioQ->stopBulk();
|
653 |
$avg = $this->getAverageCompression();
|
654 |
$fileCount = $this->_settings->fileCount;
|
@@ -668,6 +747,7 @@ class WPShortPixel {
|
|
668 |
$itemHandler = $ids[0];
|
669 |
$itemId = $itemHandler->getQueuedId();
|
670 |
$result = $this->_apiInterface->processImage($firstUrlAndPaths['URLs'], $firstUrlAndPaths['PATHs'], $itemHandler);
|
|
|
671 |
$result["ImageID"] = $itemId;
|
672 |
$meta = $itemHandler->getMeta();
|
673 |
$result["Filename"] = basename($meta->getPath());
|
@@ -681,13 +761,14 @@ class WPShortPixel {
|
|
681 |
//remove also from the failed list if it failed in the past
|
682 |
$prio = $this->prioQ->removeFromFailed($itemId);
|
683 |
$result["Type"] = $meta->getCompressionType() !== null ? ShortPixelAPI::getCompressionTypeName($meta->getCompressionType()) : '';
|
684 |
-
$result["ThumbsTotal"] = $meta->getThumbs() && is_array($meta->getThumbs()) ?
|
|
|
685 |
$result["ThumbsCount"] = $meta->getThumbsOpt()
|
686 |
? $meta->getThumbsOpt() //below is the fallback for old optimized images that don't have thumbsOpt
|
687 |
: ($this->_settings->processThumbnails ? $result["ThumbsTotal"] : 0);
|
688 |
|
689 |
$result["RetinasCount"] = $meta->getRetinasOpt();
|
690 |
-
$result["BackupEnabled"] = ($this->
|
691 |
|
692 |
if(!$prio && $itemId <= $this->prioQ->getStartBulkId()) {
|
693 |
$this->advanceBulk($itemId, $result);
|
@@ -728,7 +809,7 @@ class WPShortPixel {
|
|
728 |
$bkThumb = $backupUrl . $urlBkPath . $thumb;
|
729 |
}
|
730 |
if(strlen($thumb)) {
|
731 |
-
$uploadsUrl =
|
732 |
$urlPath = ShortPixelMetaFacade::returnSubDir($meta->getPath(), ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE);
|
733 |
//$urlPath = implode("/", array_slice($filePath, 0, count($filePath) - 1));
|
734 |
$thumb = $uploadsUrl . $urlPath . $thumb;
|
@@ -768,9 +849,12 @@ class WPShortPixel {
|
|
768 |
}
|
769 |
$result["Status"] = ShortPixelAPI::STATUS_SKIP;
|
770 |
$result["Message"] .= __(' Retry limit reached. Skipping file ID ','shortpixel-image-optimiser') . $itemId . ".";
|
771 |
-
$itemHandler->setError(ShortPixelAPI::ERR_INCORRECT_FILE_SIZE, $result["Message"] );
|
772 |
}
|
773 |
else {
|
|
|
|
|
|
|
774 |
$itemHandler->incrementRetries();
|
775 |
}
|
776 |
}
|
@@ -790,6 +874,12 @@ class WPShortPixel {
|
|
790 |
$result["CustomImageLink"] = ShortPixelMetaFacade::getHomeUrl() . $meta->getWebPath();
|
791 |
}
|
792 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
793 |
elseif ($this->prioQ->isPrio($itemId) && $result["Status"] == ShortPixelAPI::STATUS_QUOTA_EXCEEDED) {
|
794 |
if(!$this->prioQ->skippedCount()) {
|
795 |
$this->prioQ->reverse(); //for the first prio item with quota exceeded, revert the prio queue as probably the bottom ones were processed
|
@@ -836,11 +926,66 @@ class WPShortPixel {
|
|
836 |
$result["BulkMsg"] = $this->bulkProgressMessage($deltaBulkPercent, $minutesRemaining);
|
837 |
}
|
838 |
|
|
|
|
|
839 |
private function sendToProcessing($itemHandler, $compressionType = false, $onlyThumbs = false) {
|
840 |
$URLsAndPATHs = $this->getURLsAndPATHs($itemHandler, NULL, $onlyThumbs);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
841 |
//echo("URLS: "); die(var_dump($URLsAndPATHs));
|
842 |
$this->_apiInterface->doRequests($URLsAndPATHs['URLs'], false, $itemHandler,
|
843 |
-
$compressionType === false ? $this->_settings->compressionType : $compressionType);//send a request, do NOT wait for response
|
844 |
$itemHandler->setWaitingProcessing();
|
845 |
//$meta = wp_get_attachment_metadata($ID);
|
846 |
//$meta['ShortPixel']['WaitingProcessing'] = true;
|
@@ -868,9 +1013,6 @@ class WPShortPixel {
|
|
868 |
case "C-":
|
869 |
throw new Exception("HandleManualOptimization for custom images not implemented");
|
870 |
default:
|
871 |
-
if($cleanup) {
|
872 |
-
WpShortPixelMediaLbraryAdapter::fixWPMediaMetaMissingThumbs($imageId);
|
873 |
-
}
|
874 |
$this->optimizeNowHook(intval($imageId));
|
875 |
break;
|
876 |
}
|
@@ -897,6 +1039,19 @@ class WPShortPixel {
|
|
897 |
die(json_encode($ret));
|
898 |
}
|
899 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
900 |
//save error in file's meta data
|
901 |
public function handleError($ID, $result)
|
902 |
{
|
@@ -906,10 +1061,21 @@ class WPShortPixel {
|
|
906 |
}
|
907 |
|
908 |
public function getBackupFolder($file) {
|
909 |
-
|
|
|
|
|
910 |
$fileExtension = strtolower(substr($file,strrpos($file,".")+1));
|
911 |
$SubDir = ShortPixelMetaFacade::returnSubDir($file, ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE);
|
|
|
912 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
913 |
//sometimes the month of original file and backup can differ
|
914 |
if ( !file_exists(SP_BACKUP_FOLDER . '/' . $SubDir . ShortPixelAPI::MB_basename($file)) ) {
|
915 |
$SubDir = date("Y") . "/" . date("m") . "/";
|
@@ -920,8 +1086,27 @@ class WPShortPixel {
|
|
920 |
return SP_BACKUP_FOLDER . '/' . $SubDir;
|
921 |
}
|
922 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
923 |
protected function setFilePerms($file) {
|
924 |
//die(getenv('USERNAME') ? getenv('USERNAME') : getenv('USER'));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
925 |
$perms = @fileperms($file);
|
926 |
if(!($perms & 0x0100) || !($perms & 0x0080)) {
|
927 |
if(!@chmod($file, $perms | 0x0100 | 0x0080)) {
|
@@ -932,41 +1117,55 @@ class WPShortPixel {
|
|
932 |
}
|
933 |
|
934 |
protected function doRestore($attachmentID, $meta = null) {
|
935 |
-
$file = get_attached_file($attachmentID);
|
936 |
if(!$meta) {
|
937 |
$meta = wp_get_attachment_metadata($attachmentID);
|
938 |
}
|
939 |
$pathInfo = pathinfo($file);
|
940 |
|
941 |
-
$bkFolder = $this->
|
942 |
-
$
|
943 |
-
|
944 |
-
|
945 |
-
if(file_exists($bkNewFile)) {
|
946 |
-
$bkFile = $bkNewFile;
|
947 |
-
}
|
948 |
-
|
949 |
//first check if the file is readable by the current user - otherwise it will be unaccessible for the web browser
|
950 |
// - collect the thumbs paths in the process
|
951 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
952 |
$thumbsPaths = array();
|
953 |
if( !empty($meta['file']) && is_array($meta["sizes"]) ) {
|
954 |
foreach($meta["sizes"] as $size => $imageData) {
|
955 |
-
$
|
|
|
956 |
if(!file_exists($source)) continue; // if thumbs were not optimized, then the backups will not be there.
|
957 |
-
$
|
958 |
-
|
|
|
|
|
|
|
959 |
}
|
960 |
}
|
961 |
-
|
|
|
|
|
|
|
962 |
if($bkFolder) {
|
963 |
try {
|
964 |
//main file
|
965 |
-
|
|
|
|
|
966 |
//getSize to update meta if image was resized by ShortPixel
|
967 |
-
$
|
968 |
-
$
|
969 |
-
|
|
|
|
|
|
|
970 |
|
971 |
//overwriting thumbnails
|
972 |
foreach($thumbsPaths as $source => $destination) {
|
@@ -986,7 +1185,9 @@ class WPShortPixel {
|
|
986 |
}
|
987 |
wp_update_attachment_metadata($ID, $crtMeta);
|
988 |
}
|
989 |
-
|
|
|
|
|
990 |
} catch(Exception $e) {
|
991 |
//what to do, what to do?
|
992 |
return false;
|
@@ -1076,7 +1277,7 @@ class WPShortPixel {
|
|
1076 |
$meta = wp_get_attachment_metadata($ID);
|
1077 |
//die(var_dump($meta));
|
1078 |
if( isset($meta['ShortPixelImprovement'])
|
1079 |
-
&& isset($meta['sizes']) &&
|
1080 |
&& ( !isset($meta['ShortPixel']['thumbsOpt']) || $meta['ShortPixel']['thumbsOpt'] == 0)) { //optimized without thumbs, thumbs exist
|
1081 |
$meta['ShortPixel']['thumbsTodo'] = true;
|
1082 |
wp_update_attachment_metadata($ID, $meta);
|
@@ -1127,6 +1328,15 @@ class WPShortPixel {
|
|
1127 |
}
|
1128 |
}
|
1129 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1130 |
|
1131 |
public function checkQuotaAndAlert($quotaData = null, $recheck = false) {
|
1132 |
if(!$quotaData) {
|
@@ -1136,7 +1346,7 @@ class WPShortPixel {
|
|
1136 |
return $quotaData;
|
1137 |
}
|
1138 |
//$tempus = microtime(true);
|
1139 |
-
$imageCount = WpShortPixelMediaLbraryAdapter::countAllProcessableFiles();
|
1140 |
|
1141 |
$this->_settings->currentTotalFiles = $imageCount['totalFiles'];
|
1142 |
|
@@ -1161,7 +1371,7 @@ class WPShortPixel {
|
|
1161 |
|
1162 |
?><script>var shortPixelQuotaExceeded = 0;</script><?php
|
1163 |
}
|
1164 |
-
else {
|
1165 |
$this->view->displayQuotaExceededAlert($quotaData, self::getAverageCompression(), $recheck);
|
1166 |
?><script>var shortPixelQuotaExceeded = 1;</script><?php
|
1167 |
}
|
@@ -1209,7 +1419,7 @@ class WPShortPixel {
|
|
1209 |
<?php
|
1210 |
$customMediaListTable->display();
|
1211 |
//push to the processing list the pending ones, just in case
|
1212 |
-
|
1213 |
foreach ($items as $item) {
|
1214 |
if($item->status == 1){
|
1215 |
$this->prioQ->push(ShortPixelMetaFacade::queuedId(ShortPixelMetaFacade::CUSTOM_TYPE, $item->id));
|
@@ -1261,6 +1471,11 @@ class WPShortPixel {
|
|
1261 |
} else {
|
1262 |
$this->_settings->processThumbnails = 0;
|
1263 |
}
|
|
|
|
|
|
|
|
|
|
|
1264 |
$this->prioQ->startBulk();
|
1265 |
$this->_settings->customBulkPaused = 0;
|
1266 |
self::log("BULK: Start: " . $this->prioQ->getStartBulkId() . ", stop: " . $this->prioQ->getStopBulkId() . " PrioQ: "
|
@@ -1356,15 +1571,17 @@ class WPShortPixel {
|
|
1356 |
|
1357 |
|
1358 |
//parse all images and set the right flag that the image has no backup
|
|
|
1359 |
foreach($attachments as $attachment)
|
1360 |
{
|
1361 |
-
if(self::isProcessable(
|
1362 |
|
1363 |
$meta = wp_get_attachment_metadata($attachment->ID);
|
1364 |
$meta['ShortPixel']['NoBackup'] = true;
|
1365 |
wp_update_attachment_metadata($attachment->ID, $meta);
|
1366 |
}
|
1367 |
-
|
|
|
1368 |
//delete the actual files on disk
|
1369 |
$this->deleteDir(SP_BACKUP_FOLDER);//call a recursive function to empty files and sub-dirs in backup dir
|
1370 |
}
|
@@ -1373,9 +1590,16 @@ class WPShortPixel {
|
|
1373 |
public function backupFolderIsEmpty() {
|
1374 |
return count(scandir(SP_BACKUP_FOLDER)) > 2 ? false : true;
|
1375 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1376 |
|
1377 |
public function browseContent() {
|
1378 |
-
if ( !current_user_can( 'manage_options' ) ) {
|
1379 |
wp_die(__('You do not have sufficient permissions to access this page.','shortpixel-image-optimiser'));
|
1380 |
}
|
1381 |
|
@@ -1608,6 +1832,7 @@ class WPShortPixel {
|
|
1608 |
|
1609 |
$this->_settings->createWebp = (isset($_POST['createWebp']) ? 1: 0);
|
1610 |
$this->_settings->optimizeRetina = (isset($_POST['optimizeRetina']) ? 1: 0);
|
|
|
1611 |
$this->_settings->frontBootstrap = (isset($_POST['frontBootstrap']) ? 1: 0);
|
1612 |
$this->_settings->autoMediaLibrary = (isset($_POST['autoMediaLibrary']) ? 1: 0);
|
1613 |
|
@@ -1661,18 +1886,17 @@ class WPShortPixel {
|
|
1661 |
if (is_numeric($quotaData['APICallsQuota'])) {
|
1662 |
$quotaData['APICallsQuota'] .= "/month";
|
1663 |
}
|
1664 |
-
$backupFolderSize = self::formatBytes(self::folderSize(SP_BACKUP_FOLDER));
|
1665 |
$remainingImages = $quotaData['APICallsRemaining'];
|
1666 |
$remainingImages = ( $remainingImages < 0 ) ? 0 : number_format($remainingImages);
|
1667 |
$totalCallsMade = number_format($quotaData['APICallsMadeNumeric'] + $quotaData['APICallsMadeOneTimeNumeric']);
|
1668 |
|
1669 |
-
$resources =
|
1670 |
if(is_wp_error( $resources )) {
|
1671 |
$resources = array();
|
1672 |
}
|
1673 |
$this->view->displaySettings($showApiKey, $editApiKey,
|
1674 |
$quotaData, $notice, $resources, $averageCompression, $savedSpace, $savedBandwidth, $remainingImages,
|
1675 |
-
$totalCallsMade, $fileCount,
|
1676 |
$folderMsg, $folderMsg ? $addedFolder : false, isset($_POST['saveAdv']));
|
1677 |
} else {
|
1678 |
$this->view->displaySettings($showApiKey, $editApiKey, $quotaData, $notice);
|
@@ -1730,7 +1954,7 @@ class WPShortPixel {
|
|
1730 |
if($validate) {
|
1731 |
$args['body']['DomainCheck'] = get_site_url();
|
1732 |
$args['body']['Info'] = get_bloginfo('version') . '|' . phpversion();
|
1733 |
-
$imageCount = WpShortPixelMediaLbraryAdapter::countAllProcessableFiles();
|
1734 |
$args['body']['ImagesCount'] = $imageCount['mainFiles'];
|
1735 |
$args['body']['ThumbsCount'] = $imageCount['totalFiles'] - $imageCount['mainFiles'];
|
1736 |
$argsStr .= "&DomainCheck={$args['body']['DomainCheck']}&Info={$args['body']['Info']}&ImagesCount={$imageCount['mainFiles']}&ThumbsCount={$args['body']['ThumbsCount']}";
|
@@ -1814,7 +2038,7 @@ class WPShortPixel {
|
|
1814 |
}
|
1815 |
|
1816 |
if ( ( $data->APICallsMade + $data->APICallsMadeOneTime ) < ( $data->APICallsQuota + $data->APICallsQuotaOneTime ) ) //reset quota exceeded flag -> user is allowed to process more images.
|
1817 |
-
$this->
|
1818 |
else
|
1819 |
$this->_settings->quotaExceeded = 1;//activate quota limiting
|
1820 |
|
@@ -1839,16 +2063,31 @@ class WPShortPixel {
|
|
1839 |
"DomainCheck" => (isset($data->DomainCheck) ? $data->DomainCheck : null)
|
1840 |
);
|
1841 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1842 |
|
1843 |
public function generateCustomColumn( $column_name, $id, $extended = false ) {
|
1844 |
if( 'wp-shortPixel' == $column_name ) {
|
1845 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1846 |
$data = wp_get_attachment_metadata($id);
|
1847 |
-
$
|
1848 |
-
$fileExtension = strtolower(substr($file,strrpos($file,".")+1));
|
1849 |
$invalidKey = !$this->_settings->verifiedKey;
|
1850 |
$quotaExceeded = $this->_settings->quotaExceeded;
|
1851 |
-
$renderData = array("id" => $id, "showActions" => current_user_can( 'manage_options' ));
|
1852 |
|
1853 |
if($invalidKey) { //invalid key - let the user first register and only then
|
1854 |
$renderData['status'] = 'invalidKey';
|
@@ -1874,27 +2113,30 @@ class WPShortPixel {
|
|
1874 |
}
|
1875 |
|
1876 |
if(is_numeric($data['ShortPixelImprovement'])) { //already optimized
|
|
|
|
|
1877 |
$renderData['status'] = $fileExtension == "pdf" ? 'pdfOptimized' : 'imgOptimized';
|
1878 |
$renderData['percent'] = $data['ShortPixelImprovement'];
|
1879 |
$renderData['bonus'] = ($data['ShortPixelImprovement'] < 5);
|
1880 |
-
$renderData['backup'] = $this->
|
1881 |
$renderData['type'] = isset($data['ShortPixel']['type']) ? $data['ShortPixel']['type'] : '';
|
1882 |
-
$
|
1883 |
-
$renderData['
|
1884 |
-
$renderData['
|
1885 |
$renderData['retinasOpt'] = isset($data['ShortPixel']['retinasOpt']) ? $data['ShortPixel']['retinasOpt'] : null;
|
1886 |
$renderData['exifKept'] = isset($data['ShortPixel']['exifKept']) ? $data['ShortPixel']['exifKept'] : null;
|
1887 |
$renderData['date'] = isset($data['ShortPixel']['date']) ? $data['ShortPixel']['date'] : null;
|
1888 |
$renderData['quotaExceeded'] = $quotaExceeded;
|
1889 |
$webP = 0;
|
1890 |
if($extended) {
|
1891 |
-
if(file_exists(dirname($file) . '/' . basename($file, '.'
|
1892 |
$webP++;
|
1893 |
}
|
1894 |
if(isset($data['sizes'])) {
|
1895 |
-
foreach($data['sizes'] as $size) {
|
|
|
1896 |
$sizeName = $size['file'];
|
1897 |
-
if(file_exists(dirname($file) . '/' . basename($sizeName, '.'
|
1898 |
$webP++;
|
1899 |
}
|
1900 |
}
|
@@ -1903,7 +2145,12 @@ class WPShortPixel {
|
|
1903 |
$renderData['webpCount'] = $webP;
|
1904 |
}
|
1905 |
elseif($data['ShortPixelImprovement'] == __('Optimization N/A','shortpixel-image-optimiser')) { //We don't optimize this
|
1906 |
-
|
|
|
|
|
|
|
|
|
|
|
1907 |
}
|
1908 |
elseif(isset($meta['ShortPixel']['BulkProcessing'])) { //Scheduled to bulk.
|
1909 |
$renderData['status'] = $quotaExceeded ? 'quotaExceeded' : 'optimizeNow';
|
@@ -1932,7 +2179,7 @@ class WPShortPixel {
|
|
1932 |
}
|
1933 |
else { //finally
|
1934 |
$renderData['status'] = $quotaExceeded ? 'quotaExceeded' : 'optimizeNow';
|
1935 |
-
$sizes = isset($data['sizes']) ?
|
1936 |
$renderData['thumbsTotal'] = $sizes;
|
1937 |
$renderData['message'] = ($fileExtension == "pdf" ? 'PDF' : 'Image') . ' not processed.';
|
1938 |
}
|
@@ -2050,12 +2297,13 @@ class WPShortPixel {
|
|
2050 |
|
2051 |
static public function isProcessable($ID) {
|
2052 |
$path = get_attached_file($ID);//get the full file PATH
|
2053 |
-
return self::isProcessablePath($path);
|
2054 |
}
|
2055 |
|
2056 |
static public function isProcessablePath($path) {
|
2057 |
$pathParts = pathinfo($path);
|
2058 |
-
|
|
|
2059 |
return true;
|
2060 |
} else {
|
2061 |
return false;
|
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.2.6
|
7 |
* Author: ShortPixel
|
8 |
* Author URI: https://shortpixel.com
|
9 |
* Text Domain: shortpixel-image-optimiser
|
12 |
|
13 |
define('SP_RESET_ON_ACTIVATE', false); //if true TODO set false
|
14 |
|
15 |
+
//define('SHORTPIXEL_DEBUG', true);
|
16 |
+
|
17 |
define('SP_AFFILIATE_CODE', '');
|
18 |
|
19 |
+
define('PLUGIN_VERSION', "4.2.6");
|
20 |
define('SP_MAX_TIMEOUT', 10);
|
21 |
define('SP_VALIDATE_MAX_TIMEOUT', 15);
|
22 |
define('SP_BACKUP', 'ShortpixelBackups');
|
78 |
$this->prioQ = new ShortPixelQueue($this, $this->_settings);
|
79 |
$this->view = new ShortPixelView($this);
|
80 |
|
81 |
+
if(!$this->_settings->optimizePdfs) {
|
82 |
+
self::$PROCESSABLE_EXTENSIONS = array_diff(self::$PROCESSABLE_EXTENSIONS, array('pdf'));
|
83 |
+
}
|
84 |
+
|
85 |
define('QUOTA_EXCEEDED', $this->view->getQuotaExceededHTML());
|
86 |
|
87 |
$this->setDefaultViewModeList();//set default mode as list. only @ first run
|
109 |
// hook on the NextGen gallery list update
|
110 |
add_action('ngg_update_addgallery_page', array( &$this, 'addNextGenGalleriesToCustom'));
|
111 |
}
|
112 |
+
|
113 |
+
// integration with WP/LR Sync plugin
|
114 |
+
add_action( 'wplr_update_media', array( &$this, 'onWpLrUpdateMedia' ), 10, 2);
|
115 |
|
116 |
//custom hook
|
117 |
add_action( 'shortpixel-optimize-now', array( &$this, 'optimizeNowHook' ), 10, 1);
|
122 |
add_action( 'admin_menu', array( &$this, 'registerAdminPage' ) );
|
123 |
|
124 |
add_action('wp_ajax_shortpixel_browse_content', array(&$this, 'browseContent'));
|
125 |
+
add_action('wp_ajax_shortpixel_get_backup_size', array(&$this, 'getBackupSize'));
|
126 |
|
127 |
add_action( 'delete_attachment', array( &$this, 'handleDeleteAttachmentInBackup' ) );
|
128 |
add_action( 'load-upload.php', array( &$this, 'handleCustomBulk'));
|
136 |
|
137 |
//toolbar notifications
|
138 |
add_action( 'admin_bar_menu', array( &$this, 'toolbar_shortpixel_processing'), 999 );
|
139 |
+
//deactivate plugin
|
140 |
+
add_action( 'admin_post_shortpixel_deactivate_plugin', array(&$this, 'deactivatePlugin'));
|
141 |
}
|
142 |
|
143 |
//automatic optimization
|
151 |
add_action('admin_action_shortpixel_check_quota', array(&$this, 'handleCheckQuota'));
|
152 |
//This adds the constants used in PHP to be available also in JS
|
153 |
add_action( 'admin_footer', array( &$this, 'shortPixelJS') );
|
154 |
+
|
155 |
if($this->_settings->frontBootstrap) {
|
156 |
//also need to have it in the front footer then
|
157 |
add_action( 'wp_footer', array( &$this, 'shortPixelJS') );
|
207 |
ShortPixelQueue::resetBulk();
|
208 |
ShortPixelQueue::resetPrio();
|
209 |
WPShortPixelSettings::onDeactivate();
|
210 |
+
}
|
211 |
+
|
212 |
+
public static function getConflictingPlugins() {
|
213 |
+
$conflictPlugins = array(
|
214 |
+
'WP Smush - Image Optimization' => 'wp-smushit/wp-smush.php',
|
215 |
+
'Imagify Image Optimizer' => 'imagify/imagify.php',
|
216 |
+
'Compress JPEG & PNG images (TinyPNG)' => 'tiny-compress-images/tiny-compress-images.php',
|
217 |
+
'Kraken.io Image Optimizer' => 'kraken-image-optimizer/kraken.php',
|
218 |
+
'Optimus - WordPress Image Optimizer' => 'optimus/optimus.php',
|
219 |
+
'EWWW Image Optimizer' => 'ewww-image-optimizer/ewww-image-optimizer.php',
|
220 |
+
'ImageRecycle pdf & image compression' => 'imagerecycle-pdf-image-compression/wp-image-recycle.php',
|
221 |
+
'CheetahO Image Optimizer' => 'cheetaho-image-optimizer/cheetaho.php',
|
222 |
+
'Zara 4 Image Compression' => 'zara-4/zara-4.php',
|
223 |
+
'Prizm Image' => 'prizm-image/wp-prizmimage.php',
|
224 |
+
'CW Image Optimizer' => 'cw-image-optimizer/cw-image-optimizer.php'
|
225 |
+
);
|
226 |
+
$found = array();
|
227 |
+
foreach($conflictPlugins as $name => $path) {
|
228 |
+
if(is_plugin_active($path)) {
|
229 |
+
$found[] = array('name' => $name, 'path' => $path);
|
230 |
+
}
|
231 |
+
}
|
232 |
+
return $found;
|
233 |
+
}
|
234 |
|
235 |
public function displayAdminNotices() {
|
236 |
+
$dismissed = $this->_settings->dismissedNotices ? $this->_settings->dismissedNotices : array();
|
237 |
if(!$this->_settings->verifiedKey) {
|
|
|
238 |
$now = time();
|
239 |
$act = $this->_settings->activationDate ? $this->_settings->activationDate : $now;
|
240 |
if($this->_settings->activationNotice && $this->_settings->redirectedSettings >= 2) {
|
247 |
ShortPixelView::displayActivationNotice('3d');
|
248 |
}
|
249 |
}
|
250 |
+
if(!isset($dismissed['compat'])) {
|
251 |
+
$conflictPlugins = self::getConflictingPlugins();
|
252 |
+
if(count($conflictPlugins)) {
|
253 |
+
ShortPixelView::displayActivationNotice('compat', $conflictPlugins);
|
254 |
+
}
|
255 |
+
}
|
256 |
}
|
257 |
|
258 |
public function dismissAdminNotice() {
|
305 |
STATUS_SKIP: <?php echo ShortPixelAPI::STATUS_SKIP; ?>,
|
306 |
STATUS_NO_KEY: <?php echo ShortPixelAPI::STATUS_NO_KEY; ?>,
|
307 |
STATUS_RETRY: <?php echo ShortPixelAPI::STATUS_RETRY; ?>,
|
308 |
+
STATUS_QUEUE_FULL: <?php echo ShortPixelAPI::STATUS_QUEUE_FULL; ?>,
|
309 |
+
STATUS_MAINTENANCE: <?php echo ShortPixelAPI::STATUS_MAINTENANCE; ?>,
|
310 |
WP_PLUGIN_URL: '<?php echo plugins_url( '', __FILE__ ); ?>',
|
311 |
WP_ADMIN_URL: '<?php echo admin_url(); ?>',
|
312 |
API_KEY: "<?php echo $this->_settings->apiKey; ?>",
|
321 |
$jsTranslation = array(
|
322 |
'optimizeWithSP' => __( 'Optimize with ShortPixel', 'shortpixel-image-optimiser' ),
|
323 |
'changeMLToListMode' => __( 'In order to access the ShortPixel Optimization actions and info, please change to {0}List View{1}List View{2}Dismiss{3}', 'shortpixel-image-optimiser' ),
|
324 |
+
'alertOnlyAppliesToNewImages' => __( 'This type of optimization will apply to new uploaded images. Images that were already processed will not be re-optimized unless you restart the bulk process.', 'shortpixel-image-optimiser' ),
|
325 |
'areYouSureStopOptimizing' => __( 'Are you sure you want to stop optimizing the folder {0}?', 'shortpixel-image-optimiser' ),
|
326 |
'reducedBy' => __( 'Reduced by', 'shortpixel-image-optimiser' ),
|
327 |
'bonusProcessing' => __( 'Bonus processing', 'shortpixel-image-optimiser' ),
|
344 |
|
345 |
wp_enqueue_script('jquery.knob.js', plugins_url('/res/js/jquery.knob.js',__FILE__) );
|
346 |
wp_enqueue_script('jquery.tooltip.js', plugins_url('/res/js/jquery.tooltip.js',__FILE__) );
|
347 |
+
wp_enqueue_script('punycode.js', plugins_url('/res/js/punycode.js',__FILE__) );
|
348 |
}
|
349 |
|
350 |
function toolbar_shortpixel_processing( $wp_admin_bar ) {
|
351 |
|
352 |
$extraClasses = " shortpixel-hide";
|
353 |
/*translators: toolbar icon tooltip*/
|
354 |
+
$id = 'short-pixel-notice-toolbar';
|
355 |
$tooltip = __('ShortPixel optimizing...','shortpixel-image-optimiser');
|
356 |
$icon = "shortpixel.png";
|
357 |
$successLink = $link = current_user_can( 'edit_others_posts')? 'upload.php?page=wp-short-pixel-bulk' : 'upload.php';
|
359 |
if($this->prioQ->processing()) {
|
360 |
$extraClasses = " shortpixel-processing";
|
361 |
}
|
362 |
+
if($this->_settings->quotaExceeded && !isset($this->_settings->dismissedNotices['exceed'])) {
|
363 |
$extraClasses = " shortpixel-alert shortpixel-quota-exceeded";
|
364 |
/*translators: toolbar icon tooltip*/
|
365 |
+
$id = 'short-pixel-notice-exceed';
|
366 |
+
$tooltip = '';
|
367 |
+
$exceedTooltip = __('ShortPixel quota exceeded. Click for details.','shortpixel-image-optimiser');
|
368 |
//$link = "http://shortpixel.com/login/" . $this->_settings->apiKey;
|
369 |
$link = "options-general.php?page=wp-shortpixel";
|
370 |
//$blank = '_blank';
|
378 |
|
379 |
$args = array(
|
380 |
'id' => 'shortpixel_processing',
|
381 |
+
'title' => '<div id="' . $id . '" title="' . $tooltip . '" ><img src="'
|
382 |
. plugins_url( 'res/img/'.$icon, __FILE__ ) . '" success-url="' . $successLink . '"><span class="shp-alert">!</span></div>',
|
383 |
'href' => $link,
|
384 |
'meta' => array('target'=> $blank, 'class' => 'shortpixel-toolbar-processing' . $extraClasses)
|
385 |
);
|
386 |
$wp_admin_bar->add_node( $args );
|
387 |
+
if($this->_settings->quotaExceeded && !isset($this->_settings->dismissedNotices['exceed'])) {
|
388 |
+
$wp_admin_bar->add_node( array(
|
389 |
+
'id' => 'shortpixel_processing-title',
|
390 |
+
'parent' => 'shortpixel_processing',
|
391 |
+
'title' => $exceedTooltip,
|
392 |
+
'href' => $link
|
393 |
+
));
|
394 |
+
$wp_admin_bar->add_node( array(
|
395 |
+
'id' => 'shortpixel_processing-dismiss',
|
396 |
+
'parent' => 'shortpixel_processing',
|
397 |
+
'title' => '<div style="text-align: right;">Dismiss</div>',
|
398 |
+
'href' => "#",
|
399 |
+
'meta' => array('onclick'=> 'dismissShortPixelNoticeExceed(event)')
|
400 |
+
));
|
401 |
+
}
|
402 |
}
|
403 |
|
404 |
public function handleCustomBulk() {
|
494 |
$folder = new ShortPixelFolder(array("path" => $galleryPath));
|
495 |
$folderMsg = $this->spMetaDao->saveFolder($folder);
|
496 |
$folderId = $folder->getId();
|
497 |
+
//self::log("NG Image Upload: created folder from path $galleryPath : Folder info: " . json_encode($folder));
|
498 |
}
|
499 |
$pathParts = explode('/', trim($imageFsPath));
|
500 |
//Add the main image
|
612 |
//daca n-am adaugat niciuna pana acum, n-are sens sa mai selectez zona asta de id-uri in bulk-ul asta.
|
613 |
$leapStart = $this->prioQ->getStartBulkId();
|
614 |
$crtStartQueryID = $startQueryID = $itemMetaData->post_id - 1; //decrement it so we don't select it again
|
615 |
+
$res = WpShortPixelMediaLbraryAdapter::countAllProcessableFiles($this->_settings->optimizePdfs, $leapStart, $crtStartQueryID);
|
616 |
$skippedAlreadyProcessed += $res["mainProcessedFiles"] - $res["mainProc".($this->getCompressionType() == 1 ? "Lossy" : "Lossless")."Files"];
|
617 |
$this->prioQ->setStartBulkId($startQueryID);
|
618 |
} else {
|
657 |
}
|
658 |
|
659 |
self::log("HIP: 0 Priority Queue: ".json_encode($this->prioQ->get()));
|
660 |
+
//self::log("HIP: 0 Bulk running? " . $this->prioQ->bulkRunning() . " START " . $this->_settings->startBulkId . " STOP " . $this->_settings->stopBulkId);
|
661 |
|
662 |
//1: get 3 ids to process. Take them with priority from the queue
|
663 |
$ids = $this->getFromPrioAndCheck();
|
665 |
if($this->prioQ->bulkRunning()) {
|
666 |
$res = $this->getBulkItemsFromDb();
|
667 |
$bulkItems = $res['items'];
|
668 |
+
//merge them into the $ids array based on the ID (the same ID could be in prio also)
|
669 |
if($bulkItems){
|
670 |
+
foreach($bulkItems as $bi) {
|
671 |
+
$add = true;
|
672 |
+
foreach($ids as $pi) {
|
673 |
+
if($pi->getType() == ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE && $bi->getId() == $pi->getId()) {
|
674 |
+
$add = false;
|
675 |
+
}
|
676 |
+
}
|
677 |
+
$ids[] = $bi;
|
678 |
+
}
|
679 |
}
|
680 |
}
|
681 |
}
|
691 |
$ids = array_merge($ids, array_map(array('ShortPixelMetaFacade', 'getNewFromRow'), $customIds));
|
692 |
}
|
693 |
}
|
694 |
+
//var_dump($ids);
|
695 |
+
//die("za stop 2");
|
696 |
|
697 |
self::log("HIP: 1 Prio Queue: ".json_encode($this->prioQ->get()));
|
698 |
self::log("HIP: 1 Selected IDs count: ".count($ids));
|
702 |
$itemHandler = $ids[$i];
|
703 |
$tmpMeta = $itemHandler->getMeta();
|
704 |
$compType = ($tmpMeta->getCompressionType() !== null ? $tmpMeta->getCompressionType() : $this->_settings->compressionType);
|
705 |
+
try {
|
706 |
+
self::log("HIP: 1 sendToProcessing: ".$itemHandler->getId());
|
707 |
$URLsAndPATHs = $this->sendToProcessing($itemHandler, $compType, $tmpMeta->getThumbsTodo());
|
708 |
+
//make sure it gets processed even if the user stops the bulk or the bulk skips somehow
|
709 |
+
$this->prioQ->enqueue($itemHandler->getId()); //this adds it to the end of the queue instead as first as push does
|
710 |
+
if(!count($URLsAndPATHs['PATHs'])) {
|
711 |
+
throw new Exception(__('Image files are missing.','shortpixel-image-optimiser'));
|
712 |
+
}
|
713 |
} catch(Exception $e) { // Exception("Post metadata is corrupt (No attachment URL)")
|
714 |
$meta = $itemHandler->setError(ShortPixelAPI::ERR_FILE_NOT_FOUND, $e->getMessage());
|
715 |
unset($ids[$i]);
|
723 |
if ($ids === false || count( $ids ) == 0 ){
|
724 |
//if searching, than the script is searching for not processed items and found none yet, should be relaunced
|
725 |
if(isset($res['searching']) && $res['searching']) {
|
726 |
+
die(json_encode(array("Status" => ShortPixelAPI::STATUS_RETRY,
|
727 |
+
"Message" => __('Searching images to optimize... ','shortpixel-image-optimiser') . $this->prioQ->getStartBulkId() . '->' . $this->prioQ->getStopBulkId() )));
|
728 |
}
|
729 |
//in this case the queue is really empty
|
730 |
+
self::log("HIP: 1 STOP BULK");
|
731 |
$bulkEverRan = $this->prioQ->stopBulk();
|
732 |
$avg = $this->getAverageCompression();
|
733 |
$fileCount = $this->_settings->fileCount;
|
747 |
$itemHandler = $ids[0];
|
748 |
$itemId = $itemHandler->getQueuedId();
|
749 |
$result = $this->_apiInterface->processImage($firstUrlAndPaths['URLs'], $firstUrlAndPaths['PATHs'], $itemHandler);
|
750 |
+
|
751 |
$result["ImageID"] = $itemId;
|
752 |
$meta = $itemHandler->getMeta();
|
753 |
$result["Filename"] = basename($meta->getPath());
|
761 |
//remove also from the failed list if it failed in the past
|
762 |
$prio = $this->prioQ->removeFromFailed($itemId);
|
763 |
$result["Type"] = $meta->getCompressionType() !== null ? ShortPixelAPI::getCompressionTypeName($meta->getCompressionType()) : '';
|
764 |
+
$result["ThumbsTotal"] = $meta->getThumbs() && is_array($meta->getThumbs()) ? WpShortPixelMediaLbraryAdapter::countNonWebpSizes($meta->getThumbs()): 0;
|
765 |
+
$result["ThumbsTotal"] -= count($meta->getThumbsMissing());
|
766 |
$result["ThumbsCount"] = $meta->getThumbsOpt()
|
767 |
? $meta->getThumbsOpt() //below is the fallback for old optimized images that don't have thumbsOpt
|
768 |
: ($this->_settings->processThumbnails ? $result["ThumbsTotal"] : 0);
|
769 |
|
770 |
$result["RetinasCount"] = $meta->getRetinasOpt();
|
771 |
+
$result["BackupEnabled"] = ($this->getBackupFolderAny($meta->getPath(), $meta->getThumbs()) ? true : false);//$this->_settings->backupImages;
|
772 |
|
773 |
if(!$prio && $itemId <= $this->prioQ->getStartBulkId()) {
|
774 |
$this->advanceBulk($itemId, $result);
|
809 |
$bkThumb = $backupUrl . $urlBkPath . $thumb;
|
810 |
}
|
811 |
if(strlen($thumb)) {
|
812 |
+
$uploadsUrl = ShortPixelMetaFacade::getHomeUrl2();
|
813 |
$urlPath = ShortPixelMetaFacade::returnSubDir($meta->getPath(), ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE);
|
814 |
//$urlPath = implode("/", array_slice($filePath, 0, count($filePath) - 1));
|
815 |
$thumb = $uploadsUrl . $urlPath . $thumb;
|
849 |
}
|
850 |
$result["Status"] = ShortPixelAPI::STATUS_SKIP;
|
851 |
$result["Message"] .= __(' Retry limit reached. Skipping file ID ','shortpixel-image-optimiser') . $itemId . ".";
|
852 |
+
$itemHandler->setError(isset($result['Code']) ? $result['Code'] : ShortPixelAPI::ERR_INCORRECT_FILE_SIZE, $result["Message"] );
|
853 |
}
|
854 |
else {
|
855 |
+
if(isset($result['Code'])) {
|
856 |
+
$itemHandler->setError($result['Code'], $result["Message"] );
|
857 |
+
}
|
858 |
$itemHandler->incrementRetries();
|
859 |
}
|
860 |
}
|
874 |
$result["CustomImageLink"] = ShortPixelMetaFacade::getHomeUrl() . $meta->getWebPath();
|
875 |
}
|
876 |
}
|
877 |
+
elseif($result["Status"] == ShortPixelAPI::STATUS_QUEUE_FULL) {
|
878 |
+
//nimic?
|
879 |
+
}
|
880 |
+
elseif($result["Status"] == ShortPixelAPI::STATUS_MAINTENANCE) {
|
881 |
+
//nimic?
|
882 |
+
}
|
883 |
elseif ($this->prioQ->isPrio($itemId) && $result["Status"] == ShortPixelAPI::STATUS_QUOTA_EXCEEDED) {
|
884 |
if(!$this->prioQ->skippedCount()) {
|
885 |
$this->prioQ->reverse(); //for the first prio item with quota exceeded, revert the prio queue as probably the bottom ones were processed
|
926 |
$result["BulkMsg"] = $this->bulkProgressMessage($deltaBulkPercent, $minutesRemaining);
|
927 |
}
|
928 |
|
929 |
+
|
930 |
+
|
931 |
private function sendToProcessing($itemHandler, $compressionType = false, $onlyThumbs = false) {
|
932 |
$URLsAndPATHs = $this->getURLsAndPATHs($itemHandler, NULL, $onlyThumbs);
|
933 |
+
|
934 |
+
$meta = $itemHandler->getMeta();
|
935 |
+
//find thumbs that are not listed in the metadata and add them in the sizes array
|
936 |
+
if($itemHandler->getType() == ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE) {
|
937 |
+
$mainFile = $meta->getPath();
|
938 |
+
|
939 |
+
$foundThumbs = @glob(WpShortPixelMediaLbraryAdapter::thumbsSearchPattern($mainFile));
|
940 |
+
//first identify which thumbs are not in the sizes
|
941 |
+
$sizes = $meta->getThumbs();
|
942 |
+
foreach($foundThumbs as $id => $found) {
|
943 |
+
//get the mime-type from one of the thumbs metas
|
944 |
+
foreach($sizes as $size) {
|
945 |
+
if(pathinfo($mainFile, PATHINFO_EXTENSION) !== pathinfo($size['file'], PATHINFO_EXTENSION)){
|
946 |
+
continue;
|
947 |
+
}
|
948 |
+
$mimeType = $size['mime-type'];
|
949 |
+
if($size['file'] === ShortPixelAPI::MB_basename($found)) {
|
950 |
+
$foundThumbs[$id] = false;
|
951 |
+
}
|
952 |
+
}
|
953 |
+
}
|
954 |
+
// add the unfound ones to the sizes array
|
955 |
+
$ind = 1;
|
956 |
+
while (isset($sizes[ShortPixelMeta::FOUND_THUMB_PREFIX . str_pad("".$ind, 2, '0', STR_PAD_LEFT)])) $ind++;
|
957 |
+
$start = $ind;
|
958 |
+
foreach($foundThumbs as $found) {
|
959 |
+
if($found !== false) {
|
960 |
+
$size = getimagesize($found);
|
961 |
+
$sizes[ShortPixelMeta::FOUND_THUMB_PREFIX . str_pad("".$ind, 2, '0', STR_PAD_LEFT)]= array( // it's a file that has no corresponding thumb so it's the WEBP for the main file
|
962 |
+
'file' => ShortPixelAPI::MB_basename($found),
|
963 |
+
'width' => $size[0],
|
964 |
+
'height' => $size[1],
|
965 |
+
'mime-type' => $mimeType
|
966 |
+
);
|
967 |
+
$ind++;
|
968 |
+
}
|
969 |
+
}
|
970 |
+
if($ind > $start) { // at least one thumbnail added, update
|
971 |
+
$meta->setThumbs($sizes);
|
972 |
+
$itemHandler->updateMeta($meta);
|
973 |
+
$URLsAndPATHs = $this->getURLsAndPATHs($itemHandler, NULL, $onlyThumbs);
|
974 |
+
}
|
975 |
+
}
|
976 |
+
|
977 |
+
//find any missing thumbs files and mark them as such
|
978 |
+
if( isset($URLsAndPATHs['sizesMissing']) && count($URLsAndPATHs['sizesMissing'])
|
979 |
+
&& (null === $meta->getThumbsMissing() || count(array_diff_key($meta->getThumbsMissing(), array_merge($URLsAndPATHs['sizesMissing'], $meta->getThumbsMissing()))))) {
|
980 |
+
//fix missing thumbs in the metadata before sending to processing
|
981 |
+
$meta->setThumbsMissing($URLsAndPATHs['sizesMissing']);
|
982 |
+
$itemHandler->updateMeta();
|
983 |
+
}
|
984 |
+
//die(var_dump($itemHandler));
|
985 |
+
$refresh = $meta->getStatus() === ShortPixelAPI::ERR_INCORRECT_FILE_SIZE;
|
986 |
//echo("URLS: "); die(var_dump($URLsAndPATHs));
|
987 |
$this->_apiInterface->doRequests($URLsAndPATHs['URLs'], false, $itemHandler,
|
988 |
+
$compressionType === false ? $this->_settings->compressionType : $compressionType, $refresh);//send a request, do NOT wait for response
|
989 |
$itemHandler->setWaitingProcessing();
|
990 |
//$meta = wp_get_attachment_metadata($ID);
|
991 |
//$meta['ShortPixel']['WaitingProcessing'] = true;
|
1013 |
case "C-":
|
1014 |
throw new Exception("HandleManualOptimization for custom images not implemented");
|
1015 |
default:
|
|
|
|
|
|
|
1016 |
$this->optimizeNowHook(intval($imageId));
|
1017 |
break;
|
1018 |
}
|
1039 |
die(json_encode($ret));
|
1040 |
}
|
1041 |
|
1042 |
+
//WP/LR Sync plugin integration
|
1043 |
+
public function onWpLrUpdateMedia($imageId, $galleryIdsUnused) {
|
1044 |
+
$meta = wp_get_attachment_metadata($imageId);
|
1045 |
+
if(is_array($meta)) {
|
1046 |
+
unset($meta['ShortPixel']);
|
1047 |
+
$meta['ShortPixel'] = array();
|
1048 |
+
$meta['ShortPixel']['WaitingProcessing'] = true;
|
1049 |
+
$this->prioQ->push($imageId);
|
1050 |
+
wp_update_attachment_metadata($imageId, $meta);
|
1051 |
+
}
|
1052 |
+
}
|
1053 |
+
|
1054 |
+
|
1055 |
//save error in file's meta data
|
1056 |
public function handleError($ID, $result)
|
1057 |
{
|
1061 |
}
|
1062 |
|
1063 |
public function getBackupFolder($file) {
|
1064 |
+
if(realpath($file)) {
|
1065 |
+
$file = realpath($file); //found cases when $file contains for example /wp/../wp-content - clean it up
|
1066 |
+
}
|
1067 |
$fileExtension = strtolower(substr($file,strrpos($file,".")+1));
|
1068 |
$SubDir = ShortPixelMetaFacade::returnSubDir($file, ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE);
|
1069 |
+
$SubDirOld = ShortPixelMetaFacade::returnSubDirOld($file, ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE);
|
1070 |
|
1071 |
+
if ( !file_exists(SP_BACKUP_FOLDER . '/' . $SubDir . ShortPixelAPI::MB_basename($file))
|
1072 |
+
&& !file_exists(SP_BACKUP_FOLDER . '/' . date("Y") . "/" . date("m") . "/" . ShortPixelAPI::MB_basename($file)) ) {
|
1073 |
+
$SubDir = $SubDirOld; //maybe the folder was saved with the old method that returned the full path if the wp-content was not inside the root of the site.
|
1074 |
+
}
|
1075 |
+
if ( !file_exists(SP_BACKUP_FOLDER . '/' . $SubDir . ShortPixelAPI::MB_basename($file))
|
1076 |
+
&& !file_exists(SP_BACKUP_FOLDER . '/' . date("Y") . "/" . date("m") . "/" . ShortPixelAPI::MB_basename($file)) ) {
|
1077 |
+
$SubDir = trailingslashit(substr(dirname($file), 1)); //try this too
|
1078 |
+
}
|
1079 |
//sometimes the month of original file and backup can differ
|
1080 |
if ( !file_exists(SP_BACKUP_FOLDER . '/' . $SubDir . ShortPixelAPI::MB_basename($file)) ) {
|
1081 |
$SubDir = date("Y") . "/" . date("m") . "/";
|
1086 |
return SP_BACKUP_FOLDER . '/' . $SubDir;
|
1087 |
}
|
1088 |
|
1089 |
+
public function getBackupFolderAny($file, $thumbs) {
|
1090 |
+
if(!file_exists($file)) {
|
1091 |
+
//try with the thumbnails
|
1092 |
+
if(isset($thumbs)) foreach($thumbs as $size) {
|
1093 |
+
$backup = $this->getBackupFolder(trailingslashit(dirname($file)) . $size['file']);
|
1094 |
+
if($backup) return $backup;
|
1095 |
+
}
|
1096 |
+
} else {
|
1097 |
+
return $this->getBackupFolder($file);
|
1098 |
+
}
|
1099 |
+
}
|
1100 |
+
|
1101 |
protected function setFilePerms($file) {
|
1102 |
//die(getenv('USERNAME') ? getenv('USERNAME') : getenv('USER'));
|
1103 |
+
if(strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') {
|
1104 |
+
//on *nix platforms check also the owner
|
1105 |
+
$owner = fileowner($file);
|
1106 |
+
if($owner !== false && $owner != posix_getuid()) { //files with changed owner
|
1107 |
+
return false;
|
1108 |
+
}
|
1109 |
+
}
|
1110 |
$perms = @fileperms($file);
|
1111 |
if(!($perms & 0x0100) || !($perms & 0x0080)) {
|
1112 |
if(!@chmod($file, $perms | 0x0100 | 0x0080)) {
|
1117 |
}
|
1118 |
|
1119 |
protected function doRestore($attachmentID, $meta = null) {
|
1120 |
+
$file = $origFile = get_attached_file($attachmentID);
|
1121 |
if(!$meta) {
|
1122 |
$meta = wp_get_attachment_metadata($attachmentID);
|
1123 |
}
|
1124 |
$pathInfo = pathinfo($file);
|
1125 |
|
1126 |
+
$bkFolder = $this->getBackupFolderAny($file, $meta["sizes"]);
|
1127 |
+
$bkFile = trailingslashit($bkFolder) . ShortPixelAPI::MB_basename($file);
|
1128 |
+
|
|
|
|
|
|
|
|
|
|
|
1129 |
//first check if the file is readable by the current user - otherwise it will be unaccessible for the web browser
|
1130 |
// - collect the thumbs paths in the process
|
1131 |
+
$bkCount = 0; $main = false;
|
1132 |
+
if(file_exists($bkFile)) {
|
1133 |
+
if(!$this->setFilePerms($bkFile) || (file_exists($file) && !$this->setFilePerms($file)) ) {
|
1134 |
+
return false;
|
1135 |
+
}
|
1136 |
+
$bkCount++;
|
1137 |
+
$main = true;
|
1138 |
+
}
|
1139 |
$thumbsPaths = array();
|
1140 |
if( !empty($meta['file']) && is_array($meta["sizes"]) ) {
|
1141 |
foreach($meta["sizes"] as $size => $imageData) {
|
1142 |
+
$dest = $pathInfo['dirname'] . '/' . $imageData['file'];
|
1143 |
+
$source = trailingslashit($bkFolder) . $imageData['file'];
|
1144 |
if(!file_exists($source)) continue; // if thumbs were not optimized, then the backups will not be there.
|
1145 |
+
if(!$this->setFilePerms($source) || (file_exists($dest) && !$this->setFilePerms($dest))) {
|
1146 |
+
return false;
|
1147 |
+
}
|
1148 |
+
$bkCount++;
|
1149 |
+
$thumbsPaths[$source] = $dest;
|
1150 |
}
|
1151 |
}
|
1152 |
+
if(!$bkCount) {
|
1153 |
+
return false;
|
1154 |
+
}
|
1155 |
+
|
1156 |
if($bkFolder) {
|
1157 |
try {
|
1158 |
//main file
|
1159 |
+
if($main) {
|
1160 |
+
$this->renameWithRetina($bkFile, $file);
|
1161 |
+
}
|
1162 |
//getSize to update meta if image was resized by ShortPixel
|
1163 |
+
$width = false;
|
1164 |
+
if(file_exists($file)) {
|
1165 |
+
$size = getimagesize($file);
|
1166 |
+
$width = $size[0];
|
1167 |
+
$height = $size[1];
|
1168 |
+
}
|
1169 |
|
1170 |
//overwriting thumbnails
|
1171 |
foreach($thumbsPaths as $source => $destination) {
|
1185 |
}
|
1186 |
wp_update_attachment_metadata($ID, $crtMeta);
|
1187 |
}
|
1188 |
+
unset($meta["ShortPixelImprovement"]);
|
1189 |
+
unset($meta['ShortPixel']);
|
1190 |
+
|
1191 |
} catch(Exception $e) {
|
1192 |
//what to do, what to do?
|
1193 |
return false;
|
1277 |
$meta = wp_get_attachment_metadata($ID);
|
1278 |
//die(var_dump($meta));
|
1279 |
if( isset($meta['ShortPixelImprovement'])
|
1280 |
+
&& isset($meta['sizes']) && WpShortPixelMediaLbraryAdapter::countNonWebpSizes($meta['sizes'])
|
1281 |
&& ( !isset($meta['ShortPixel']['thumbsOpt']) || $meta['ShortPixel']['thumbsOpt'] == 0)) { //optimized without thumbs, thumbs exist
|
1282 |
$meta['ShortPixel']['thumbsTodo'] = true;
|
1283 |
wp_update_attachment_metadata($ID, $meta);
|
1328 |
}
|
1329 |
}
|
1330 |
}
|
1331 |
+
|
1332 |
+
public function deactivatePlugin() {
|
1333 |
+
if ( ! wp_verify_nonce( $_GET['_wpnonce'], 'sp_deactivate_plugin_nonce' ) ) {
|
1334 |
+
wp_nonce_ays( '' );
|
1335 |
+
}
|
1336 |
+
deactivate_plugins( $_GET['plugin'] );
|
1337 |
+
wp_safe_redirect( wp_get_referer() );
|
1338 |
+
die();
|
1339 |
+
}
|
1340 |
|
1341 |
public function checkQuotaAndAlert($quotaData = null, $recheck = false) {
|
1342 |
if(!$quotaData) {
|
1346 |
return $quotaData;
|
1347 |
}
|
1348 |
//$tempus = microtime(true);
|
1349 |
+
$imageCount = WpShortPixelMediaLbraryAdapter::countAllProcessableFiles($this->_settings->optimizePdfs);
|
1350 |
|
1351 |
$this->_settings->currentTotalFiles = $imageCount['totalFiles'];
|
1352 |
|
1371 |
|
1372 |
?><script>var shortPixelQuotaExceeded = 0;</script><?php
|
1373 |
}
|
1374 |
+
else {
|
1375 |
$this->view->displayQuotaExceededAlert($quotaData, self::getAverageCompression(), $recheck);
|
1376 |
?><script>var shortPixelQuotaExceeded = 1;</script><?php
|
1377 |
}
|
1419 |
<?php
|
1420 |
$customMediaListTable->display();
|
1421 |
//push to the processing list the pending ones, just in case
|
1422 |
+
//$count = $this->spMetaDao->getCustomMetaCount();
|
1423 |
foreach ($items as $item) {
|
1424 |
if($item->status == 1){
|
1425 |
$this->prioQ->push(ShortPixelMetaFacade::queuedId(ShortPixelMetaFacade::CUSTOM_TYPE, $item->id));
|
1471 |
} else {
|
1472 |
$this->_settings->processThumbnails = 0;
|
1473 |
}
|
1474 |
+
//clean the custom files errors in order to process them again
|
1475 |
+
if($this->_settings->hasCustomFolders) {
|
1476 |
+
$this->spMetaDao->resetFailed();
|
1477 |
+
}
|
1478 |
+
|
1479 |
$this->prioQ->startBulk();
|
1480 |
$this->_settings->customBulkPaused = 0;
|
1481 |
self::log("BULK: Start: " . $this->prioQ->getStartBulkId() . ", stop: " . $this->prioQ->getStopBulkId() . " PrioQ: "
|
1571 |
|
1572 |
|
1573 |
//parse all images and set the right flag that the image has no backup
|
1574 |
+
/* this is obsolete as the backup exists decision is taken on verfication of the actual backup files
|
1575 |
foreach($attachments as $attachment)
|
1576 |
{
|
1577 |
+
if(self::isProcessable($attachment->ID) == false) continue;
|
1578 |
|
1579 |
$meta = wp_get_attachment_metadata($attachment->ID);
|
1580 |
$meta['ShortPixel']['NoBackup'] = true;
|
1581 |
wp_update_attachment_metadata($attachment->ID, $meta);
|
1582 |
}
|
1583 |
+
*/
|
1584 |
+
|
1585 |
//delete the actual files on disk
|
1586 |
$this->deleteDir(SP_BACKUP_FOLDER);//call a recursive function to empty files and sub-dirs in backup dir
|
1587 |
}
|
1590 |
public function backupFolderIsEmpty() {
|
1591 |
return count(scandir(SP_BACKUP_FOLDER)) > 2 ? false : true;
|
1592 |
}
|
1593 |
+
|
1594 |
+
public function getBackupSize() {
|
1595 |
+
if ( !current_user_can( 'manage_options' ) ) {
|
1596 |
+
wp_die(__('You do not have sufficient permissions to access this page.','shortpixel-image-optimiser'));
|
1597 |
+
}
|
1598 |
+
die(self::formatBytes(self::folderSize(SP_BACKUP_FOLDER)));
|
1599 |
+
}
|
1600 |
|
1601 |
public function browseContent() {
|
1602 |
+
if ( !current_user_can( 'manage_options' ) ) {
|
1603 |
wp_die(__('You do not have sufficient permissions to access this page.','shortpixel-image-optimiser'));
|
1604 |
}
|
1605 |
|
1832 |
|
1833 |
$this->_settings->createWebp = (isset($_POST['createWebp']) ? 1: 0);
|
1834 |
$this->_settings->optimizeRetina = (isset($_POST['optimizeRetina']) ? 1: 0);
|
1835 |
+
$this->_settings->optimizePdfs = (isset($_POST['optimizePdfs']) ? 1: 0);
|
1836 |
$this->_settings->frontBootstrap = (isset($_POST['frontBootstrap']) ? 1: 0);
|
1837 |
$this->_settings->autoMediaLibrary = (isset($_POST['autoMediaLibrary']) ? 1: 0);
|
1838 |
|
1886 |
if (is_numeric($quotaData['APICallsQuota'])) {
|
1887 |
$quotaData['APICallsQuota'] .= "/month";
|
1888 |
}
|
|
|
1889 |
$remainingImages = $quotaData['APICallsRemaining'];
|
1890 |
$remainingImages = ( $remainingImages < 0 ) ? 0 : number_format($remainingImages);
|
1891 |
$totalCallsMade = number_format($quotaData['APICallsMadeNumeric'] + $quotaData['APICallsMadeOneTimeNumeric']);
|
1892 |
|
1893 |
+
$resources = wp_remote_post($this->_settings->httpProto . "://shortpixel.com/resources-frag");
|
1894 |
if(is_wp_error( $resources )) {
|
1895 |
$resources = array();
|
1896 |
}
|
1897 |
$this->view->displaySettings($showApiKey, $editApiKey,
|
1898 |
$quotaData, $notice, $resources, $averageCompression, $savedSpace, $savedBandwidth, $remainingImages,
|
1899 |
+
$totalCallsMade, $fileCount, null /*folder size now on AJAX*/, $customFolders,
|
1900 |
$folderMsg, $folderMsg ? $addedFolder : false, isset($_POST['saveAdv']));
|
1901 |
} else {
|
1902 |
$this->view->displaySettings($showApiKey, $editApiKey, $quotaData, $notice);
|
1954 |
if($validate) {
|
1955 |
$args['body']['DomainCheck'] = get_site_url();
|
1956 |
$args['body']['Info'] = get_bloginfo('version') . '|' . phpversion();
|
1957 |
+
$imageCount = WpShortPixelMediaLbraryAdapter::countAllProcessableFiles($this->_settings->optimizePdfs);
|
1958 |
$args['body']['ImagesCount'] = $imageCount['mainFiles'];
|
1959 |
$args['body']['ThumbsCount'] = $imageCount['totalFiles'] - $imageCount['mainFiles'];
|
1960 |
$argsStr .= "&DomainCheck={$args['body']['DomainCheck']}&Info={$args['body']['Info']}&ImagesCount={$imageCount['mainFiles']}&ThumbsCount={$args['body']['ThumbsCount']}";
|
2038 |
}
|
2039 |
|
2040 |
if ( ( $data->APICallsMade + $data->APICallsMadeOneTime ) < ( $data->APICallsQuota + $data->APICallsQuotaOneTime ) ) //reset quota exceeded flag -> user is allowed to process more images.
|
2041 |
+
$this->resetQuotaExceeded();
|
2042 |
else
|
2043 |
$this->_settings->quotaExceeded = 1;//activate quota limiting
|
2044 |
|
2063 |
"DomainCheck" => (isset($data->DomainCheck) ? $data->DomainCheck : null)
|
2064 |
);
|
2065 |
}
|
2066 |
+
|
2067 |
+
public function resetQuotaExceeded() {
|
2068 |
+
if( $this->_settings->quotaExceeded == 1) {
|
2069 |
+
$dismissed = $this->_settings->dismissedNotices;
|
2070 |
+
unset($dismissed['exceed']);
|
2071 |
+
$this->_settings->dismissedNotices = $dismissed;
|
2072 |
+
}
|
2073 |
+
$this->_settings->quotaExceeded = 0;
|
2074 |
+
}
|
2075 |
|
2076 |
public function generateCustomColumn( $column_name, $id, $extended = false ) {
|
2077 |
if( 'wp-shortPixel' == $column_name ) {
|
2078 |
|
2079 |
+
$file = get_attached_file($id);
|
2080 |
+
if(!self::isProcessablePath($file)) {
|
2081 |
+
$renderData['status'] = 'n/a';
|
2082 |
+
$this->view->renderCustomColumn($id, $renderData, $extended);
|
2083 |
+
return;
|
2084 |
+
}
|
2085 |
+
|
2086 |
$data = wp_get_attachment_metadata($id);
|
2087 |
+
$fileExtension = strtolower(pathinfo($file, PATHINFO_EXTENSION));
|
|
|
2088 |
$invalidKey = !$this->_settings->verifiedKey;
|
2089 |
$quotaExceeded = $this->_settings->quotaExceeded;
|
2090 |
+
$renderData = array("id" => $id, "showActions" => (current_user_can( 'manage_options' ) || current_user_can( 'upload_files' ) || current_user_can( 'edit_posts' )));
|
2091 |
|
2092 |
if($invalidKey) { //invalid key - let the user first register and only then
|
2093 |
$renderData['status'] = 'invalidKey';
|
2113 |
}
|
2114 |
|
2115 |
if(is_numeric($data['ShortPixelImprovement'])) { //already optimized
|
2116 |
+
$sizesCount = isset($data['sizes']) ? WpShortPixelMediaLbraryAdapter::countNonWebpSizes($data['sizes']) : 0;
|
2117 |
+
|
2118 |
$renderData['status'] = $fileExtension == "pdf" ? 'pdfOptimized' : 'imgOptimized';
|
2119 |
$renderData['percent'] = $data['ShortPixelImprovement'];
|
2120 |
$renderData['bonus'] = ($data['ShortPixelImprovement'] < 5);
|
2121 |
+
$renderData['backup'] = $this->getBackupFolderAny(get_attached_file($id), $sizesCount? $data['sizes'] : array());
|
2122 |
$renderData['type'] = isset($data['ShortPixel']['type']) ? $data['ShortPixel']['type'] : '';
|
2123 |
+
$renderData['thumbsTotal'] = $sizesCount;
|
2124 |
+
$renderData['thumbsOpt'] = isset($data['ShortPixel']['thumbsOpt']) ? $data['ShortPixel']['thumbsOpt'] : $sizesCount;
|
2125 |
+
$renderData['thumbsMissing'] = isset($data['ShortPixel']['thumbsMissing']) ? $data['ShortPixel']['thumbsMissing'] : array();
|
2126 |
$renderData['retinasOpt'] = isset($data['ShortPixel']['retinasOpt']) ? $data['ShortPixel']['retinasOpt'] : null;
|
2127 |
$renderData['exifKept'] = isset($data['ShortPixel']['exifKept']) ? $data['ShortPixel']['exifKept'] : null;
|
2128 |
$renderData['date'] = isset($data['ShortPixel']['date']) ? $data['ShortPixel']['date'] : null;
|
2129 |
$renderData['quotaExceeded'] = $quotaExceeded;
|
2130 |
$webP = 0;
|
2131 |
if($extended) {
|
2132 |
+
if(file_exists(dirname($file) . '/' . basename($file, '.'.$fileExtension) . '.webp' )){
|
2133 |
$webP++;
|
2134 |
}
|
2135 |
if(isset($data['sizes'])) {
|
2136 |
+
foreach($data['sizes'] as $key => $size) {
|
2137 |
+
if (strpos($key, ShortPixelMeta::WEBP_THUMB_PREFIX) === 0) continue;
|
2138 |
$sizeName = $size['file'];
|
2139 |
+
if(file_exists(dirname($file) . '/' . basename($sizeName, '.'.$fileExtension) . '.webp' )){
|
2140 |
$webP++;
|
2141 |
}
|
2142 |
}
|
2145 |
$renderData['webpCount'] = $webP;
|
2146 |
}
|
2147 |
elseif($data['ShortPixelImprovement'] == __('Optimization N/A','shortpixel-image-optimiser')) { //We don't optimize this
|
2148 |
+
if('pdf' === $fileExtension && $this->_settings->optimizePdfs) {
|
2149 |
+
$renderData['status'] = $quotaExceeded ? 'quotaExceeded' : 'optimizeNow';
|
2150 |
+
$renderData['message'] = 'PDF not processed.';
|
2151 |
+
} else {
|
2152 |
+
$renderData['status'] = 'n/a';
|
2153 |
+
}
|
2154 |
}
|
2155 |
elseif(isset($meta['ShortPixel']['BulkProcessing'])) { //Scheduled to bulk.
|
2156 |
$renderData['status'] = $quotaExceeded ? 'quotaExceeded' : 'optimizeNow';
|
2179 |
}
|
2180 |
else { //finally
|
2181 |
$renderData['status'] = $quotaExceeded ? 'quotaExceeded' : 'optimizeNow';
|
2182 |
+
$sizes = isset($data['sizes']) ? WpShortPixelMediaLbraryAdapter::countNonWebpSizes($data['sizes']) : 0;
|
2183 |
$renderData['thumbsTotal'] = $sizes;
|
2184 |
$renderData['message'] = ($fileExtension == "pdf" ? 'PDF' : 'Image') . ' not processed.';
|
2185 |
}
|
2297 |
|
2298 |
static public function isProcessable($ID) {
|
2299 |
$path = get_attached_file($ID);//get the full file PATH
|
2300 |
+
return $path ? self::isProcessablePath($path) : false;
|
2301 |
}
|
2302 |
|
2303 |
static public function isProcessablePath($path) {
|
2304 |
$pathParts = pathinfo($path);
|
2305 |
+
$ext = $pathParts['extension'];
|
2306 |
+
if( isset($ext) && in_array(strtolower($ext), self::$PROCESSABLE_EXTENSIONS)) {
|
2307 |
return true;
|
2308 |
} else {
|
2309 |
return false;
|