Version Description
- Major update
- when validating the API Key on a multisite a message with instructions on how to add the API Key in wp-config.php is displayed
- check when an optimized image cannot be saved and stop bulk processing (if running)
- restore backup is not displayed when option is not activated
- change image status in the Media Library ShortPixel Compression column imediately after the image is reduced, not only after reloading the page. Add spinner to the "Image waiting to be processed" status.
- images with relative URLs are converted to absolute URL so they can be processed by the plugin
- proper handling of images with non-standard latin chars inside
- better average compression computation
- rewritten handleImageUpload
- removed MUST_HAVE_KEY
- changed isProcessable
- and others :)
Download this release
Release Info
Developer | ShortPixel |
Plugin | ShortPixel Image Optimizer |
Version | 3.0.0 |
Comparing to | |
See all releases |
Code changes from version 2.1.10 to 3.0.0
- css/short-pixel.css +125 -0
- img/loading-dark-big.gif +0 -0
- img/loading-dark.gif +0 -0
- img/loading.gif +0 -0
- img/shortpixel-alert.png +0 -0
- img/shortpixel.png +0 -0
- img/slider.png +0 -0
- js/short-pixel.js +244 -0
- readme.txt +24 -12
- shortpixel_api.php +428 -407
- shortpixel_queue.php +254 -0
- shortpixel_view.php +154 -0
- wp-shortpixel.php +1526 -1556
css/short-pixel.css
ADDED
@@ -0,0 +1,125 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
li.shortpixel-toolbar-processing > a.ab-item > div,
|
2 |
+
#wpadminbar li.shortpixel-toolbar-processing > a.ab-item > div{
|
3 |
+
background-image: url("../img/loading-dark-big.gif");
|
4 |
+
background-position: center center;
|
5 |
+
background-repeat: no-repeat;
|
6 |
+
height: 33px;
|
7 |
+
margin-top: -1px;
|
8 |
+
padding: 0 3px;
|
9 |
+
}
|
10 |
+
li.shortpixel-toolbar-processing > a.ab-item > div > img,
|
11 |
+
#wpadminbar li.shortpixel-toolbar-processing > a.ab-item > div > img{
|
12 |
+
margin-right: 2px;
|
13 |
+
margin-top: 6px;
|
14 |
+
}
|
15 |
+
li.shortpixel-toolbar-processing > a.ab-item > div > span.shp-alert,
|
16 |
+
#wpadminbar li.shortpixel-toolbar-processing > a.ab-item > div > span.shp-alert{
|
17 |
+
display:none;
|
18 |
+
}
|
19 |
+
li.shortpixel-toolbar-processing.shortpixel-alert > a.ab-item > div > span.shp-alert,
|
20 |
+
#wpadminbar li.shortpixel-toolbar-processing.shortpixel-alert > a.ab-item > div > span.shp-alert{
|
21 |
+
display: inline;
|
22 |
+
font-size: 26px;
|
23 |
+
color: red;
|
24 |
+
font-weight: bold;
|
25 |
+
vertical-align: top;
|
26 |
+
}
|
27 |
+
li.shortpixel-toolbar-processing.shortpixel-alert > a.ab-item > div,
|
28 |
+
#wpadminbar li.shortpixel-toolbar-processing.shortpixel-alert > a.ab-item > div{
|
29 |
+
background-image: none;
|
30 |
+
}
|
31 |
+
li.shortpixel-hide {
|
32 |
+
display:none;
|
33 |
+
}
|
34 |
+
.bulk-progress {
|
35 |
+
padding: 20px 32px 17px;
|
36 |
+
background-color: #ffffff;
|
37 |
+
border: 1px dotted #c4c2c2;
|
38 |
+
}
|
39 |
+
.bulk-progress.bulk-stats > div{
|
40 |
+
display:inline-block;
|
41 |
+
}
|
42 |
+
.bulk-progress.bulk-stats > div.label{
|
43 |
+
width: 320px;
|
44 |
+
}
|
45 |
+
.progress {
|
46 |
+
background-color: #ecedee;
|
47 |
+
height: 30px;
|
48 |
+
position: relative;
|
49 |
+
width: 60%;
|
50 |
+
display: inline-block;
|
51 |
+
margin-right: 28px;
|
52 |
+
}
|
53 |
+
.progress .progress-img {
|
54 |
+
position: absolute;
|
55 |
+
top: -10px;
|
56 |
+
z-index: 2;
|
57 |
+
margin-left: -35px;
|
58 |
+
line-height: 48px;
|
59 |
+
font-size: 22px;
|
60 |
+
font-weight: bold;
|
61 |
+
}
|
62 |
+
.progress .progress-img span {
|
63 |
+
vertical-align: top;
|
64 |
+
margin-left: -7px;
|
65 |
+
}
|
66 |
+
.progress .progress-left {
|
67 |
+
background-color: #1cbecb;
|
68 |
+
bottom: 0;
|
69 |
+
left: 0;
|
70 |
+
position: absolute;
|
71 |
+
top: 0;
|
72 |
+
z-index: 1;
|
73 |
+
font-size: 22px;
|
74 |
+
font-weight: bold;
|
75 |
+
line-height: 28px;
|
76 |
+
text-align: center;
|
77 |
+
color: #ffffff;
|
78 |
+
}
|
79 |
+
.bulk-estimate {
|
80 |
+
font-size: 20px;
|
81 |
+
line-height: 30px;
|
82 |
+
vertical-align: top;
|
83 |
+
display: inline-block;
|
84 |
+
}
|
85 |
+
.wp-core-ui .button-secondary.bulk-cancel {
|
86 |
+
float: right;
|
87 |
+
height: 30px;
|
88 |
+
}
|
89 |
+
.short-pixel-block-title {
|
90 |
+
font-size: 22px;
|
91 |
+
margin-bottom: 15px;
|
92 |
+
}
|
93 |
+
.bulk-slider-container {
|
94 |
+
margin-top: 20px;
|
95 |
+
display: none;
|
96 |
+
min-height: 500px;
|
97 |
+
}
|
98 |
+
.bulk-slider-container h2{
|
99 |
+
margin-bottom: 15px;
|
100 |
+
}
|
101 |
+
.bulk-slider .bulk-slide {
|
102 |
+
position: absolute;
|
103 |
+
width: 100%;
|
104 |
+
}
|
105 |
+
.bulk-slider .img-original,
|
106 |
+
.bulk-slider .img-optimized{
|
107 |
+
display:inline-block;
|
108 |
+
margin-right:20px;
|
109 |
+
text-align: center;
|
110 |
+
}
|
111 |
+
.bulk-slider .img-original div,
|
112 |
+
.bulk-slider .img-optimized div{
|
113 |
+
max-height: 450px;
|
114 |
+
overflow: hidden;
|
115 |
+
}
|
116 |
+
.bulk-slider .img-original img,
|
117 |
+
.bulk-slider .img-optimized img{
|
118 |
+
max-width: 300px;
|
119 |
+
}
|
120 |
+
.bulk-slider .img-info{
|
121 |
+
display:inline-block;
|
122 |
+
vertical-align: top;
|
123 |
+
font-size: 48px;
|
124 |
+
max-width: 150px;
|
125 |
+
}
|
img/loading-dark-big.gif
ADDED
Binary file
|
img/loading-dark.gif
ADDED
Binary file
|
img/loading.gif
ADDED
Binary file
|
img/shortpixel-alert.png
ADDED
Binary file
|
img/shortpixel.png
ADDED
Binary file
|
img/slider.png
ADDED
Binary file
|
js/short-pixel.js
ADDED
@@ -0,0 +1,244 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Short Pixel WordPress Plugin javascript
|
3 |
+
*/
|
4 |
+
|
5 |
+
jQuery(document).ready(function($){
|
6 |
+
//are we on media list?
|
7 |
+
if( jQuery('table.wp-list-table.media').length > 0) {
|
8 |
+
//register a bulk action
|
9 |
+
jQuery('select[name^="action"] option:last-child').before('<option value="short-pixel-bulk">Optimize with ShortPixel</option>');
|
10 |
+
}
|
11 |
+
//check if bulk processing
|
12 |
+
checkQuotaExceededAlert();
|
13 |
+
checkBulkProgress();
|
14 |
+
});
|
15 |
+
|
16 |
+
var ShortPixel = function() {
|
17 |
+
|
18 |
+
function setOptions(options) {
|
19 |
+
for(var opt in options) {
|
20 |
+
ShortPixel[opt] = options[opt];
|
21 |
+
}
|
22 |
+
}
|
23 |
+
|
24 |
+
return {
|
25 |
+
setOptions: setOptions
|
26 |
+
}
|
27 |
+
}();
|
28 |
+
|
29 |
+
function showToolBarAlert($status, $message) {
|
30 |
+
switch($status) {
|
31 |
+
case ShortPixel.STATUS_QUOTA_EXCEEDED:
|
32 |
+
jQuery("li.shortpixel-toolbar-processing").addClass("shortpixel-alert");
|
33 |
+
jQuery("li.shortpixel-toolbar-processing").addClass("shortpixel-quota-exceeded");
|
34 |
+
jQuery("li.shortpixel-toolbar-processing a").attr("href", "http://shortpixel.com/login/" + ShortPixel.API_KEY);
|
35 |
+
jQuery("li.shortpixel-toolbar-processing a div").attr("title", "ShortPixel quota exceeded. Click to top-up");
|
36 |
+
break;
|
37 |
+
case ShortPixel.STATUS_FAIL:
|
38 |
+
jQuery("li.shortpixel-toolbar-processing").addClass("shortpixel-alert shortpixel-processing");
|
39 |
+
jQuery("li.shortpixel-toolbar-processing a div").attr("title", $message);
|
40 |
+
break;
|
41 |
+
}
|
42 |
+
jQuery("li.shortpixel-toolbar-processing").removeClass("shortpixel-hide");
|
43 |
+
}
|
44 |
+
function hideToolBarAlert () {
|
45 |
+
jQuery("li.shortpixel-toolbar-processing.shortpixel-processing").addClass("shortpixel-hide");
|
46 |
+
}
|
47 |
+
|
48 |
+
function hideQuotaExceededToolBarAlert () {
|
49 |
+
jQuery("li.shortpixel-toolbar-processing.shortpixel-quota-exceeded").addClass("shortpixel-hide");
|
50 |
+
}
|
51 |
+
|
52 |
+
function checkQuotaExceededAlert() {
|
53 |
+
if(typeof shortPixelQuotaExceeded != 'undefined') {
|
54 |
+
if(shortPixelQuotaExceeded == 1) {
|
55 |
+
showToolBarAlert(ShortPixel.STATUS_QUOTA_EXCEEDED);
|
56 |
+
} else {
|
57 |
+
hideQuotaExceededToolBarAlert();
|
58 |
+
}
|
59 |
+
}
|
60 |
+
}
|
61 |
+
/**
|
62 |
+
* JavaScript image processing - this method gets executed on every footer load and afterwards
|
63 |
+
* calls itself until receives an Empty queue message
|
64 |
+
*/
|
65 |
+
function checkBulkProgress() {
|
66 |
+
//if I'm not the bulk processor, check every 20 sec. if the bulk processor is running, otherwise take the role
|
67 |
+
if(ShortPixel.bulkProcessor == true || typeof localStorage.bulkTime == 'undefined' || Math.floor(Date.now() / 1000) - localStorage.bulkTime > 90) {
|
68 |
+
ShortPixel.bulkProcessor = true;
|
69 |
+
localStorage.bulkTime = Math.floor(Date.now() / 1000);
|
70 |
+
console.log(localStorage.bulkTime);
|
71 |
+
checkBulkProcessingCallApi();
|
72 |
+
} else {
|
73 |
+
console.log("not the bulk processor");
|
74 |
+
setTimeout(checkBulkProgress, 5000);
|
75 |
+
}
|
76 |
+
}
|
77 |
+
|
78 |
+
function checkBulkProcessingCallApi(){
|
79 |
+
var data = { 'action': 'shortpixel_image_processing' };
|
80 |
+
// since WP 2.8 ajaxurl is always defined in the admin header and points to admin-ajax.php
|
81 |
+
jQuery.post(ajaxurl, data, function(response)
|
82 |
+
{
|
83 |
+
if(response.length > 0) {
|
84 |
+
var data = JSON.parse(response);
|
85 |
+
var id = data["ImageID"];
|
86 |
+
|
87 |
+
var isBulkPage = (jQuery("div.short-pixel-bulk-page").length > 0);
|
88 |
+
|
89 |
+
switch (data["Status"]) {
|
90 |
+
case ShortPixel.STATUS_QUOTA_EXCEEDED:
|
91 |
+
setCellMessage(id, data["Message"] + " | <a href=\"https://shortpixel.com/login/"
|
92 |
+
+ ShortPixel.API_KEY + ")\">Extend Quota</a>");
|
93 |
+
showToolBarAlert(ShortPixel.STATUS_QUOTA_EXCEEDED);
|
94 |
+
break;
|
95 |
+
case ShortPixel.STATUS_FAIL:
|
96 |
+
setCellMessage(id, data["Message"]);
|
97 |
+
if(isBulkPage) {
|
98 |
+
showToolBarAlert(ShortPixel.STATUS_FAIL, data["Message"]);
|
99 |
+
}
|
100 |
+
console.log(data["Message"]);
|
101 |
+
break;
|
102 |
+
case ShortPixel.STATUS_EMPTY_QUEUE:
|
103 |
+
console.log(data["Message"]);
|
104 |
+
clearBulkProcessor(); //nothing to process, leave the role. Next page load will check again
|
105 |
+
hideToolBarAlert();
|
106 |
+
var progress = jQuery("#bulk-progress");
|
107 |
+
if(isBulkPage && progress.length && data["BulkStatus"] != '2') {
|
108 |
+
progressUpdate(100, "Bulk finished!");
|
109 |
+
jQuery("a.bulk-cancel").attr("disabled", "disabled");
|
110 |
+
hideSlider();
|
111 |
+
//showStats();
|
112 |
+
setTimeout(function(){
|
113 |
+
window.location.reload();
|
114 |
+
}, 3000);
|
115 |
+
}
|
116 |
+
break;
|
117 |
+
case ShortPixel.STATUS_SUCCESS:
|
118 |
+
var percent = data["PercentImprovement"];
|
119 |
+
setCellMessage(id, "Reduced by <span class='percent'>" + percent + "%</span> | <a href=\"admin.php?action=shortpixel_restore_backup&attachment_ID=" + id + ")\">Restore backup</a>");
|
120 |
+
var animator = new PercentageAnimator("#sp-msg-" + id + " span.percent", percent);
|
121 |
+
animator.animate(percent);
|
122 |
+
if(isBulkPage && typeof data["Thumb"] !== 'undefined' && data["PercentImprovement"] > 0) {
|
123 |
+
progressUpdate(data["BulkPercent"], data["BulkMsg"]);
|
124 |
+
if(data["Thumb"].length > 0){
|
125 |
+
sliderUpdate(id, data["Thumb"], data["BkThumb"], data["PercentImprovement"]);
|
126 |
+
}
|
127 |
+
}
|
128 |
+
//fall through
|
129 |
+
case ShortPixel.STATUS_ERROR: //for error and skip also we retry
|
130 |
+
case ShortPixel.STATUS_SKIP:
|
131 |
+
console.log('Server response: ' + response);
|
132 |
+
setTimeout(checkBulkProgress, 2000);
|
133 |
+
}
|
134 |
+
}
|
135 |
+
});
|
136 |
+
}
|
137 |
+
|
138 |
+
function clearBulkProcessor(){
|
139 |
+
ShortPixel.bulkProcessor = false; //nothing to process, leave the role. Next page load will check again
|
140 |
+
localStorage.bulkTime = 0;
|
141 |
+
}
|
142 |
+
|
143 |
+
function setCellMessage(id, message){
|
144 |
+
var msg = jQuery("#sp-msg-" + id);
|
145 |
+
if(typeof msg !== "undefined") {
|
146 |
+
msg.html(message);
|
147 |
+
}
|
148 |
+
}
|
149 |
+
|
150 |
+
function manualOptimization(id) {
|
151 |
+
setCellMessage(id, "<img src='" + ShortPixel.WP_PLUGIN_URL + "/shortpixel-image-optimiser/img/loading.gif'>Image waiting to be processed");
|
152 |
+
jQuery("li.shortpixel-toolbar-processing").removeClass("shortpixel-hide");
|
153 |
+
var data = { action : 'shortpixel_manual_optimization',
|
154 |
+
image_id: id};
|
155 |
+
jQuery.get(ajaxurl, data, function(response) {
|
156 |
+
data = JSON.parse(response);
|
157 |
+
if(data["Status"] == ShortPixel.STATUS_SUCCESS) {
|
158 |
+
setTimeout(checkBulkProgress, 2000);
|
159 |
+
} else {
|
160 |
+
setCellMessage(id, "This content is not processable.");
|
161 |
+
}
|
162 |
+
//aici e aici
|
163 |
+
});
|
164 |
+
}
|
165 |
+
|
166 |
+
function PercentageAnimator(outputSelector, targetPercentage) {
|
167 |
+
this.animationSpeed = 10;
|
168 |
+
this.increment = 2;
|
169 |
+
this.curPercentage = 0;
|
170 |
+
this.targetPercentage = targetPercentage;
|
171 |
+
this.outputSelector = outputSelector;
|
172 |
+
|
173 |
+
this.animate = function(percentage) {
|
174 |
+
this.targetPercentage = percentage;
|
175 |
+
setTimeout(PercentageTimer.bind(null, this), this.animationSpeed);
|
176 |
+
}
|
177 |
+
}
|
178 |
+
|
179 |
+
function PercentageTimer(animator) {
|
180 |
+
if (animator.curPercentage - animator.targetPercentage < -animator.increment) {
|
181 |
+
animator.curPercentage += animator.increment;
|
182 |
+
} else if (animator.curPercentage - animator.targetPercentage > animator.increment) {
|
183 |
+
animator.curPercentage -= animator.increment;
|
184 |
+
} else {
|
185 |
+
animator.curPercentage = animator.targetPercentage;
|
186 |
+
}
|
187 |
+
|
188 |
+
jQuery(animator.outputSelector).text(animator.curPercentage + "%");
|
189 |
+
|
190 |
+
if (animator.curPercentage != animator.targetPercentage) {
|
191 |
+
setTimeout(PercentageTimer.bind(null,animator), animator.animationSpeed)
|
192 |
+
}
|
193 |
+
}
|
194 |
+
|
195 |
+
function progressUpdate(percent, message) {
|
196 |
+
var progress = jQuery("#bulk-progress");
|
197 |
+
if(progress.length) {
|
198 |
+
jQuery(".progress-left", progress).css("width", percent + "%");
|
199 |
+
jQuery(".progress-img", progress).css("left", percent + "%");
|
200 |
+
if(percent > 24) {
|
201 |
+
jQuery(".progress-img span", progress).html("");
|
202 |
+
jQuery(".progress-left", progress).html(percent + "%");
|
203 |
+
} else {
|
204 |
+
jQuery(".progress-img span", progress).html(percent + "%");
|
205 |
+
jQuery(".progress-left", progress).html("");
|
206 |
+
}
|
207 |
+
jQuery(".bulk-estimate").html(message);
|
208 |
+
}
|
209 |
+
}
|
210 |
+
|
211 |
+
function sliderUpdate(id, thumb, bkThumb, percent){
|
212 |
+
var oldSlide = jQuery(".bulk-slider div.bulk-slide:first-child");
|
213 |
+
var newSlide = oldSlide.clone();
|
214 |
+
newSlide.attr("id", "slide-" + id);
|
215 |
+
if(oldSlide.attr("id") != "empty-slide") {
|
216 |
+
newSlide.hide();
|
217 |
+
}
|
218 |
+
oldSlide.css("z-index", 1000);
|
219 |
+
jQuery(".bulk-img-opt", newSlide).attr("src", thumb);
|
220 |
+
jQuery(".bulk-img-orig", newSlide).attr("src", bkThumb);
|
221 |
+
jQuery(".bulk-opt-percent", newSlide).text(percent + "%");
|
222 |
+
|
223 |
+
jQuery(".bulk-slider").append(newSlide);
|
224 |
+
if(oldSlide.attr("id") == "empty-slide") {
|
225 |
+
oldSlide.remove();
|
226 |
+
jQuery(".bulk-slider-container").css("display", "block");
|
227 |
+
} else {
|
228 |
+
oldSlide.animate({ left: oldSlide.width() }, 'slow', 'swing', function(){
|
229 |
+
oldSlide.remove();
|
230 |
+
newSlide.fadeIn("slow");
|
231 |
+
});
|
232 |
+
}
|
233 |
+
}
|
234 |
+
|
235 |
+
function hideSlider() {
|
236 |
+
jQuery(".bulk-slider-container").css("display", "none");
|
237 |
+
}
|
238 |
+
|
239 |
+
function showStats() {
|
240 |
+
var statsDiv = jQuery(".bulk-stats");
|
241 |
+
if(statsDiv.length > 0) {
|
242 |
+
|
243 |
+
}
|
244 |
+
}
|
readme.txt
CHANGED
@@ -1,14 +1,15 @@
|
|
1 |
=== ShortPixel Image Optimizer ===
|
2 |
|
3 |
Contributors: AlexSP
|
4 |
-
Tags: picture, optimization, image editor, pngout, upload speed, shortpixel, compression, jpegmini, webp, lossless, cwebp, media,
|
|
|
5 |
Requires at least: 3.0.0 or higher
|
6 |
Tested up to: 4.2
|
7 |
-
Stable tag:
|
8 |
License: GPLv2 or later
|
9 |
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
10 |
|
11 |
-
|
12 |
|
13 |
== Description ==
|
14 |
|
@@ -25,7 +26,7 @@ ShortPixel uses powerful algorithms that enable your website to load faster, use
|
|
25 |
* **Backup and restore originals:** if you ever want to return to the original version, images are automatically stored in a backup folder on your hosting servers.
|
26 |
* **Bulk image optimization:** Crunch your image gallery, and downsize your website. This feature may take up to several hours, depending on the number and size of existing images.
|
27 |
|
28 |
-
On the https://ShortPixel.com website, we offer free access to the
|
29 |
|
30 |
== Installation ==
|
31 |
|
@@ -118,9 +119,20 @@ The ShortPixel team is here to help. <a href="https://shortpixel.com/contact">Co
|
|
118 |
|
119 |
== Changelog ==
|
120 |
|
121 |
-
=
|
122 |
-
|
123 |
-
*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
124 |
|
125 |
= 2.1.9 =
|
126 |
|
@@ -146,7 +158,7 @@ The ShortPixel team is here to help. <a href="https://shortpixel.com/contact">Co
|
|
146 |
* when quota is exceeded user can more easily increase it
|
147 |
* extra warning regarding the number of thumbs available additionally to main images
|
148 |
* improved counting of images
|
149 |
-
* check if https works if not use http for
|
150 |
* better handling of error messages when API service cannot be contacted
|
151 |
|
152 |
= 2.1.5 =
|
@@ -159,7 +171,7 @@ The ShortPixel team is here to help. <a href="https://shortpixel.com/contact">Co
|
|
159 |
= 2.1.4 =
|
160 |
|
161 |
* fixed global variable issue for some variables
|
162 |
-
* fixed API Key validation that
|
163 |
|
164 |
= 2.1.3 =
|
165 |
|
@@ -167,7 +179,7 @@ The ShortPixel team is here to help. <a href="https://shortpixel.com/contact">Co
|
|
167 |
* removed forgotten debug message
|
168 |
* changed "optimised" to "optimized". Welcome USA :)
|
169 |
* improved bulk handling and also "cancel" and "resume" options
|
170 |
-
* fixed
|
171 |
|
172 |
= 2.1.2 =
|
173 |
|
@@ -206,7 +218,7 @@ The ShortPixel team is here to help. <a href="https://shortpixel.com/contact">Co
|
|
206 |
* fixed issue with "missing" images
|
207 |
* save plugin version for easier debugging
|
208 |
* list mode is set for media library for first time run
|
209 |
-
* fixed bug that prevented
|
210 |
|
211 |
= 2.0.6 =
|
212 |
|
@@ -324,7 +336,7 @@ The ShortPixel team is here to help. <a href="https://shortpixel.com/contact">Co
|
|
324 |
= 1.4.0 =
|
325 |
|
326 |
* Bulk image processing improved so it can optimize all the images in background while admin page is open
|
327 |
-
* small changes in readme.txt
|
328 |
|
329 |
= 1.3.5 =
|
330 |
|
1 |
=== ShortPixel Image Optimizer ===
|
2 |
|
3 |
Contributors: AlexSP
|
4 |
+
Tags: picture, optimization, image editor, pngout, upload speed, shortpixel, compression, jpegmini, webp, lossless, cwebp, media, jpegtran,image, image optimisation, shrink, picture, photo, optimize photos, compress, performance, tinypng, crunch, pngquant, attachment, optimize, pictures,fast, images, image files, image quality, lossy, upload, kraken, resize, seo, smushit, optipng, kraken image optimizer, ewww, photo optimization, gifsicle, image optimizer, images, krakenio, png, gmagick, image optimize, pdf, pdf optimisation, pdf optimization, optimize pdf, optimise pdf, shrink pdf, jpg, jpeg, jpg optimisation, jpg optimization, optimize jpg, optimise jpg, shrink jpg, gif, animated gif, optimize gif, optimise gif, optimizer, optimiser, compresion, optimization, cruncher, image cruncher, compress png, compress jpg, compress jpeg, faster loading times, image optimiser, improve pagerank, optimise, optimize animated gif, optimise jpeg, optimize jpeg, optimize png, optimise png, tinyjpg, short pixel, shortpixel
|
5 |
+
|
6 |
Requires at least: 3.0.0 or higher
|
7 |
Tested up to: 4.2
|
8 |
+
Stable tag: 3.0.0
|
9 |
License: GPLv2 or later
|
10 |
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
11 |
|
12 |
+
Fast, easy-to-use and lightweight plugin that optimizes images & PDFs. Preserve a high visual quality of images and make your website load faster.
|
13 |
|
14 |
== Description ==
|
15 |
|
26 |
* **Backup and restore originals:** if you ever want to return to the original version, images are automatically stored in a backup folder on your hosting servers.
|
27 |
* **Bulk image optimization:** Crunch your image gallery, and downsize your website. This feature may take up to several hours, depending on the number and size of existing images.
|
28 |
|
29 |
+
On the https://ShortPixel.com website, we offer free access to the ShortPixel API which you can use for further image optimization purposes.
|
30 |
|
31 |
== Installation ==
|
32 |
|
119 |
|
120 |
== Changelog ==
|
121 |
|
122 |
+
= 3.0.0 =
|
123 |
+
|
124 |
+
* Major update
|
125 |
+
* when validating the API Key on a multisite a message with instructions on how to add the API Key in wp-config.php is displayed
|
126 |
+
* check when an optimized image cannot be saved and stop bulk processing (if running)
|
127 |
+
* restore backup is not displayed when option is not activated
|
128 |
+
* change image status in the Media Library ShortPixel Compression column imediately after the image is reduced, not only after reloading the page. Add spinner to the "Image waiting to be processed" status.
|
129 |
+
* images with relative URLs are converted to absolute URL so they can be processed by the plugin
|
130 |
+
* proper handling of images with non-standard latin chars inside
|
131 |
+
* better average compression computation
|
132 |
+
* rewritten handleImageUpload
|
133 |
+
* removed MUST_HAVE_KEY
|
134 |
+
* changed isProcessable
|
135 |
+
* and others :)
|
136 |
|
137 |
= 2.1.9 =
|
138 |
|
158 |
* when quota is exceeded user can more easily increase it
|
159 |
* extra warning regarding the number of thumbs available additionally to main images
|
160 |
* improved counting of images
|
161 |
+
* check if https works if not use http for communications with the API
|
162 |
* better handling of error messages when API service cannot be contacted
|
163 |
|
164 |
= 2.1.5 =
|
171 |
= 2.1.4 =
|
172 |
|
173 |
* fixed global variable issue for some variables
|
174 |
+
* fixed API Key validation that occurred for some of the hosting providers out there when HTTPS was used
|
175 |
|
176 |
= 2.1.3 =
|
177 |
|
179 |
* removed forgotten debug message
|
180 |
* changed "optimised" to "optimized". Welcome USA :)
|
181 |
* improved bulk handling and also "cancel" and "resume" options
|
182 |
+
* fixed conflict with wpmandrill on wp_mail function
|
183 |
|
184 |
= 2.1.2 =
|
185 |
|
218 |
* fixed issue with "missing" images
|
219 |
* save plugin version for easier debugging
|
220 |
* list mode is set for media library for first time run
|
221 |
+
* fixed bug that prevented backup-ed files to remove when the original was removed
|
222 |
|
223 |
= 2.0.6 =
|
224 |
|
336 |
= 1.4.0 =
|
337 |
|
338 |
* Bulk image processing improved so it can optimize all the images in background while admin page is open
|
339 |
+
* small changes in readme.txt description
|
340 |
|
341 |
= 1.3.5 =
|
342 |
|
shortpixel_api.php
CHANGED
@@ -1,412 +1,433 @@
|
|
1 |
<?php
|
2 |
if ( !function_exists( 'download_url' ) ) {
|
3 |
-
|
4 |
}
|
5 |
|
6 |
-
class
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
|
188 |
-
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
|
240 |
-
|
241 |
-
|
242 |
-
|
243 |
-
|
244 |
-
|
245 |
-
|
246 |
-
|
247 |
-
|
248 |
-
|
249 |
-
|
250 |
-
|
251 |
-
|
252 |
-
|
253 |
-
|
254 |
-
|
255 |
-
|
256 |
-
|
257 |
-
|
258 |
-
|
259 |
-
|
260 |
-
|
261 |
-
|
262 |
-
|
263 |
-
|
264 |
-
|
265 |
-
|
266 |
-
|
267 |
-
|
268 |
-
|
269 |
-
|
270 |
-
|
271 |
-
|
272 |
-
|
273 |
-
|
274 |
-
|
275 |
-
|
276 |
-
|
277 |
-
|
278 |
-
|
279 |
-
|
280 |
-
|
281 |
-
|
282 |
-
|
283 |
-
|
284 |
-
|
285 |
-
|
286 |
-
|
287 |
-
|
288 |
-
|
289 |
-
|
290 |
-
|
291 |
-
|
292 |
-
|
293 |
-
|
294 |
-
|
295 |
-
|
296 |
-
|
297 |
-
|
298 |
-
|
299 |
-
|
300 |
-
|
301 |
-
|
302 |
-
|
303 |
-
|
304 |
-
|
305 |
-
|
306 |
-
|
307 |
-
|
308 |
-
|
309 |
-
|
310 |
-
|
311 |
-
|
312 |
-
|
313 |
-
|
314 |
-
|
315 |
-
|
316 |
-
|
317 |
-
|
318 |
-
|
319 |
-
|
320 |
-
|
321 |
-
|
322 |
-
|
323 |
-
|
324 |
-
|
325 |
-
|
326 |
-
|
327 |
-
|
328 |
-
|
329 |
-
|
330 |
-
|
331 |
-
|
332 |
-
|
333 |
-
|
334 |
-
|
335 |
-
|
336 |
-
|
337 |
-
|
338 |
-
|
339 |
-
|
340 |
-
|
341 |
-
|
342 |
-
|
343 |
-
|
344 |
-
|
345 |
-
|
346 |
-
|
347 |
-
|
348 |
-
|
349 |
-
|
350 |
-
|
351 |
-
|
352 |
-
|
353 |
-
|
354 |
-
|
355 |
-
|
356 |
-
|
357 |
-
|
358 |
-
|
359 |
-
|
360 |
-
|
361 |
-
|
362 |
-
|
363 |
-
|
364 |
-
|
365 |
-
|
366 |
-
|
367 |
-
|
368 |
-
|
369 |
-
|
370 |
-
|
371 |
-
|
372 |
-
|
373 |
-
|
374 |
-
|
375 |
-
|
376 |
-
|
377 |
-
|
378 |
-
|
379 |
-
|
380 |
-
|
381 |
-
|
382 |
-
|
383 |
-
|
384 |
-
|
385 |
-
|
386 |
-
|
387 |
-
|
388 |
-
|
389 |
-
|
390 |
-
|
391 |
-
|
392 |
-
|
393 |
-
|
394 |
-
|
395 |
-
|
396 |
-
|
397 |
-
|
398 |
-
|
399 |
-
|
400 |
-
|
401 |
-
|
402 |
-
|
403 |
-
|
404 |
-
|
405 |
-
|
406 |
-
|
407 |
-
|
408 |
-
|
409 |
-
|
410 |
-
|
411 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
412 |
}
|
1 |
<?php
|
2 |
if ( !function_exists( 'download_url' ) ) {
|
3 |
+
require_once( ABSPATH . 'wp-admin/includes/file.php' );
|
4 |
}
|
5 |
|
6 |
+
class ShortPixelAPI {
|
7 |
+
|
8 |
+
const STATUS_SUCCESS = 1;
|
9 |
+
const STATUS_UNCHANGED = 0;
|
10 |
+
const STATUS_ERROR = -1;
|
11 |
+
const STATUS_FAIL = -2;
|
12 |
+
const STATUS_QUOTA_EXCEEDED = -3;
|
13 |
+
const STATUS_SKIP = -4;
|
14 |
+
const STATUS_NOT_FOUND = -5;
|
15 |
+
|
16 |
+
private $_apiKey = '';
|
17 |
+
private $_compressionType = '';
|
18 |
+
private $_CMYKtoRGBconversion = '';
|
19 |
+
private $_maxAttempts = 10;
|
20 |
+
private $_apiEndPoint = 'https://api.shortpixel.com/v2/reducer.php';
|
21 |
+
|
22 |
+
public function setCompressionType($compressionType) {
|
23 |
+
$this->_compressionType = $compressionType;
|
24 |
+
}
|
25 |
+
|
26 |
+
public function setCMYKtoRGB($CMYK2RGB) {
|
27 |
+
$this->_CMYKtoRGBconversion = $CMYK2RGB;
|
28 |
+
}
|
29 |
+
public function getCompressionType() {
|
30 |
+
return $this->_compressionType;
|
31 |
+
}
|
32 |
+
|
33 |
+
public function setApiKey($apiKey) {
|
34 |
+
$this->_apiKey = $apiKey;
|
35 |
+
}
|
36 |
+
|
37 |
+
public function getApiKey() {
|
38 |
+
return $this->_apiKey;
|
39 |
+
}
|
40 |
+
|
41 |
+
public function __construct($apiKey, $compressionType, $CMYK2RGB) {
|
42 |
+
$this->_apiKey = $apiKey;
|
43 |
+
$this->setCompressionType($compressionType);
|
44 |
+
$this->setCMYKtoRGB($CMYK2RGB);
|
45 |
+
add_action('processImageAction', array(&$this, 'processImageAction'), 10, 4);
|
46 |
+
}
|
47 |
+
|
48 |
+
public function processImageAction($url, $filePaths, $ID, $time) {
|
49 |
+
$this->processImage($URLs, $PATHs, $ID, $time);
|
50 |
+
}
|
51 |
+
|
52 |
+
public function doRequests($URLs, $Blocking, $ID) {
|
53 |
+
|
54 |
+
$requestParameters = array(
|
55 |
+
'plugin_version' => PLUGIN_VERSION,
|
56 |
+
'key' => $this->_apiKey,
|
57 |
+
'lossy' => $this->_compressionType,
|
58 |
+
'cmyk2rgb' => $this->_CMYKtoRGBconversion,
|
59 |
+
'urllist' => $URLs
|
60 |
+
);
|
61 |
+
$arguments = array(
|
62 |
+
'method' => 'POST',
|
63 |
+
'timeout' => 45,
|
64 |
+
'redirection' => 3,
|
65 |
+
'sslverify' => false,
|
66 |
+
'httpversion' => '1.0',
|
67 |
+
'blocking' => $Blocking,
|
68 |
+
'headers' => array(),
|
69 |
+
'body' => json_encode($requestParameters),
|
70 |
+
'cookies' => array()
|
71 |
+
);
|
72 |
+
|
73 |
+
$response = wp_remote_post($this->_apiEndPoint, $arguments );
|
74 |
+
|
75 |
+
//only if $Blocking is true analyze the response
|
76 |
+
if ( $Blocking )
|
77 |
+
{
|
78 |
+
//there was an error, save this error inside file's SP optimization field
|
79 |
+
if ( is_object($response) && get_class($response) == 'WP_Error' )
|
80 |
+
{
|
81 |
+
$errorMessage = $response->errors['http_request_failed'][0];
|
82 |
+
$errorCode = 503;
|
83 |
+
}
|
84 |
+
elseif ( isset($response['response']['code']) && $response['response']['code'] <> 200 )
|
85 |
+
{
|
86 |
+
$errorMessage = $response['response']['code'] . " - " . $response['response']['message'];
|
87 |
+
$errorCode = $response['response']['code'];
|
88 |
+
}
|
89 |
+
|
90 |
+
if ( isset($errorMessage) )
|
91 |
+
{//set details inside file so user can know what happened
|
92 |
+
$meta = wp_get_attachment_metadata($ID);
|
93 |
+
$meta['ShortPixelImprovement'] = 'Error: <i>' . $errorMessage . '</i>';
|
94 |
+
unset($meta['ShortPixel']['WaitingProcessing']);
|
95 |
+
wp_update_attachment_metadata($ID, $meta);
|
96 |
+
return array("response" => array("code" => $errorCode, "message" => $errorMessage ));
|
97 |
+
}
|
98 |
+
|
99 |
+
return $response;//this can be an error or a good response
|
100 |
+
}
|
101 |
+
|
102 |
+
return $response;
|
103 |
+
}
|
104 |
+
|
105 |
+
public function parseResponse($response) {
|
106 |
+
$data = $response['body'];
|
107 |
+
$data = $this->parseJSON($data);
|
108 |
+
return (array)$data;
|
109 |
+
}
|
110 |
+
|
111 |
+
//handles the processing of the image using the ShortPixel API
|
112 |
+
public function processImage($URLs, $PATHs, $ID = null, $startTime = 0)
|
113 |
+
{
|
114 |
+
|
115 |
+
$PATHs = self::CheckAndFixImagePaths($PATHs);//check for images to make sure they exist on disk
|
116 |
+
if ( $PATHs === false )
|
117 |
+
return array("Status" => self::STATUS_SKIP, "Message" => 'The file(s) do not exist on disk, Image #$ID');
|
118 |
+
|
119 |
+
//tries multiple times (till timeout almost reached) to fetch images.
|
120 |
+
if($startTime == 0) {
|
121 |
+
$startTime = time();
|
122 |
+
}
|
123 |
+
$apiRetries = get_option('wp-short-pixel-api-retries');
|
124 |
+
if( time() - $startTime > MAX_EXECUTION_TIME)
|
125 |
+
{//keeps track of time
|
126 |
+
if ( $apiRetries > MAX_API_RETRIES )//we tried to process this time too many times, giving up...
|
127 |
+
{
|
128 |
+
$meta = wp_get_attachment_metadata($ID);
|
129 |
+
$meta['ShortPixelImprovement'] = 'Timed out while processing.';
|
130 |
+
unset($meta['ShortPixel']['WaitingProcessing']);
|
131 |
+
update_option('wp-short-pixel-api-retries', 0);//fai added to solve a bug?
|
132 |
+
wp_update_attachment_metadata($ID, $meta);
|
133 |
+
return array("Status" => self::STATUS_SKIP, "Message" => 'Skip this image, tries the next one.');
|
134 |
+
}
|
135 |
+
else
|
136 |
+
{//we'll try again next time user visits a page on admin panel
|
137 |
+
$apiRetries++;
|
138 |
+
update_option('wp-short-pixel-api-retries', $apiRetries);
|
139 |
+
return array("Status" => self::STATUS_ERROR, "Message" => 'Timed out while processing. (pass '.$apiRetries.')');
|
140 |
+
}
|
141 |
+
}
|
142 |
+
$response = $this->doRequests($URLs, true, $ID);//send requests to API
|
143 |
+
WPShortPixel::log("FAIPASS:" . json_encode($response));//fai remove
|
144 |
+
WPShortPixel::log("FAIPASS:" . json_encode($URLs));//fai remove
|
145 |
+
WPShortPixel::log("FAIPASS:" . $apiRetries);//fai remove
|
146 |
+
|
147 |
+
if($response['response']['code'] != 200)//response <> 200 -> there was an error apparently?
|
148 |
+
return array("Status" => self::STATUS_FAIL, "Message" => "There was an error and your request was not processed.");
|
149 |
+
|
150 |
+
$APIresponse = $this->parseResponse($response);//get the actual response from API, its an array
|
151 |
+
|
152 |
+
if ( isset($APIresponse[0]) )//API returned image details
|
153 |
+
{
|
154 |
+
foreach ( $APIresponse as $imageObject )//this part makes sure that all the sizes were processed and ready to be downloaded
|
155 |
+
{
|
156 |
+
if ( $imageObject->Status->Code == 0 || $imageObject->Status->Code == 1 )
|
157 |
+
{
|
158 |
+
sleep(1);
|
159 |
+
return $this->processImage($URLs, $PATHs, $ID, $startTime);
|
160 |
+
}
|
161 |
+
}
|
162 |
+
|
163 |
+
$firstImage = $APIresponse[0];//extract as object first image
|
164 |
+
switch($firstImage->Status->Code)
|
165 |
+
{
|
166 |
+
case 2:
|
167 |
+
//handle image has been processed
|
168 |
+
update_option( 'wp-short-pixel-quota-exceeded', 0);//reset the quota exceeded flag
|
169 |
+
return $this->handleSuccess($APIresponse, $URLs, $PATHs, $ID);
|
170 |
+
break;
|
171 |
+
default:
|
172 |
+
//handle error
|
173 |
+
if ( !file_exists($PATHs[0]) )
|
174 |
+
return array("Status" => self::STATUS_NOT_FOUND, "Message" => "File not found on disk.");
|
175 |
+
elseif ( isset($APIresponse[0]->Status->Message) )
|
176 |
+
return array("Status" => self::STATUS_FAIL, "Message" => "There was an error and your request was not processed.");
|
177 |
+
|
178 |
+
return "Unknown error";
|
179 |
+
break;
|
180 |
+
}
|
181 |
+
}
|
182 |
+
|
183 |
+
switch($APIresponse['Status']->Code)
|
184 |
+
{
|
185 |
+
|
186 |
+
case -403:
|
187 |
+
@delete_option('bulkProcessingStatus');
|
188 |
+
update_option( 'wp-short-pixel-quota-exceeded', 1);
|
189 |
+
return array("Status" => self::STATUS_QUOTA_EXCEEDED, "Message" => "Quota exceeded.");
|
190 |
+
break;
|
191 |
+
}
|
192 |
+
|
193 |
+
//sometimes the response array can be different
|
194 |
+
if ( is_numeric($APIresponse['Status']->Code) )
|
195 |
+
return array("Status" => self::STATUS_FAIL, "Message" => $APIresponse['Status']->Message);
|
196 |
+
else
|
197 |
+
return array("Status" => self::STATUS_FAIL, "Message" => $APIresponse[0]->Status->Message);
|
198 |
+
|
199 |
+
}
|
200 |
+
|
201 |
+
public function handleDownload($fileData,$counter){
|
202 |
+
//var_dump($fileData);
|
203 |
+
if($this->_compressionType)
|
204 |
+
{
|
205 |
+
$fileType = "LossyURL";
|
206 |
+
$fileSize = "LossySize";
|
207 |
+
}
|
208 |
+
else
|
209 |
+
{
|
210 |
+
$fileType = "LosslessURL";
|
211 |
+
$fileSize = "LoselessSize";
|
212 |
+
}
|
213 |
+
|
214 |
+
//if there is no improvement in size then we do not download this file
|
215 |
+
if ( $fileData->OriginalSize == $fileData->$fileSize )
|
216 |
+
return array("Status" => self::STATUS_UNCHANGED, "Message" => "File wasn't optimized so we do not download it.");
|
217 |
+
|
218 |
+
$correctFileSize = $fileData->$fileSize;
|
219 |
+
$tempFiles[$counter] = download_url(urldecode($fileData->$fileType));
|
220 |
+
//var_dump($tempFiles);
|
221 |
+
|
222 |
+
if(is_wp_error( $tempFiles[$counter] )) //also tries with http instead of https
|
223 |
+
{
|
224 |
+
$tempFiles[$counter] = download_url(str_replace('https://', 'http://', urldecode($fileData->$fileType)));
|
225 |
+
}
|
226 |
+
//on success we return this
|
227 |
+
$returnMessage = array("Status" => self::STATUS_SUCCESS, "Message" => $tempFiles[$counter]);
|
228 |
+
|
229 |
+
if ( is_wp_error( $tempFiles[$counter] ) ) {
|
230 |
+
@unlink($tempFiles[$counter]);
|
231 |
+
$returnMessage = array("Status" => self::STATUS_ERROR, "Message" => "Error downloading file " . $tempFiles[$counter]->get_error_message());
|
232 |
+
}
|
233 |
+
//check response so that download is OK
|
234 |
+
elseif( filesize($tempFiles[$counter]) != $correctFileSize) {
|
235 |
+
@unlink($tempFiles[$counter]);
|
236 |
+
$size = filesize($tempFiles[$counter]);
|
237 |
+
$returnMessage = array("Status" => self::STATUS_ERROR, "Message" => "Error downloading file - incorrect file size (downloaded: {$size}, correct: {$correctFileSize} )");
|
238 |
+
}
|
239 |
+
elseif (!file_exists($tempFiles[$counter])) {
|
240 |
+
$returnMessage = array("Status" => self::STATUS_ERROR, "Message" => "Unable to locate downloaded file " . $tempFiles[$counter]);
|
241 |
+
}
|
242 |
+
return $returnMessage;
|
243 |
+
}
|
244 |
+
|
245 |
+
public function handleSuccess($APIresponse, $URLs, $PATHs, $ID) {
|
246 |
+
$counter = $savedSpace = $originalSpace = $optimizedSpace = $averageCompression = 0;
|
247 |
+
|
248 |
+
//download each file from array and process it
|
249 |
+
foreach ( $APIresponse as $fileData )
|
250 |
+
{
|
251 |
+
if ( $fileData->Status->Code == 2 ) //file was processed OK
|
252 |
+
{
|
253 |
+
if ( $counter == 0 )//save percent improvement for main file
|
254 |
+
$percentImprovement = $fileData->PercentImprovement;
|
255 |
+
else //count thumbnails only
|
256 |
+
update_option( 'wp-short-pixel-thumbnail-count', get_option('wp-short-pixel-thumbnail-count') + 1 );
|
257 |
+
$downloadResult = $this->handleDownload($fileData,$counter);
|
258 |
+
//when the status is STATUS_UNCHANGED we just skip the array line for that one
|
259 |
+
if ( $downloadResult['Status'] == self::STATUS_SUCCESS ) {
|
260 |
+
$tempFiles[$counter] = $downloadResult['Message'];
|
261 |
+
}
|
262 |
+
elseif ( $downloadResult['Status'] <> self::STATUS_UNCHANGED )
|
263 |
+
return array("Status" => $downloadResult['Status'], "Message" => $downloadResult['Message']);
|
264 |
+
}
|
265 |
+
else //there was an error while trying to download a file
|
266 |
+
$tempFiles[$counter] = "";
|
267 |
+
|
268 |
+
$counter++;
|
269 |
+
}
|
270 |
+
|
271 |
+
//figure out in what SubDir files should land
|
272 |
+
$SubDir = $this->returnSubDir(get_attached_file($ID));
|
273 |
+
|
274 |
+
//if backup is enabled - we try to save the images
|
275 |
+
if( get_option('wp-short-backup_images') )
|
276 |
+
{
|
277 |
+
$uploadDir = wp_upload_dir();
|
278 |
+
$source = $PATHs;//array with final paths for this files
|
279 |
+
|
280 |
+
if( !file_exists(SP_BACKUP_FOLDER) && !@mkdir(SP_BACKUP_FOLDER, 0777, true) ) {//creates backup folder if it doesn't exist
|
281 |
+
return array("Status" => self::STATUS_FAIL, "Message" => "Backup folder does not exist and it cannot be created");
|
282 |
+
}
|
283 |
+
//create subdir in backup folder if needed
|
284 |
+
@mkdir( SP_BACKUP_FOLDER . DIRECTORY_SEPARATOR . $SubDir, 0777, true);
|
285 |
+
|
286 |
+
foreach ( $source as $fileID => $filePATH )//create destination files array
|
287 |
+
{
|
288 |
+
$destination[$fileID] = SP_BACKUP_FOLDER . DIRECTORY_SEPARATOR . $SubDir . self::MB_basename($source[$fileID]);
|
289 |
+
}
|
290 |
+
|
291 |
+
//now that we have original files and where we should back them up we attempt to do just that
|
292 |
+
if(is_writable(SP_BACKUP_FOLDER))
|
293 |
+
{
|
294 |
+
foreach ( $destination as $fileID => $filePATH )
|
295 |
+
{
|
296 |
+
if ( !file_exists($filePATH) )
|
297 |
+
{
|
298 |
+
if ( !@copy($source[$fileID], $destination[$fileID]) )
|
299 |
+
{//file couldn't have been saved in backup folder
|
300 |
+
ShortPixelAPI::SaveMessageinMetadata($ID, 'Cannot save file <i>' . self::MB_basename($source[$fileID]) . '</i> in backup directory');
|
301 |
+
return array("Status" => self::STATUS_FAIL, "Message" => 'Cannot save file <i>' . self::MB_basename($source[$fileID]) . '</i> in backup directory');
|
302 |
+
}
|
303 |
+
}
|
304 |
+
}
|
305 |
+
} else {//cannot write to the backup dir, return with an error
|
306 |
+
ShortPixelAPI::SaveMessageinMetadata($ID, 'Cannot save file in backup directory');
|
307 |
+
return array("Status" => self::STATUS_FAIL, "Message" => 'Cannot save file in backup directory');
|
308 |
+
}
|
309 |
+
|
310 |
+
}//end backup section
|
311 |
+
|
312 |
+
|
313 |
+
$writeFailed = 0;
|
314 |
+
|
315 |
+
if ( !empty($tempFiles) )
|
316 |
+
{
|
317 |
+
//overwrite the original files with the optimized ones
|
318 |
+
foreach ( $tempFiles as $tempFileID => $tempFilePATH )
|
319 |
+
{
|
320 |
+
if ( file_exists($tempFilePATH) && file_exists($PATHs[$tempFileID]) && is_writable($PATHs[$tempFileID]) )
|
321 |
+
{
|
322 |
+
copy($tempFilePATH, $PATHs[$tempFileID]);
|
323 |
+
@unlink($tempFilePATH);
|
324 |
+
}
|
325 |
+
else
|
326 |
+
$writeFailed++;
|
327 |
+
|
328 |
+
if ( $writeFailed > 0 )//there was an error
|
329 |
+
{
|
330 |
+
ShortPixelAPI::SaveMessageinMetadata($ID, 'Error: optimized version of ' . $writeFailed . ' file(s) couldn\'t be updated.');
|
331 |
+
update_option('bulkProcessingStatus', "error");
|
332 |
+
return array("Status" => self::STATUS_FAIL, "Message" => 'Error: optimized version of ' . $writeFailed . ' file(s) couldn\'t be updated.');
|
333 |
+
}
|
334 |
+
else
|
335 |
+
{//all files were copied, optimization data regarding the savings locally in DB
|
336 |
+
$fileType = ( $this->_compressionType ) ? "LossySize" : "LoselessSize";
|
337 |
+
$savedSpace += $APIresponse[$tempFileID]->OriginalSize - $APIresponse[$tempFileID]->$fileType;
|
338 |
+
$originalSpace += $APIresponse[$tempFileID]->OriginalSize;
|
339 |
+
$optimizedSpace += $APIresponse[$tempFileID]->$fileType;
|
340 |
+
$averageCompression += $fileData->PercentImprovement;
|
341 |
+
|
342 |
+
//add the number of files with < 5% optimization
|
343 |
+
if ( ( ( 1 - $APIresponse[$tempFileID]->$fileType/$APIresponse[$tempFileID]->OriginalSize ) * 100 ) < 5 )
|
344 |
+
update_option( 'wp-short-pixel-files-under-5-percent', get_option('wp-short-pixel-files-under-5-percent') + 1);
|
345 |
+
|
346 |
+
}
|
347 |
+
}
|
348 |
+
}
|
349 |
+
//old average counting
|
350 |
+
update_option('wp-short-pixel-savedSpace', get_option('wp-short-pixel-savedSpace') + $savedSpace);
|
351 |
+
$averageCompression = get_option('wp-short-pixel-averageCompression') * get_option('wp-short-pixel-fileCount');
|
352 |
+
$averageCompression = $averageCompression / (get_option('wp-short-pixel-fileCount') + count($APIresponse));
|
353 |
+
update_option('wp-short-pixel-averageCompression', $averageCompression);
|
354 |
+
update_option('wp-short-pixel-fileCount', get_option('wp-short-pixel-fileCount') + count($APIresponse));
|
355 |
+
//new average counting
|
356 |
+
update_option('wp-short-pixel-total-original', get_option('wp-short-pixel-total-original') + $originalSpace);
|
357 |
+
update_option('wp-short-pixel-total-optimized', get_option('wp-short-pixel-total-optimized') + $optimizedSpace);
|
358 |
+
//update metadata for this file
|
359 |
+
$meta = wp_get_attachment_metadata($ID);
|
360 |
+
$meta['ShortPixelImprovement'] = round($percentImprovement,2);
|
361 |
+
wp_update_attachment_metadata($ID, $meta);
|
362 |
+
//we reset the retry counter in case of success
|
363 |
+
update_option('wp-short-pixel-api-retries', 0);
|
364 |
+
|
365 |
+
return array("Status" => self::STATUS_SUCCESS, "Message" => 'Success: No pixels remained unsqueezed :-)', "PercentImprovement" => $percentImprovement);
|
366 |
+
}//end handleSuccess
|
367 |
+
|
368 |
+
static public function returnSubDir($file)//return subdir for that particular attached file
|
369 |
+
{
|
370 |
+
$Atoms = explode("/", $file);
|
371 |
+
$Counter = count($Atoms);
|
372 |
+
$SubDir = $Atoms[$Counter-3] . DIRECTORY_SEPARATOR . $Atoms[$Counter-2] . DIRECTORY_SEPARATOR;
|
373 |
+
|
374 |
+
return $SubDir;
|
375 |
+
}
|
376 |
+
|
377 |
+
//a basename alternative that deals OK with multibyte charsets (e.g. Arabic)
|
378 |
+
static public function MB_basename($Path){
|
379 |
+
$Separator = " qq ";
|
380 |
+
$Path = preg_replace("/[^ ]/u", $Separator."\$0".$Separator, $Path);
|
381 |
+
$Base = basename($Path);
|
382 |
+
$Base = str_replace($Separator, "", $Base);
|
383 |
+
return $Base;
|
384 |
+
}
|
385 |
+
|
386 |
+
//sometimes, the paths to the files as defined in metadata are wrong, we try to automatically correct them
|
387 |
+
static public function CheckAndFixImagePaths($PATHs){
|
388 |
+
|
389 |
+
$ErrorCount = 0;
|
390 |
+
$uploadDir = wp_upload_dir();
|
391 |
+
$Tmp = explode("/", $uploadDir['basedir']);
|
392 |
+
$TmpCount = count($Tmp);
|
393 |
+
$StichString = $Tmp[$TmpCount-2] . "/" . $Tmp[$TmpCount-1];
|
394 |
+
//files exist on disk?
|
395 |
+
foreach ( $PATHs as $Id => $File )
|
396 |
+
{
|
397 |
+
//we try again with a different path
|
398 |
+
if ( !file_exists($File) ){
|
399 |
+
$NewFile = $uploadDir['basedir'] . substr($File,strpos($File, $StichString)+strlen($StichString));
|
400 |
+
if ( file_exists($NewFile) )
|
401 |
+
$PATHs[$Id] = $NewFile;
|
402 |
+
else
|
403 |
+
$ErrorCount++;
|
404 |
+
}
|
405 |
+
}
|
406 |
+
|
407 |
+
if ( $ErrorCount > 0 )
|
408 |
+
return false;
|
409 |
+
else
|
410 |
+
return $PATHs;
|
411 |
+
|
412 |
+
}
|
413 |
+
|
414 |
+
|
415 |
+
static private function SaveMessageinMetadata($ID, $Message)
|
416 |
+
{
|
417 |
+
$meta = wp_get_attachment_metadata($ID);
|
418 |
+
$meta['ShortPixelImprovement'] = $Message;
|
419 |
+
unset($meta['ShortPixel']['WaitingProcessing']);
|
420 |
+
wp_update_attachment_metadata($ID, $meta);
|
421 |
+
}
|
422 |
+
|
423 |
+
public function parseJSON($data) {
|
424 |
+
if ( function_exists('json_decode') ) {
|
425 |
+
$data = json_decode( $data );
|
426 |
+
} else {
|
427 |
+
require_once( 'JSON/JSON.php' );
|
428 |
+
$json = new Services_JSON( );
|
429 |
+
$data = $json->decode( $data );
|
430 |
+
}
|
431 |
+
return $data;
|
432 |
+
}
|
433 |
}
|
shortpixel_queue.php
ADDED
@@ -0,0 +1,254 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class ShortPixelQueue {
|
4 |
+
|
5 |
+
private $ctrl;
|
6 |
+
private $startBulkId;
|
7 |
+
private $stopBulkId;
|
8 |
+
private $bulkCount;
|
9 |
+
private $bulkSkippedCount;
|
10 |
+
private $bulkAlreadyDoneCount;
|
11 |
+
private $lastBulkStartTime;
|
12 |
+
private $lastBulkSuccessTime;
|
13 |
+
private $bulkRunningTime;
|
14 |
+
|
15 |
+
//handling older
|
16 |
+
public function ShortPixelQueue($controller) {
|
17 |
+
$this->__construct($controller);
|
18 |
+
}
|
19 |
+
|
20 |
+
public function __construct($controller) {
|
21 |
+
$this->ctrl = $controller;
|
22 |
+
//init the option if needed
|
23 |
+
if(!isset($_SESSION["wp-short-pixel-priorityQueue"])) {
|
24 |
+
//take the priority list from the options (we persist there the priority IDs from the previous session)
|
25 |
+
$prioQueueOpt = WPShortPixel::getOpt( 'wp-short-pixel-priorityQueue', array());//here we save the IDs for the files that need to be processed after an image upload for example
|
26 |
+
$_SESSION["wp-short-pixel-priorityQueue"] = array();
|
27 |
+
foreach($prioQueueOpt as $ID) {
|
28 |
+
$meta = wp_get_attachment_metadata($ID);
|
29 |
+
WPShortPixel::log("INIT: Item $ID from options has metadata: " .json_encode($meta));
|
30 |
+
if(!isset($meta['ShortPixelImprovement'])) {
|
31 |
+
$this->push($ID);
|
32 |
+
}
|
33 |
+
}
|
34 |
+
update_option('wp-short-pixel-priorityQueue', $_SESSION["wp-short-pixel-priorityQueue"]);
|
35 |
+
WPShortPixel::log("INIT: Session queue not found, updated from Options with "
|
36 |
+
.json_encode($_SESSION["wp-short-pixel-priorityQueue"]));
|
37 |
+
}
|
38 |
+
|
39 |
+
$this->startBulkId = WPShortPixel::getOpt( 'wp-short-pixel-query-id-start', 0);//current query ID used for postmeta queries
|
40 |
+
$this->stopBulkId = WPShortPixel::getOpt( 'wp-short-pixel-query-id-stop', 0);//min ID used for postmeta queries
|
41 |
+
$this->bulkCount = WPShortPixel::getOpt( "wp-short-pixel-bulk-count", 0);
|
42 |
+
$this->bulkSkippedCount = WPShortPixel::getOpt( "wp-short-pixel-bulk-skipped-count", 0);
|
43 |
+
$this->bulkAlreadyDoneCount = WPShortPixel::getOpt( "wp-short-pixel-bulk-done-count", 0);
|
44 |
+
$this->lastBulkStartTime = WPShortPixel::getOpt( 'wp-short-pixel-last-bulk-start-time', 0);//time of the last start of the bulk.
|
45 |
+
$this->lastBulkSuccessTime = WPShortPixel::getOpt( 'wp-short-pixel-last-bulk-success-time', 0);//time of the last start of the bulk.
|
46 |
+
$this->bulkRunningTime = WPShortPixel::getOpt( 'wp-short-pixel-bulk-running-time', 0);//how long the bulk ran that far.
|
47 |
+
}
|
48 |
+
|
49 |
+
public function get() {
|
50 |
+
return $_SESSION["wp-short-pixel-priorityQueue"];//get_option("wp-short-pixel-priorityQueue");
|
51 |
+
}
|
52 |
+
|
53 |
+
public function push($ID)//add an ID to priority queue
|
54 |
+
{
|
55 |
+
$priorityQueue = $_SESSION["wp-short-pixel-priorityQueue"]; //get_option("wp-short-pixel-priorityQueue");
|
56 |
+
WPShortPixel::log("PUSH: Push ID $ID into queue ".json_encode($priorityQueue));
|
57 |
+
array_push($priorityQueue, $ID);
|
58 |
+
$prioQ = array_unique($priorityQueue);
|
59 |
+
$_SESSION["wp-short-pixel-priorityQueue"] = $prioQ;
|
60 |
+
//push also to the options queue, in case the session gets killed retrieve frm there
|
61 |
+
update_option('wp-short-pixel-priorityQueue', $prioQ);
|
62 |
+
|
63 |
+
WPShortPixel::log("PUSH: Updated: ".json_encode($_SESSION["wp-short-pixel-priorityQueue"]));//get_option("wp-short-pixel-priorityQueue")));
|
64 |
+
}
|
65 |
+
|
66 |
+
public function getFirst($count = 1)//return the first values added to priority queue
|
67 |
+
{
|
68 |
+
$priorityQueue = $_SESSION["wp-short-pixel-priorityQueue"];//self::getOpt("wp-short-pixel-priorityQueue", array());
|
69 |
+
$count = min(count($priorityQueue), $count);
|
70 |
+
return(array_slice($priorityQueue, count($priorityQueue) - $count, $count));
|
71 |
+
}
|
72 |
+
|
73 |
+
public function remove($ID)//remove an ID from priority queue
|
74 |
+
{
|
75 |
+
$priorityQueue = $_SESSION["wp-short-pixel-priorityQueue"];//get_option("wp-short-pixel-priorityQueue");
|
76 |
+
WPShortPixel::log("REM: Remove ID $ID from queue ".json_encode($priorityQueue));
|
77 |
+
$newPriorityQueue = array();
|
78 |
+
$found = false;
|
79 |
+
foreach($priorityQueue as $item) {
|
80 |
+
if($item != $ID) {
|
81 |
+
$newPriorityQueue[] = $item;
|
82 |
+
} else {
|
83 |
+
$found = true;
|
84 |
+
}
|
85 |
+
}
|
86 |
+
//update_option("wp-short-pixel-priorityQueue", $newPriorityQueue);
|
87 |
+
$_SESSION["wp-short-pixel-priorityQueue"] = $newPriorityQueue;
|
88 |
+
WPShortPixel::log("REM: " . ($found ? "Updated: " : "Not found") . json_encode($_SESSION["wp-short-pixel-priorityQueue"]));//get_option("wp-short-pixel-priorityQueue")));
|
89 |
+
return $found;
|
90 |
+
}
|
91 |
+
|
92 |
+
public function bulkRunning() {
|
93 |
+
//$bulkProcessingStatus = get_option('bulkProcessingStatus');
|
94 |
+
return $this->startBulkId > $this->stopBulkId;
|
95 |
+
}
|
96 |
+
|
97 |
+
public function bulkPaused() {
|
98 |
+
WPShortPixel::log("Bulk Paused: " . get_option( 'wp-short-pixel-cancel-pointer'));
|
99 |
+
return WPShortPixel::getOpt( 'wp-short-pixel-cancel-pointer', 0);
|
100 |
+
}
|
101 |
+
|
102 |
+
public function bulkRan() {
|
103 |
+
return WPShortPixel::getOpt("wp-short-pixel-bulk-ever-ran", 0) != 0;
|
104 |
+
}
|
105 |
+
|
106 |
+
public function processing() {
|
107 |
+
WPShortPixel::log("QUEUE: processing(): get:" . json_encode($this->get()));
|
108 |
+
return $this->bulkRunning() || count($this->get());
|
109 |
+
}
|
110 |
+
|
111 |
+
public function getFlagBulkId() {
|
112 |
+
return WPShortPixel::getOpt("wp-short-pixel-flag-id",0);
|
113 |
+
}
|
114 |
+
|
115 |
+
public function getStartBulkId() {
|
116 |
+
return $this->startBulkId;
|
117 |
+
}
|
118 |
+
|
119 |
+
public function resetStartBulkId() {
|
120 |
+
$this->setStartBulkId($this->ctrl->getMaxMediaId());
|
121 |
+
}
|
122 |
+
|
123 |
+
public function setStartBulkId($start){
|
124 |
+
$this->startBulkId = $start;
|
125 |
+
update_option("wp-short-pixel-query-id-start", $this->startBulkId);
|
126 |
+
}
|
127 |
+
|
128 |
+
public function getStopBulkId() {
|
129 |
+
return $this->stopBulkId;
|
130 |
+
}
|
131 |
+
|
132 |
+
public function resetStopBulkId() {
|
133 |
+
$this->stopBulkId = $this->ctrl->getMinMediaId();
|
134 |
+
update_option("wp-short-pixel-query-id-stop", $this->stopBulkId);
|
135 |
+
}
|
136 |
+
|
137 |
+
public function resetBulkCount() {
|
138 |
+
$res = $this->ctrl->countAllProcessableFiles($this->getFlagBulkId(), $this->stopBulkId);
|
139 |
+
$this->bulkCount = $res["mainFiles"];
|
140 |
+
update_option("wp-short-pixel-bulk-count", $this->bulkCount);
|
141 |
+
}
|
142 |
+
|
143 |
+
public function resetBulkAlreadyDoneCount() {
|
144 |
+
$res = $this->ctrl->countAllProcessedFiles($this->getFlagBulkId(), $this->stopBulkId);
|
145 |
+
$this->bulkAlreadyDoneCount = $res["mainFiles"];
|
146 |
+
update_option("wp-short-pixel-bulk-done-count", $this->bulkAlreadyDoneCount);
|
147 |
+
}
|
148 |
+
|
149 |
+
public function resetBulkSkippedCount() {
|
150 |
+
$this->bulkSkippedCount = 0;
|
151 |
+
update_option("wp-short-pixel-bulk-skipped-count", $this->bulkSkippedCount);
|
152 |
+
}
|
153 |
+
|
154 |
+
public function flagBulkStart() {
|
155 |
+
update_option("wp-short-pixel-flag-id", $this->startBulkId);
|
156 |
+
delete_option('bulkProcessingStatus');
|
157 |
+
add_option('bulkProcessingStatus', 'running');//set bulk flag
|
158 |
+
}
|
159 |
+
|
160 |
+
public function startBulk() {
|
161 |
+
$this->resetStartBulkId(); //start downwards from the biggest item ID
|
162 |
+
$this->resetStopBulkId();
|
163 |
+
$this->flagBulkStart(); //we use this to detect new added files while bulk is running
|
164 |
+
$this->resetBulkCount(); //call this only after the resets above;
|
165 |
+
$this->resetBulkAlreadyDoneCount();//call this only after the resets above;
|
166 |
+
$this->resetBulkSkippedCount();
|
167 |
+
update_option( 'wp-short-pixel-bulk-ever-ran', 1);
|
168 |
+
}
|
169 |
+
|
170 |
+
public function pauseBulk() {
|
171 |
+
update_option( 'wp-short-pixel-cancel-pointer', $this->startBulkId);//we save this so we can resume bulk processing
|
172 |
+
WPShortPixel::log("PAUSE: Pointer = ".get_option( 'wp-short-pixel-cancel-pointer'));
|
173 |
+
$this->stopBulk();
|
174 |
+
}
|
175 |
+
|
176 |
+
public function stopBulk() {
|
177 |
+
$this->startBulkId = $this->ctrl->getMaxMediaId();
|
178 |
+
$this->stopBulkId = $this->startBulkId;
|
179 |
+
update_option("wp-short-pixel-query-id-start", $this->startBulkId);
|
180 |
+
update_option("wp-short-pixel-query-id-stop", $this->stopBulkId);
|
181 |
+
delete_option('bulkProcessingStatus');
|
182 |
+
$this->resetBulkSkippedCount();
|
183 |
+
return WPShortPixel::getOpt('wp-short-pixel-bulk-ever-ran', 0);
|
184 |
+
}
|
185 |
+
|
186 |
+
public function resumeBulk() {
|
187 |
+
$this->startBulkId = get_option( 'wp-short-pixel-cancel-pointer');
|
188 |
+
update_option("wp-short-pixel-query-id-start", $this->startBulkId);//start downwards from the biggest item ID
|
189 |
+
$this->stopBulkId = $this->ctrl->getMinMediaId();
|
190 |
+
update_option("wp-short-pixel-query-id-stop", $this->stopBulkId);
|
191 |
+
//update_option("wp-short-pixel-flag-id", $this->startBulkId);//we use to detect new added files while bulk is running
|
192 |
+
add_option('bulkProcessingStatus', 'running');//set bulk flag
|
193 |
+
$this->resetBulkSkippedCount();
|
194 |
+
delete_option( 'wp-short-pixel-cancel-pointer');
|
195 |
+
WPShortPixel::log("Resumed: (pause says: " . $this->bulkPaused() . ") Start from: " . $this->startBulkId . " to " . $this->stopBulkId);
|
196 |
+
}
|
197 |
+
|
198 |
+
public function addBulkSkipped($skipped) {
|
199 |
+
$this->bulkSkippedCount += $skipped;
|
200 |
+
update_option( "wp-short-pixel-bulk-skipped-count", $this->bulkSkippedCount);
|
201 |
+
}
|
202 |
+
|
203 |
+
public function markBulkComplete() {
|
204 |
+
delete_option('bulkProcessingStatus');
|
205 |
+
delete_option( 'wp-short-pixel-cancel-pointer');
|
206 |
+
}
|
207 |
+
|
208 |
+
public function resetBulk() {
|
209 |
+
delete_option('bulkProcessingStatus');
|
210 |
+
delete_option( 'wp-short-pixel-cancel-pointer');
|
211 |
+
$this->startBulkId = $this->stopBulkId = $this->ctrl->getMaxMediaId();
|
212 |
+
update_option( 'wp-short-pixel-query-id-stop', $this->startBulkId );
|
213 |
+
update_option( 'wp-short-pixel-query-id-start', $this->startBulkId );
|
214 |
+
update_option('wp-short-pixel-bulk-running-time', 0);
|
215 |
+
update_option('wp-short-pixel-last-bulk-start-time', 0);
|
216 |
+
update_option('wp-short-pixel-last-bulk-success-time', 0);
|
217 |
+
}
|
218 |
+
|
219 |
+
public function logBulkProgress() {
|
220 |
+
$t = time();
|
221 |
+
if($t - $this->lastBulkSuccessTime > 120) { //if break longer than two minutes we mark a pause in the bulk
|
222 |
+
$this->bulkRunningTime += ($this->lastBulkSuccessTime - $this->lastBulkStartTime);
|
223 |
+
update_option('wp-short-pixel-bulk-running-time', $this->bulkRunningTime);
|
224 |
+
$this->lastBulkStartTime = $this->lastBulkSuccessTime = $t;
|
225 |
+
update_option('wp-short-pixel-last-bulk-start-time', $t);
|
226 |
+
update_option('wp-short-pixel-last-bulk-success-time', $t);
|
227 |
+
} else {
|
228 |
+
$this->lastBulkSuccessTime = $t;
|
229 |
+
update_option('wp-short-pixel-last-bulk-success-time', $t);
|
230 |
+
}
|
231 |
+
}
|
232 |
+
|
233 |
+
public function getBulkPercent() {
|
234 |
+
WPShortPixel::log("QUEUE.getBulkPercent: Flag:" . get_option("wp-short-pixel-flag-id"). " Start:" . $this->startBulkId . " Already done: " . $this->bulkAlreadyDoneCount . " Skipped: " . $this->bulkSkippedCount . " Bulk count:" . $this->bulkCount);
|
235 |
+
WPShortPixel::log(" calculated percent:" . round((get_option("wp-short-pixel-flag-id") - $this->startBulkId + $this->bulkAlreadyDoneCount - $this->bulkSkippedCount) / $this->bulkCount * 100));
|
236 |
+
|
237 |
+
if($this->bulkCount == 0) return 100;
|
238 |
+
// return maximum 99%
|
239 |
+
return min(99, round((get_option("wp-short-pixel-flag-id") - $this->startBulkId + $this->bulkAlreadyDoneCount - $this->bulkSkippedCount) / $this->bulkCount * 100));
|
240 |
+
}
|
241 |
+
|
242 |
+
public function getDeltaBulkPercent() {
|
243 |
+
WPShortPixel::log("QUEUE.getDeltaBulkPercent: Flag:" . get_option("wp-short-pixel-flag-id"). " Start:" . $this->startBulkId . " Already done: " . $this->bulkAlreadyDoneCount . " Bulk count:" . $this->bulkCount);
|
244 |
+
return $this->getBulkPercent() - round($this->bulkAlreadyDoneCount / $this->bulkCount * 100);
|
245 |
+
}
|
246 |
+
|
247 |
+
public function getTimeRemaining (){
|
248 |
+
$p = $this->getBulkPercent();
|
249 |
+
$pAlready = round($this->bulkAlreadyDoneCount / $this->bulkCount * 100);
|
250 |
+
// die("" . ($this->lastBulkSuccessTime - $this->lastBulkStartTime));
|
251 |
+
if(($p - $pAlready) == 0) return 0;
|
252 |
+
return round(((100 - $p) / ($p - $pAlready)) * ($this->bulkRunningTime + $this->lastBulkSuccessTime - $this->lastBulkStartTime)/60);
|
253 |
+
}
|
254 |
+
}
|
shortpixel_view.php
ADDED
@@ -0,0 +1,154 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class ShortPixelView {
|
4 |
+
|
5 |
+
private $ctrl;
|
6 |
+
|
7 |
+
//handling older
|
8 |
+
public function ShortPixelView($controller) {
|
9 |
+
$this->__construct($controller);
|
10 |
+
}
|
11 |
+
|
12 |
+
public function __construct($controller) {
|
13 |
+
$this->ctrl = $controller;
|
14 |
+
}
|
15 |
+
|
16 |
+
public function displayQuotaExceededAlert($quotaData)
|
17 |
+
{ ?>
|
18 |
+
<br/>
|
19 |
+
<div style="background-color: #fff; border-left: 4px solid #ff0000; box-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.1); padding: 1px 12px;">
|
20 |
+
<h3>Quota Exceeded</h3>
|
21 |
+
<p>
|
22 |
+
The plugin has optimized <?=number_format($quotaData['APICallsMadeNumeric'] + $quotaData['APICallsMadeOneTimeNumeric'])?> images and stopped because it reached the available quota limit.
|
23 |
+
</p>
|
24 |
+
<p>
|
25 |
+
It’s simple to upgrade, just click here to <a href='https://shortpixel.com/login/<?=$this->ctrl->getApiKey()?>' target='_blank'>log into your account</a> and see the options in the billing page.
|
26 |
+
</p>
|
27 |
+
<p>
|
28 |
+
You can immediately start processing 5,000 images/month for $4,99, choose another plan that suits you or <a href='https://shortpixel.com/contact' target='_blank'>contact us</a> for larger compression needs.
|
29 |
+
</p>
|
30 |
+
</div> <?php
|
31 |
+
}
|
32 |
+
|
33 |
+
public function displayApiKeyAlert()
|
34 |
+
{ ?>
|
35 |
+
<p>In order to start the optimization process, you need to validate your API key in the <a href="options-general.php?page=wp-shortpixel">ShortPixel Settings</a> page in your WordPress Admin.</p>
|
36 |
+
<p>If you don’t have an API Key, you can get one delivered to your inbox, for free.</p>
|
37 |
+
<p>Please <a href="https://shortpixel.com/wp-apikey" target="_blank">sign up</a> to get your API key.</p>
|
38 |
+
<?php
|
39 |
+
}
|
40 |
+
|
41 |
+
public function displayBulkProcessingForm($imageCount, $imgProcessedCount, $thumbsProcessedCount, $under5PercentCount, $bulkRan, $averageCompression, $filesOptimized, $savedSpace, $percent) {
|
42 |
+
?>
|
43 |
+
<div class="wrap short-pixel-bulk-page">
|
44 |
+
<h1>Bulk Image Optimization by ShortPixel</h1>
|
45 |
+
<?php
|
46 |
+
if ( !$bulkRan ) { ?>
|
47 |
+
<p>You have <?=number_format($imageCount['mainFiles'])?> images in your Media Library and <?=number_format($imageCount['totalFiles'] - $imageCount['mainFiles'])?> smaller thumbnails, associated to these images.</p>
|
48 |
+
<?php if($imgProcessedCount["totalFiles"] > 0) { ?>
|
49 |
+
<p>From these, <?=number_format($imgProcessedCount['mainFiles'])?> images and <?=number_format($imgProcessedCount['totalFiles'] - $imgProcessedCount['mainFiles'])?> thumbnails were already processed by ShorPixel</p>
|
50 |
+
<?php } ?>
|
51 |
+
<p>If the box below is checked, <b>ShortPixel will process a total of <?=number_format($imageCount['totalFiles'] - $imgProcessedCount['totalFiles'])?> images.</b> However, images with less than 5% optimization will not be counted out of your quota, so the final number of counted images could be smaller.</p>
|
52 |
+
<p>Thumbnails are important because they are displayed on most of your website's pages and they may generate more traffic than the originals. Optimizing thumbnails will improve your overall website speed. However, if you don't want to optimize thumbnails, please uncheck the box below.</p>
|
53 |
+
|
54 |
+
<form action='' method='POST' >
|
55 |
+
<input type='checkbox' name='thumbnails' <?=$this->ctrl->processThumbnails() ? "checked":""?>> Include thumbnails
|
56 |
+
<p>The plugin will replace the original images with the optimized ones starting with the newest images added to your Media Library. You will be able to pause the process anytime.</p>
|
57 |
+
<?=$this->ctrl->backupImages() ? "<p>Your original images will be stored in a separate back-up folder.</p>" : ""?>
|
58 |
+
<input type='submit' name='bulkProcess' id='bulkProcess' class='button button-primary' value='Start Optimizing'>
|
59 |
+
</form>
|
60 |
+
<?php
|
61 |
+
} elseif($percent) // bulk is paused
|
62 |
+
{ ?>
|
63 |
+
<p>Bulk processing is paused. You can continue optimizing your Media Gallery from where you left, by clicking the button below. Already optimized images will not be reprocessed.</p>
|
64 |
+
<?=$this->displayBulkProgressBar(false, $percent, "")?>
|
65 |
+
<p>Please see below the optimization status so far:</p>
|
66 |
+
<?=$this->displayBulkStats($filesOptimized, $thumbsProcessedCount, $under5PercentCount, $averageCompression, $savedSpace)?>
|
67 |
+
<?php
|
68 |
+
} else { ?>
|
69 |
+
<p>Congratulations, your media library has been successfully optimized!</p>
|
70 |
+
<p>Go to the ShortPixel <a href='" . get_admin_url() . "options-general.php?page=wp-shortpixel#facts'>Stats</a> and see all your websites' optimized stats.
|
71 |
+
|
72 |
+
<?=$this->displayBulkStats($filesOptimized, $thumbsProcessedCount, $under5PercentCount, $averageCompression, $savedSpace)?>
|
73 |
+
<p>Download your detailed <a href="https://api.shortpixel.com/v2/report.php?key=<?=$this->ctrl->getApiKey()?>">Optimization Report</a> to check your image optimization statistics for the last 40 days</p>
|
74 |
+
<p>Restart the optimization process for new images added to your library:
|
75 |
+
<form action='' method='POST' >
|
76 |
+
<input type='checkbox' name='thumbnails' <?=$this->ctrl->processThumbnails() ? "checked":""?>> Include thumbnails<br><br>
|
77 |
+
<input type='submit' name='bulkProcess' id='bulkProcess' class='button button-primary' value='Restart Optimizing'>
|
78 |
+
</form>
|
79 |
+
<?php } ?>
|
80 |
+
</div>
|
81 |
+
<?php
|
82 |
+
}
|
83 |
+
|
84 |
+
public function displayBulkProcessingRunning($percent, $message) {
|
85 |
+
?>
|
86 |
+
<div class="wrap short-pixel-bulk-page">
|
87 |
+
<h1>Bulk Image Optimization by ShortPixel</h1>
|
88 |
+
<p>Bulk optimization has started. This process will take some time, depending on the number of images in your library. In the meantime, you can continue using the admin as usual. However, if you close the WordPress admin, the bulk processing will pause until you open it again. </p>
|
89 |
+
<?=$this->displayBulkProgressBar(true, $percent, $message)?>
|
90 |
+
<div class="bulk-progress bulk-slider-container">
|
91 |
+
<div style="margin-bottom: 10px;"><span class="short-pixel-block-title">Just optimized:</span></div>
|
92 |
+
<div class="bulk-slider">
|
93 |
+
<div class="bulk-slide" id="empty-slide">
|
94 |
+
<div class="img-original">
|
95 |
+
<div><img class="bulk-img-orig" src=""></div>
|
96 |
+
<div>Original image</div>
|
97 |
+
</div>
|
98 |
+
<div class="img-optimized">
|
99 |
+
<div><img class="bulk-img-opt" src=""></div>
|
100 |
+
<div>Optimized image</div>
|
101 |
+
</div>
|
102 |
+
<div class="img-info">
|
103 |
+
<div style="font-size: 14px; line-height: 10px; margin-bottom:16px;">Optimized by:</div>
|
104 |
+
<span class="bulk-opt-percent"></span>
|
105 |
+
</div>
|
106 |
+
</div>
|
107 |
+
</div>
|
108 |
+
</div>
|
109 |
+
</div>
|
110 |
+
<?php
|
111 |
+
}
|
112 |
+
|
113 |
+
public function displayBulkProgressBar($running, $percent, $message) {
|
114 |
+
$percentBefore = $percentAfter = '';
|
115 |
+
if($percent > 24) {
|
116 |
+
$percentBefore = $percent . "%";
|
117 |
+
} else {
|
118 |
+
$percentAfter = $percent . "%";
|
119 |
+
}
|
120 |
+
?>
|
121 |
+
<div class="bulk-progress">
|
122 |
+
<div id="bulk-progress" class="progress" >
|
123 |
+
<div class="progress-img" style="left: <?=$percent?>%;">
|
124 |
+
<img src="<?=WP_PLUGIN_URL?>/shortpixel-image-optimiser/img/slider.png">
|
125 |
+
<span><?=$percentAfter?></span>
|
126 |
+
</div>
|
127 |
+
<div class="progress-left" style="width: <?=$percent?>%"><?=$percentBefore?></div>
|
128 |
+
</div>
|
129 |
+
<div class="bulk-estimate">
|
130 |
+
<?=$message?>
|
131 |
+
</div>
|
132 |
+
<form action='' method='POST' style="display:inline;">
|
133 |
+
<input type="submit" class="button button-secondary bulk-cancel" onclick="clearBulkProcessor();"
|
134 |
+
name="<?=$running ? "bulkProcessPause" : "bulkProcessResume"?>" value="<?=$running ? "Pause" : "Resume Processing"?>"/>
|
135 |
+
</form>
|
136 |
+
</div>
|
137 |
+
<?php
|
138 |
+
}
|
139 |
+
|
140 |
+
public function displayBulkStats($filesOptimized, $thumbsProcessedCount, $under5PercentCount, $averageCompression, $savedSpace) {
|
141 |
+
?>
|
142 |
+
<div class="bulk-progress bulk-stats">
|
143 |
+
<div class="label">Images/PDFs processed with ShortPixel:</div><div><?=number_format($filesOptimized - $thumbsProcessedCount)?></div><br>
|
144 |
+
<div class="label">Thumbnails processed with ShortPixel:</div><div><?=number_format($thumbsProcessedCount)?></div><br>
|
145 |
+
<div class="label totals">Total:</div><div><?=number_format($filesOptimized)?></div><br>
|
146 |
+
<div class="label totals">Images & thumbs with less than 5% optimization (free):</div><div><?=number_format($under5PercentCount)?></div><br>
|
147 |
+
<div class="label totals">Used quota:</div><div><?=number_format($filesOptimized - $under5PercentCount)?></div><br>
|
148 |
+
<div class="label">Average optimization:</div><div><?=$averageCompression?>%</div><br>
|
149 |
+
<div class="label">Saved space:</div><div><?=$savedSpace?></div>
|
150 |
+
</div>
|
151 |
+
<?php
|
152 |
+
}
|
153 |
+
|
154 |
+
}
|
wp-shortpixel.php
CHANGED
@@ -1,1556 +1,1526 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Plugin Name: ShortPixel Image Optimizer
|
4 |
-
* Plugin URI: https://shortpixel.com/
|
5 |
-
* Description: ShortPixel
|
6 |
-
* Version:
|
7 |
-
* Author: ShortPixel
|
8 |
-
* Author URI: https://shortpixel.com
|
9 |
-
*/
|
10 |
-
|
11 |
-
require_once('shortpixel_api.php');
|
12 |
-
require_once(
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
define('
|
21 |
-
|
22 |
-
define('
|
23 |
-
define('
|
24 |
-
define('
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
|
188 |
-
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
|
240 |
-
|
241 |
-
|
242 |
-
|
243 |
-
|
244 |
-
|
245 |
-
|
246 |
-
|
247 |
-
|
248 |
-
|
249 |
-
|
250 |
-
|
251 |
-
|
252 |
-
|
253 |
-
|
254 |
-
|
255 |
-
|
256 |
-
|
257 |
-
|
258 |
-
|
259 |
-
|
260 |
-
|
261 |
-
|
262 |
-
|
263 |
-
|
264 |
-
|
265 |
-
|
266 |
-
|
267 |
-
|
268 |
-
|
269 |
-
|
270 |
-
|
271 |
-
|
272 |
-
|
273 |
-
|
274 |
-
|
275 |
-
|
276 |
-
|
277 |
-
|
278 |
-
|
279 |
-
|
280 |
-
|
281 |
-
|
282 |
-
|
283 |
-
|
284 |
-
|
285 |
-
|
286 |
-
|
287 |
-
|
288 |
-
|
289 |
-
|
290 |
-
|
291 |
-
|
292 |
-
|
293 |
-
|
294 |
-
|
295 |
-
|
296 |
-
|
297 |
-
|
298 |
-
|
299 |
-
|
300 |
-
|
301 |
-
|
302 |
-
|
303 |
-
|
304 |
-
|
305 |
-
|
306 |
-
|
307 |
-
|
308 |
-
|
309 |
-
|
310 |
-
|
311 |
-
|
312 |
-
|
313 |
-
|
314 |
-
|
315 |
-
|
316 |
-
|
317 |
-
|
318 |
-
|
319 |
-
|
320 |
-
|
321 |
-
|
322 |
-
|
323 |
-
|
324 |
-
|
325 |
-
|
326 |
-
|
327 |
-
|
328 |
-
|
329 |
-
|
330 |
-
|
331 |
-
|
332 |
-
|
333 |
-
|
334 |
-
|
335 |
-
|
336 |
-
|
337 |
-
|
338 |
-
|
339 |
-
|
340 |
-
|
341 |
-
|
342 |
-
|
343 |
-
|
344 |
-
|
345 |
-
|
346 |
-
|
347 |
-
|
348 |
-
|
349 |
-
|
350 |
-
|
351 |
-
|
352 |
-
|
353 |
-
|
354 |
-
|
355 |
-
|
356 |
-
|
357 |
-
|
358 |
-
|
359 |
-
|
360 |
-
|
361 |
-
|
362 |
-
|
363 |
-
|
364 |
-
|
365 |
-
|
366 |
-
|
367 |
-
|
368 |
-
|
369 |
-
|
370 |
-
|
371 |
-
|
372 |
-
|
373 |
-
|
374 |
-
|
375 |
-
|
376 |
-
|
377 |
-
|
378 |
-
|
379 |
-
|
380 |
-
|
381 |
-
|
382 |
-
|
383 |
-
|
384 |
-
|
385 |
-
|
386 |
-
|
387 |
-
|
388 |
-
|
389 |
-
|
390 |
-
|
391 |
-
|
392 |
-
|
393 |
-
|
394 |
-
|
395 |
-
|
396 |
-
|
397 |
-
|
398 |
-
|
399 |
-
|
400 |
-
|
401 |
-
|
402 |
-
|
403 |
-
|
404 |
-
|
405 |
-
|
406 |
-
|
407 |
-
|
408 |
-
|
409 |
-
|
410 |
-
|
411 |
-
|
412 |
-
|
413 |
-
|
414 |
-
|
415 |
-
|
416 |
-
|
417 |
-
|
418 |
-
|
419 |
-
|
420 |
-
|
421 |
-
|
422 |
-
|
423 |
-
|
424 |
-
|
425 |
-
|
426 |
-
|
427 |
-
|
428 |
-
|
429 |
-
|
430 |
-
|
431 |
-
|
432 |
-
|
433 |
-
|
434 |
-
|
435 |
-
|
436 |
-
|
437 |
-
|
438 |
-
|
439 |
-
|
440 |
-
|
441 |
-
|
442 |
-
|
443 |
-
|
444 |
-
|
445 |
-
|
446 |
-
|
447 |
-
|
448 |
-
|
449 |
-
|
450 |
-
|
451 |
-
|
452 |
-
|
453 |
-
|
454 |
-
|
455 |
-
|
456 |
-
|
457 |
-
|
458 |
-
|
459 |
-
|
460 |
-
|
461 |
-
|
462 |
-
|
463 |
-
|
464 |
-
|
465 |
-
|
466 |
-
|
467 |
-
|
468 |
-
|
469 |
-
|
470 |
-
|
471 |
-
|
472 |
-
|
473 |
-
|
474 |
-
|
475 |
-
|
476 |
-
|
477 |
-
|
478 |
-
|
479 |
-
|
480 |
-
|
481 |
-
|
482 |
-
|
483 |
-
|
484 |
-
|
485 |
-
|
486 |
-
|
487 |
-
|
488 |
-
|
489 |
-
|
490 |
-
|
491 |
-
|
492 |
-
|
493 |
-
|
494 |
-
|
495 |
-
|
496 |
-
|
497 |
-
|
498 |
-
|
499 |
-
|
500 |
-
|
501 |
-
|
502 |
-
|
503 |
-
|
504 |
-
|
505 |
-
|
506 |
-
|
507 |
-
|
508 |
-
|
509 |
-
|
510 |
-
|
511 |
-
|
512 |
-
|
513 |
-
|
514 |
-
|
515 |
-
|
516 |
-
|
517 |
-
|
518 |
-
|
519 |
-
|
520 |
-
|
521 |
-
|
522 |
-
|
523 |
-
|
524 |
-
|
525 |
-
|
526 |
-
|
527 |
-
|
528 |
-
|
529 |
-
|
530 |
-
|
531 |
-
|
532 |
-
|
533 |
-
|
534 |
-
|
535 |
-
|
536 |
-
|
537 |
-
|
538 |
-
|
539 |
-
|
540 |
-
|
541 |
-
|
542 |
-
|
543 |
-
|
544 |
-
|
545 |
-
|
546 |
-
|
547 |
-
|
548 |
-
|
549 |
-
|
550 |
-
|
551 |
-
|
552 |
-
|
553 |
-
|
554 |
-
|
555 |
-
|
556 |
-
|
557 |
-
|
558 |
-
|
559 |
-
|
560 |
-
|
561 |
-
|
562 |
-
|
563 |
-
|
564 |
-
|
565 |
-
|
566 |
-
|
567 |
-
|
568 |
-
|
569 |
-
|
570 |
-
|
571 |
-
|
572 |
-
|
573 |
-
|
574 |
-
|
575 |
-
|
576 |
-
|
577 |
-
|
578 |
-
|
579 |
-
|
580 |
-
|
581 |
-
|
582 |
-
|
583 |
-
|
584 |
-
|
585 |
-
|
586 |
-
|
587 |
-
|
588 |
-
|
589 |
-
|
590 |
-
|
591 |
-
|
592 |
-
|
593 |
-
|
594 |
-
|
595 |
-
|
596 |
-
|
597 |
-
|
598 |
-
|
599 |
-
|
600 |
-
|
601 |
-
|
602 |
-
|
603 |
-
|
604 |
-
|
605 |
-
|
606 |
-
|
607 |
-
|
608 |
-
|
609 |
-
|
610 |
-
|
611 |
-
|
612 |
-
|
613 |
-
|
614 |
-
|
615 |
-
|
616 |
-
|
617 |
-
|
618 |
-
|
619 |
-
|
620 |
-
|
621 |
-
|
622 |
-
|
623 |
-
|
624 |
-
|
625 |
-
|
626 |
-
|
627 |
-
|
628 |
-
|
629 |
-
|
630 |
-
|
631 |
-
|
632 |
-
|
633 |
-
|
634 |
-
|
635 |
-
|
636 |
-
|
637 |
-
|
638 |
-
|
639 |
-
|
640 |
-
|
641 |
-
|
642 |
-
|
643 |
-
|
644 |
-
|
645 |
-
|
646 |
-
|
647 |
-
|
648 |
-
|
649 |
-
|
650 |
-
|
651 |
-
|
652 |
-
|
653 |
-
|
654 |
-
|
655 |
-
|
656 |
-
|
657 |
-
|
658 |
-
|
659 |
-
|
660 |
-
|
661 |
-
|
662 |
-
|
663 |
-
|
664 |
-
|
665 |
-
|
666 |
-
|
667 |
-
|
668 |
-
|
669 |
-
|
670 |
-
|
671 |
-
|
672 |
-
|
673 |
-
|
674 |
-
|
675 |
-
|
676 |
-
|
677 |
-
|
678 |
-
|
679 |
-
|
680 |
-
|
681 |
-
|
682 |
-
|
683 |
-
|
684 |
-
|
685 |
-
|
686 |
-
|
687 |
-
|
688 |
-
|
689 |
-
|
690 |
-
|
691 |
-
|
692 |
-
|
693 |
-
|
694 |
-
|
695 |
-
|
696 |
-
|
697 |
-
|
698 |
-
|
699 |
-
|
700 |
-
|
701 |
-
|
702 |
-
|
703 |
-
|
704 |
-
|
705 |
-
|
706 |
-
|
707 |
-
|
708 |
-
|
709 |
-
|
710 |
-
|
711 |
-
|
712 |
-
|
713 |
-
|
714 |
-
|
715 |
-
|
716 |
-
|
717 |
-
|
718 |
-
|
719 |
-
|
720 |
-
|
721 |
-
|
722 |
-
|
723 |
-
|
724 |
-
|
725 |
-
|
726 |
-
|
727 |
-
|
728 |
-
|
729 |
-
|
730 |
-
|
731 |
-
|
732 |
-
|
733 |
-
|
734 |
-
|
735 |
-
|
736 |
-
|
737 |
-
|
738 |
-
|
739 |
-
|
740 |
-
|
741 |
-
|
742 |
-
|
743 |
-
|
744 |
-
|
745 |
-
|
746 |
-
|
747 |
-
|
748 |
-
|
749 |
-
|
750 |
-
|
751 |
-
|
752 |
-
|
753 |
-
|
754 |
-
|
755 |
-
|
756 |
-
|
757 |
-
|
758 |
-
|
759 |
-
|
760 |
-
|
761 |
-
|
762 |
-
|
763 |
-
|
764 |
-
|
765 |
-
|
766 |
-
|
767 |
-
|
768 |
-
|
769 |
-
|
770 |
-
|
771 |
-
|
772 |
-
|
773 |
-
|
774 |
-
|
775 |
-
|
776 |
-
|
777 |
-
|
778 |
-
|
779 |
-
|
780 |
-
|
781 |
-
|
782 |
-
|
783 |
-
|
784 |
-
|
785 |
-
|
786 |
-
|
787 |
-
|
788 |
-
|
789 |
-
|
790 |
-
|
791 |
-
|
792 |
-
|
793 |
-
|
794 |
-
|
795 |
-
|
796 |
-
|
797 |
-
|
798 |
-
|
799 |
-
|
800 |
-
|
801 |
-
|
802 |
-
|
803 |
-
|
804 |
-
|
805 |
-
|
806 |
-
|
807 |
-
|
808 |
-
|
809 |
-
|
810 |
-
|
811 |
-
|
812 |
-
|
813 |
-
|
814 |
-
|
815 |
-
|
816 |
-
|
817 |
-
|
818 |
-
|
819 |
-
}
|
820 |
-
|
821 |
-
|
822 |
-
|
823 |
-
|
824 |
-
|
825 |
-
|
826 |
-
|
827 |
-
|
828 |
-
|
829 |
-
|
830 |
-
|
831 |
-
|
832 |
-
|
833 |
-
|
834 |
-
|
835 |
-
|
836 |
-
|
837 |
-
|
838 |
-
|
839 |
-
|
840 |
-
|
841 |
-
|
842 |
-
|
843 |
-
|
844 |
-
|
845 |
-
|
846 |
-
|
847 |
-
|
848 |
-
|
849 |
-
|
850 |
-
|
851 |
-
|
852 |
-
|
853 |
-
|
854 |
-
|
855 |
-
|
856 |
-
|
857 |
-
|
858 |
-
|
859 |
-
|
860 |
-
|
861 |
-
|
862 |
-
|
863 |
-
|
864 |
-
|
865 |
-
|
866 |
-
|
867 |
-
|
868 |
-
|
869 |
-
|
870 |
-
|
871 |
-
|
872 |
-
|
873 |
-
|
874 |
-
|
875 |
-
|
876 |
-
|
877 |
-
|
878 |
-
|
879 |
-
|
880 |
-
|
881 |
-
|
882 |
-
|
883 |
-
|
884 |
-
|
885 |
-
|
886 |
-
|
887 |
-
|
888 |
-
|
889 |
-
|
890 |
-
|
891 |
-
|
892 |
-
|
893 |
-
|
894 |
-
|
895 |
-
|
896 |
-
|
897 |
-
|
898 |
-
|
899 |
-
|
900 |
-
|
901 |
-
|
902 |
-
|
903 |
-
|
904 |
-
|
905 |
-
|
906 |
-
|
907 |
-
|
908 |
-
|
909 |
-
|
910 |
-
|
911 |
-
|
912 |
-
|
913 |
-
|
914 |
-
|
915 |
-
|
916 |
-
|
917 |
-
|
918 |
-
|
919 |
-
|
920 |
-
|
921 |
-
|
922 |
-
|
923 |
-
|
924 |
-
|
925 |
-
|
926 |
-
|
927 |
-
|
928 |
-
|
929 |
-
|
930 |
-
|
931 |
-
|
932 |
-
|
933 |
-
|
934 |
-
|
935 |
-
|
936 |
-
|
937 |
-
|
938 |
-
|
939 |
-
|
940 |
-
|
941 |
-
|
942 |
-
|
943 |
-
|
944 |
-
|
945 |
-
|
946 |
-
|
947 |
-
|
948 |
-
|
949 |
-
|
950 |
-
|
951 |
-
|
952 |
-
|
953 |
-
|
954 |
-
|
955 |
-
|
956 |
-
|
957 |
-
|
958 |
-
|
959 |
-
|
960 |
-
|
961 |
-
<
|
962 |
-
<
|
963 |
-
<
|
964 |
-
<th scope="row"><label for="
|
965 |
-
<td
|
966 |
-
|
967 |
-
|
968 |
-
</
|
969 |
-
|
970 |
-
|
971 |
-
|
972 |
-
|
973 |
-
|
974 |
-
|
975 |
-
|
976 |
-
|
977 |
-
|
978 |
-
|
979 |
-
<
|
980 |
-
|
981 |
-
|
982 |
-
|
983 |
-
|
984 |
-
|
985 |
-
|
986 |
-
|
987 |
-
|
988 |
-
|
989 |
-
|
990 |
-
|
991 |
-
|
992 |
-
|
993 |
-
</
|
994 |
-
|
995 |
-
</
|
996 |
-
<
|
997 |
-
|
998 |
-
|
999 |
-
|
1000 |
-
|
1001 |
-
|
1002 |
-
|
1003 |
-
<
|
1004 |
-
<
|
1005 |
-
<th scope="row"><label for="
|
1006 |
-
<td
|
1007 |
-
</tr>
|
1008 |
-
|
1009 |
-
|
1010 |
-
|
1011 |
-
|
1012 |
-
|
1013 |
-
|
1014 |
-
<
|
1015 |
-
<
|
1016 |
-
<
|
1017 |
-
<
|
1018 |
-
|
1019 |
-
|
1020 |
-
</
|
1021 |
-
</
|
1022 |
-
|
1023 |
-
|
1024 |
-
|
1025 |
-
|
1026 |
-
|
1027 |
-
|
1028 |
-
|
1029 |
-
|
1030 |
-
|
1031 |
-
|
1032 |
-
|
1033 |
-
|
1034 |
-
|
1035 |
-
|
1036 |
-
|
1037 |
-
|
1038 |
-
|
1039 |
-
|
1040 |
-
|
1041 |
-
|
1042 |
-
|
1043 |
-
|
1044 |
-
|
1045 |
-
|
1046 |
-
|
1047 |
-
|
1048 |
-
|
1049 |
-
|
1050 |
-
|
1051 |
-
|
1052 |
-
|
1053 |
-
|
1054 |
-
|
1055 |
-
|
1056 |
-
|
1057 |
-
|
1058 |
-
|
1059 |
-
|
1060 |
-
|
1061 |
-
|
1062 |
-
|
1063 |
-
|
1064 |
-
|
1065 |
-
|
1066 |
-
</
|
1067 |
-
|
1068 |
-
|
1069 |
-
|
1070 |
-
|
1071 |
-
|
1072 |
-
|
1073 |
-
|
1074 |
-
|
1075 |
-
</
|
1076 |
-
|
1077 |
-
|
1078 |
-
|
1079 |
-
|
1080 |
-
|
1081 |
-
|
1082 |
-
|
1083 |
-
|
1084 |
-
|
1085 |
-
|
1086 |
-
|
1087 |
-
|
1088 |
-
|
1089 |
-
|
1090 |
-
|
1091 |
-
|
1092 |
-
|
1093 |
-
|
1094 |
-
<
|
1095 |
-
|
1096 |
-
|
1097 |
-
|
1098 |
-
|
1099 |
-
|
1100 |
-
|
1101 |
-
|
1102 |
-
|
1103 |
-
|
1104 |
-
|
1105 |
-
|
1106 |
-
|
1107 |
-
|
1108 |
-
|
1109 |
-
|
1110 |
-
|
1111 |
-
|
1112 |
-
|
1113 |
-
|
1114 |
-
|
1115 |
-
|
1116 |
-
|
1117 |
-
|
1118 |
-
|
1119 |
-
|
1120 |
-
|
1121 |
-
|
1122 |
-
|
1123 |
-
|
1124 |
-
|
1125 |
-
|
1126 |
-
|
1127 |
-
</
|
1128 |
-
|
1129 |
-
|
1130 |
-
|
1131 |
-
|
1132 |
-
|
1133 |
-
|
1134 |
-
|
1135 |
-
|
1136 |
-
|
1137 |
-
|
1138 |
-
|
1139 |
-
|
1140 |
-
|
1141 |
-
|
1142 |
-
|
1143 |
-
|
1144 |
-
|
1145 |
-
|
1146 |
-
|
1147 |
-
|
1148 |
-
|
1149 |
-
|
1150 |
-
|
1151 |
-
|
1152 |
-
|
1153 |
-
|
1154 |
-
|
1155 |
-
|
1156 |
-
|
1157 |
-
|
1158 |
-
|
1159 |
-
|
1160 |
-
|
1161 |
-
|
1162 |
-
|
1163 |
-
|
1164 |
-
|
1165 |
-
|
1166 |
-
|
1167 |
-
|
1168 |
-
|
1169 |
-
|
1170 |
-
|
1171 |
-
|
1172 |
-
|
1173 |
-
|
1174 |
-
|
1175 |
-
|
1176 |
-
|
1177 |
-
|
1178 |
-
|
1179 |
-
|
1180 |
-
|
1181 |
-
|
1182 |
-
|
1183 |
-
|
1184 |
-
|
1185 |
-
|
1186 |
-
|
1187 |
-
|
1188 |
-
|
1189 |
-
|
1190 |
-
|
1191 |
-
|
1192 |
-
|
1193 |
-
|
1194 |
-
|
1195 |
-
|
1196 |
-
|
1197 |
-
|
1198 |
-
|
1199 |
-
|
1200 |
-
|
1201 |
-
|
1202 |
-
|
1203 |
-
|
1204 |
-
|
1205 |
-
|
1206 |
-
|
1207 |
-
|
1208 |
-
|
1209 |
-
|
1210 |
-
|
1211 |
-
|
1212 |
-
|
1213 |
-
|
1214 |
-
|
1215 |
-
|
1216 |
-
|
1217 |
-
|
1218 |
-
|
1219 |
-
|
1220 |
-
|
1221 |
-
|
1222 |
-
|
1223 |
-
|
1224 |
-
|
1225 |
-
|
1226 |
-
|
1227 |
-
|
1228 |
-
|
1229 |
-
|
1230 |
-
|
1231 |
-
|
1232 |
-
|
1233 |
-
|
1234 |
-
|
1235 |
-
|
1236 |
-
|
1237 |
-
|
1238 |
-
|
1239 |
-
|
1240 |
-
|
1241 |
-
|
1242 |
-
|
1243 |
-
|
1244 |
-
|
1245 |
-
|
1246 |
-
|
1247 |
-
|
1248 |
-
|
1249 |
-
|
1250 |
-
|
1251 |
-
|
1252 |
-
|
1253 |
-
|
1254 |
-
|
1255 |
-
|
1256 |
-
|
1257 |
-
|
1258 |
-
|
1259 |
-
|
1260 |
-
|
1261 |
-
|
1262 |
-
|
1263 |
-
|
1264 |
-
|
1265 |
-
|
1266 |
-
|
1267 |
-
|
1268 |
-
|
1269 |
-
|
1270 |
-
|
1271 |
-
|
1272 |
-
|
1273 |
-
|
1274 |
-
|
1275 |
-
|
1276 |
-
|
1277 |
-
|
1278 |
-
|
1279 |
-
|
1280 |
-
|
1281 |
-
|
1282 |
-
|
1283 |
-
|
1284 |
-
|
1285 |
-
|
1286 |
-
|
1287 |
-
|
1288 |
-
|
1289 |
-
|
1290 |
-
|
1291 |
-
|
1292 |
-
|
1293 |
-
|
1294 |
-
|
1295 |
-
|
1296 |
-
|
1297 |
-
|
1298 |
-
|
1299 |
-
|
1300 |
-
|
1301 |
-
|
1302 |
-
|
1303 |
-
|
1304 |
-
|
1305 |
-
|
1306 |
-
|
1307 |
-
|
1308 |
-
|
1309 |
-
|
1310 |
-
|
1311 |
-
|
1312 |
-
|
1313 |
-
|
1314 |
-
|
1315 |
-
|
1316 |
-
|
1317 |
-
|
1318 |
-
|
1319 |
-
|
1320 |
-
|
1321 |
-
|
1322 |
-
|
1323 |
-
|
1324 |
-
|
1325 |
-
|
1326 |
-
|
1327 |
-
|
1328 |
-
|
1329 |
-
|
1330 |
-
|
1331 |
-
|
1332 |
-
|
1333 |
-
|
1334 |
-
|
1335 |
-
|
1336 |
-
|
1337 |
-
|
1338 |
-
|
1339 |
-
|
1340 |
-
|
1341 |
-
|
1342 |
-
|
1343 |
-
|
1344 |
-
|
1345 |
-
|
1346 |
-
|
1347 |
-
|
1348 |
-
|
1349 |
-
|
1350 |
-
|
1351 |
-
|
1352 |
-
|
1353 |
-
|
1354 |
-
|
1355 |
-
|
1356 |
-
|
1357 |
-
|
1358 |
-
|
1359 |
-
|
1360 |
-
|
1361 |
-
|
1362 |
-
|
1363 |
-
|
1364 |
-
|
1365 |
-
|
1366 |
-
|
1367 |
-
|
1368 |
-
|
1369 |
-
|
1370 |
-
|
1371 |
-
|
1372 |
-
|
1373 |
-
|
1374 |
-
|
1375 |
-
|
1376 |
-
|
1377 |
-
|
1378 |
-
|
1379 |
-
|
1380 |
-
|
1381 |
-
|
1382 |
-
|
1383 |
-
|
1384 |
-
|
1385 |
-
|
1386 |
-
|
1387 |
-
|
1388 |
-
|
1389 |
-
|
1390 |
-
|
1391 |
-
|
1392 |
-
|
1393 |
-
|
1394 |
-
|
1395 |
-
|
1396 |
-
|
1397 |
-
|
1398 |
-
|
1399 |
-
|
1400 |
-
|
1401 |
-
|
1402 |
-
|
1403 |
-
|
1404 |
-
|
1405 |
-
|
1406 |
-
|
1407 |
-
|
1408 |
-
|
1409 |
-
|
1410 |
-
|
1411 |
-
|
1412 |
-
|
1413 |
-
|
1414 |
-
|
1415 |
-
|
1416 |
-
|
1417 |
-
|
1418 |
-
|
1419 |
-
|
1420 |
-
|
1421 |
-
|
1422 |
-
|
1423 |
-
|
1424 |
-
|
1425 |
-
|
1426 |
-
|
1427 |
-
|
1428 |
-
|
1429 |
-
|
1430 |
-
|
1431 |
-
|
1432 |
-
|
1433 |
-
|
1434 |
-
|
1435 |
-
|
1436 |
-
|
1437 |
-
|
1438 |
-
|
1439 |
-
|
1440 |
-
|
1441 |
-
|
1442 |
-
|
1443 |
-
|
1444 |
-
|
1445 |
-
|
1446 |
-
|
1447 |
-
|
1448 |
-
|
1449 |
-
|
1450 |
-
|
1451 |
-
|
1452 |
-
|
1453 |
-
|
1454 |
-
|
1455 |
-
|
1456 |
-
|
1457 |
-
|
1458 |
-
|
1459 |
-
|
1460 |
-
|
1461 |
-
|
1462 |
-
|
1463 |
-
|
1464 |
-
|
1465 |
-
|
1466 |
-
|
1467 |
-
|
1468 |
-
|
1469 |
-
|
1470 |
-
|
1471 |
-
|
1472 |
-
|
1473 |
-
|
1474 |
-
|
1475 |
-
|
1476 |
-
|
1477 |
-
|
1478 |
-
|
1479 |
-
|
1480 |
-
|
1481 |
-
|
1482 |
-
|
1483 |
-
|
1484 |
-
|
1485 |
-
|
1486 |
-
|
1487 |
-
|
1488 |
-
|
1489 |
-
|
1490 |
-
|
1491 |
-
|
1492 |
-
|
1493 |
-
|
1494 |
-
|
1495 |
-
|
1496 |
-
|
1497 |
-
|
1498 |
-
|
1499 |
-
|
1500 |
-
|
1501 |
-
|
1502 |
-
|
1503 |
-
|
1504 |
-
|
1505 |
-
|
1506 |
-
|
1507 |
-
|
1508 |
-
|
1509 |
-
|
1510 |
-
|
1511 |
-
|
1512 |
-
|
1513 |
-
|
1514 |
-
|
1515 |
-
|
1516 |
-
|
1517 |
-
|
1518 |
-
|
1519 |
-
|
1520 |
-
|
1521 |
-
|
1522 |
-
|
1523 |
-
|
1524 |
-
|
1525 |
-
|
1526 |
-
|
1527 |
-
|
1528 |
-
public function migrateBackupFolder() {
|
1529 |
-
$oldBackupFolder = WP_CONTENT_DIR . DIRECTORY_SEPARATOR . 'ShortpixelBackups';
|
1530 |
-
|
1531 |
-
if(!file_exists($oldBackupFolder)) return; //if old backup folder does not exist then there is nothing to do
|
1532 |
-
|
1533 |
-
if(!file_exists(SP_BACKUP_FOLDER)) {
|
1534 |
-
//we check that the backup folder exists, if not we create it so we can copy into it
|
1535 |
-
if(!mkdir(SP_BACKUP_FOLDER, 0777, true)) return;
|
1536 |
-
}
|
1537 |
-
|
1538 |
-
$scannedDirectory = array_diff(scandir($oldBackupFolder), array('..', '.'));
|
1539 |
-
foreach($scannedDirectory as $file) {
|
1540 |
-
@rename($oldBackupFolder.DIRECTORY_SEPARATOR.$file, SP_BACKUP_FOLDER.DIRECTORY_SEPARATOR.$file);
|
1541 |
-
}
|
1542 |
-
$scannedDirectory = array_diff(scandir($oldBackupFolder), array('..', '.'));
|
1543 |
-
if(empty($scannedDirectory)) {
|
1544 |
-
@rmdir($oldBackupFolder);
|
1545 |
-
}
|
1546 |
-
|
1547 |
-
return;
|
1548 |
-
}
|
1549 |
-
|
1550 |
-
|
1551 |
-
}
|
1552 |
-
|
1553 |
-
$pluginInstance = new WPShortPixel();
|
1554 |
-
global $pluginInstance;
|
1555 |
-
|
1556 |
-
?>
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Plugin Name: ShortPixel Image Optimizer
|
4 |
+
* Plugin URI: https://shortpixel.com/
|
5 |
+
* Description: ShortPixel optimizes images automatically, while guarding the quality of your images. Check your <a href="options-general.php?page=wp-shortpixel" target="_blank">Settings > ShortPixel</a> page on how to start optimizing your image library and make your website load faster.
|
6 |
+
* Version: 3.0.0
|
7 |
+
* Author: ShortPixel
|
8 |
+
* Author URI: https://shortpixel.com
|
9 |
+
*/
|
10 |
+
|
11 |
+
require_once('shortpixel_api.php');
|
12 |
+
require_once('shortpixel_queue.php');
|
13 |
+
require_once('shortpixel_view.php');
|
14 |
+
require_once( ABSPATH . 'wp-admin/includes/image.php' );
|
15 |
+
include_once( ABSPATH . 'wp-admin/includes/plugin.php' );
|
16 |
+
if ( !is_plugin_active( 'wpmandrill/wpmandrill.php' ) ) {
|
17 |
+
require_once( ABSPATH . 'wp-includes/pluggable.php' );//to avoid conflict with wpmandrill plugin
|
18 |
+
}
|
19 |
+
|
20 |
+
define('SP_RESET_ON_ACTIVATE', false);
|
21 |
+
|
22 |
+
define('PLUGIN_VERSION', "3.0.0");
|
23 |
+
define('SP_MAX_TIMEOUT', 10);
|
24 |
+
define('SP_BACKUP', 'ShortpixelBackups');
|
25 |
+
define('SP_BACKUP_FOLDER', WP_CONTENT_DIR . DIRECTORY_SEPARATOR . 'uploads' . DIRECTORY_SEPARATOR . SP_BACKUP);
|
26 |
+
define('MAX_API_RETRIES', 5);
|
27 |
+
$MAX_EXECUTION_TIME = ini_get('max_execution_time');
|
28 |
+
if ( is_numeric($MAX_EXECUTION_TIME) )
|
29 |
+
define('MAX_EXECUTION_TIME', $MAX_EXECUTION_TIME - 5 ); //in seconds
|
30 |
+
else
|
31 |
+
define('MAX_EXECUTION_TIME', 25 );
|
32 |
+
define("SP_MAX_RESULTS_QUERY", 6);
|
33 |
+
|
34 |
+
class WPShortPixel {
|
35 |
+
|
36 |
+
const BULK_EMPTY_QUEUE = 0;
|
37 |
+
|
38 |
+
private $_apiKey = '';
|
39 |
+
private $_compressionType = 1;
|
40 |
+
private $_processThumbnails = 1;
|
41 |
+
private $_CMYKtoRGBconversion = 1;
|
42 |
+
private $_backupImages = 1;
|
43 |
+
private $_verifiedKey = false;
|
44 |
+
|
45 |
+
private $_apiInterface = null;
|
46 |
+
private $prioQ = null;
|
47 |
+
private $view = null;
|
48 |
+
|
49 |
+
//handling older
|
50 |
+
public function WPShortPixel() {
|
51 |
+
$this->__construct();
|
52 |
+
}
|
53 |
+
|
54 |
+
public function __construct() {
|
55 |
+
session_start();
|
56 |
+
|
57 |
+
$this->populateOptions();
|
58 |
+
|
59 |
+
$this->_apiInterface = new ShortPixelAPI($this->_apiKey, $this->_compressionType, $this->_CMYKtoRGBconversion);
|
60 |
+
$this->prioQ = new ShortPixelQueue($this);
|
61 |
+
$this->view = new ShortPixelView($this);
|
62 |
+
|
63 |
+
define('QUOTA_EXCEEDED', "Quota Exceeded. <a href='https://shortpixel.com/login/".$this->_apiKey."' target='_blank'>Extend Quota</a>");
|
64 |
+
|
65 |
+
$this->setDefaultViewModeList();//set default mode as list. only @ first run
|
66 |
+
|
67 |
+
//add hook for image upload processing
|
68 |
+
add_filter( 'wp_generate_attachment_metadata', array( &$this, 'handleImageUpload' ), 10, 2 );
|
69 |
+
add_filter( 'manage_media_columns', array( &$this, 'columns' ) );//add media library column header
|
70 |
+
add_filter( 'plugin_action_links_' . plugin_basename(__FILE__), array(&$this, 'generatePluginLinks'));//for plugin settings page
|
71 |
+
|
72 |
+
//add_action( 'admin_footer', array(&$this, 'handleImageProcessing'));
|
73 |
+
add_action( 'manage_media_custom_column', array( &$this, 'generateCustomColumn' ), 10, 2 );//generate the media library column
|
74 |
+
|
75 |
+
//add settings page
|
76 |
+
add_action( 'admin_menu', array( &$this, 'registerSettingsPage' ) );//display SP in Settings menu
|
77 |
+
add_action( 'admin_menu', array( &$this, 'registerAdminPage' ) );
|
78 |
+
add_action( 'delete_attachment', array( &$this, 'handleDeleteAttachmentInBackup' ) );
|
79 |
+
add_action( 'load-upload.php', array( &$this, 'handleCustomBulk'));
|
80 |
+
|
81 |
+
//when plugin is activated run this
|
82 |
+
register_activation_hook( __FILE__, array( &$this, 'shortPixelActivatePlugin' ) );
|
83 |
+
register_deactivation_hook( __FILE__, array( &$this, 'shortPixelDeactivatePlugin' ) );
|
84 |
+
|
85 |
+
//automatic optimization
|
86 |
+
add_action( 'wp_ajax_shortpixel_image_processing', array( &$this, 'handleImageProcessing') );
|
87 |
+
//manual optimization
|
88 |
+
add_action( 'wp_ajax_shortpixel_manual_optimization', array(&$this, 'handleManualOptimization'));
|
89 |
+
//backup restore
|
90 |
+
add_action('admin_action_shortpixel_restore_backup', array(&$this, 'handleRestoreBackup'));
|
91 |
+
|
92 |
+
//This adds the constants used in PHP to be available also in JS
|
93 |
+
add_action( 'admin_footer', array( &$this, 'shortPixelJS') );
|
94 |
+
|
95 |
+
|
96 |
+
//example toolbar by fai, to be configured
|
97 |
+
add_action( 'admin_bar_menu', array( &$this, 'toolbar_shortpixel_processing'), 999 );
|
98 |
+
|
99 |
+
$this->migrateBackupFolder();
|
100 |
+
}
|
101 |
+
|
102 |
+
public function populateOptions() {
|
103 |
+
|
104 |
+
$this->_apiKey = self::getOpt('wp-short-pixel-apiKey', '');
|
105 |
+
$this->_verifiedKey = self::getOpt('wp-short-pixel-verifiedKey', $this->_verifiedKey);
|
106 |
+
$this->_compressionType = self::getOpt('wp-short-pixel-compression', $this->_compressionType);
|
107 |
+
$this->_processThumbnails = self::getOpt('wp-short-process_thumbnails', $this->_processThumbnails);
|
108 |
+
$this->_CMYKtoRGBconversion = self::getOpt('wp-short-pixel_cmyk2rgb', $this->_CMYKtoRGBconversion);
|
109 |
+
$this->_backupImages = self::getOpt('wp-short-backup_images', $this->_backupImages);
|
110 |
+
// the following practically set defaults for options if they're not set
|
111 |
+
self::getOpt( 'wp-short-pixel-fileCount', 0);
|
112 |
+
self::getOpt( 'wp-short-pixel-thumbnail-count', 0);//amount of optimized thumbnails
|
113 |
+
self::getOpt( 'wp-short-pixel-files-under-5-percent', 0);//amount of optimized thumbnails
|
114 |
+
self::getOpt( 'wp-short-pixel-savedSpace', 0);
|
115 |
+
self::getOpt( 'wp-short-pixel-api-retries', 0);//sometimes we need to retry processing/downloading a file multiple times
|
116 |
+
self::getOpt( 'wp-short-pixel-quota-exceeded', 0);
|
117 |
+
self::getOpt( 'wp-short-pixel-total-original', 0);//amount of original data
|
118 |
+
self::getOpt( 'wp-short-pixel-total-optimized', 0);//amount of optimized
|
119 |
+
self::getOpt( 'wp-short-pixel-protocol', 'https');
|
120 |
+
}
|
121 |
+
|
122 |
+
public function shortPixelActivatePlugin()//reset some params to avoid trouble for plugins that were activated/deactivated/activated
|
123 |
+
{
|
124 |
+
$this->prioQ->resetBulk();
|
125 |
+
if(SP_RESET_ON_ACTIVATE === true && WP_DEBUG === true) { //force reset plugin counters, only on specific occasions and on test environments
|
126 |
+
update_option( 'wp-short-pixel-fileCount', 0);
|
127 |
+
update_option( 'wp-short-pixel-thumbnail-count', 0);
|
128 |
+
update_option( 'wp-short-pixel-files-under-5-percent', 0);
|
129 |
+
update_option( 'wp-short-pixel-savedSpace', 0);
|
130 |
+
update_option( 'wp-short-pixel-api-retries', 0);//sometimes we need to retry processing/downloading a file multiple times
|
131 |
+
update_option( 'wp-short-pixel-quota-exceeded', 0);
|
132 |
+
update_option( 'wp-short-pixel-total-original', 0);//amount of original data
|
133 |
+
update_option( 'wp-short-pixel-total-optimized', 0);//amount of optimized
|
134 |
+
update_option( 'wp-short-pixel-bulk-ever-ran', 0);
|
135 |
+
delete_option('wp-short-pixel-priorityQueue');
|
136 |
+
unset($_SESSION["wp-short-pixel-priorityQueue"]);
|
137 |
+
}
|
138 |
+
}
|
139 |
+
|
140 |
+
public function shortPixelDeactivatePlugin()//reset some params to avoid trouble for plugins that were activated/deactivated/activated
|
141 |
+
{
|
142 |
+
$this->prioQ->resetBulk();
|
143 |
+
}
|
144 |
+
|
145 |
+
//set default move as "list". only set once, it won't try to set the default mode again.
|
146 |
+
public function setDefaultViewModeList()
|
147 |
+
{
|
148 |
+
if(get_option('wp-short-pixel-view-mode') === false)
|
149 |
+
{
|
150 |
+
add_option('wp-short-pixel-view-mode', 1, '', 'yes' );
|
151 |
+
if ( function_exists('get_currentuserinfo') )
|
152 |
+
{
|
153 |
+
global $current_user;
|
154 |
+
get_currentuserinfo();
|
155 |
+
$currentUserID = $current_user->ID;
|
156 |
+
update_user_meta($currentUserID, "wp_media_library_mode", "list");
|
157 |
+
}
|
158 |
+
}
|
159 |
+
|
160 |
+
}
|
161 |
+
|
162 |
+
static function log($message) {
|
163 |
+
if (WP_DEBUG === true) {
|
164 |
+
if (is_array($message) || is_object($message)) {
|
165 |
+
error_log(print_r($message, true));
|
166 |
+
} else {
|
167 |
+
error_log($message);
|
168 |
+
}
|
169 |
+
}
|
170 |
+
}
|
171 |
+
|
172 |
+
function shortPixelJS() { ?>
|
173 |
+
<script type="text/javascript" >
|
174 |
+
jQuery(document).ready(function($){
|
175 |
+
ShortPixel.setOptions({
|
176 |
+
STATUS_SUCCESS: <?= ShortPixelAPI::STATUS_SUCCESS ?>,
|
177 |
+
STATUS_EMPTY_QUEUE: <?= self::BULK_EMPTY_QUEUE ?>,
|
178 |
+
STATUS_ERROR: <?= ShortPixelAPI::STATUS_ERROR ?>,
|
179 |
+
STATUS_FAIL: <?= ShortPixelAPI::STATUS_FAIL ?>,
|
180 |
+
STATUS_SKIP: <?= ShortPixelAPI::STATUS_SKIP ?>,
|
181 |
+
STATUS_QUOTA_EXCEEDED: <?= ShortPixelAPI::STATUS_QUOTA_EXCEEDED ?>,
|
182 |
+
WP_PLUGIN_URL: '<?= WP_PLUGIN_URL ?>',
|
183 |
+
API_KEY: "<?= $this->_apiKey ?>"
|
184 |
+
});
|
185 |
+
});
|
186 |
+
</script> <?php
|
187 |
+
wp_enqueue_style('short-pixel.css', plugins_url('/css/short-pixel.css',__FILE__) );
|
188 |
+
}
|
189 |
+
|
190 |
+
function toolbar_shortpixel_processing( $wp_admin_bar ) {
|
191 |
+
wp_enqueue_script('short-pixel.js', plugins_url('/js/short-pixel.js',__FILE__) );
|
192 |
+
|
193 |
+
$extraClasses = " shortpixel-hide";
|
194 |
+
$tooltip = "ShortPixel optimizing...";
|
195 |
+
$icon = "shortpixel.png";
|
196 |
+
$link = 'upload.php?page=wp-short-pixel-bulk';
|
197 |
+
$blank = "";
|
198 |
+
if($this->prioQ->processing()) {
|
199 |
+
$extraClasses = " shortpixel-processing";
|
200 |
+
}
|
201 |
+
self::log("TOOLBAR: Quota exceeded: " . self::getOpt( 'wp-short-pixel-quota-exceeded', 0));
|
202 |
+
if(self::getOpt( 'wp-short-pixel-quota-exceeded', 0)) {
|
203 |
+
$extraClasses = " shortpixel-alert shortpixel-quota-exceeded";
|
204 |
+
$tooltip = "ShortPixel quota exceeded. Click to top-up";
|
205 |
+
$link = "http://shortpixel.com/login/" . $this->_apiKey;
|
206 |
+
$blank = '_blank';
|
207 |
+
//$icon = "shortpixel-alert.png";
|
208 |
+
}
|
209 |
+
self::log("TB: Start: " . $this->prioQ->getStartBulkId() . ", stop: " . $this->prioQ->getStopBulkId() . " PrioQ: "
|
210 |
+
.json_encode($this->prioQ->get()));
|
211 |
+
|
212 |
+
$args = array(
|
213 |
+
'id' => 'shortpixel_processing',
|
214 |
+
'title' => '<div title="' . $tooltip . '" ><img src="'
|
215 |
+
. WP_PLUGIN_URL . '/shortpixel-image-optimiser/img/' . $icon . '"><span class="shp-alert">!</span></div>',
|
216 |
+
'href' => $link,
|
217 |
+
'meta' => array('target'=> $blank, 'class' => 'shortpixel-toolbar-processing' . $extraClasses)
|
218 |
+
);
|
219 |
+
$wp_admin_bar->add_node( $args );
|
220 |
+
}
|
221 |
+
|
222 |
+
public static function getOpt($key, $default) {
|
223 |
+
if(get_option($key) === false) {
|
224 |
+
add_option( $key, $default, '', 'yes' );
|
225 |
+
}
|
226 |
+
return get_option($key);
|
227 |
+
}
|
228 |
+
|
229 |
+
public function handleCustomBulk() {
|
230 |
+
// 1. get the action
|
231 |
+
$wp_list_table = _get_list_table('WP_Media_List_Table');
|
232 |
+
$action = $wp_list_table->current_action();
|
233 |
+
|
234 |
+
switch($action) {
|
235 |
+
// 2. Perform the action
|
236 |
+
case 'short-pixel-bulk':
|
237 |
+
// security check
|
238 |
+
check_admin_referer('bulk-media');
|
239 |
+
if(!is_array($_GET['media'])) {
|
240 |
+
break;
|
241 |
+
}
|
242 |
+
$mediaIds = array_reverse($_GET['media']);
|
243 |
+
foreach( $mediaIds as $ID ) {
|
244 |
+
$meta = wp_get_attachment_metadata($ID);
|
245 |
+
if( (!isset($meta['ShortPixel']) || !isset($meta['ShortPixel']['WaitingProcessing']) || $meta['ShortPixel']['WaitingProcessing'] != true)
|
246 |
+
&& (!isset($meta['ShortPixelImprovement']) || $meta['ShortPixelImprovement'] != 'Optimization N/A')) {
|
247 |
+
$this->prioQ->push($ID);
|
248 |
+
$meta['ShortPixel']['WaitingProcessing'] = true;
|
249 |
+
wp_update_attachment_metadata($ID, $meta);
|
250 |
+
}
|
251 |
+
}
|
252 |
+
break;
|
253 |
+
}
|
254 |
+
}
|
255 |
+
|
256 |
+
public function handleImageUpload($meta, $ID = null)
|
257 |
+
{
|
258 |
+
if( !$this->_verifiedKey) {// no API Key set/verified -> do nothing here, just return
|
259 |
+
return $meta;
|
260 |
+
}
|
261 |
+
//else
|
262 |
+
self::log("IMG: Auto-analyzing file ID #{$ID}");
|
263 |
+
|
264 |
+
if( self::isProcessable($ID) == false )
|
265 |
+
{//not a file that we can process
|
266 |
+
$meta['ShortPixelImprovement'] = 'Optimization N/A';
|
267 |
+
return $meta;
|
268 |
+
}
|
269 |
+
else
|
270 |
+
{//the kind of file we can process. goody.
|
271 |
+
$this->prioQ->push($ID);
|
272 |
+
$URLsAndPATHs = $this->getURLsAndPATHs($ID, $meta);
|
273 |
+
$this->_apiInterface->doRequests($URLsAndPATHs['URLs'], false, $ID);//send a processing request right after a file was uploaded, do NOT wait for response
|
274 |
+
self::log("IMG: sent: " . json_encode($URLsAndPATHs));
|
275 |
+
$meta['ShortPixel']['WaitingProcessing'] = true;
|
276 |
+
return $meta;
|
277 |
+
}
|
278 |
+
|
279 |
+
}//end handleImageUpload
|
280 |
+
|
281 |
+
public function getCurrentBulkItemsCount(){
|
282 |
+
global $wpdb;
|
283 |
+
|
284 |
+
$startQueryID = $this->prioQ->getFlagBulkId();
|
285 |
+
$endQueryID = $this->prioQ->getStopBulkId();
|
286 |
+
|
287 |
+
if ( $startQueryID <= $endQueryID ) {
|
288 |
+
return 0;
|
289 |
+
}
|
290 |
+
$queryPostMeta = "SELECT COUNT(DISTINCT post_id) items FROM " . $wpdb->prefix . "postmeta
|
291 |
+
WHERE ( post_id <= $startQueryID AND post_id > $endQueryID ) AND (
|
292 |
+
meta_key = '_wp_attached_file'
|
293 |
+
OR meta_key = '_wp_attachment_metadata' )";
|
294 |
+
$res = $wpdb->get_results($queryPostMeta);
|
295 |
+
return $res[0]->items;
|
296 |
+
}
|
297 |
+
|
298 |
+
public function getBulkItemsFromDb(){
|
299 |
+
global $wpdb;
|
300 |
+
|
301 |
+
$startQueryID = $this->prioQ->getStartBulkId();
|
302 |
+
$endQueryID = $this->prioQ->getStopBulkId();
|
303 |
+
$skippedAlreadyProcessed = 0;
|
304 |
+
|
305 |
+
if ( $startQueryID <= $endQueryID ) {
|
306 |
+
return false;
|
307 |
+
}
|
308 |
+
$idList = array();
|
309 |
+
for ($sanityCheck = 0, $crtStartQueryID = $startQueryID;
|
310 |
+
$crtStartQueryID > $endQueryID && count($idList) < 3; $sanityCheck++) {
|
311 |
+
|
312 |
+
self::log("GETDB: current StartID: " . $crtStartQueryID);
|
313 |
+
|
314 |
+
$queryPostMeta = "SELECT * FROM " . $wpdb->prefix . "postmeta
|
315 |
+
WHERE ( post_id <= $crtStartQueryID AND post_id > $endQueryID )
|
316 |
+
AND ( meta_key = '_wp_attached_file' OR meta_key = '_wp_attachment_metadata' )
|
317 |
+
ORDER BY post_id DESC
|
318 |
+
LIMIT " . SP_MAX_RESULTS_QUERY;
|
319 |
+
$resultsPostMeta = $wpdb->get_results($queryPostMeta);
|
320 |
+
|
321 |
+
if($sanityCheck > 1000) {
|
322 |
+
die("oops! $crtStartQueryID -- $startQueryID -> $endQueryID");
|
323 |
+
}
|
324 |
+
if ( empty($resultsPostMeta) ) {
|
325 |
+
$crtStartQueryID -= SP_MAX_RESULTS_QUERY;
|
326 |
+
continue;
|
327 |
+
}
|
328 |
+
|
329 |
+
foreach ( $resultsPostMeta as $itemMetaData ) {
|
330 |
+
$crtStartQueryID = $itemMetaData->post_id;
|
331 |
+
if(!in_array($crtStartQueryID, $idList) && self::isProcessable($crtStartQueryID)) {
|
332 |
+
$meta = wp_get_attachment_metadata($crtStartQueryID);
|
333 |
+
if(!isset($meta["ShortPixelImprovement"]) || !is_numeric($meta["ShortPixelImprovement"])) {
|
334 |
+
$idList[] = $crtStartQueryID;
|
335 |
+
} elseif($itemMetaData->meta_key == '_wp_attachment_metadata') { //count skipped
|
336 |
+
$skippedAlreadyProcessed++;
|
337 |
+
}
|
338 |
+
}
|
339 |
+
}
|
340 |
+
if(!count($idList) && $crtStartQueryID <= $startQueryID) {
|
341 |
+
//daca n-am adaugat niciuna pana acum, n-are sens sa mai selectez zona asta de id-uri in bulk-ul asta.
|
342 |
+
$leapStart = $this->prioQ->getStartBulkId();
|
343 |
+
$crtStartQueryID = $startQueryID = $itemMetaData->post_id - 1; //decrement it so we don't select it again
|
344 |
+
$res = self::countAllProcessedFiles($leapStart, $crtStartQueryID);
|
345 |
+
$skippedAlreadyProcessed += $res["mainFiles"];
|
346 |
+
$this->prioQ->setStartBulkId($startQueryID);
|
347 |
+
} else {
|
348 |
+
$crtStartQueryID--;
|
349 |
+
}
|
350 |
+
}
|
351 |
+
return array("ids" => $idList, "skipped" => $skippedAlreadyProcessed);
|
352 |
+
}
|
353 |
+
|
354 |
+
/**
|
355 |
+
* Get last added items from priority
|
356 |
+
* @return type
|
357 |
+
*/
|
358 |
+
public function getFromPrioAndCheck() {
|
359 |
+
$ids = array();
|
360 |
+
$removeIds = array();
|
361 |
+
|
362 |
+
$idsPrio = $this->prioQ->get();
|
363 |
+
for($i = count($idsPrio) - 1, $cnt = 0; $i>=0 && $cnt < 3; $i--) {
|
364 |
+
$id = $idsPrio[$i];
|
365 |
+
if(wp_get_attachment_url($id)) {
|
366 |
+
$ids[] = $id; //valid ID
|
367 |
+
} else {
|
368 |
+
$removeIds[] = $id;//absent, to remove
|
369 |
+
}
|
370 |
+
}
|
371 |
+
foreach($removeIds as $rId){
|
372 |
+
self::log("HIP: Unfound ID $rID Remove from Priority Queue: ".json_encode(get_option($this->prioQ->get())));
|
373 |
+
$this->prioQ->remove($rId);
|
374 |
+
}
|
375 |
+
return $ids;
|
376 |
+
}
|
377 |
+
|
378 |
+
public function handleImageProcessing($ID = null) {
|
379 |
+
//die();
|
380 |
+
//0: check key
|
381 |
+
if( $this->_verifiedKey == false) {
|
382 |
+
echo "Missing API Key";
|
383 |
+
die();
|
384 |
+
}
|
385 |
+
|
386 |
+
self::log("HIP: 0 Priority Queue: ".json_encode($this->prioQ->get()));
|
387 |
+
|
388 |
+
//1: get 3 ids to process. Take them with priority from the queue
|
389 |
+
$ids = $this->getFromPrioAndCheck();
|
390 |
+
if(count($ids) < 3 ) { //take from bulk if bulk processing active
|
391 |
+
$bulkStatus = $this->prioQ->bulkRunning();
|
392 |
+
if($bulkStatus =='running') {
|
393 |
+
$res = $this->getBulkItemsFromDb();
|
394 |
+
$bulkItems = $res['ids'];
|
395 |
+
if($bulkItems){
|
396 |
+
$ids = array_merge ($ids, $bulkItems);
|
397 |
+
}
|
398 |
+
$this->prioQ->addBulkSkipped($res['skipped']);
|
399 |
+
}
|
400 |
+
}
|
401 |
+
if ($ids === false || count( $ids ) == 0 ){
|
402 |
+
$bulkEverRan = $this->prioQ->stopBulk();
|
403 |
+
$avg = self::getAverageCompression();
|
404 |
+
$fileCount = get_option('wp-short-pixel-fileCount');
|
405 |
+
die(json_encode(array("Status" => self::BULK_EMPTY_QUEUE,
|
406 |
+
"Message" => 'Empty queue ' . $this->prioQ->getStartBulkId() . '->' . $this->prioQ->getStopBulkId(),
|
407 |
+
"BulkStatus" => ($this->prioQ->bulkRunning()
|
408 |
+
? "1" : ($this->prioQ->bulkPaused() ? "2" : "0")),
|
409 |
+
"AverageCompression" => $avg,
|
410 |
+
"FileCount" => $fileCount,
|
411 |
+
"BulkPercent" => $this->prioQ->getBulkPercent())));
|
412 |
+
}
|
413 |
+
|
414 |
+
self::log("HIP: 1 Prio Queue: ".json_encode($this->prioQ->get()));
|
415 |
+
|
416 |
+
//2: Send up to 3 files to the server for processing
|
417 |
+
for($i = 0; $i < min(3, count($ids)); $i++) {
|
418 |
+
$ID = $ids[$i];
|
419 |
+
$URLsAndPATHs = $this->sendToProcessing($ID);
|
420 |
+
if($i == 0) { //save for later use
|
421 |
+
$firstUrlAndPaths = $URLsAndPATHs;
|
422 |
+
}
|
423 |
+
}
|
424 |
+
|
425 |
+
self::log("HIP: 2 Prio Queue: ".json_encode($this->prioQ->get()));
|
426 |
+
|
427 |
+
//3: Retrieve the file for the first element of the list
|
428 |
+
$ID = $ids[0];
|
429 |
+
$result = $this->_apiInterface->processImage($firstUrlAndPaths['URLs'], $firstUrlAndPaths['PATHs'], $ID);
|
430 |
+
$result["ImageID"] = $ID;
|
431 |
+
|
432 |
+
self::log("HIP: 3 Prio Queue: ".json_encode($this->prioQ->get()));
|
433 |
+
|
434 |
+
//4: update counters and priority list
|
435 |
+
if( $result["Status"] == ShortPixelAPI::STATUS_SUCCESS) {
|
436 |
+
self::log("HIP: Image ID $ID optimized successfully: ".json_encode($result));
|
437 |
+
$prio = $this->prioQ->remove($ID);
|
438 |
+
if(!$prio && $ID <= $this->prioQ->getStartBulkId()) {
|
439 |
+
$this->prioQ->setStartBulkId($ID - 1);
|
440 |
+
$this->prioQ->logBulkProgress();
|
441 |
+
|
442 |
+
$deltaBulkPercent = $this->prioQ->getDeltaBulkPercent();
|
443 |
+
$msg = $this->bulkProgressMessage($deltaBulkPercent, $this->prioQ->getTimeRemaining());
|
444 |
+
|
445 |
+
$thumb = $bkThumb = "";
|
446 |
+
$percent = 0;
|
447 |
+
$meta = wp_get_attachment_metadata($ID);
|
448 |
+
if(isset($meta["ShortPixelImprovement"]) && isset($meta["file"])){
|
449 |
+
$percent = $meta["ShortPixelImprovement"];
|
450 |
+
|
451 |
+
$filePath = explode("/", $meta["file"]);
|
452 |
+
$uploadsUrl = content_url() . "/uploads/";
|
453 |
+
$urlPath = implode("/", array_slice($filePath, 0, count($filePath) - 1));
|
454 |
+
$thumb = (isset($meta["sizes"]["medium"]) ? $meta["sizes"]["medium"]["file"] : (isset($meta["sizes"]["thumbnail"]) ? $meta["sizes"]["thumbnail"]["file"]: ""));
|
455 |
+
if(strlen($thumb) && get_option('wp-short-backup_images')) {
|
456 |
+
$bkThumb = $uploadsUrl . SP_BACKUP . "/" . $urlPath . "/" . $thumb;
|
457 |
+
}
|
458 |
+
if(strlen($thumb)) {
|
459 |
+
$thumb = $uploadsUrl . $urlPath . "/" . $thumb;
|
460 |
+
}
|
461 |
+
$result["Thumb"] = $thumb;
|
462 |
+
$result["BkThumb"] = $bkThumb;
|
463 |
+
$result["BulkPercent"] = $this->prioQ->getBulkPercent();;
|
464 |
+
$result["BulkMsg"] = $msg;
|
465 |
+
}
|
466 |
+
}
|
467 |
+
}
|
468 |
+
elseif ($result["Status"] == ShortPixelAPI::STATUS_SKIP
|
469 |
+
|| $result["Status"] == ShortPixelAPI::STATUS_FAIL) {
|
470 |
+
$prio = $this->prioQ->remove($ID);
|
471 |
+
if(!$prio && $ID <= $this->prioQ->getStartBulkId()) {
|
472 |
+
$this->prioQ->setStartBulkId($ID - 1);
|
473 |
+
}
|
474 |
+
}
|
475 |
+
die(json_encode($result));
|
476 |
+
}
|
477 |
+
|
478 |
+
private function sendToProcessing($ID) {
|
479 |
+
$URLsAndPATHs = $this->getURLsAndPATHs($ID);
|
480 |
+
$this->_apiInterface->doRequests($URLsAndPATHs['URLs'], false, $ID);//send a request, do NOT wait for response
|
481 |
+
$meta = wp_get_attachment_metadata($ID);
|
482 |
+
$meta['ShortPixel']['WaitingProcessing'] = true;
|
483 |
+
wp_update_attachment_metadata($ID, $meta);
|
484 |
+
return $URLsAndPATHs;
|
485 |
+
}
|
486 |
+
|
487 |
+
public function handleManualOptimization() {
|
488 |
+
$imageId = intval($_GET['image_id']);
|
489 |
+
|
490 |
+
if(self::isProcessable($imageId)) {
|
491 |
+
$this->prioQ->push($imageId);
|
492 |
+
$this->sendToProcessing($imageId);
|
493 |
+
$ret = array("Status" => ShortPixelAPI::STATUS_SUCCESS, "message" => "");
|
494 |
+
} else {
|
495 |
+
die(var_dump($pathParts));
|
496 |
+
}
|
497 |
+
die(json_encode($ret));
|
498 |
+
|
499 |
+
$urlList[] = wp_get_attachment_url($attachmentID);
|
500 |
+
$filePath[] = get_attached_file($attachmentID);
|
501 |
+
$meta = wp_get_attachment_metadata($attachmentID);
|
502 |
+
|
503 |
+
$processThumbnails = get_option('wp-short-process_thumbnails');
|
504 |
+
|
505 |
+
//process all files (including thumbs)
|
506 |
+
if($processThumbnails && !empty($meta['sizes'])) {
|
507 |
+
//we generate an array with the URLs that need to be handled
|
508 |
+
$SubDir = $this->_apiInterface->returnSubDir($meta['file']);
|
509 |
+
foreach($meta['sizes'] as $thumbnailInfo)
|
510 |
+
{
|
511 |
+
$urlList[]= str_replace(ShortPixelAPI::MB_basename($filePath[0]), $thumbnailInfo['file'], $urlList[0]);
|
512 |
+
$filePath[] = str_replace(ShortPixelAPI::MB_basename($filePath[0]), $thumbnailInfo['file'], $filePath[0]);
|
513 |
+
}
|
514 |
+
}
|
515 |
+
|
516 |
+
$result = $this->_apiInterface->processImage($urlList, $filePath, $attachmentID);//request to process all the images
|
517 |
+
|
518 |
+
if ( !is_array($result) )//there was an error, we save it in ShortPixelImprovement data
|
519 |
+
$this->handleError($attachmentID, $result);
|
520 |
+
|
521 |
+
// store the referring webpage location
|
522 |
+
$sendback = wp_get_referer();
|
523 |
+
// sanitize the referring webpage location
|
524 |
+
$sendback = preg_replace('|[^a-z0-9-~+_.?#=&;,/:]|i', '', $sendback);
|
525 |
+
// send the user back where they came from
|
526 |
+
wp_redirect($sendback);
|
527 |
+
// we are done,
|
528 |
+
}
|
529 |
+
|
530 |
+
//save error in file's meta data
|
531 |
+
public function handleError($ID, $result)
|
532 |
+
{
|
533 |
+
$meta = wp_get_attachment_metadata($ID);
|
534 |
+
$meta['ShortPixelImprovement'] = $result;
|
535 |
+
wp_update_attachment_metadata($ID, $meta);
|
536 |
+
}
|
537 |
+
|
538 |
+
public function handleRestoreBackup() {
|
539 |
+
$attachmentID = intval($_GET['attachment_ID']);
|
540 |
+
|
541 |
+
$file = get_attached_file($attachmentID);
|
542 |
+
$meta = wp_get_attachment_metadata($attachmentID);
|
543 |
+
$pathInfo = pathinfo($file);
|
544 |
+
|
545 |
+
$fileExtension = strtolower(substr($file,strrpos($file,".")+1));
|
546 |
+
$SubDir = $this->_apiInterface->returnSubDir($file);
|
547 |
+
|
548 |
+
//sometimes the month of original file and backup can differ
|
549 |
+
if ( !file_exists(SP_BACKUP_FOLDER . DIRECTORY_SEPARATOR . $SubDir . ShortPixelAPI::MB_basename($file)) )
|
550 |
+
$SubDir = date("Y") . "/" . date("m") . "/";
|
551 |
+
|
552 |
+
try {
|
553 |
+
//main file
|
554 |
+
@rename(SP_BACKUP_FOLDER . DIRECTORY_SEPARATOR . $SubDir . ShortPixelAPI::MB_basename($file), $file);
|
555 |
+
|
556 |
+
//overwriting thumbnails
|
557 |
+
if( !empty($meta['file']) ) {
|
558 |
+
foreach($meta["sizes"] as $size => $imageData) {
|
559 |
+
$source = SP_BACKUP_FOLDER . DIRECTORY_SEPARATOR . $SubDir . $imageData['file'];
|
560 |
+
$destination = $pathInfo['dirname'] . DIRECTORY_SEPARATOR . $imageData['file'];
|
561 |
+
@rename($source, $destination);
|
562 |
+
}
|
563 |
+
}
|
564 |
+
unset($meta["ShortPixelImprovement"]);
|
565 |
+
unset($meta['ShortPixel']['WaitingProcessing']);
|
566 |
+
wp_update_attachment_metadata($attachmentID, $meta);
|
567 |
+
|
568 |
+
} catch(Exception $e) {
|
569 |
+
//what to do, what to do?
|
570 |
+
}
|
571 |
+
// store the referring webpage location
|
572 |
+
$sendback = wp_get_referer();
|
573 |
+
// sanitize the referring webpage location
|
574 |
+
$sendback = preg_replace('|[^a-z0-9-~+_.?#=&;,/:]|i', '', $sendback);
|
575 |
+
// send the user back where they came from
|
576 |
+
wp_redirect($sendback);
|
577 |
+
// we are done
|
578 |
+
}
|
579 |
+
|
580 |
+
|
581 |
+
public function handleDeleteAttachmentInBackup($ID) {
|
582 |
+
$file = get_attached_file($ID);
|
583 |
+
$meta = wp_get_attachment_metadata($ID);
|
584 |
+
|
585 |
+
if(self::isProcessable($ID) != false)
|
586 |
+
{
|
587 |
+
$SubDir = $this->_apiInterface->returnSubDir($file);
|
588 |
+
try {
|
589 |
+
$SubDir = $this->_apiInterface->returnSubDir($file);
|
590 |
+
|
591 |
+
@unlink(SP_BACKUP_FOLDER . DIRECTORY_SEPARATOR . $SubDir . ShortPixelAPI::MB_basename($file));
|
592 |
+
|
593 |
+
if ( !empty($meta['file']) )
|
594 |
+
{
|
595 |
+
$filesPath = SP_BACKUP_FOLDER . DIRECTORY_SEPARATOR . $SubDir;//base BACKUP path
|
596 |
+
//remove thumbs thumbnails
|
597 |
+
if(isset($meta["sizes"])) {
|
598 |
+
foreach($meta["sizes"] as $size => $imageData) {
|
599 |
+
@unlink($filesPath . ShortPixelAPI::MB_basename($imageData['file']));//remove thumbs
|
600 |
+
}
|
601 |
+
}
|
602 |
+
}
|
603 |
+
|
604 |
+
} catch(Exception $e) {
|
605 |
+
//what to do, what to do?
|
606 |
+
}
|
607 |
+
}
|
608 |
+
}
|
609 |
+
|
610 |
+
public function registerSettingsPage() {
|
611 |
+
add_options_page( 'ShortPixel Settings', 'ShortPixel', 'manage_options', 'wp-shortpixel', array($this, 'renderSettingsMenu'));
|
612 |
+
}
|
613 |
+
|
614 |
+
function registerAdminPage( ) {
|
615 |
+
add_media_page( 'ShortPixel Bulk Process', 'Bulk ShortPixel', 'edit_others_posts', 'wp-short-pixel-bulk', array( &$this, 'bulkProcess' ) );
|
616 |
+
}
|
617 |
+
|
618 |
+
public function checkQuotaAndAlert() {
|
619 |
+
$quotaData = $this->getQuotaInformation();
|
620 |
+
if ( !$quotaData['APIKeyValid']) {
|
621 |
+
return $quotaData;
|
622 |
+
}
|
623 |
+
if($quotaData['APICallsQuotaNumeric'] + $quotaData['APICallsQuotaOneTimeNumeric'] > $quotaData['APICallsMadeNumeric'] + $quotaData['APICallsMadeOneTimeNumeric']) {
|
624 |
+
update_option('wp-short-pixel-quota-exceeded','0');
|
625 |
+
?><script>var shortPixelQuotaExceeded = 0;</script><?php
|
626 |
+
}
|
627 |
+
else {
|
628 |
+
$this->view->displayQuotaExceededAlert($quotaData);
|
629 |
+
?><script>var shortPixelQuotaExceeded = 1;</script><?php
|
630 |
+
}
|
631 |
+
return $quotaData;
|
632 |
+
}
|
633 |
+
|
634 |
+
public function bulkProcess() {
|
635 |
+
global $wpdb;
|
636 |
+
|
637 |
+
if( $this->_verifiedKey == false ) {//invalid API Key
|
638 |
+
$this->view->displayApiKeyAlert();
|
639 |
+
return;
|
640 |
+
}
|
641 |
+
|
642 |
+
$quotaData = $this->checkQuotaAndAlert();
|
643 |
+
if(self::getOpt('wp-short-pixel-quota-exceeded', 0) != 0) return;
|
644 |
+
|
645 |
+
if(isset($_POST['bulkProcessPause']))
|
646 |
+
{//pause an ongoing bulk processing, it might be needed sometimes
|
647 |
+
$this->prioQ->pauseBulk();
|
648 |
+
}
|
649 |
+
|
650 |
+
if(isset($_POST["bulkProcess"]))
|
651 |
+
{
|
652 |
+
//set the thumbnails option
|
653 |
+
if ( isset($_POST['thumbnails']) ) {
|
654 |
+
update_option('wp-short-process_thumbnails', 1);
|
655 |
+
} else {
|
656 |
+
update_option('wp-short-process_thumbnails', 0);
|
657 |
+
}
|
658 |
+
$this->prioQ->startBulk();
|
659 |
+
self::log("BULK: Start: " . $this->prioQ->getStartBulkId() . ", stop: " . $this->prioQ->getStopBulkId() . " PrioQ: "
|
660 |
+
.json_encode($this->prioQ->get()));
|
661 |
+
}//end bulk process was clicked
|
662 |
+
|
663 |
+
if(isset($_POST["bulkProcessResume"]))
|
664 |
+
{
|
665 |
+
$this->prioQ->resumeBulk();
|
666 |
+
}//resume was clicked
|
667 |
+
|
668 |
+
//figure out all the files that could be processed
|
669 |
+
$qry = "SELECT count(*) FilesToBeProcessed FROM " . $wpdb->prefix . "postmeta
|
670 |
+
WHERE meta_key = '_wp_attached_file' ";
|
671 |
+
$allFiles = $wpdb->get_results($qry);
|
672 |
+
//figure out the files that are left to be processed
|
673 |
+
$qry_left = "SELECT count(*) FilesLeftToBeProcessed FROM " . $wpdb->prefix . "postmeta
|
674 |
+
WHERE meta_key = '_wp_attached_file' AND post_id <= " . $this->prioQ->getStartBulkId();
|
675 |
+
$filesLeft = $wpdb->get_results($qry_left);
|
676 |
+
|
677 |
+
if ( $filesLeft[0]->FilesLeftToBeProcessed > 0 && $this->prioQ->bulkRunning() )//bulk processing was started and is still running
|
678 |
+
{
|
679 |
+
$msg = $this->bulkProgressMessage($this->prioQ->getDeltaBulkPercent(), $this->prioQ->getTimeRemaining());
|
680 |
+
$this->view->displayBulkProcessingRunning($this->prioQ->getBulkPercent(), $msg);
|
681 |
+
|
682 |
+
// $imagesLeft = $filesLeft[0]->FilesLeftToBeProcessed;
|
683 |
+
// $totalImages = $allFiles[0]->FilesToBeProcessed;
|
684 |
+
// echo "<p>{$imagesLeft} out of {$totalImages} images left to process.</p>";
|
685 |
+
// echo ' <a class="button button-secondary" href="' . get_admin_url() . 'upload.php">Media Library</a> ';
|
686 |
+
} else
|
687 |
+
{
|
688 |
+
if($this->prioQ->bulkRan() && !$this->prioQ->bulkPaused()) {
|
689 |
+
$this->prioQ->markBulkComplete();
|
690 |
+
}
|
691 |
+
|
692 |
+
//image count
|
693 |
+
$imageCount = $this->countAllProcessableFiles();
|
694 |
+
$imgProcessedCount = $this->countAllProcessedFiles();
|
695 |
+
$imageOnlyThumbs = $imageCount['totalFiles'] - $imageCount['mainFiles'];
|
696 |
+
$thumbsProcessedCount = self::getOpt( 'wp-short-pixel-thumbnail-count', 0);//amount of optimized thumbnails
|
697 |
+
$under5PercentCount = self::getOpt( 'wp-short-pixel-files-under-5-percent', 0);//amount of under 5% optimized imgs.
|
698 |
+
|
699 |
+
//average compression
|
700 |
+
$averageCompression = self::getAverageCompression();
|
701 |
+
// $this->view->displayBulkProcessingForm($imageCount, $imageOnlyThumbs, $this->prioQ->bulkRan(), $averageCompression,
|
702 |
+
$this->view->displayBulkProcessingForm($imageCount, $imgProcessedCount, $thumbsProcessedCount, $under5PercentCount,
|
703 |
+
$this->prioQ->bulkRan(), $averageCompression, get_option('wp-short-pixel-fileCount'),
|
704 |
+
self::formatBytes(get_option('wp-short-pixel-savedSpace')), $this->prioQ->bulkPaused() ? $this->prioQ->getBulkPercent() : false);
|
705 |
+
}
|
706 |
+
}
|
707 |
+
//end bulk processing
|
708 |
+
|
709 |
+
public function bulkProgressMessage($percent, $minutes) {
|
710 |
+
$timeEst = "";
|
711 |
+
self::log("bulkProgressMessage(): percent: " . $percent);
|
712 |
+
if($percent < 1 || $minutes == 0) {
|
713 |
+
$timeEst = "";
|
714 |
+
} elseif( $minutes > 2880) {
|
715 |
+
$timeEst = "~ " . round($minutes / 1440) . " days left";
|
716 |
+
} elseif ($minutes > 240) {
|
717 |
+
$timeEst = "~ " . round($minutes / 60) . " hours left";
|
718 |
+
} elseif ($minutes > 60) {
|
719 |
+
$timeEst = "~ " . round($minutes / 60) . " hours " . round($minutes%60/10) * 10 . " min. left";
|
720 |
+
} elseif ($minutes > 20) {
|
721 |
+
$timeEst = "~ " . round($minutes / 10) * 10 . " minutes left";
|
722 |
+
} else {
|
723 |
+
$timeEst = "~ " . $minutes . " minutes left";
|
724 |
+
}
|
725 |
+
return $timeEst;
|
726 |
+
}
|
727 |
+
|
728 |
+
public function emptyBackup(){
|
729 |
+
if(file_exists(SP_BACKUP_FOLDER)) {
|
730 |
+
|
731 |
+
//extract all images from DB in an array. of course
|
732 |
+
$attachments = null;
|
733 |
+
$attachments = get_posts( array(
|
734 |
+
'numberposts' => -1,
|
735 |
+
'post_type' => 'attachment',
|
736 |
+
'post_mime_type' => 'image'
|
737 |
+
));
|
738 |
+
|
739 |
+
|
740 |
+
//parse all images and set the right flag that the image has no backup
|
741 |
+
foreach($attachments as $attachment)
|
742 |
+
{
|
743 |
+
if(self::isProcessable(get_attached_file($attachment->ID)) == false) continue;
|
744 |
+
|
745 |
+
$meta = wp_get_attachment_metadata($attachment->ID);
|
746 |
+
$meta['ShortPixel']['NoBackup'] = true;
|
747 |
+
wp_update_attachment_metadata($attachment->ID, $meta);
|
748 |
+
}
|
749 |
+
|
750 |
+
//delete the actual files on disk
|
751 |
+
$this->deleteDir(SP_BACKUP_FOLDER);//call a recursive function to empty files and sub-dirs in backup dir
|
752 |
+
}
|
753 |
+
}
|
754 |
+
|
755 |
+
public function renderSettingsMenu() {
|
756 |
+
if ( !current_user_can( 'manage_options' ) ) {
|
757 |
+
wp_die('You do not have sufficient permissions to access this page.');
|
758 |
+
}
|
759 |
+
|
760 |
+
$quotaData = $this->checkQuotaAndAlert();
|
761 |
+
|
762 |
+
echo '<h1>ShortPixel Plugin Settings</h1>';
|
763 |
+
echo '<p>
|
764 |
+
<a href="https://shortpixel.com" target="_blank">ShortPixel.com</a> |
|
765 |
+
<a href="https://wordpress.org/plugins/shortpixel-image-optimiser/installation/" target="_blank">Installation </a> |
|
766 |
+
<a href="https://shortpixel.com/contact" target="_blank">Support </a>
|
767 |
+
</p>';
|
768 |
+
echo '<p>New images uploaded to the Media Library will be optimized automatically.<br/>If you have existing images you would like to optimize, you can use the <a href="' . get_admin_url() . 'upload.php?page=wp-short-pixel-bulk">Bulk Optimization Tool</a>.</p>';
|
769 |
+
|
770 |
+
$noticeHTML = "<br/><div style=\"background-color: #fff; border-left: 4px solid %s; box-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.1); padding: 1px 12px;\"><p>%s</p></div>";
|
771 |
+
|
772 |
+
//by default we try to fetch the API Key from wp-config.php (if defined)
|
773 |
+
if ( !isset($_POST['submit']) && !get_option('wp-short-pixel-verifiedKey') && defined("SHORTPIXEL_API_KEY") && strlen(SHORTPIXEL_API_KEY) == 20 )
|
774 |
+
{
|
775 |
+
$_POST['validate'] = "validate";
|
776 |
+
$_POST['key'] = SHORTPIXEL_API_KEY;
|
777 |
+
}
|
778 |
+
|
779 |
+
if(isset($_POST['submit']) || isset($_POST['validate'])) {
|
780 |
+
|
781 |
+
//handle API Key - common for submit and validate
|
782 |
+
$_POST['key'] = trim(str_replace("*","",$_POST['key']));
|
783 |
+
|
784 |
+
if ( strlen($_POST['key']) <> 20 )
|
785 |
+
{
|
786 |
+
$KeyLength = strlen($_POST['key']);
|
787 |
+
|
788 |
+
printf($noticeHTML, '#ff0000', "The key you provided has " . $KeyLength . " characters. The API key should have 20 characters, letters and numbers only.<BR> <b>Please check that the API key is the same as the one you received in your confirmation email.</b><BR>
|
789 |
+
If this problem persists, please contact us at <a href='mailto:support@shortpixel.com?Subject=API Key issues' target='_top'>support@shortpixel.com</a> or <a href='https://shortpixel.com/contact' target='_blank'>here</a>.");
|
790 |
+
}
|
791 |
+
else
|
792 |
+
{
|
793 |
+
$validityData = $this->getQuotaInformation($_POST['key'], true);
|
794 |
+
|
795 |
+
$this->_apiKey = $_POST['key'];
|
796 |
+
$this->_apiInterface->setApiKey($this->_apiKey);
|
797 |
+
update_option('wp-short-pixel-apiKey', $_POST['key']);
|
798 |
+
if($validityData['APIKeyValid']) {
|
799 |
+
if(isset($_POST['validate'])) {
|
800 |
+
//display notification
|
801 |
+
if(in_array($_SERVER["SERVER_ADDR"], array("127.0.0.1","::1"))) {
|
802 |
+
printf($noticeHTML, '#FFC800', "API Key is valid but your server seems to have a local address.
|
803 |
+
Please make sure that your server is accessible from the Internet before using the API or otherwise we won't be able to optimize them.");
|
804 |
+
} else {
|
805 |
+
|
806 |
+
if ( function_exists("is_multisite") && is_multisite() )
|
807 |
+
printf($noticeHTML, '#7ad03a', "API Key valid! <br>You seem to be running a multisite, please note that API Key can also be configured in wp-config.php like this:<BR> <b>define('SHORTPIXEL_API_KEY', '".$this->_apiKey."');</b>");
|
808 |
+
else
|
809 |
+
printf($noticeHTML, '#7ad03a', 'API Key valid!');
|
810 |
+
}
|
811 |
+
}
|
812 |
+
update_option('wp-short-pixel-verifiedKey', true);
|
813 |
+
$this->_verifiedKey = true;
|
814 |
+
//test that the "uploads" have the right rights and also we can create the backup dir for ShortPixel
|
815 |
+
if ( !file_exists(SP_BACKUP_FOLDER) && !@mkdir(SP_BACKUP_FOLDER, 0777, true) )
|
816 |
+
printf($noticeHTML, '#ff0000', "There is something preventing us to create a new folder for backing up your original files.<BR>
|
817 |
+
Please make sure that folder <b>" .
|
818 |
+
WP_CONTENT_DIR . DIRECTORY_SEPARATOR . "uploads</b> has the necessary write and read rights." );
|
819 |
+
} else {
|
820 |
+
if(isset($_POST['validate'])) {
|
821 |
+
//display notification
|
822 |
+
printf($noticeHTML, '#ff0000', $validityData["Message"]);
|
823 |
+
}
|
824 |
+
update_option('wp-short-pixel-verifiedKey', false);
|
825 |
+
$this->_verifiedKey = false;
|
826 |
+
}
|
827 |
+
}
|
828 |
+
|
829 |
+
|
830 |
+
//if save button - we process the rest of the form elements
|
831 |
+
if(isset($_POST['submit'])) {
|
832 |
+
update_option('wp-short-pixel-compression', $_POST['compressionType']);
|
833 |
+
$this->_compressionType = $_POST['compressionType'];
|
834 |
+
$this->_apiInterface->setCompressionType($this->_compressionType);
|
835 |
+
if(isset($_POST['thumbnails'])) { $this->_processThumbnails = 1; } else { $this->_processThumbnails = 0; }
|
836 |
+
if(isset($_POST['backupImages'])) { $this->_backupImages = 1; } else { $this->_backupImages = 0; }
|
837 |
+
if(isset($_POST['cmyk2rgb'])) { $this->_CMYKtoRGBconversion = 1; } else { $this->_CMYKtoRGBconversion = 0; }
|
838 |
+
update_option('wp-short-process_thumbnails', $this->_processThumbnails);
|
839 |
+
update_option('wp-short-backup_images', $this->_backupImages);
|
840 |
+
update_option('wp-short-pixel_cmyk2rgb', $this->_CMYKtoRGBconversion);
|
841 |
+
}
|
842 |
+
}
|
843 |
+
|
844 |
+
|
845 |
+
//empty backup
|
846 |
+
if(isset($_POST['emptyBackup'])) {
|
847 |
+
$this->emptyBackup();
|
848 |
+
}
|
849 |
+
|
850 |
+
$checked = '';
|
851 |
+
if($this->_processThumbnails) { $checked = 'checked'; }
|
852 |
+
|
853 |
+
$checkedBackupImages = '';
|
854 |
+
if($this->_backupImages) { $checkedBackupImages = 'checked'; }
|
855 |
+
|
856 |
+
$cmyk2rgb = '';
|
857 |
+
if($this->_CMYKtoRGBconversion) { $cmyk2rgb = 'checked'; }
|
858 |
+
|
859 |
+
|
860 |
+
$formHTML = <<< HTML
|
861 |
+
<form name='wp_shortpixel_options' action='' method='post' id='wp_shortpixel_options'>
|
862 |
+
<table class="form-table">
|
863 |
+
<tbody><tr>
|
864 |
+
<th scope="row"><label for="key">API Key:</label></th>
|
865 |
+
<td><input name="key" type="text" id="key" value="{$this->_apiKey}" class="regular-text">
|
866 |
+
<input type="submit" name="validate" id="validate" class="button button-primary" title="Validate the provided API key" value="Validate">
|
867 |
+
</td>
|
868 |
+
</tr>
|
869 |
+
HTML;
|
870 |
+
|
871 |
+
if(!$this->_verifiedKey) {
|
872 |
+
|
873 |
+
//if invalid key we display the link to the API Key
|
874 |
+
$formHTML .= '<tr><td style="padding-left: 0px;" colspan="2">Don’t have an API Key? <a href="https://shortpixel.com/wp-apikey" target="_blank">Sign up, it’s free.</a></td></tr>';
|
875 |
+
$formHTML .= '</form>';
|
876 |
+
} else {
|
877 |
+
//if valid key we display the rest of the options
|
878 |
+
$formHTML .= <<< HTML
|
879 |
+
<tr><th scope="row">
|
880 |
+
<label for="compressionType">Compression type:</label>
|
881 |
+
</th><td>
|
882 |
+
HTML;
|
883 |
+
|
884 |
+
if($this->_compressionType == 1) {
|
885 |
+
$formHTML .= '<input type="radio" name="compressionType" value="1" checked>Lossy</br></br>';
|
886 |
+
$formHTML .= '<input type="radio" name="compressionType" value="0" >Lossless';
|
887 |
+
} else {
|
888 |
+
$formHTML .= '<input type="radio" name="compressionType" value="1">Lossy</br></br>';
|
889 |
+
$formHTML .= '<input type="radio" name="compressionType" value="0" checked>Lossless';
|
890 |
+
}
|
891 |
+
|
892 |
+
$formHTML .= <<<HTML
|
893 |
+
</td>
|
894 |
+
</tr>
|
895 |
+
</tbody></table>
|
896 |
+
<p style="color: #818181;">
|
897 |
+
<b>Lossy compression: </b>lossy has a better compression rate than lossless compression.</br>The resulting image
|
898 |
+
is not 100% identical with the original. Works well for photos taken with your camera.</br></br>
|
899 |
+
<b>Lossless compression: </b> the shrunk image will be identical with the original and smaller in size.</br>Use this
|
900 |
+
when you do not want to lose any of the original image's details. Works best for technical drawings,
|
901 |
+
clip art and comics.
|
902 |
+
</p>
|
903 |
+
<table class="form-table">
|
904 |
+
<tbody><tr>
|
905 |
+
<th scope="row"><label for="thumbnails">Image thumbnails:</label></th>
|
906 |
+
<td><input name="thumbnails" type="checkbox" id="thumbnails" {$checked}> Apply compression also to image thumbnails.</td>
|
907 |
+
</tr>
|
908 |
+
<tr>
|
909 |
+
<th scope="row"><label for="backupImages">Image backup</label></th>
|
910 |
+
<td>
|
911 |
+
<input name="backupImages" type="checkbox" id="backupImages" {$checkedBackupImages}> Save and keep a backup of your original images in a separate folder.
|
912 |
+
</td>
|
913 |
+
</tr>
|
914 |
+
<tr>
|
915 |
+
<th scope="row"><label for="backupImages">CMYK to RGB conversion</label></th>
|
916 |
+
<td>
|
917 |
+
<input name="cmyk2rgb" type="checkbox" id="cmyk2rgb" {$cmyk2rgb}>Adjust your images for computer and mobile screen display.
|
918 |
+
</td>
|
919 |
+
</tr>
|
920 |
+
</tr>
|
921 |
+
</tbody></table>
|
922 |
+
<p class="submit">
|
923 |
+
<input type="submit" name="submit" id="submit" class="button button-primary" title="Save Changes" value="Save Changes">
|
924 |
+
<a class="button button-primary" title="Process all the images in your Media Library" href="upload.php?page=wp-short-pixel-bulk">Bulk Process</a>
|
925 |
+
</p>
|
926 |
+
</form>
|
927 |
+
<script>
|
928 |
+
var rad = document.wp_shortpixel_options.compressionType;
|
929 |
+
var prev = null;
|
930 |
+
for(var i = 0; i < rad.length; i++) {
|
931 |
+
rad[i].onclick = function() {
|
932 |
+
|
933 |
+
if(this !== prev) {
|
934 |
+
prev = this;
|
935 |
+
}
|
936 |
+
alert('This type of optimization will apply to new uploaded images. <BR>Images that were already processed will not be re-optimized.');
|
937 |
+
};
|
938 |
+
}
|
939 |
+
</script>
|
940 |
+
HTML;
|
941 |
+
}
|
942 |
+
|
943 |
+
echo $formHTML;
|
944 |
+
|
945 |
+
if($this->_verifiedKey) {
|
946 |
+
$fileCount = number_format(get_option('wp-short-pixel-fileCount'));
|
947 |
+
$savedSpace = self::formatBytes(get_option('wp-short-pixel-savedSpace'),2);
|
948 |
+
$averageCompression = self::getAverageCompression();
|
949 |
+
$savedBandwidth = self::formatBytes(get_option('wp-short-pixel-savedSpace') * 10000,2);
|
950 |
+
if (is_numeric($quotaData['APICallsQuota'])) {
|
951 |
+
$quotaData['APICallsQuota'] .= "/month";
|
952 |
+
}
|
953 |
+
$backupFolderSize = self::formatBytes(self::folderSize(SP_BACKUP_FOLDER));
|
954 |
+
$remainingImages = $quotaData['APICallsQuotaNumeric'] + $quotaData['APICallsQuotaOneTimeNumeric'] - $quotaData['APICallsMadeNumeric'] - $quotaData['APICallsMadeOneTimeNumeric'];
|
955 |
+
$remainingImages = ( $remainingImages < 0 ) ? 0 : number_format($remainingImages);
|
956 |
+
$totalCallsMade = number_format($quotaData['APICallsMadeNumeric'] + $quotaData['APICallsMadeOneTimeNumeric']);
|
957 |
+
|
958 |
+
$statHTML = <<< HTML
|
959 |
+
<a id="facts"></a>
|
960 |
+
<h3>Your ShortPixel Stats</h3>
|
961 |
+
<table class="form-table">
|
962 |
+
<tbody>
|
963 |
+
<tr>
|
964 |
+
<th scope="row"><label for="averagCompression">Average compression of your files:</label></th>
|
965 |
+
<td>$averageCompression%</td>
|
966 |
+
</tr>
|
967 |
+
<tr>
|
968 |
+
<th scope="row"><label for="savedSpace">Saved disk space by ShortPixel</label></th>
|
969 |
+
<td>$savedSpace</td>
|
970 |
+
</tr>
|
971 |
+
<tr>
|
972 |
+
<th scope="row"><label for="savedBandwidth">Bandwith* saved with ShortPixel:</label></th>
|
973 |
+
<td>$savedBandwidth</td>
|
974 |
+
</tr>
|
975 |
+
</tbody></table>
|
976 |
+
|
977 |
+
<p style="padding-top: 0px; color: #818181;" >* Saved bandwidth is calculated at 10,000 impressions/image</p>
|
978 |
+
|
979 |
+
<h3>Your ShortPixel Plan</h3>
|
980 |
+
<table class="form-table">
|
981 |
+
<tbody>
|
982 |
+
<tr>
|
983 |
+
<th scope="row" bgcolor="#ffffff"><label for="apiQuota">Your ShortPixel plan</label></th>
|
984 |
+
<td bgcolor="#ffffff">{$quotaData['APICallsQuota']}/month ( <a href="https://shortpixel.com/login/{$this->_apiKey}" target="_blank">Need More? See the options available</a> )
|
985 |
+
</tr>
|
986 |
+
<tr>
|
987 |
+
<th scope="row"><label for="usedQUota">One time credits:</label></th>
|
988 |
+
<td>{$quotaData['APICallsQuotaOneTimeNumeric']}</td>
|
989 |
+
</tr>
|
990 |
+
<tr>
|
991 |
+
<th scope="row"><label for="usedQUota">Number of images processed this month:</label></th>
|
992 |
+
<td>{$totalCallsMade} (<a href="https://api.shortpixel.com/v2/report.php?key={$this->_apiKey}" target="_blank">see report</a>)</td>
|
993 |
+
</tr>
|
994 |
+
<tr>
|
995 |
+
<th scope="row"><label for="remainingImages">Remaining** images in your plan: </label></th>
|
996 |
+
<td>{$remainingImages} images</td>
|
997 |
+
</tr>
|
998 |
+
</tbody></table>
|
999 |
+
|
1000 |
+
<p style="padding-top: 0px; color: #818181;" >** Increase your image quota by <a href="https://shortpixel.com/login/{$this->_apiKey}" target="_blank">upgrading</a> your ShortPixel plan.</p>
|
1001 |
+
|
1002 |
+
<table class="form-table">
|
1003 |
+
<tbody>
|
1004 |
+
<tr>
|
1005 |
+
<th scope="row"><label for="totalFiles">Total number of processed files:</label></th>
|
1006 |
+
<td>{$fileCount}</td>
|
1007 |
+
</tr>
|
1008 |
+
|
1009 |
+
|
1010 |
+
|
1011 |
+
HTML;
|
1012 |
+
if($this->_backupImages) {
|
1013 |
+
$statHTML .= <<< HTML
|
1014 |
+
<form action="" method="POST">
|
1015 |
+
<tr>
|
1016 |
+
<th scope="row"><label for="sizeBackup">Original images are stored in a backup folder. Your backup folder size is now:</label></th>
|
1017 |
+
<td>
|
1018 |
+
{$backupFolderSize}
|
1019 |
+
<input type="submit" style="margin-left: 15px; vertical-align: middle;" class="button button-secondary" name="emptyBackup" value="Empty backups"/>
|
1020 |
+
</td>
|
1021 |
+
</tr>
|
1022 |
+
</form>
|
1023 |
+
HTML;
|
1024 |
+
}
|
1025 |
+
|
1026 |
+
$statHTML .= <<< HTML
|
1027 |
+
</tbody></table>
|
1028 |
+
HTML;
|
1029 |
+
|
1030 |
+
echo $statHTML;
|
1031 |
+
|
1032 |
+
|
1033 |
+
}
|
1034 |
+
|
1035 |
+
}
|
1036 |
+
|
1037 |
+
public function getAverageCompression(){
|
1038 |
+
return get_option('wp-short-pixel-total-optimized') > 0
|
1039 |
+
? round(( 1 - ( get_option('wp-short-pixel-total-optimized') / get_option('wp-short-pixel-total-original') ) ) * 100, 2)
|
1040 |
+
: 0;
|
1041 |
+
}
|
1042 |
+
|
1043 |
+
public function getQuotaInformation($apiKey = null, $appendUserAgent = false) {
|
1044 |
+
|
1045 |
+
if(is_null($apiKey)) { $apiKey = $this->_apiKey; }
|
1046 |
+
|
1047 |
+
$requestURL = 'https://api.shortpixel.com/v2/api-status.php';
|
1048 |
+
$args = array('timeout'=> SP_MAX_TIMEOUT,
|
1049 |
+
'sslverify' => false,
|
1050 |
+
'body' => array('key' => $apiKey)
|
1051 |
+
);
|
1052 |
+
|
1053 |
+
if($appendUserAgent) {
|
1054 |
+
$args['body']['useragent'] = "Agent" . urlencode($_SERVER['HTTP_USER_AGENT']);
|
1055 |
+
}
|
1056 |
+
$response = wp_remote_post($requestURL, $args);
|
1057 |
+
|
1058 |
+
if(is_wp_error( $response )) //some hosting providers won't allow https:// POST connections so we try http:// as well
|
1059 |
+
$response = wp_remote_post(str_replace('https://', 'http://', $requestURL), $args);
|
1060 |
+
|
1061 |
+
if(is_wp_error( $response ))
|
1062 |
+
$response = wp_remote_get(str_replace('https://', 'http://', $requestURL), $args);
|
1063 |
+
|
1064 |
+
$defaultData = array(
|
1065 |
+
"APIKeyValid" => false,
|
1066 |
+
"Message" => 'API Key could not be validated due to a connectivity error.<BR>Your firewall may be blocking us. Please contact your hosting provider and ask them to allow connections from your site to IP 176.9.106.46.<BR> If you still cannot validate your API Key after this, please <a href="https://shortpixel.com/contact" target="_blank">contact us</a> and we will try to help. ',
|
1067 |
+
"APICallsMade" => 'Information unavailable. Please check your API key.',
|
1068 |
+
"APICallsQuota" => 'Information unavailable. Please check your API key.');
|
1069 |
+
|
1070 |
+
if(is_object($response) && get_class($response) == 'WP_Error') {
|
1071 |
+
|
1072 |
+
$urlElements = parse_url($requestURL);
|
1073 |
+
$portConnect = @fsockopen($urlElements['host'],8,$errno,$errstr,15);
|
1074 |
+
if(!$portConnect)
|
1075 |
+
$defaultData['Message'] .= "<BR>Debug info: <i>$errstr</i>";
|
1076 |
+
|
1077 |
+
return $defaultData;
|
1078 |
+
}
|
1079 |
+
|
1080 |
+
if($response['response']['code'] != 200) {
|
1081 |
+
return $defaultData;
|
1082 |
+
}
|
1083 |
+
|
1084 |
+
$data = $response['body'];
|
1085 |
+
$data = $this->parseJSON($data);
|
1086 |
+
|
1087 |
+
if(empty($data)) { return $defaultData; }
|
1088 |
+
|
1089 |
+
if($data->Status->Code != 2) {
|
1090 |
+
$defaultData['Message'] = $data->Status->Message;
|
1091 |
+
return $defaultData;
|
1092 |
+
}
|
1093 |
+
|
1094 |
+
if ( ( $data->APICallsMade + $data->APICallsMadeOneTime ) < ( $data->APICallsQuota + $data->APICallsQuotaOneTime ) ) //reset quota exceeded flag -> user is allowed to process more images.
|
1095 |
+
update_option('wp-short-pixel-quota-exceeded',0);
|
1096 |
+
else
|
1097 |
+
update_option('wp-short-pixel-quota-exceeded',1);//activate quota limiting
|
1098 |
+
|
1099 |
+
return array(
|
1100 |
+
"APIKeyValid" => true,
|
1101 |
+
"APICallsMade" => number_format($data->APICallsMade) . ' images',
|
1102 |
+
"APICallsQuota" => number_format($data->APICallsQuota) . ' images',
|
1103 |
+
"APICallsMadeOneTime" => number_format($data->APICallsMadeOneTime) . ' images',
|
1104 |
+
"APICallsQuotaOneTime" => number_format($data->APICallsQuotaOneTime) . ' images',
|
1105 |
+
"APICallsMadeNumeric" => $data->APICallsMade,
|
1106 |
+
"APICallsQuotaNumeric" => $data->APICallsQuota,
|
1107 |
+
"APICallsMadeOneTimeNumeric" => $data->APICallsMadeOneTime,
|
1108 |
+
"APICallsQuotaOneTimeNumeric" => $data->APICallsQuotaOneTime
|
1109 |
+
);
|
1110 |
+
|
1111 |
+
|
1112 |
+
}
|
1113 |
+
|
1114 |
+
public function generateCustomColumn( $column_name, $id ) {
|
1115 |
+
if( 'wp-shortPixel' == $column_name ) {
|
1116 |
+
$data = wp_get_attachment_metadata($id);
|
1117 |
+
$file = get_attached_file($id);
|
1118 |
+
$fileExtension = strtolower(substr($file,strrpos($file,".")+1));
|
1119 |
+
|
1120 |
+
print "<div id='sp-msg-{$id}'>";
|
1121 |
+
|
1122 |
+
if ( empty($data) )
|
1123 |
+
{
|
1124 |
+
if ( $fileExtension <> "pdf" )
|
1125 |
+
{
|
1126 |
+
if(!$this->_verifiedKey)
|
1127 |
+
print 'Invalid API Key. <a href="options-general.php?page=wp-shortpixel">Check your Settings</a>';
|
1128 |
+
else
|
1129 |
+
print 'Optimization N/A';
|
1130 |
+
}
|
1131 |
+
else
|
1132 |
+
{
|
1133 |
+
if ( get_option('wp-short-pixel-quota-exceeded') )
|
1134 |
+
{
|
1135 |
+
print QUOTA_EXCEEDED;
|
1136 |
+
return;
|
1137 |
+
}
|
1138 |
+
else
|
1139 |
+
{
|
1140 |
+
print 'PDF not processed';
|
1141 |
+
print " | <a href=\"javascript:manualOptimization({$id})\">Optimize now</a>";
|
1142 |
+
return;
|
1143 |
+
}
|
1144 |
+
}
|
1145 |
+
}
|
1146 |
+
elseif ( isset( $data['ShortPixelImprovement'] ) )
|
1147 |
+
{
|
1148 |
+
if(isset($meta['ShortPixel']['BulkProcessing']))
|
1149 |
+
{
|
1150 |
+
if ( get_option('wp-short-pixel-quota-exceeded') )
|
1151 |
+
{
|
1152 |
+
print QUOTA_EXCEEDED;
|
1153 |
+
}
|
1154 |
+
else
|
1155 |
+
{
|
1156 |
+
print 'Waiting for bulk processing';
|
1157 |
+
print " | <a href=\"javascript:manualOptimization({$id})\">Optimize now</a>";
|
1158 |
+
}
|
1159 |
+
}
|
1160 |
+
elseif( is_numeric($data['ShortPixelImprovement']) && !isset($data['ShortPixel']['NoBackup']) ) {
|
1161 |
+
|
1162 |
+
if ( $data['ShortPixelImprovement'] < 5 )
|
1163 |
+
{
|
1164 |
+
print $data['ShortPixelImprovement'] . '%';
|
1165 |
+
print " optimized<BR> Bonus processing";
|
1166 |
+
|
1167 |
+
}
|
1168 |
+
else
|
1169 |
+
{
|
1170 |
+
print 'Reduced by ';
|
1171 |
+
print $data['ShortPixelImprovement'] . '%';
|
1172 |
+
}
|
1173 |
+
if ( get_option('wp-short-backup_images') ) //display restore backup option only when backup is active
|
1174 |
+
print " | <a href=\"admin.php?action=shortpixel_restore_backup&attachment_ID={$id}\">Restore backup</a>";
|
1175 |
+
}
|
1176 |
+
elseif ( is_numeric($data['ShortPixelImprovement']) )
|
1177 |
+
{
|
1178 |
+
if ( $data['ShortPixelImprovement'] < 5 )
|
1179 |
+
{
|
1180 |
+
print $data['ShortPixelImprovement'] . '%';
|
1181 |
+
print " optimized<BR> Bonus processing";
|
1182 |
+
|
1183 |
+
}
|
1184 |
+
else
|
1185 |
+
{
|
1186 |
+
print 'Reduced by ';
|
1187 |
+
print $data['ShortPixelImprovement'] . '%';
|
1188 |
+
}
|
1189 |
+
}
|
1190 |
+
elseif ( $data['ShortPixelImprovement'] <> "Optimization N/A" )
|
1191 |
+
{
|
1192 |
+
if ( trim(strip_tags($data['ShortPixelImprovement'])) == "Quota exceeded" )
|
1193 |
+
{
|
1194 |
+
print QUOTA_EXCEEDED;
|
1195 |
+
if ( !get_option('wp-short-pixel-quota-exceeded') )
|
1196 |
+
print " | <a href=\"javascript:manualOptimization({$id})\">Try again</a>";
|
1197 |
+
}
|
1198 |
+
elseif ( trim(strip_tags($data['ShortPixelImprovement'])) == "Cannot write optimized file" )
|
1199 |
+
{
|
1200 |
+
print $data['ShortPixelImprovement'];
|
1201 |
+
print " - <a href='https://shortpixel.com/faq#cannot-write-optimized-file' target='_blank'>Why?</a>";
|
1202 |
+
}
|
1203 |
+
else
|
1204 |
+
{
|
1205 |
+
print $data['ShortPixelImprovement'];
|
1206 |
+
print " | <a href=\"javascript:manualOptimization({$id})\">Try again</a>";
|
1207 |
+
}
|
1208 |
+
}
|
1209 |
+
else
|
1210 |
+
{
|
1211 |
+
print "Optimization N/A";
|
1212 |
+
}
|
1213 |
+
} elseif(isset($data['ShortPixel']['WaitingProcessing'])) {
|
1214 |
+
if ( get_option('wp-short-pixel-quota-exceeded') )
|
1215 |
+
{
|
1216 |
+
print QUOTA_EXCEEDED;
|
1217 |
+
}
|
1218 |
+
else
|
1219 |
+
{
|
1220 |
+
print "<img src=\"" . WP_PLUGIN_URL . "/shortpixel-image-optimiser/img/loading.gif\">Image waiting to be processed
|
1221 |
+
| <a href=\"javascript:manualOptimization({$id})\">Retry</a></div>";
|
1222 |
+
$this->prioQ->push($id); //should be there but just to make sure
|
1223 |
+
}
|
1224 |
+
|
1225 |
+
} elseif(isset($data['ShortPixel']['NoFileOnDisk'])) {
|
1226 |
+
print 'Image does not exist';
|
1227 |
+
|
1228 |
+
} else {
|
1229 |
+
|
1230 |
+
if ( wp_attachment_is_image( $id ) )
|
1231 |
+
{
|
1232 |
+
if ( get_option('wp-short-pixel-quota-exceeded') )
|
1233 |
+
{
|
1234 |
+
print QUOTA_EXCEEDED;
|
1235 |
+
}
|
1236 |
+
else
|
1237 |
+
{
|
1238 |
+
print 'Image not processed';
|
1239 |
+
print " | <a href=\"javascript:manualOptimization({$id})\">Optimize now</a>";
|
1240 |
+
}
|
1241 |
+
}
|
1242 |
+
elseif ( $fileExtension == "pdf" )
|
1243 |
+
{
|
1244 |
+
if ( get_option('wp-short-pixel-quota-exceeded') )
|
1245 |
+
{
|
1246 |
+
print QUOTA_EXCEEDED;
|
1247 |
+
}
|
1248 |
+
else
|
1249 |
+
{
|
1250 |
+
print 'PDF not processed';
|
1251 |
+
print " | <a href=\"javascript:manualOptimization({$id})\">Optimize now</a>";
|
1252 |
+
}
|
1253 |
+
}
|
1254 |
+
}
|
1255 |
+
print "</div>";
|
1256 |
+
}
|
1257 |
+
}
|
1258 |
+
|
1259 |
+
public function columns( $defaults ) {
|
1260 |
+
$defaults['wp-shortPixel'] = 'ShortPixel Compression';
|
1261 |
+
return $defaults;
|
1262 |
+
}
|
1263 |
+
|
1264 |
+
public function generatePluginLinks($links) {
|
1265 |
+
$in = '<a href="options-general.php?page=wp-shortpixel">Settings</a>';
|
1266 |
+
array_unshift($links, $in);
|
1267 |
+
return $links;
|
1268 |
+
}
|
1269 |
+
|
1270 |
+
public function parseJSON($data) {
|
1271 |
+
if ( function_exists('json_decode') ) {
|
1272 |
+
$data = json_decode( $data );
|
1273 |
+
} else {
|
1274 |
+
require_once( 'JSON/JSON.php' );
|
1275 |
+
$json = new Services_JSON( );
|
1276 |
+
$data = $json->decode( $data );
|
1277 |
+
}
|
1278 |
+
return $data;
|
1279 |
+
}
|
1280 |
+
|
1281 |
+
|
1282 |
+
static public function formatBytes($bytes, $precision = 2) {
|
1283 |
+
$units = array('B', 'KB', 'MB', 'GB', 'TB');
|
1284 |
+
|
1285 |
+
$bytes = max($bytes, 0);
|
1286 |
+
$pow = floor(($bytes ? log($bytes) : 0) / log(1024));
|
1287 |
+
$pow = min($pow, count($units) - 1);
|
1288 |
+
|
1289 |
+
$bytes /= pow(1024, $pow);
|
1290 |
+
|
1291 |
+
return round($bytes, $precision) . ' ' . $units[$pow];
|
1292 |
+
}
|
1293 |
+
|
1294 |
+
static public function isProcessable($ID) {
|
1295 |
+
$path = get_attached_file($ID);//get the full file PATH
|
1296 |
+
$pathParts = pathinfo($path);
|
1297 |
+
if( isset($pathParts['extension']) && in_array(strtolower($pathParts['extension']), array('jpg', 'jpeg', 'gif', 'png', 'pdf'))) {
|
1298 |
+
return true;
|
1299 |
+
} else {
|
1300 |
+
return false;
|
1301 |
+
}
|
1302 |
+
}
|
1303 |
+
|
1304 |
+
|
1305 |
+
//return an array with URL(s) and PATH(s) for this file
|
1306 |
+
public function getURLsAndPATHs($ID, $meta = NULL) {
|
1307 |
+
|
1308 |
+
if ( !parse_url(WP_CONTENT_URL, PHP_URL_SCHEME) )
|
1309 |
+
{//no absolute URLs used -> we implement a hack
|
1310 |
+
$url = get_site_url() . wp_get_attachment_url($ID);//get the file URL
|
1311 |
+
}
|
1312 |
+
else
|
1313 |
+
$url = wp_get_attachment_url($ID);//get the file URL
|
1314 |
+
|
1315 |
+
$urlList[] = $url;
|
1316 |
+
$path = get_attached_file($ID);//get the full file PATH
|
1317 |
+
$filePath[] = $path;
|
1318 |
+
if ( $meta == NULL ) {
|
1319 |
+
$meta = wp_get_attachment_metadata($ID);
|
1320 |
+
}
|
1321 |
+
|
1322 |
+
//it is NOT a PDF file and thumbs are processable
|
1323 |
+
if ( strtolower(substr($filePath[0],strrpos($filePath[0], ".")+1)) != "pdf"
|
1324 |
+
&& $this->_processThumbnails
|
1325 |
+
&& isset($meta['sizes']) && is_array($meta['sizes']))
|
1326 |
+
{
|
1327 |
+
foreach( $meta['sizes'] as $thumbnailInfo )
|
1328 |
+
{
|
1329 |
+
$urlList[] = str_replace(ShortPixelAPI::MB_basename($urlList[0]), $thumbnailInfo['file'], $url);
|
1330 |
+
$filePath[] = str_replace(ShortPixelAPI::MB_basename($filePath[0]), $thumbnailInfo['file'], $path);
|
1331 |
+
}
|
1332 |
+
}
|
1333 |
+
if(!isset($meta['sizes']) || !is_array($meta['sizes'])) {
|
1334 |
+
self::log("getURLsAndPATHs: no meta sizes for ID $ID : " . json_encode($meta));
|
1335 |
+
}
|
1336 |
+
return array("URLs" => $urlList, "PATHs" => $filePath);
|
1337 |
+
}
|
1338 |
+
|
1339 |
+
|
1340 |
+
public static function deleteDir($dirPath) {
|
1341 |
+
if (substr($dirPath, strlen($dirPath) - 1, 1) !=
|
1342 |
+
'/') {
|
1343 |
+
$dirPath .= '/';
|
1344 |
+
}
|
1345 |
+
$files = glob($dirPath . '*', GLOB_MARK);
|
1346 |
+
foreach ($files as $file) {
|
1347 |
+
if (is_dir($file)) {
|
1348 |
+
self::deleteDir($file);
|
1349 |
+
@rmdir($file);//remove empty dir
|
1350 |
+
} else {
|
1351 |
+
@unlink($file);//remove file
|
1352 |
+
}
|
1353 |
+
}
|
1354 |
+
}
|
1355 |
+
|
1356 |
+
static public function folderSize($path) {
|
1357 |
+
$total_size = 0;
|
1358 |
+
if(file_exists($path)) {
|
1359 |
+
$files = scandir($path);
|
1360 |
+
} else {
|
1361 |
+
return $total_size;
|
1362 |
+
}
|
1363 |
+
$cleanPath = rtrim($path, '/'). '/';
|
1364 |
+
foreach($files as $t) {
|
1365 |
+
if ($t<>"." && $t<>"..")
|
1366 |
+
{
|
1367 |
+
$currentFile = $cleanPath . $t;
|
1368 |
+
if (is_dir($currentFile)) {
|
1369 |
+
$size = self::folderSize($currentFile);
|
1370 |
+
$total_size += $size;
|
1371 |
+
}
|
1372 |
+
else {
|
1373 |
+
$size = filesize($currentFile);
|
1374 |
+
$total_size += $size;
|
1375 |
+
}
|
1376 |
+
}
|
1377 |
+
}
|
1378 |
+
return $total_size;
|
1379 |
+
}
|
1380 |
+
|
1381 |
+
public function getMaxMediaId() {
|
1382 |
+
global $wpdb;
|
1383 |
+
$queryMax = "SELECT max(post_id) as QueryID FROM " . $wpdb->prefix . "postmeta";
|
1384 |
+
$resultQuery = $wpdb->get_results($queryMax);
|
1385 |
+
return $resultQuery[0]->QueryID;
|
1386 |
+
}
|
1387 |
+
|
1388 |
+
public function getMinMediaId() {
|
1389 |
+
global $wpdb;
|
1390 |
+
$queryMax = "SELECT min(post_id) as QueryID FROM " . $wpdb->prefix . "postmeta";
|
1391 |
+
$resultQuery = $wpdb->get_results($queryMax);
|
1392 |
+
return $resultQuery[0]->QueryID;
|
1393 |
+
}
|
1394 |
+
|
1395 |
+
//count all the processable files in media library (while limiting the results to max 10000)
|
1396 |
+
public function countAllProcessableFiles($maxId = PHP_INT_MAX, $minId = 0){
|
1397 |
+
global $wpdb;
|
1398 |
+
|
1399 |
+
$totalFiles = 0;
|
1400 |
+
$mainFiles = 0;
|
1401 |
+
$limit = 500;
|
1402 |
+
$pointer = 0;
|
1403 |
+
|
1404 |
+
//count all the files, main and thumbs
|
1405 |
+
while ( 1 )
|
1406 |
+
{
|
1407 |
+
$filesList= $wpdb->get_results("SELECT * FROM " . $wpdb->prefix . "postmeta
|
1408 |
+
WHERE ( post_id <= $maxId AND post_id > $minId )
|
1409 |
+
AND ( meta_key = '_wp_attached_file' OR meta_key = '_wp_attachment_metadata' )
|
1410 |
+
LIMIT $pointer,$limit");
|
1411 |
+
if ( empty($filesList) ) //we parsed all the results
|
1412 |
+
break;
|
1413 |
+
|
1414 |
+
foreach ( $filesList as $file )
|
1415 |
+
{
|
1416 |
+
if ( $file->meta_key == "_wp_attached_file" )
|
1417 |
+
{//count pdf files only
|
1418 |
+
$extension = substr($file->meta_value, strrpos($file->meta_value,".") + 1 );
|
1419 |
+
if ( $extension == "pdf" )
|
1420 |
+
{
|
1421 |
+
$totalFiles++;
|
1422 |
+
$mainFiles++;
|
1423 |
+
}
|
1424 |
+
}
|
1425 |
+
else
|
1426 |
+
{
|
1427 |
+
$attachment = unserialize($file->meta_value);
|
1428 |
+
if ( isset($attachment['sizes']) )
|
1429 |
+
$totalFiles += count($attachment['sizes']);
|
1430 |
+
|
1431 |
+
if ( isset($attachment['file']) )
|
1432 |
+
{
|
1433 |
+
$totalFiles++;
|
1434 |
+
$mainFiles++;
|
1435 |
+
}
|
1436 |
+
}
|
1437 |
+
}
|
1438 |
+
unset($filesList);
|
1439 |
+
$pointer += $limit;
|
1440 |
+
|
1441 |
+
}//end while
|
1442 |
+
|
1443 |
+
return array("totalFiles" => $totalFiles, "mainFiles" => $mainFiles);
|
1444 |
+
}
|
1445 |
+
|
1446 |
+
|
1447 |
+
//count all the processable files in media library (while limiting the results to max 10000)
|
1448 |
+
public function countAllProcessedFiles($maxId = PHP_INT_MAX, $minId = 0){
|
1449 |
+
global $wpdb;
|
1450 |
+
|
1451 |
+
$processedMainFiles = $processedTotalFiles = 0;
|
1452 |
+
$limit = 500;
|
1453 |
+
$pointer = 0;
|
1454 |
+
|
1455 |
+
//count all the files, main and thumbs
|
1456 |
+
while ( 1 )
|
1457 |
+
{
|
1458 |
+
$filesList= $wpdb->get_results("SELECT * FROM " . $wpdb->prefix . "postmeta
|
1459 |
+
WHERE ( post_id <= $maxId AND post_id > $minId )
|
1460 |
+
AND ( meta_key = '_wp_attached_file' OR meta_key = '_wp_attachment_metadata' )
|
1461 |
+
LIMIT $pointer,$limit");
|
1462 |
+
if ( empty($filesList) ) {//we parsed all the results
|
1463 |
+
break;
|
1464 |
+
}
|
1465 |
+
foreach ( $filesList as $file )
|
1466 |
+
{
|
1467 |
+
if ( $file->meta_key == "_wp_attached_file" ) {
|
1468 |
+
continue;
|
1469 |
+
}
|
1470 |
+
$attachment = unserialize($file->meta_value);
|
1471 |
+
if ( isset($attachment['ShortPixelImprovement']) && $attachment['ShortPixelImprovement'] > 0 ) {
|
1472 |
+
$processedMainFiles++;
|
1473 |
+
$processedTotalFiles++;
|
1474 |
+
if ( isset($attachment['sizes']) ) {
|
1475 |
+
$processedTotalFiles += count($attachment['sizes']);
|
1476 |
+
}
|
1477 |
+
}
|
1478 |
+
}
|
1479 |
+
unset($filesList);
|
1480 |
+
$pointer += $limit;
|
1481 |
+
|
1482 |
+
}//end while
|
1483 |
+
|
1484 |
+
return array("totalFiles" => $processedTotalFiles, "mainFiles" => $processedMainFiles);
|
1485 |
+
}
|
1486 |
+
|
1487 |
+
public function migrateBackupFolder() {
|
1488 |
+
$oldBackupFolder = WP_CONTENT_DIR . DIRECTORY_SEPARATOR . 'ShortpixelBackups';
|
1489 |
+
|
1490 |
+
if(!file_exists($oldBackupFolder)) return; //if old backup folder does not exist then there is nothing to do
|
1491 |
+
|
1492 |
+
if(!file_exists(SP_BACKUP_FOLDER)) {
|
1493 |
+
//we check that the backup folder exists, if not we create it so we can copy into it
|
1494 |
+
if(!mkdir(SP_BACKUP_FOLDER, 0777, true)) return;
|
1495 |
+
}
|
1496 |
+
|
1497 |
+
$scannedDirectory = array_diff(scandir($oldBackupFolder), array('..', '.'));
|
1498 |
+
foreach($scannedDirectory as $file) {
|
1499 |
+
@rename($oldBackupFolder.DIRECTORY_SEPARATOR.$file, SP_BACKUP_FOLDER.DIRECTORY_SEPARATOR.$file);
|
1500 |
+
}
|
1501 |
+
$scannedDirectory = array_diff(scandir($oldBackupFolder), array('..', '.'));
|
1502 |
+
if(empty($scannedDirectory)) {
|
1503 |
+
@rmdir($oldBackupFolder);
|
1504 |
+
}
|
1505 |
+
|
1506 |
+
return;
|
1507 |
+
}
|
1508 |
+
|
1509 |
+
public function getApiKey() {
|
1510 |
+
return $this->_apiKey;
|
1511 |
+
}
|
1512 |
+
|
1513 |
+
public function backupImages() {
|
1514 |
+
return $this->_backupImages;
|
1515 |
+
}
|
1516 |
+
|
1517 |
+
public function processThumbnails() {
|
1518 |
+
return $this->_processThumbnails;
|
1519 |
+
}
|
1520 |
+
|
1521 |
+
}
|
1522 |
+
|
1523 |
+
$pluginInstance = new WPShortPixel();
|
1524 |
+
global $pluginInstance;
|
1525 |
+
|
1526 |
+
?>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|