Kraken.io Image Optimizer - Version 2.5.0

Version Description

  • Ability to disable optimization of main image, allowing faster uploads from Media Library. You can optimize the main image later from within your Media Library.
  • Ability to restrict the maximum dimensions of image uploads (resizing), by width and/or height.
  • When using resize feature, resized images are enhanced for sharper results using various advanced techniques.
  • Ability to force JPEG quality to a discrete "quality" value, for greater savings if you know what you're doing.
  • Ability to preserve certain EXIF metadata tags, including Date, Copyright, Orientation, Geotag and Profile.
  • Ability to automatically orient images according to their Orientation EXIF metadata.
  • Improvements and simplifications to interface elements and Kraken.io Settings page.
Download this release

Release Info

Developer karim79
Plugin Icon 128x128 Kraken.io Image Optimizer
Version 2.5.0
Comparing to
See all releases

Code changes from version 2.0.0 to 2.5.0

Files changed (7) hide show
  1. css/admin.css +154 -25
  2. css/dist/kraken.min.css +1 -1
  3. js/ajax.js +114 -84
  4. js/dist/kraken.min.js +2 -3
  5. kraken.php +625 -172
  6. lib/Kraken.php +40 -45
  7. readme.txt +19 -12
css/admin.css CHANGED
@@ -34,26 +34,46 @@
34
  float: left;
35
  clear: left;
36
  }
 
37
  .kraken_req, .kraken_req_bulk {
38
- border: 1px solid #efab00;
39
- color: #222;
40
  padding: 3px 8px 4px;
41
  font-size: 11px;
42
- text-shadow: 0 1px 0 rgba(255,255,255,0.5);
43
- background: #ffc942;
44
- background-image: -webkit-gradient(linear,left top,left bottom,from(#ffc942),to(#efab00));
45
- background-image: -webkit-linear-gradient(top,#ffc942,#efab00);
46
- background-image: -moz-linear-gradient(top,#ffc942,#efab00);
47
- background-image: -o-linear-gradient(top,#ffc942,#efab00);
48
- background-image: linear-gradient(to bottom,#ffc942,#efab00);
49
  -webkit-border-radius: 2px;
50
  -moz-border-radius: 2px;
51
  border-radius: 2px;
52
  cursor: pointer;
53
- font-weight: bold;
 
 
 
 
 
54
  }
 
 
 
 
 
55
  .kraken_req_bulk {
56
  font-size: 16px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
57
  }
58
  .buttonWrap {
59
  position: relative;
@@ -115,27 +135,65 @@ p.apiStatus {
115
  font-size: 16px;
116
  margin-bottom: 10px;
117
  font-weight: bold;
 
 
 
 
 
118
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
119
  #kraken-bulk-modal {
120
  position: absolute !important;
121
- top: 100px;
122
  width: 785px;
 
123
  }
124
  #kraken-bulk-modal label {
125
  margin-bottom: 11px;
126
  }
 
127
  #kraken-bulk {
128
- width: 780px;
129
- margin: 0 auto;
130
- margin-bottom: 10px;
131
- border-spacing: 1px;
132
- border-collapse: separate;
 
 
 
133
  }
 
 
 
 
 
 
 
 
 
 
 
134
  .kraken-bulk-header td {
135
  font-weight: bold;
136
- font-size: 14px;
137
- padding: 4px 0 4px 2px;
 
 
 
138
  }
 
139
  td.kraken-krakedsize {
140
  text-align: left;
141
  }
@@ -156,10 +214,25 @@ span.kraken-bulk-choose-type {
156
  font-weight: bold;
157
  cursor: pointer;
158
  }
 
159
  .radiosWrap {
160
- display: inline-block;
161
- margin: 0 0 5px 4px;
 
 
162
  }
 
 
 
 
 
 
 
 
 
 
 
 
163
  .kraken-bulk-small {
164
  font-size: 12px;
165
  display: inline-block;
@@ -177,7 +250,7 @@ small.krakenReset {
177
  width: 10px;
178
  height: 10px;
179
  background: url('https://kraken-nekkraug.netdna-ssl.com/assets/images/spinner.gif') no-repeat 0 0;
180
- background-size: 10px;
181
  }
182
  h1.kraken-admin-section-title {
183
  margin-bottom: 30px;
@@ -196,11 +269,11 @@ span.kraken-reset-all.enabled {
196
  cursor: pointer;
197
  }
198
  td.krakenAdvancedSettings {
199
- padding: 0;
200
  }
201
  td.krakenAdvancedSettingsDescription {
202
  padding: 0;
203
- padding-bottom: 10px;
204
  }
205
  td.krakenAdvancedSettings h3 {
206
  margin-bottom: 2px;
@@ -230,14 +303,70 @@ td.krakenAdvancedSettings h3 span.kraken-advanced-toggle {
230
  user-select: none;
231
  }
232
  .kraken-advanced-settings {
233
- display: none;
234
  }
235
  #krakenSettings .form-table {
236
  margin-bottom: 30px;
237
  }
 
238
  #krakenSettings .form-table th {
239
- width: 370px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
240
  }
 
 
 
 
 
 
 
 
 
241
  .kraken.error.settings-error, .kraken.updated.settings-error {
242
  margin-bottom: 30px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
243
  }
34
  float: left;
35
  clear: left;
36
  }
37
+
38
  .kraken_req, .kraken_req_bulk {
39
+ border: none;
40
+ color: #fff;
41
  padding: 3px 8px 4px;
42
  font-size: 11px;
43
+ background: #3498DB;
 
 
 
 
 
 
44
  -webkit-border-radius: 2px;
45
  -moz-border-radius: 2px;
46
  border-radius: 2px;
47
  cursor: pointer;
48
+ transition: all 0.15s;
49
+ }
50
+
51
+ .kraken_req:hover,
52
+ .kraken_req_bulk:hover {
53
+ background: #2881BD;
54
  }
55
+
56
+ .kraken_req {
57
+ margin-right: 2px;
58
+ }
59
+
60
  .kraken_req_bulk {
61
  font-size: 16px;
62
+ margin: 0 auto;
63
+ width: 150px;
64
+ padding: 10px 0;
65
+ display: block;
66
+ }
67
+
68
+ td.kraken-bulk-filename {
69
+ width: 360px;
70
+ max-width: 360px;
71
+ overflow: hidden;
72
+ text-overflow: ellipsis;
73
+ white-space: nowrap;
74
+ }
75
+ td.kraken-krakedsize {
76
+ width: 170px;
77
  }
78
  .buttonWrap {
79
  position: relative;
135
  font-size: 16px;
136
  margin-bottom: 10px;
137
  font-weight: bold;
138
+ padding: 15px 20px;
139
+ border-bottom: 1px solid #ddd;
140
+ margin: 0;
141
+ background: #fafafa;
142
+ position: relative;
143
  }
144
+
145
+ .krakenBulkHeader span {
146
+ position: absolute;
147
+ top: 5px;
148
+ right: 15px;
149
+ font-size: 30px;
150
+ color: #777;
151
+ }
152
+
153
+ .krakenBulkHeader span:hover {
154
+ color: #222;
155
+ }
156
+
157
  #kraken-bulk-modal {
158
  position: absolute !important;
159
+ top: 100px;
160
  width: 785px;
161
+ padding: 0 0 20px 0;
162
  }
163
  #kraken-bulk-modal label {
164
  margin-bottom: 11px;
165
  }
166
+
167
  #kraken-bulk {
168
+ width: 770px;
169
+ margin: 0 auto 20px;
170
+ border-collapse: collapse;
171
+ }
172
+
173
+ #kraken-bulk td {
174
+ border: 1px solid #ddd;
175
+ padding: 5px 10px;
176
  }
177
+
178
+ #kraken-bulk tr:nth-child(odd) {
179
+ background-color: #eee;
180
+ }
181
+
182
+ #kraken-bulk-modal .the-following {
183
+ margin: 0;
184
+ text-align: center;
185
+ padding: 15px 0;
186
+ }
187
+
188
  .kraken-bulk-header td {
189
  font-weight: bold;
190
+ font-size: 13px;
191
+ padding: 7px 10px !important;
192
+ background: #ddd;
193
+ color: #212121;
194
+ border: 1px solid #ccc !important;
195
  }
196
+
197
  td.kraken-krakedsize {
198
  text-align: left;
199
  }
214
  font-weight: bold;
215
  cursor: pointer;
216
  }
217
+
218
  .radiosWrap {
219
+ width: 100%;
220
+ text-align: center;
221
+ padding: 15px 0;
222
+ border-bottom: 1px solid #ddd;
223
  }
224
+
225
+ .radiosWrap p {
226
+ padding: 0;
227
+ margin: 0 0 5px 0;
228
+ font-weight: bold;
229
+ }
230
+
231
+ .radiosWrap input[type="radio"] {
232
+ margin-top: -1px;
233
+ vertical-align: middle;
234
+ }
235
+
236
  .kraken-bulk-small {
237
  font-size: 12px;
238
  display: inline-block;
250
  width: 10px;
251
  height: 10px;
252
  background: url('https://kraken-nekkraug.netdna-ssl.com/assets/images/spinner.gif') no-repeat 0 0;
253
+ background-size: 10px;
254
  }
255
  h1.kraken-admin-section-title {
256
  margin-bottom: 30px;
269
  cursor: pointer;
270
  }
271
  td.krakenAdvancedSettings {
272
+ padding: 20px 0 0 0 !important;
273
  }
274
  td.krakenAdvancedSettingsDescription {
275
  padding: 0;
276
+ padding: 10px 0 !important;
277
  }
278
  td.krakenAdvancedSettings h3 {
279
  margin-bottom: 2px;
303
  user-select: none;
304
  }
305
  .kraken-advanced-settings {
306
+ /*display: none;*/
307
  }
308
  #krakenSettings .form-table {
309
  margin-bottom: 30px;
310
  }
311
+
312
  #krakenSettings .form-table th {
313
+ width: 270px;
314
+ border-bottom: 1px solid #ddd;
315
+ padding: 25px 0;
316
+ }
317
+
318
+ #krakenSettings .form-table td {
319
+ border-bottom: 1px solid #ddd;
320
+ padding: 25px 0;
321
+ }
322
+
323
+ #krakenSettings .form-table .no-border td,
324
+ #krakenSettings .form-table .no-border th {
325
+ border: none;
326
+ }
327
+
328
+ #krakenSettings .form-table .with-tip td,
329
+ #krakenSettings .form-table .with-tip th {
330
+ border-bottom: none;
331
+ padding-bottom: 10px;
332
+ }
333
+
334
+ .tip td {
335
+ padding: 10px 0 20px 0 !important;
336
  }
337
+
338
+ .tip td div {
339
+ border: 1px solid #BCE8F1;
340
+ background: #D9EDF7;
341
+ padding: 5px 10px;
342
+ line-height: 20px;
343
+ font-size: 12px;
344
+ }
345
+
346
  .kraken.error.settings-error, .kraken.updated.settings-error {
347
  margin-bottom: 30px;
348
+ }
349
+ .blog-kraker-info-block-wrap {
350
+ margin-top: 10px;
351
+ margin-left: 10px;
352
+ padding-bottom: 110px;
353
+ width: 600px;
354
+ }
355
+ .blog-kraker-image-summary {
356
+ width: 50%;
357
+ float: left;
358
+ }
359
+ .blog-kraker-kraken-statistics {
360
+ width: 50%;
361
+ float: right;
362
+ }
363
+ input[name=blog_kraker_mode] {
364
+ margin-right: 10px;
365
+ }
366
+ label[for=blog_kraker_mode_thumbs] {
367
+ margin-right: 10px;
368
+ }
369
+ .kraken-item-details {
370
+ cursor: pointer;
371
+ text-decoration: underline;
372
  }
css/dist/kraken.min.css CHANGED
@@ -1 +1 @@
1
- .tipsy-ne .tipsy-arrow,.tipsy-nw .tipsy-arrow{border-top:none;top:0;border-bottom-style:solid}.tipsy-inner,td.kraken-krakedsize{text-align:left}.kraken-plus-minus,td.krakenAdvancedSettings h3>.kraken-advanced-settings-label:hover{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-khtml-user-select:none}.kraken-modal{display:none;width:600px;background:#fff;padding:15px 30px;border-radius:8px;-webkit-box-shadow:0 0 10px #000;-moz-box-shadow:0 0 10px #000;-o-box-shadow:0 0 10px #000;-ms-box-shadow:0 0 10px #000;box-shadow:0 0 10px #000}.kraken-modal,.kraken-modal-spinner{-o-border-radius:8px;-ms-border-radius:8px;-webkit-border-radius:8px;-moz-border-radius:8px}.kraken-modal-spinner{display:none;width:64px;height:64px;position:fixed;top:50%;left:50%;margin-right:-32px;margin-top:-32px;background:url(spinner.gif)center center no-repeat #111;border-radius:8px}.tipsy{font-size:10px;position:absolute;padding:5px;z-index:100000}.tipsy-inner{background-color:#000;color:#FFF;max-width:300px;padding:5px 8px 4px;border-radius:3px;-moz-border-radius:3px;-webkit-border-radius:3px;box-shadow:0 0 5px #000;-webkit-box-shadow:0 0 5px #000;-moz-box-shadow:0 0 5px #000}.head_cell,.head_file_name,.item_file_name{height:20px;padding-top:5px}.tipsy-arrow{position:absolute;width:0;height:0;line-height:0;border:5px dashed #000}.tipsy-arrow-n{border-bottom-color:#000}.tipsy-arrow-s{border-top-color:#000}.tipsy-arrow-e{border-left-color:#000}.tipsy-n .tipsy-arrow,.tipsy-ne .tipsy-arrow,.tipsy-nw .tipsy-arrow,.tipsy-s .tipsy-arrow,.tipsy-se .tipsy-arrow,.tipsy-sw .tipsy-arrow{border-left-color:transparent}.tipsy-arrow-w{border-right-color:#000}.tipsy-n .tipsy-arrow,.tipsy-ne .tipsy-arrow,.tipsy-nw .tipsy-arrow,.tipsy-s .tipsy-arrow,.tipsy-se .tipsy-arrow,.tipsy-sw .tipsy-arrow{border-right-color:transparent}.tipsy-n .tipsy-arrow{top:0;left:50%;margin-left:-5px;border-bottom-style:solid;border-top:none}.tipsy-nw .tipsy-arrow{left:10px}.tipsy-ne .tipsy-arrow{right:10px}.tipsy-s .tipsy-arrow,.tipsy-se .tipsy-arrow,.tipsy-sw .tipsy-arrow{border-bottom:none;border-top-style:solid}.tipsy-e .tipsy-arrow,.tipsy-w .tipsy-arrow{border-bottom-color:transparent;top:50%;border-top-color:transparent}.tipsy-s .tipsy-arrow{bottom:0;left:50%;margin-left:-5px}.tipsy-sw .tipsy-arrow{bottom:0;left:10px}.tipsy-se .tipsy-arrow{bottom:0;right:10px}.tipsy-e .tipsy-arrow{right:0;margin-top:-5px;border-left-style:solid;border-right:none}.tipsy-w .tipsy-arrow{left:0;margin-top:-5px;border-right-style:solid;border-left:none}.item_cell,.item_file_name{background-color:#F8F8F8;margin-top:5px}.head_cell{float:left;width:10em;background-color:#F0F0F0}.head_file_name{float:left;width:30em;background-color:#F0F0F0;padding-left:2px}.item_cell{float:left;width:10em;height:20px;padding-top:5px}.item_file_name{float:left;width:30em;padding-left:2px}.apiInvalid,.apiValid{position:absolute;width:16px}#kraken_loading{float:left;clear:left}.kraken_req,.kraken_req_bulk{border:1px solid #efab00;color:#222;padding:3px 8px 4px;font-size:11px;text-shadow:0 1px 0 rgba(255,255,255,.5);background:#ffc942;background-image:-webkit-gradient(linear,left top,left bottom,from(#ffc942),to(#efab00));background-image:-webkit-linear-gradient(top,#ffc942,#efab00);background-image:-moz-linear-gradient(top,#ffc942,#efab00);background-image:-o-linear-gradient(top,#ffc942,#efab00);background-image:linear-gradient(to bottom,#ffc942,#efab00);-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px;cursor:pointer;font-weight:700}.krakenBulkSpinner,.krakenSpinner,.resetSpinner{background:url(https://kraken-nekkraug.netdna-ssl.com/assets/images/spinner.gif)no-repeat}.kraken_req_bulk{font-size:16px}.buttonWrap{position:relative;margin-bottom:5px}.apiValid{left:0;display:inline-block;height:16px;top:3px}.apiInvalid{left:0;display:inline-block;height:16px;top:2px}p.apiStatus{padding-left:26px;position:relative;width:400px}.krakenSpinner{display:none;position:absolute;width:16px;height:16px;top:5px}.krakenBulkSpinner{display:none;padding:0;margin:0;width:16px;height:16px}.krakenError,.noSavings{margin-left:2px}.kraken-bulk-small,.kraken-plus-minus,.radiosWrap,.resetSpinner,.visible{display:inline-block}.krakenErrorWrap{margin-top:10px;margin-bottom:4px}.krakenError{font-weight:700;color:#dd3d36}.krakenBulkHeader{font-size:16px;margin-bottom:10px;font-weight:700}#kraken-bulk-modal{position:absolute!important;top:100px;width:785px}#kraken-bulk-modal label{margin-bottom:11px}#kraken-bulk{width:780px;margin:0 auto 10px;border-spacing:1px;border-collapse:separate}.kraken-bulk-header td{font-weight:700;font-size:14px;padding:4px 0 4px 2px}tr.kraken-item-row td{padding:2px;height:20px}span.kraken-bulk-choose-type{font-weight:700;margin-right:5px}#kraken-bulk-type-lossy{margin-right:5px}.close-kraken-bulk{font-size:12px;margin-left:10px;font-weight:700;cursor:pointer}.radiosWrap{margin:0 0 5px 4px}.kraken-bulk-small{font-size:12px;margin:0 0 4px 4px}small.krakenReset{text-decoration:underline;cursor:pointer}.resetSpinner{margin-right:3px;margin-top:4px;vertical-align:baseline;width:10px;height:10px;background-size:10px}h1.kraken-admin-section-title{margin-bottom:30px}.kraken_show_reset{margin-right:11px}small.krakenWhatsThis{font-size:9px}span.kraken-reset-all{font-size:11px}span.kraken-reset-all.enabled{text-decoration:underline;cursor:pointer}td.krakenAdvancedSettings{padding:0}td.krakenAdvancedSettingsDescription{padding:0 0 10px}td.krakenAdvancedSettings h3{margin-bottom:2px}#krakenSettings .form-table,.kraken.error.settings-error,.kraken.updated.settings-error{margin-bottom:30px}td.krakenAdvancedSettings h3>.kraken-advanced-settings-label:hover{cursor:pointer;color:#45bbe6;user-select:none}td.krakenAdvancedSettings h3 span.kraken-advanced-toggle{color:#45bbe6;font-size:10px}.kraken-plus-minus{cursor:pointer;line-height:24px;width:20px;user-select:none}.kraken-advanced-settings{display:none}#krakenSettings .form-table th{width:370px}
1
+ .tipsy-ne .tipsy-arrow,.tipsy-nw .tipsy-arrow{border-top:none;top:0;border-bottom-style:solid}.kraken-plus-minus,td.krakenAdvancedSettings h3>.kraken-advanced-settings-label:hover{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-khtml-user-select:none}.kraken-modal{display:none;width:600px;background:#fff;padding:15px 30px;border-radius:8px;-webkit-box-shadow:0 0 10px #000;-moz-box-shadow:0 0 10px #000;-o-box-shadow:0 0 10px #000;-ms-box-shadow:0 0 10px #000;box-shadow:0 0 10px #000}.kraken-modal,.kraken-modal-spinner{-o-border-radius:8px;-ms-border-radius:8px;-webkit-border-radius:8px;-moz-border-radius:8px}.kraken-modal-spinner{display:none;width:64px;height:64px;position:fixed;top:50%;left:50%;margin-right:-32px;margin-top:-32px;background:url(spinner.gif)center center no-repeat #111;border-radius:8px}.tipsy{font-size:10px;position:absolute;padding:5px;z-index:100000}.tipsy-inner{background-color:#000;color:#FFF;max-width:300px;padding:5px 8px 4px;text-align:left;border-radius:3px;-moz-border-radius:3px;-webkit-border-radius:3px;box-shadow:0 0 5px #000;-webkit-box-shadow:0 0 5px #000;-moz-box-shadow:0 0 5px #000}.head_cell,.head_file_name,.item_file_name{height:20px;padding-top:5px}.tipsy-arrow{position:absolute;width:0;height:0;line-height:0;border:5px dashed #000}.tipsy-arrow-n{border-bottom-color:#000}.tipsy-arrow-s{border-top-color:#000}.tipsy-arrow-e{border-left-color:#000}.tipsy-n .tipsy-arrow,.tipsy-ne .tipsy-arrow,.tipsy-nw .tipsy-arrow,.tipsy-s .tipsy-arrow,.tipsy-se .tipsy-arrow,.tipsy-sw .tipsy-arrow{border-left-color:transparent}.tipsy-arrow-w{border-right-color:#000}.tipsy-n .tipsy-arrow,.tipsy-ne .tipsy-arrow,.tipsy-nw .tipsy-arrow,.tipsy-s .tipsy-arrow,.tipsy-se .tipsy-arrow,.tipsy-sw .tipsy-arrow{border-right-color:transparent}.tipsy-n .tipsy-arrow{top:0;left:50%;margin-left:-5px;border-bottom-style:solid;border-top:none}.tipsy-nw .tipsy-arrow{left:10px}.tipsy-ne .tipsy-arrow{right:10px}.tipsy-s .tipsy-arrow,.tipsy-se .tipsy-arrow,.tipsy-sw .tipsy-arrow{border-bottom:none;border-top-style:solid}.tipsy-e .tipsy-arrow,.tipsy-w .tipsy-arrow{border-bottom-color:transparent;top:50%;border-top-color:transparent}.tipsy-s .tipsy-arrow{bottom:0;left:50%;margin-left:-5px}.tipsy-sw .tipsy-arrow{bottom:0;left:10px}.tipsy-se .tipsy-arrow{bottom:0;right:10px}.tipsy-e .tipsy-arrow{right:0;margin-top:-5px;border-left-style:solid;border-right:none}.tipsy-w .tipsy-arrow{left:0;margin-top:-5px;border-right-style:solid;border-left:none}.item_cell,.item_file_name{background-color:#F8F8F8;margin-top:5px}.head_cell{float:left;width:10em;background-color:#F0F0F0}.head_file_name{float:left;width:30em;background-color:#F0F0F0;padding-left:2px}.item_cell{float:left;width:10em;height:20px;padding-top:5px}.item_file_name{float:left;width:30em;padding-left:2px}#kraken_loading{float:left;clear:left}.kraken_req,.kraken_req_bulk{border:none;color:#fff;padding:3px 8px 4px;font-size:11px;background:#3498DB;-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px;cursor:pointer;transition:all .15s}.kraken_req:hover,.kraken_req_bulk:hover{background:#2881BD}.krakenBulkSpinner,.krakenSpinner{background:url(https://kraken-nekkraug.netdna-ssl.com/assets/images/spinner.gif)no-repeat}.kraken_req{margin-right:2px}.kraken_req_bulk{font-size:16px;margin:0 auto;width:150px;padding:10px 0;display:block}td.kraken-bulk-filename{width:360px;max-width:360px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}td.kraken-krakedsize{width:170px}.apiInvalid,.apiValid{position:absolute;width:16px}.buttonWrap{position:relative;margin-bottom:5px}.apiValid{left:0;display:inline-block;height:16px;top:3px}.apiInvalid{left:0;display:inline-block;height:16px;top:2px}p.apiStatus{padding-left:26px;position:relative;width:400px}.krakenSpinner{display:none;position:absolute;width:16px;height:16px;top:5px}.krakenBulkSpinner{display:none;padding:0;margin:0;width:16px;height:16px}.krakenError,.noSavings{margin-left:2px}.kraken-bulk-small,.kraken-plus-minus,.resetSpinner,.visible{display:inline-block}.krakenErrorWrap{margin-top:10px;margin-bottom:4px}.krakenError{font-weight:700;color:#dd3d36}.krakenBulkHeader{font-size:16px;font-weight:700;padding:15px 20px;border-bottom:1px solid #ddd;margin:0;background:#fafafa;position:relative}.krakenBulkHeader span{position:absolute;top:5px;right:15px;font-size:30px;color:#777}.krakenBulkHeader span:hover{color:#222}#kraken-bulk-modal{position:absolute!important;top:100px;width:785px;padding:0 0 20px}#kraken-bulk-modal label{margin-bottom:11px}#kraken-bulk{width:770px;margin:0 auto 20px;border-collapse:collapse}#kraken-bulk td{border:1px solid #ddd;padding:5px 10px}#kraken-bulk tr:nth-child(odd){background-color:#eee}#kraken-bulk-modal .the-following{margin:0;text-align:center;padding:15px 0}.kraken-bulk-header td{font-weight:700;font-size:13px;padding:7px 10px!important;background:#ddd;color:#212121;border:1px solid #ccc!important}td.kraken-krakedsize{text-align:left}tr.kraken-item-row td{padding:2px;height:20px}span.kraken-bulk-choose-type{font-weight:700;margin-right:5px}#kraken-bulk-type-lossy{margin-right:5px}.close-kraken-bulk{font-size:12px;margin-left:10px;font-weight:700;cursor:pointer}.radiosWrap{width:100%;text-align:center;padding:15px 0;border-bottom:1px solid #ddd}.radiosWrap p{padding:0;margin:0 0 5px;font-weight:700}.radiosWrap input[type=radio]{margin-top:-1px;vertical-align:middle}.kraken-bulk-small{font-size:12px;margin:0 0 4px 4px}small.krakenReset{text-decoration:underline;cursor:pointer}.resetSpinner{margin-right:3px;margin-top:4px;vertical-align:baseline;width:10px;height:10px;background:url(https://kraken-nekkraug.netdna-ssl.com/assets/images/spinner.gif)no-repeat;background-size:10px}h1.kraken-admin-section-title{margin-bottom:30px}.kraken_show_reset{margin-right:11px}small.krakenWhatsThis{font-size:9px}span.kraken-reset-all{font-size:11px}span.kraken-reset-all.enabled{text-decoration:underline;cursor:pointer}td.krakenAdvancedSettings{padding:20px 0 0!important}td.krakenAdvancedSettingsDescription{padding:10px 0!important}td.krakenAdvancedSettings h3{margin-bottom:2px}#krakenSettings .form-table,.kraken.error.settings-error,.kraken.updated.settings-error{margin-bottom:30px}td.krakenAdvancedSettings h3>.kraken-advanced-settings-label:hover{cursor:pointer;color:#45bbe6;user-select:none}td.krakenAdvancedSettings h3 span.kraken-advanced-toggle{color:#45bbe6;font-size:10px}.kraken-plus-minus{cursor:pointer;line-height:24px;width:20px;user-select:none}#krakenSettings .form-table th{width:270px;border-bottom:1px solid #ddd;padding:25px 0}#krakenSettings .form-table td{border-bottom:1px solid #ddd;padding:25px 0}#krakenSettings .form-table .no-border td,#krakenSettings .form-table .no-border th{border:none}#krakenSettings .form-table .with-tip td,#krakenSettings .form-table .with-tip th{border-bottom:none;padding-bottom:10px}.tip td{padding:10px 0 20px!important}.tip td div{border:1px solid #BCE8F1;background:#D9EDF7;padding:5px 10px;line-height:20px;font-size:12px}.blog-kraker-info-block-wrap{margin-top:10px;margin-left:10px;padding-bottom:110px;width:600px}.blog-kraker-image-summary{width:50%;float:left}.blog-kraker-kraken-statistics{width:50%;float:right}input[name=blog_kraker_mode],label[for=blog_kraker_mode_thumbs]{margin-right:10px}.kraken-item-details{cursor:pointer;text-decoration:underline}
js/ajax.js CHANGED
@@ -1,40 +1,28 @@
1
  jQuery(document).ready(function($) {
2
 
3
- var errors = [{
4
- code: 401,
5
- msg: 'Unnknown API Key. Please check your API key and try again'
6
- }, {
7
- code: 403,
8
- msg: 'Your account has been temporarily suspended'
9
- }, {
10
- code: 413,
11
- msg: 'File size too large. The maximum file size for your plan is 1048576 bytes'
12
- }, {
13
- code: 415,
14
- msg: 'File type not supported'
15
- }, {
16
- code: 415,
17
- msg: 'WebP compression is non available for SVG images'
18
- }, {
19
- code: 422,
20
- msg: 'You need to specify either callback_url or wait flag'
21
- }, {
22
- code: 422,
23
- msg: 'This image can not be optimized any further'
24
- }, {
25
- code: 500,
26
- msg: 'Kraken has encountered an unexpected error and cannot fulfill your request'
27
- }, {
28
- code: 502,
29
- msg: 'Couldn\'t get this file'
30
- }];
31
-
32
 
33
  $('.krakenWhatsThis').tipsy({
34
  fade: true,
35
  gravity: 'w'
36
  });
37
 
 
 
 
 
 
38
  var data = {
39
  action: 'kraken_request'
40
  },
@@ -48,23 +36,24 @@ jQuery(document).ready(function($) {
48
 
49
  var requestSuccess = function(data, textStatus, jqXHR) {
50
  var $button = $(this),
51
- $parent = $(this).parent(),
52
  $cell = $(this).closest("td");
53
 
54
- if (data.success && typeof data.error === 'undefined') {
55
-
56
  $button.text("Image optimized");
57
 
58
  var type = data.type,
59
- krakedSize = data.kraked_size,
60
  originalSize = data.original_size,
61
- savingsPercent = data.savings_percent,
62
  $originalSizeColumn = $(this).parent().prev("td.original_size"),
63
  krakedData = '';
64
 
65
  $parent.fadeOut("fast", function() {
66
- $cell.find(".noSavings, .krakenErrorWrap").remove();
67
- $(this).replaceWith(data.html);
 
 
 
 
68
  $originalSizeColumn.html(originalSize);
69
  $parent.remove();
70
  });
@@ -137,40 +126,42 @@ jQuery(document).ready(function($) {
137
  return rv;
138
  };
139
 
 
 
 
 
 
 
 
 
140
  var renderBulkImageSummary = function(bulkImageData) {
141
- var modalOptions = {
142
- zIndex: 4,
143
- escapeClose: true,
144
- clickClose: false,
145
- closeText: 'close',
146
- showClose: false
147
- },
148
- setting = kraken_settings.api_lossy,
149
- nImages = bulkImageData.length,
150
- header = '<p class="krakenBulkHeader">Kraken Bulk Image Optimization</p>',
151
- krakEmAll = '<button class="kraken_req_bulk">Krak \'em all</button>',
152
- typeRadios = '<span class="radiosWrap"><span class="kraken-bulk-choose-type">Choose:</span>' + '<input type="radio" id="kraken-bulk-type-lossy" value="Lossy" name="kraken-bulk-type"/>' + '<label for="kraken-bulk-type-lossy">Lossy</label>&nbsp;' + '<input type="radio" id="kraken-bulk-type-lossless" value="Lossless" name="kraken-bulk-type"/>' + '<label for="kraken-bulk-type-lossless">Lossless</label></span>',
153
- $modal = $('<div id="kraken-bulk-modal" class="kraken-modal"></div>')
154
- .html(header)
155
- .append(typeRadios)
156
- .append('<br /><small class="kraken-bulk-small">The following <strong>' + nImages + '</strong> images will be optimized by Kraken.io using the <strong class="bulkSetting">' + setting + '</strong> setting:</small><br />')
157
- .appendTo("body")
158
- .kmodal(modalOptions)
159
- .bind($.kmodal.BEFORE_CLOSE, function(event, modal) {
160
 
161
- })
162
- .bind($.kmodal.OPEN, function(event, modal) {
163
 
164
- })
165
- .bind($.kmodal.CLOSE, function(event, modal) {
166
- $("#kraken-bulk-modal").remove();
167
- })
168
- .css({
169
- top: "10px",
170
- marginTop: "40px"
171
- });
172
 
173
- if (setting === 'lossy') {
174
  $("#kraken-bulk-type-lossy").attr("checked", true);
175
  } else {
176
  $("#kraken-bulk-type-lossless").attr("checked", true);
@@ -193,17 +184,16 @@ jQuery(document).ready(function($) {
193
  });
194
 
195
  var $table = $('<table id="kraken-bulk"></table>'),
196
- $headerRow = $('<tr class="kraken-bulk-header"><td>File</td><td style="width:120px">Original Size</td><td style="width:120px">Kraked Size</td><td style="width:120px">Savings</td><td style="width:120px">% Savings</td></tr>');
197
 
198
  $table.append($headerRow);
199
  $.each(bulkImageData, function(index, element) {
200
- $table.append('<tr class="kraken-item-row" data-krakenbulkid="' + element.id + '"><td class="kraken-filename">' + element.filename + '</td><td class="kraken-originalsize">' + element.originalSize + '</td><td class="kraken-krakedsize"><span class="krakenBulkSpinner hidden"></span></td><td class="kraken-savings"></td><td class="kraken-savingsPercent"></td></tr>');
201
  });
202
 
203
  $modal
204
  .append($table)
205
- .append(krakEmAll)
206
- .append('<span class="close-kraken-bulk">Close Window</span>');
207
 
208
  $(".close-kraken-bulk").click(function() {
209
  $.kmodal.close();
@@ -218,6 +208,7 @@ jQuery(document).ready(function($) {
218
  }
219
  };
220
 
 
221
  var bulkAction = function(bulkImageData) {
222
 
223
  $bulkTable = $("#kraken-bulk");
@@ -242,37 +233,44 @@ jQuery(document).ready(function($) {
242
  data: {
243
  'action': 'kraken_request',
244
  'id': id,
245
- 'type': $("input[name='kraken-bulk-type']:checked").val().toLowerCase()
 
246
  },
247
  type: "post",
248
  dataType: "json",
249
  timeout: 360000
250
  })
251
  .done(function(data, textStatus, jqXHR) {
252
- if (data.success && typeof data.error === 'undefined') {
253
  var type = data.type,
254
  originalSize = data.original_size,
255
- krakedSize = data.kraked_size,
256
  savingsPercent = data.savings_percent,
257
  savingsBytes = data.saved_bytes;
258
 
259
- $krakedSizeColumn.text(krakedSize);
 
 
 
 
 
260
  $savingsPercentColumn.text(savingsPercent);
261
  $savingsBytesColumn.text(savingsBytes);
262
 
263
  var $button = $("button[id='krakenid-" + id + "']"),
264
  $parent = $button.parent(),
265
  $cell = $button.closest("td"),
266
- $originalSizeColumn = $button.parent().prev("td.original_size")
267
 
268
 
269
  $parent.fadeOut("fast", function() {
270
  $cell.find(".noSavings, .krakenErrorWrap").remove();
271
- krakedData = '<strong>' + krakedSize + '</strong><br /><small>Type:&nbsp;' + type + '</small><br /><small>Savings: ' + savingsPercent + '</small>';
272
- if (typeof data.thumbs_data !== 'undefined') {
273
- krakedData += '<br /><small>' + data.thumbs_data.length + ' thumbs optimized</small>';
274
- }
275
- $(this).replaceWith(krakedData);
 
276
  $originalSizeColumn.html(originalSize);
277
  $parent.remove();
278
  });
@@ -284,7 +282,6 @@ jQuery(document).ready(function($) {
284
 
285
  }
286
  }
287
-
288
  })
289
 
290
  .fail(function() {
@@ -338,13 +335,45 @@ jQuery(document).ready(function($) {
338
  }
339
  });
340
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
341
  $('body').on('click', 'small.krakenReset', function(e) {
342
  e.preventDefault();
343
  var $resetButton = $(this);
344
  var resetData = {
345
  action: 'kraken_reset'
346
  };
 
347
  resetData.id = $(this).data("id");
 
348
 
349
  var $spinner = $('<span class="resetSpinner"></span>');
350
  $resetButton.after($spinner);
@@ -358,13 +387,14 @@ jQuery(document).ready(function($) {
358
  })
359
  .done(function(data, textStatus, jqXHR) {
360
  if (data.success !== 'undefined') {
361
- $resetButton
362
- .closest('.kraked_size.column-kraked_size')
363
  .hide()
364
  .html(data.html)
365
  .fadeIn()
366
  .prev(".original_size.column-original_size")
367
  .html(data.original_size);
 
 
368
  }
369
  });
370
  });
@@ -417,7 +447,7 @@ jQuery(document).ready(function($) {
417
  $rows.show();
418
  $plusMinus
419
  .removeClass('dashicons-arrow-right')
420
- .addClass('dashicons-arrow-down');
421
  }
422
  });
423
 
1
  jQuery(document).ready(function($) {
2
 
3
+ var tipsySettings = {
4
+ gravity: 'e',
5
+ html: true,
6
+ trigger: 'manual',
7
+ className: function() {
8
+ return 'tipsy-' + $(this).data('id');
9
+ },
10
+ title: function() {
11
+ activeId = $(this).data('id');
12
+ return $(this).attr('original-title');
13
+ }
14
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
 
16
  $('.krakenWhatsThis').tipsy({
17
  fade: true,
18
  gravity: 'w'
19
  });
20
 
21
+ $('.krakenError').tipsy({
22
+ fade: true,
23
+ gravity: 'e'
24
+ });
25
+
26
  var data = {
27
  action: 'kraken_request'
28
  },
36
 
37
  var requestSuccess = function(data, textStatus, jqXHR) {
38
  var $button = $(this),
39
+ $parent = $(this).closest('.kraken-wrap, .buttonWrap'),
40
  $cell = $(this).closest("td");
41
 
42
+ if (data.html) {
 
43
  $button.text("Image optimized");
44
 
45
  var type = data.type,
 
46
  originalSize = data.original_size,
 
47
  $originalSizeColumn = $(this).parent().prev("td.original_size"),
48
  krakedData = '';
49
 
50
  $parent.fadeOut("fast", function() {
51
+ $cell
52
+ .find(".noSavings, .krakenErrorWrap")
53
+ .remove();
54
+ $cell.html(data.html);
55
+ $cell.find('.kraken-item-details')
56
+ .tipsy(tipsySettings);
57
  $originalSizeColumn.html(originalSize);
58
  $parent.remove();
59
  });
126
  return rv;
127
  };
128
 
129
+ var bulkModalOptions = {
130
+ zIndex: 4,
131
+ escapeClose: true,
132
+ clickClose: false,
133
+ closeText: 'close',
134
+ showClose: false
135
+ };
136
+
137
  var renderBulkImageSummary = function(bulkImageData) {
138
+ var setting = kraken_settings.api_lossy;
139
+ var nImages = bulkImageData.length;
140
+ var header = '<p class="krakenBulkHeader">Kraken Bulk Image Optimization <span class="close-kraken-bulk">&times;</span></p>';
141
+ var krakEmAll = '<button class="kraken_req_bulk">Krak \'em all</button>';
142
+ var typeRadios = '<div class="radiosWrap"><p>Choose optimization mode:</p><label><input type="radio" id="kraken-bulk-type-lossy" value="Lossy" name="kraken-bulk-type"/>Intelligent Lossy</label>&nbsp;&nbsp;&nbsp;<label><input type="radio" id="kraken-bulk-type-lossless" value="Lossless" name="kraken-bulk-type"/>Lossless</label></div>';
143
+
144
+ var $modal = $('<div id="kraken-bulk-modal" class="kraken-modal"></div>')
145
+ .html(header)
146
+ .append(typeRadios)
147
+ .append('<p class="the-following">The following <strong>' + nImages + '</strong> images will be optimized by Kraken.io using the <strong class="bulkSetting">' + setting + '</strong> setting:</p>')
148
+ .appendTo("body")
149
+ .kmodal(bulkModalOptions)
150
+ .bind($.kmodal.BEFORE_CLOSE, function(event, modal) {
 
 
 
 
 
 
151
 
152
+ })
153
+ .bind($.kmodal.OPEN, function(event, modal) {
154
 
155
+ })
156
+ .bind($.kmodal.CLOSE, function(event, modal) {
157
+ $("#kraken-bulk-modal").remove();
158
+ })
159
+ .css({
160
+ top: "10px",
161
+ marginTop: "40px"
162
+ });
163
 
164
+ if (setting === "lossy") {
165
  $("#kraken-bulk-type-lossy").attr("checked", true);
166
  } else {
167
  $("#kraken-bulk-type-lossless").attr("checked", true);
184
  });
185
 
186
  var $table = $('<table id="kraken-bulk"></table>'),
187
+ $headerRow = $('<tr class="kraken-bulk-header"><td>File Name</td><td style="width:120px">Original Size</td><td style="width:120px">Kraken.io Stats</td></tr>');
188
 
189
  $table.append($headerRow);
190
  $.each(bulkImageData, function(index, element) {
191
+ $table.append('<tr class="kraken-item-row" data-krakenbulkid="' + element.id + '"><td class="kraken-bulk-filename">' + element.filename + '</td><td class="kraken-originalsize">' + element.originalSize + '</td><td class="kraken-krakedsize"><span class="krakenBulkSpinner hidden"></span></td></tr>');
192
  });
193
 
194
  $modal
195
  .append($table)
196
+ .append(krakEmAll);
 
197
 
198
  $(".close-kraken-bulk").click(function() {
199
  $.kmodal.close();
208
  }
209
  };
210
 
211
+
212
  var bulkAction = function(bulkImageData) {
213
 
214
  $bulkTable = $("#kraken-bulk");
233
  data: {
234
  'action': 'kraken_request',
235
  'id': id,
236
+ 'type': $("input[name='kraken-bulk-type']:checked").val().toLowerCase(),
237
+ 'origin': 'bulk_optimizer'
238
  },
239
  type: "post",
240
  dataType: "json",
241
  timeout: 360000
242
  })
243
  .done(function(data, textStatus, jqXHR) {
244
+ if (data.success && typeof data.message === 'undefined') {
245
  var type = data.type,
246
  originalSize = data.original_size,
247
+ krakedSize = data.html,
248
  savingsPercent = data.savings_percent,
249
  savingsBytes = data.saved_bytes;
250
 
251
+ $krakedSizeColumn.html(data.html);
252
+
253
+ $krakedSizeColumn
254
+ .find('.kraken-item-details')
255
+ .remove();
256
+
257
  $savingsPercentColumn.text(savingsPercent);
258
  $savingsBytesColumn.text(savingsBytes);
259
 
260
  var $button = $("button[id='krakenid-" + id + "']"),
261
  $parent = $button.parent(),
262
  $cell = $button.closest("td"),
263
+ $originalSizeColumn = $button.parent().prev("td.original_size");
264
 
265
 
266
  $parent.fadeOut("fast", function() {
267
  $cell.find(".noSavings, .krakenErrorWrap").remove();
268
+ $cell
269
+ .empty()
270
+ .html(data.html);
271
+ $cell
272
+ .find('.kraken-item-details')
273
+ .tipsy(tipsySettings);
274
  $originalSizeColumn.html(originalSize);
275
  $parent.remove();
276
  });
282
 
283
  }
284
  }
 
285
  })
286
 
287
  .fail(function() {
335
  }
336
  });
337
 
338
+ var activeId = null;
339
+ $('.kraken-item-details').tipsy(tipsySettings);
340
+
341
+ var $activePopup = null;
342
+ $('body').on('click', '.kraken-item-details', function(e) {
343
+ //$('.tipsy[class="tipsy-' + activeId + '"]').remove();
344
+
345
+ var id = $(this).data('id');
346
+ $('.tipsy').remove();
347
+ if (id == activeId) {
348
+ activeId = null;
349
+ $(this).text('Show details');
350
+ return;
351
+ }
352
+ $('.kraken-item-details').text('Show details');
353
+ $(this).tipsy('show');
354
+ $(this).text('Hide details');
355
+ });
356
+
357
+ $('body').on('click', function(e) {
358
+ var $t = $(e.target);
359
+ if (($t.hasClass('tipsy') || $t.closest('.tipsy').length) || $t.hasClass('kraken-item-details')) {
360
+ return;
361
+ } else {
362
+ activeId = null;
363
+ $('.kraken-item-details').text('Show details');
364
+ $('.tipsy').remove();
365
+ }
366
+ });
367
+
368
  $('body').on('click', 'small.krakenReset', function(e) {
369
  e.preventDefault();
370
  var $resetButton = $(this);
371
  var resetData = {
372
  action: 'kraken_reset'
373
  };
374
+
375
  resetData.id = $(this).data("id");
376
+ $row = $('#post-' + resetData.id).find('.kraked_size');
377
 
378
  var $spinner = $('<span class="resetSpinner"></span>');
379
  $resetButton.after($spinner);
387
  })
388
  .done(function(data, textStatus, jqXHR) {
389
  if (data.success !== 'undefined') {
390
+ $row
 
391
  .hide()
392
  .html(data.html)
393
  .fadeIn()
394
  .prev(".original_size.column-original_size")
395
  .html(data.original_size);
396
+
397
+ $('.tipsy').remove();
398
  }
399
  });
400
  });
447
  $rows.show();
448
  $plusMinus
449
  .removeClass('dashicons-arrow-right')
450
+ .addClass('dashicons-arrow-down');
451
  }
452
  });
453
 
js/dist/kraken.min.js CHANGED
@@ -1,3 +1,2 @@
1
- !function(){function only_once(fn){var called=!1;return function(){if(called)throw new Error("Callback was already called.");called=!0,fn.apply(root,arguments)}}var root,previous_async,async={};root=this,null!=root&&(previous_async=root.async),async.noConflict=function(){return root.async=previous_async,async};var _each=function(arr,iterator){if(arr.forEach)return arr.forEach(iterator);for(var i=0;i<arr.length;i+=1)iterator(arr[i],i,arr)},_map=function(arr,iterator){if(arr.map)return arr.map(iterator);var results=[];return _each(arr,function(x,i,a){results.push(iterator(x,i,a))}),results},_reduce=function(arr,iterator,memo){return arr.reduce?arr.reduce(iterator,memo):(_each(arr,function(x,i,a){memo=iterator(memo,x,i,a)}),memo)},_keys=function(obj){if(Object.keys)return Object.keys(obj);var keys=[];for(var k in obj)obj.hasOwnProperty(k)&&keys.push(k);return keys};"undefined"!=typeof process&&process.nextTick?(async.nextTick=process.nextTick,"undefined"!=typeof setImmediate?async.setImmediate=function(fn){setImmediate(fn)}:async.setImmediate=async.nextTick):"function"==typeof setImmediate?(async.nextTick=function(fn){setImmediate(fn)},async.setImmediate=async.nextTick):(async.nextTick=function(fn){setTimeout(fn,0)},async.setImmediate=async.nextTick),async.each=function(arr,iterator,callback){if(callback=callback||function(){},!arr.length)return callback();var completed=0;_each(arr,function(x){iterator(x,only_once(function(err){err?(callback(err),callback=function(){}):(completed+=1,completed>=arr.length&&callback(null))}))})},async.forEach=async.each,async.eachSeries=function(arr,iterator,callback){if(callback=callback||function(){},!arr.length)return callback();var completed=0,iterate=function(){iterator(arr[completed],function(err){err?(callback(err),callback=function(){}):(completed+=1,completed>=arr.length?callback(null):iterate())})};iterate()},async.forEachSeries=async.eachSeries,async.eachLimit=function(arr,limit,iterator,callback){var fn=_eachLimit(limit);fn.apply(null,[arr,iterator,callback])},async.forEachLimit=async.eachLimit;var _eachLimit=function(limit){return function(arr,iterator,callback){if(callback=callback||function(){},!arr.length||0>=limit)return callback();var completed=0,started=0,running=0;!function replenish(){if(completed>=arr.length)return callback();for(;limit>running&&started<arr.length;)started+=1,running+=1,iterator(arr[started-1],function(err){err?(callback(err),callback=function(){}):(completed+=1,running-=1,completed>=arr.length?callback():replenish())})}()}},doParallel=function(fn){return function(){var args=Array.prototype.slice.call(arguments);return fn.apply(null,[async.each].concat(args))}},doParallelLimit=function(limit,fn){return function(){var args=Array.prototype.slice.call(arguments);return fn.apply(null,[_eachLimit(limit)].concat(args))}},doSeries=function(fn){return function(){var args=Array.prototype.slice.call(arguments);return fn.apply(null,[async.eachSeries].concat(args))}},_asyncMap=function(eachfn,arr,iterator,callback){var results=[];arr=_map(arr,function(x,i){return{index:i,value:x}}),eachfn(arr,function(x,callback){iterator(x.value,function(err,v){results[x.index]=v,callback(err)})},function(err){callback(err,results)})};async.map=doParallel(_asyncMap),async.mapSeries=doSeries(_asyncMap),async.mapLimit=function(arr,limit,iterator,callback){return _mapLimit(limit)(arr,iterator,callback)};var _mapLimit=function(limit){return doParallelLimit(limit,_asyncMap)};async.reduce=function(arr,memo,iterator,callback){async.eachSeries(arr,function(x,callback){iterator(memo,x,function(err,v){memo=v,callback(err)})},function(err){callback(err,memo)})},async.inject=async.reduce,async.foldl=async.reduce,async.reduceRight=function(arr,memo,iterator,callback){var reversed=_map(arr,function(x){return x}).reverse();async.reduce(reversed,memo,iterator,callback)},async.foldr=async.reduceRight;var _filter=function(eachfn,arr,iterator,callback){var results=[];arr=_map(arr,function(x,i){return{index:i,value:x}}),eachfn(arr,function(x,callback){iterator(x.value,function(v){v&&results.push(x),callback()})},function(err){callback(_map(results.sort(function(a,b){return a.index-b.index}),function(x){return x.value}))})};async.filter=doParallel(_filter),async.filterSeries=doSeries(_filter),async.select=async.filter,async.selectSeries=async.filterSeries;var _reject=function(eachfn,arr,iterator,callback){var results=[];arr=_map(arr,function(x,i){return{index:i,value:x}}),eachfn(arr,function(x,callback){iterator(x.value,function(v){v||results.push(x),callback()})},function(err){callback(_map(results.sort(function(a,b){return a.index-b.index}),function(x){return x.value}))})};async.reject=doParallel(_reject),async.rejectSeries=doSeries(_reject);var _detect=function(eachfn,arr,iterator,main_callback){eachfn(arr,function(x,callback){iterator(x,function(result){result?(main_callback(x),main_callback=function(){}):callback()})},function(err){main_callback()})};async.detect=doParallel(_detect),async.detectSeries=doSeries(_detect),async.some=function(arr,iterator,main_callback){async.each(arr,function(x,callback){iterator(x,function(v){v&&(main_callback(!0),main_callback=function(){}),callback()})},function(err){main_callback(!1)})},async.any=async.some,async.every=function(arr,iterator,main_callback){async.each(arr,function(x,callback){iterator(x,function(v){v||(main_callback(!1),main_callback=function(){}),callback()})},function(err){main_callback(!0)})},async.all=async.every,async.sortBy=function(arr,iterator,callback){async.map(arr,function(x,callback){iterator(x,function(err,criteria){err?callback(err):callback(null,{value:x,criteria:criteria})})},function(err,results){if(err)return callback(err);var fn=function(left,right){var a=left.criteria,b=right.criteria;return b>a?-1:a>b?1:0};callback(null,_map(results.sort(fn),function(x){return x.value}))})},async.auto=function(tasks,callback){callback=callback||function(){};var keys=_keys(tasks);if(!keys.length)return callback(null);var results={},listeners=[],addListener=function(fn){listeners.unshift(fn)},removeListener=function(fn){for(var i=0;i<listeners.length;i+=1)if(listeners[i]===fn)return void listeners.splice(i,1)},taskComplete=function(){_each(listeners.slice(0),function(fn){fn()})};addListener(function(){_keys(results).length===keys.length&&(callback(null,results),callback=function(){})}),_each(keys,function(k){var task=tasks[k]instanceof Function?[tasks[k]]:tasks[k],taskCallback=function(err){var args=Array.prototype.slice.call(arguments,1);if(args.length<=1&&(args=args[0]),err){var safeResults={};_each(_keys(results),function(rkey){safeResults[rkey]=results[rkey]}),safeResults[k]=args,callback(err,safeResults),callback=function(){}}else results[k]=args,async.setImmediate(taskComplete)},requires=task.slice(0,Math.abs(task.length-1))||[],ready=function(){return _reduce(requires,function(a,x){return a&&results.hasOwnProperty(x)},!0)&&!results.hasOwnProperty(k)};if(ready())task[task.length-1](taskCallback,results);else{var listener=function(){ready()&&(removeListener(listener),task[task.length-1](taskCallback,results))};addListener(listener)}})},async.waterfall=function(tasks,callback){if(callback=callback||function(){},tasks.constructor!==Array){var err=new Error("First argument to waterfall must be an array of functions");return callback(err)}if(!tasks.length)return callback();var wrapIterator=function(iterator){return function(err){if(err)callback.apply(null,arguments),callback=function(){};else{var args=Array.prototype.slice.call(arguments,1),next=iterator.next();args.push(next?wrapIterator(next):callback),async.setImmediate(function(){iterator.apply(null,args)})}}};wrapIterator(async.iterator(tasks))()};var _parallel=function(eachfn,tasks,callback){if(callback=callback||function(){},tasks.constructor===Array)eachfn.map(tasks,function(fn,callback){fn&&fn(function(err){var args=Array.prototype.slice.call(arguments,1);args.length<=1&&(args=args[0]),callback.call(null,err,args)})},callback);else{var results={};eachfn.each(_keys(tasks),function(k,callback){tasks[k](function(err){var args=Array.prototype.slice.call(arguments,1);args.length<=1&&(args=args[0]),results[k]=args,callback(err)})},function(err){callback(err,results)})}};async.parallel=function(tasks,callback){_parallel({map:async.map,each:async.each},tasks,callback)},async.parallelLimit=function(tasks,limit,callback){_parallel({map:_mapLimit(limit),each:_eachLimit(limit)},tasks,callback)},async.series=function(tasks,callback){if(callback=callback||function(){},tasks.constructor===Array)async.mapSeries(tasks,function(fn,callback){fn&&fn(function(err){var args=Array.prototype.slice.call(arguments,1);args.length<=1&&(args=args[0]),callback.call(null,err,args)})},callback);else{var results={};async.eachSeries(_keys(tasks),function(k,callback){tasks[k](function(err){var args=Array.prototype.slice.call(arguments,1);args.length<=1&&(args=args[0]),results[k]=args,callback(err)})},function(err){callback(err,results)})}},async.iterator=function(tasks){var makeCallback=function(index){var fn=function(){return tasks.length&&tasks[index].apply(null,arguments),fn.next()};return fn.next=function(){return index<tasks.length-1?makeCallback(index+1):null},fn};return makeCallback(0)},async.apply=function(fn){var args=Array.prototype.slice.call(arguments,1);return function(){return fn.apply(null,args.concat(Array.prototype.slice.call(arguments)))}};var _concat=function(eachfn,arr,fn,callback){var r=[];eachfn(arr,function(x,cb){fn(x,function(err,y){r=r.concat(y||[]),cb(err)})},function(err){callback(err,r)})};async.concat=doParallel(_concat),async.concatSeries=doSeries(_concat),async.whilst=function(test,iterator,callback){test()?iterator(function(err){return err?callback(err):void async.whilst(test,iterator,callback)}):callback()},async.doWhilst=function(iterator,test,callback){iterator(function(err){return err?callback(err):void(test()?async.doWhilst(iterator,test,callback):callback())})},async.until=function(test,iterator,callback){test()?callback():iterator(function(err){return err?callback(err):void async.until(test,iterator,callback)})},async.doUntil=function(iterator,test,callback){iterator(function(err){return err?callback(err):void(test()?callback():async.doUntil(iterator,test,callback))})},async.queue=function(worker,concurrency){function _insert(q,data,pos,callback){data.constructor!==Array&&(data=[data]),_each(data,function(task){var item={data:task,callback:"function"==typeof callback?callback:null};pos?q.tasks.unshift(item):q.tasks.push(item),q.saturated&&q.tasks.length===concurrency&&q.saturated(),async.setImmediate(q.process)})}void 0===concurrency&&(concurrency=1);var workers=0,q={tasks:[],concurrency:concurrency,saturated:null,empty:null,drain:null,push:function(data,callback){_insert(q,data,!1,callback)},unshift:function(data,callback){_insert(q,data,!0,callback)},process:function(){if(workers<q.concurrency&&q.tasks.length){var task=q.tasks.shift();q.empty&&0===q.tasks.length&&q.empty(),workers+=1;var next=function(){workers-=1,task.callback&&task.callback.apply(task,arguments),q.drain&&q.tasks.length+workers===0&&q.drain(),q.process()},cb=only_once(next);worker(task.data,cb)}},length:function(){return q.tasks.length},running:function(){return workers}};return q},async.cargo=function(worker,payload){var working=!1,tasks=[],cargo={tasks:tasks,payload:payload,saturated:null,empty:null,drain:null,push:function(data,callback){data.constructor!==Array&&(data=[data]),_each(data,function(task){tasks.push({data:task,callback:"function"==typeof callback?callback:null}),cargo.saturated&&tasks.length===payload&&cargo.saturated()}),async.setImmediate(cargo.process)},process:function process(){if(!working){if(0===tasks.length)return void(cargo.drain&&cargo.drain());var ts="number"==typeof payload?tasks.splice(0,payload):tasks.splice(0),ds=_map(ts,function(task){return task.data});cargo.empty&&cargo.empty(),working=!0,worker(ds,function(){working=!1;var args=arguments;_each(ts,function(data){data.callback&&data.callback.apply(null,args)}),process()})}},length:function(){return tasks.length},running:function(){return working}};return cargo};var _console_fn=function(name){return function(fn){var args=Array.prototype.slice.call(arguments,1);fn.apply(null,args.concat([function(err){var args=Array.prototype.slice.call(arguments,1);"undefined"!=typeof console&&(err?console.error&&console.error(err):console[name]&&_each(args,function(x){console[name](x)}))}]))}};async.log=_console_fn("log"),async.dir=_console_fn("dir"),async.memoize=function(fn,hasher){var memo={},queues={};hasher=hasher||function(x){return x};var memoized=function(){var args=Array.prototype.slice.call(arguments),callback=args.pop(),key=hasher.apply(null,args);key in memo?callback.apply(null,memo[key]):key in queues?queues[key].push(callback):(queues[key]=[callback],fn.apply(null,args.concat([function(){memo[key]=arguments;var q=queues[key];delete queues[key];for(var i=0,l=q.length;l>i;i++)q[i].apply(null,arguments)}])))};return memoized.memo=memo,memoized.unmemoized=fn,memoized},async.unmemoize=function(fn){return function(){return(fn.unmemoized||fn).apply(null,arguments)}},async.times=function(count,iterator,callback){for(var counter=[],i=0;count>i;i++)counter.push(i);return async.map(counter,iterator,callback)},async.timesSeries=function(count,iterator,callback){for(var counter=[],i=0;count>i;i++)counter.push(i);return async.mapSeries(counter,iterator,callback)},async.compose=function(){var fns=Array.prototype.reverse.call(arguments);return function(){var that=this,args=Array.prototype.slice.call(arguments),callback=args.pop();async.reduce(fns,args,function(newargs,fn,cb){fn.apply(that,newargs.concat([function(){var err=arguments[0],nextargs=Array.prototype.slice.call(arguments,1);cb(err,nextargs)}]))},function(err,results){callback.apply(that,[err].concat(results))})}};var _applyEach=function(eachfn,fns){var go=function(){var that=this,args=Array.prototype.slice.call(arguments),callback=args.pop();return eachfn(fns,function(fn,cb){fn.apply(that,args.concat([cb]))},callback)};if(arguments.length>2){var args=Array.prototype.slice.call(arguments,2);return go.apply(this,args)}return go};async.applyEach=doParallel(_applyEach),async.applyEachSeries=doSeries(_applyEach),async.forever=function(fn,callback){function next(err){if(err){if(callback)return callback(err);throw err}fn(next)}next()},"undefined"!=typeof define&&define.amd?define([],function(){return async}):"undefined"!=typeof module&&module.exports?module.exports=async:root.async=async}(),function($){function maybeCall(thing,ctx){return"function"==typeof thing?thing.call(ctx):thing}function isElementInDOM(ele){for(;ele=ele.parentNode;)if(ele==document)return!0;return!1}function Tipsy(element,options){this.$element=$(element),this.options=options,this.enabled=!0,this.fixTitle()}Tipsy.prototype={show:function(){var title=this.getTitle();if(title&&this.enabled){var $tip=this.tip();$tip.find(".tipsy-inner")[this.options.html?"html":"text"](title),$tip[0].className="tipsy",$tip.remove().css({top:0,left:0,visibility:"hidden",display:"block"}).prependTo(document.body);var tp,pos=$.extend({},this.$element.offset(),{width:this.$element[0].offsetWidth,height:this.$element[0].offsetHeight}),actualWidth=$tip[0].offsetWidth,actualHeight=$tip[0].offsetHeight,gravity=maybeCall(this.options.gravity,this.$element[0]);switch(gravity.charAt(0)){case"n":tp={top:pos.top+pos.height+this.options.offset,left:pos.left+pos.width/2-actualWidth/2};break;case"s":tp={top:pos.top-actualHeight-this.options.offset,left:pos.left+pos.width/2-actualWidth/2};break;case"e":tp={top:pos.top+pos.height/2-actualHeight/2,left:pos.left-actualWidth-this.options.offset};break;case"w":tp={top:pos.top+pos.height/2-actualHeight/2,left:pos.left+pos.width+this.options.offset}}2==gravity.length&&("w"==gravity.charAt(1)?tp.left=pos.left+pos.width/2-15:tp.left=pos.left+pos.width/2-actualWidth+15),$tip.css(tp).addClass("tipsy-"+gravity),$tip.find(".tipsy-arrow")[0].className="tipsy-arrow tipsy-arrow-"+gravity.charAt(0),this.options.className&&$tip.addClass(maybeCall(this.options.className,this.$element[0])),this.options.fade?$tip.stop().css({opacity:0,display:"block",visibility:"visible"}).animate({opacity:this.options.opacity}):$tip.css({visibility:"visible",opacity:this.options.opacity})}},hide:function(){this.options.fade?this.tip().stop().fadeOut(function(){$(this).remove()}):this.tip().remove()},fixTitle:function(){var $e=this.$element;($e.attr("title")||"string"!=typeof $e.attr("original-title"))&&$e.attr("original-title",$e.attr("title")||"").removeAttr("title")},getTitle:function(){var title,$e=this.$element,o=this.options;this.fixTitle();var title,o=this.options;return"string"==typeof o.title?title=$e.attr("title"==o.title?"original-title":o.title):"function"==typeof o.title&&(title=o.title.call($e[0])),title=(""+title).replace(/(^\s*|\s*$)/,""),title||o.fallback},tip:function(){return this.$tip||(this.$tip=$('<div class="tipsy"></div>').html('<div class="tipsy-arrow"></div><div class="tipsy-inner"></div>'),this.$tip.data("tipsy-pointee",this.$element[0])),this.$tip},validate:function(){this.$element[0].parentNode||(this.hide(),this.$element=null,this.options=null)},enable:function(){this.enabled=!0},disable:function(){this.enabled=!1},toggleEnabled:function(){this.enabled=!this.enabled}},$.fn.tipsy=function(options){function get(ele){var tipsy=$.data(ele,"tipsy");return tipsy||(tipsy=new Tipsy(ele,$.fn.tipsy.elementOptions(ele,options)),$.data(ele,"tipsy",tipsy)),tipsy}function enter(){var tipsy=get(this);tipsy.hoverState="in",0==options.delayIn?tipsy.show():(tipsy.fixTitle(),setTimeout(function(){"in"==tipsy.hoverState&&tipsy.show()},options.delayIn))}function leave(){var tipsy=get(this);tipsy.hoverState="out",0==options.delayOut?tipsy.hide():setTimeout(function(){"out"==tipsy.hoverState&&tipsy.hide()},options.delayOut)}if(options===!0)return this.data("tipsy");if("string"==typeof options){var tipsy=this.data("tipsy");return tipsy&&tipsy[options](),this}if(options=$.extend({},$.fn.tipsy.defaults,options),options.live||this.each(function(){get(this)}),"manual"!=options.trigger){var binder=options.live?"live":"bind",eventIn="hover"==options.trigger?"mouseenter":"focus",eventOut="hover"==options.trigger?"mouseleave":"blur";this[binder](eventIn,enter)[binder](eventOut,leave)}return this},$.fn.tipsy.defaults={className:null,delayIn:0,delayOut:0,fade:!1,fallback:"",gravity:"n",html:!1,live:!1,offset:0,opacity:.8,title:"title",trigger:"hover"},$.fn.tipsy.revalidate=function(){$(".tipsy").each(function(){var pointee=$.data(this,"tipsy-pointee");pointee&&isElementInDOM(pointee)||$(this).remove()})},$.fn.tipsy.elementOptions=function(ele,options){return $.metadata?$.extend({},options,$(ele).metadata()):options},$.fn.tipsy.autoNS=function(){return $(this).offset().top>$(document).scrollTop()+$(window).height()/2?"s":"n"},$.fn.tipsy.autoWE=function(){return $(this).offset().left>$(document).scrollLeft()+$(window).width()/2?"e":"w"},$.fn.tipsy.autoBounds=function(margin,prefer){return function(){var dir={ns:prefer[0],ew:prefer.length>1?prefer[1]:!1},boundTop=$(document).scrollTop()+margin,boundLeft=$(document).scrollLeft()+margin,$this=$(this);return $this.offset().top<boundTop&&(dir.ns="n"),$this.offset().left<boundLeft&&(dir.ew="w"),$(window).width()+$(document).scrollLeft()-$this.offset().left<margin&&(dir.ew="e"),$(window).height()+$(document).scrollTop()-$this.offset().top<margin&&(dir.ns="s"),dir.ns+(dir.ew?dir.ew:"")}}}(jQuery),function($){var current=null;$.kmodal=function(el,options){$.kmodal.close();var remove,target;if(this.$body=$("body"),this.options=$.extend({},$.kmodal.defaults,options),this.options.doFade=!isNaN(parseInt(this.options.fadeDuration,10)),el.is("a"))if(target=el.attr("href"),/^#/.test(target)){if(this.$elm=$(target),1!==this.$elm.length)return null;this.open()}else this.$elm=$("<div>"),this.$body.append(this.$elm),remove=function(event,modal){modal.elm.remove()},this.showSpinner(),el.trigger($.kmodal.AJAX_SEND),$.get(target).done(function(html){current&&(el.trigger($.kmodal.AJAX_SUCCESS),current.$elm.empty().append(html).on($.kmodal.CLOSE,remove),current.hideSpinner(),current.open(),el.trigger($.kmodal.AJAX_COMPLETE))}).fail(function(){el.trigger($.kmodal.AJAX_FAIL),current.hideSpinner(),el.trigger($.kmodal.AJAX_COMPLETE)});else this.$elm=el,this.$body.append(this.$elm),this.open()},$.kmodal.prototype={constructor:$.kmodal,open:function(){var m=this;this.options.doFade?(this.block(),setTimeout(function(){m.show()},this.options.fadeDuration*this.options.fadeDelay)):(this.block(),this.show()),this.options.escapeClose&&$(document).on("keydown.modal",function(event){27==event.which&&$.kmodal.close()}),this.options.clickClose&&this.blocker.click($.kmodal.close)},close:function(){this.unblock(),this.hide(),$(document).off("keydown.modal")},block:function(){var initialOpacity=this.options.doFade?0:this.options.opacity;this.$elm.trigger($.kmodal.BEFORE_BLOCK,[this._ctx()]),this.blocker=$('<div class="jquery-modal blocker"></div>').css({top:0,right:0,bottom:0,left:0,width:"100%",height:"100%",position:"fixed",zIndex:this.options.zIndex,background:this.options.overlay,opacity:initialOpacity}),this.$body.append(this.blocker),this.options.doFade&&this.blocker.animate({opacity:this.options.opacity},this.options.fadeDuration),this.$elm.trigger($.kmodal.BLOCK,[this._ctx()])},unblock:function(){this.options.doFade?this.blocker.fadeOut(this.options.fadeDuration,function(){$(this).remove()}):this.blocker.remove()},show:function(){this.$elm.trigger($.kmodal.BEFORE_OPEN,[this._ctx()]),this.options.showClose&&(this.closeButton=$('<a href="#close-modal" rel="modal:close" class="close-modal '+this.options.closeClass+'">'+this.options.closeText+"</a>"),this.$elm.append(this.closeButton)),this.$elm.addClass(this.options.modalClass+" current"),this.center(),this.options.doFade?this.$elm.fadeIn(this.options.fadeDuration):this.$elm.show(),this.$elm.trigger($.kmodal.OPEN,[this._ctx()])},hide:function(){this.$elm.trigger($.kmodal.BEFORE_CLOSE,[this._ctx()]),this.closeButton&&this.closeButton.remove(),this.$elm.removeClass("current"),this.options.doFade?this.$elm.fadeOut(this.options.fadeDuration):this.$elm.hide(),this.$elm.trigger($.kmodal.CLOSE,[this._ctx()])},showSpinner:function(){this.options.showSpinner&&(this.spinner=this.spinner||$('<div class="'+this.options.modalClass+'-spinner"></div>').append(this.options.spinnerHtml),this.$body.append(this.spinner),this.spinner.show())},hideSpinner:function(){this.spinner&&this.spinner.remove()},center:function(){this.$elm.css({position:"fixed",top:"50%",left:"50%",marginTop:-(this.$elm.outerHeight()/2),marginLeft:-(this.$elm.outerWidth()/2),zIndex:this.options.zIndex+1})},_ctx:function(){return{elm:this.$elm,blocker:this.blocker,options:this.options}}},$.kmodal.prototype.resize=$.kmodal.prototype.center,$.kmodal.close=function(event){if(current){event&&event.preventDefault(),current.close();var that=current.$elm;return current=null,that}},$.kmodal.resize=function(){current&&current.resize()},$.kmodal.isActive=function(){return current?!0:!1},$.kmodal.defaults={overlay:"#000",opacity:.75,zIndex:1,escapeClose:!0,clickClose:!0,closeText:"Close",closeClass:"",modalClass:"kraken-modal",spinnerHtml:null,showSpinner:!0,showClose:!0,fadeDuration:null,fadeDelay:1},$.kmodal.BEFORE_BLOCK="modal:before-block",$.kmodal.BLOCK="modal:block",$.kmodal.BEFORE_OPEN="modal:before-open",$.kmodal.OPEN="modal:open",$.kmodal.BEFORE_CLOSE="modal:before-close",$.kmodal.CLOSE="modal:close",$.kmodal.AJAX_SEND="modal:ajax:send",$.kmodal.AJAX_SUCCESS="modal:ajax:success",$.kmodal.AJAX_FAIL="modal:ajax:fail",$.kmodal.AJAX_COMPLETE="modal:ajax:complete",$.fn.kmodal=function(options){return 1===this.length&&(current=new $.kmodal(this,options)),this},$(document).on("click.modal",'a[rel="modal:close"]',$.kmodal.close),$(document).on("click.modal",'a[rel="modal:open"]',function(event){event.preventDefault(),$(this).kmodal()})}(jQuery),jQuery(document).ready(function($){$(".krakenWhatsThis").tipsy({fade:!0,gravity:"w"});var data={action:"kraken_request"},errorTpl='<div class="krakenErrorWrap"><a class="krakenError">Failed! Hover here</a></div>',$btnApplyBulkAction=$("#doaction"),$btnApplyBulkAction2=$("#doaction2"),$topBulkActionDropdown=$(".tablenav.top .bulkactions select[name='action']"),$bottomBulkActionDropdown=$(".tablenav.bottom .bulkactions select[name='action2']"),requestSuccess=function(data,textStatus,jqXHR){var $button=$(this),$parent=$(this).parent(),$cell=$(this).closest("td");if(data.success&&"undefined"==typeof data.error){$button.text("Image optimized");var originalSize=(data.type,data.kraked_size,data.original_size),$originalSizeColumn=(data.savings_percent,$(this).parent().prev("td.original_size"));$parent.fadeOut("fast",function(){$cell.find(".noSavings, .krakenErrorWrap").remove(),$(this).replaceWith(data.html),$originalSizeColumn.html(originalSize),$parent.remove()})}else if(data.error){var $error=$(errorTpl).attr("title",data.error);$parent.closest("td").find(".krakenErrorWrap").remove(),$parent.after($error),$error.tipsy({fade:!0,gravity:"e"}),$button.text("Retry request").removeAttr("disabled").css({opacity:1})}},requestFail=function(jqXHR,textStatus,errorThrown){$(this).removeAttr("disabled")},requestComplete=function(jqXHR,textStatus,errorThrown){$(this).removeAttr("disabled"),$(this).parent().find(".krakenSpinner").css("display","none")},opts='<option value="kraken-bulk-lossy">Krak \'em all</option>';$topBulkActionDropdown.find("option:last-child").before(opts),$bottomBulkActionDropdown.find("option:last-child").before(opts);var getBulkImageData=function(){var $rows=$("tr[id^='post-']"),$row=null,postId=0,$krakBtn=null,btnData={},originalSize="",rv=[];return $rows.each(function(){$row=$(this),postId=this.id.replace(/^\D+/g,""),$row.find("input[type='checkbox'][value='"+postId+"']:checked").length&&($krakBtn=$row.find(".kraken_req"),$krakBtn.length&&(btnData=$krakBtn.data(),originalSize=$.trim($row.find("td.original_size").text()),btnData.originalSize=originalSize,rv.push(btnData)))}),rv},renderBulkImageSummary=function(bulkImageData){var modalOptions={zIndex:4,escapeClose:!0,clickClose:!1,closeText:"close",showClose:!1},setting=kraken_settings.api_lossy,nImages=bulkImageData.length,header='<p class="krakenBulkHeader">Kraken Bulk Image Optimization</p>',krakEmAll='<button class="kraken_req_bulk">Krak \'em all</button>',typeRadios='<span class="radiosWrap"><span class="kraken-bulk-choose-type">Choose:</span><input type="radio" id="kraken-bulk-type-lossy" value="Lossy" name="kraken-bulk-type"/><label for="kraken-bulk-type-lossy">Lossy</label>&nbsp;<input type="radio" id="kraken-bulk-type-lossless" value="Lossless" name="kraken-bulk-type"/><label for="kraken-bulk-type-lossless">Lossless</label></span>',$modal=$('<div id="kraken-bulk-modal" class="kraken-modal"></div>').html(header).append(typeRadios).append('<br /><small class="kraken-bulk-small">The following <strong>'+nImages+'</strong> images will be optimized by Kraken.io using the <strong class="bulkSetting">'+setting+"</strong> setting:</small><br />").appendTo("body").kmodal(modalOptions).bind($.kmodal.BEFORE_CLOSE,function(event,modal){}).bind($.kmodal.OPEN,function(event,modal){}).bind($.kmodal.CLOSE,function(event,modal){$("#kraken-bulk-modal").remove()}).css({top:"10px",marginTop:"40px"});"lossy"===setting?$("#kraken-bulk-type-lossy").attr("checked",!0):$("#kraken-bulk-type-lossless").attr("checked",!0),$bulkSettingSpan=$(".bulkSetting"),$("input[name='kraken-bulk-type']").change(function(){var text="kraken-bulk-type-lossy"===this.id?"lossy":"lossless";$bulkSettingSpan.text(text)}),$(".jquery-modal.blocker").click(function(e){return!1}),$("#menu-media ul.wp-submenu").css({"z-index":1});var $table=$('<table id="kraken-bulk"></table>'),$headerRow=$('<tr class="kraken-bulk-header"><td>File</td><td style="width:120px">Original Size</td><td style="width:120px">Kraked Size</td><td style="width:120px">Savings</td><td style="width:120px">% Savings</td></tr>');$table.append($headerRow),$.each(bulkImageData,function(index,element){$table.append('<tr class="kraken-item-row" data-krakenbulkid="'+element.id+'"><td class="kraken-filename">'+element.filename+'</td><td class="kraken-originalsize">'+element.originalSize+'</td><td class="kraken-krakedsize"><span class="krakenBulkSpinner hidden"></span></td><td class="kraken-savings"></td><td class="kraken-savingsPercent"></td></tr>')}),$modal.append($table).append(krakEmAll).append('<span class="close-kraken-bulk">Close Window</span>'),$(".close-kraken-bulk").click(function(){$.kmodal.close()}),nImages||$(".kraken_req_bulk").attr("disabled",!0).css({opacity:.5})},bulkAction=function(bulkImageData){$bulkTable=$("#kraken-bulk");var jqxhr=null,q=async.queue(function(task,callback){var id=task.id,$row=(task.filename,$bulkTable.find("tr[data-krakenbulkid='"+id+"']")),$krakedSizeColumn=$row.find(".kraken-krakedsize"),$spinner=$krakedSizeColumn.find(".krakenBulkSpinner").css({display:"inline-block"}),$savingsPercentColumn=$row.find(".kraken-savingsPercent"),$savingsBytesColumn=$row.find(".kraken-savings");jqxhr=$.ajax({url:ajax_object.ajax_url,data:{action:"kraken_request",id:id,type:$("input[name='kraken-bulk-type']:checked").val().toLowerCase()},type:"post",dataType:"json",timeout:36e4}).done(function(data,textStatus,jqXHR){if(data.success&&"undefined"==typeof data.error){var type=data.type,originalSize=data.original_size,krakedSize=data.kraked_size,savingsPercent=data.savings_percent,savingsBytes=data.saved_bytes;$krakedSizeColumn.text(krakedSize),$savingsPercentColumn.text(savingsPercent),$savingsBytesColumn.text(savingsBytes);var $button=$("button[id='krakenid-"+id+"']"),$parent=$button.parent(),$cell=$button.closest("td"),$originalSizeColumn=$button.parent().prev("td.original_size");$parent.fadeOut("fast",function(){$cell.find(".noSavings, .krakenErrorWrap").remove(),krakedData="<strong>"+krakedSize+"</strong><br /><small>Type:&nbsp;"+type+"</small><br /><small>Savings: "+savingsPercent+"</small>","undefined"!=typeof data.thumbs_data&&(krakedData+="<br /><small>"+data.thumbs_data.length+" thumbs optimized</small>"),$(this).replaceWith(krakedData),$originalSizeColumn.html(originalSize),$parent.remove()})}else data.error&&"This image can not be optimized any further"===data.error&&$krakedSizeColumn.text("No savings found.")}).fail(function(){}).always(function(){$spinner.css({display:"none"}),callback()})},kraken_settings.bulk_async_limit);q.drain=function(){$(".kraken_req_bulk").removeAttr("disabled").css({opacity:1}).text("Done").unbind("click").click(function(){$.kmodal.close()})},q.push(bulkImageData,function(err){})};$btnApplyBulkAction.add($btnApplyBulkAction2).click(function(e){if("kraken-bulk-lossy"===$(this).prev("select").val()){e.preventDefault();var bulkImageData=getBulkImageData();renderBulkImageSummary(bulkImageData),$(".kraken_req_bulk").click(function(e){e.preventDefault(),$(this).attr("disabled",!0).css({opacity:.5}),bulkAction(bulkImageData)})}}),$("body").on("click","small.krakenReset",function(e){e.preventDefault();var $resetButton=$(this),resetData={action:"kraken_reset"};resetData.id=$(this).data("id");var $spinner=$('<span class="resetSpinner"></span>');$resetButton.after($spinner);$.ajax({url:ajax_object.ajax_url,data:resetData,type:"post",dataType:"json",timeout:36e4}).done(function(data,textStatus,jqXHR){"undefined"!==data.success&&$resetButton.closest(".kraked_size.column-kraked_size").hide().html(data.html).fadeIn().prev(".original_size.column-original_size").html(data.original_size)})}),$("body").on("click",".kraken-reset-all",function(e){e.preventDefault();var reset=confirm("This will immediately remove all Kraken metadata associated with your images. \n\nAre you sure you want to do this?");if(reset){var $resetButton=$(this);$resetButton.text("Resetting images, pleaes wait...").attr("disabled",!0);
2
-
3
- var resetData={action:"kraken_reset_all"},$spinner=$('<span class="resetSpinner"></span>');$resetButton.after($spinner);{$.ajax({url:ajax_object.ajax_url,data:resetData,type:"post",dataType:"json",timeout:36e4}).done(function(data,textStatus,jqXHR){$spinner.remove(),$resetButton.text("Your images have been reset.").removeAttr("disabled").removeClass("enabled")})}}}),$(".krakenAdvancedSettings h3").on("click",function(){var $rows=$(".kraken-advanced-settings"),$plusMinus=$(".kraken-plus-minus");$rows.is(":visible")?($rows.hide(),$plusMinus.removeClass("dashicons-arrow-down").addClass("dashicons-arrow-right")):($rows.show(),$plusMinus.removeClass("dashicons-arrow-right").addClass("dashicons-arrow-down"))}),$("body").on("click",".kraken_req",function(e){e.preventDefault();var $button=$(this),$parent=$(this).parent();data.id=$(this).data("id"),$button.text("Optimizing image...").attr("disabled",!0).css({opacity:.5}),$parent.find(".krakenSpinner").css("display","inline");$.ajax({url:ajax_object.ajax_url,data:data,type:"post",dataType:"json",timeout:36e4,context:$button}).done(requestSuccess).fail(requestFail).always(requestComplete)})});
1
+ !function(){function only_once(fn){var called=!1;return function(){if(called)throw new Error("Callback was already called.");called=!0,fn.apply(root,arguments)}}var root,previous_async,async={};root=this,null!=root&&(previous_async=root.async),async.noConflict=function(){return root.async=previous_async,async};var _each=function(arr,iterator){if(arr.forEach)return arr.forEach(iterator);for(var i=0;i<arr.length;i+=1)iterator(arr[i],i,arr)},_map=function(arr,iterator){if(arr.map)return arr.map(iterator);var results=[];return _each(arr,function(x,i,a){results.push(iterator(x,i,a))}),results},_reduce=function(arr,iterator,memo){return arr.reduce?arr.reduce(iterator,memo):(_each(arr,function(x,i,a){memo=iterator(memo,x,i,a)}),memo)},_keys=function(obj){if(Object.keys)return Object.keys(obj);var keys=[];for(var k in obj)obj.hasOwnProperty(k)&&keys.push(k);return keys};"undefined"!=typeof process&&process.nextTick?(async.nextTick=process.nextTick,"undefined"!=typeof setImmediate?async.setImmediate=function(fn){setImmediate(fn)}:async.setImmediate=async.nextTick):"function"==typeof setImmediate?(async.nextTick=function(fn){setImmediate(fn)},async.setImmediate=async.nextTick):(async.nextTick=function(fn){setTimeout(fn,0)},async.setImmediate=async.nextTick),async.each=function(arr,iterator,callback){if(callback=callback||function(){},!arr.length)return callback();var completed=0;_each(arr,function(x){iterator(x,only_once(function(err){err?(callback(err),callback=function(){}):(completed+=1,completed>=arr.length&&callback(null))}))})},async.forEach=async.each,async.eachSeries=function(arr,iterator,callback){if(callback=callback||function(){},!arr.length)return callback();var completed=0,iterate=function(){iterator(arr[completed],function(err){err?(callback(err),callback=function(){}):(completed+=1,completed>=arr.length?callback(null):iterate())})};iterate()},async.forEachSeries=async.eachSeries,async.eachLimit=function(arr,limit,iterator,callback){var fn=_eachLimit(limit);fn.apply(null,[arr,iterator,callback])},async.forEachLimit=async.eachLimit;var _eachLimit=function(limit){return function(arr,iterator,callback){if(callback=callback||function(){},!arr.length||0>=limit)return callback();var completed=0,started=0,running=0;!function replenish(){if(completed>=arr.length)return callback();for(;limit>running&&started<arr.length;)started+=1,running+=1,iterator(arr[started-1],function(err){err?(callback(err),callback=function(){}):(completed+=1,running-=1,completed>=arr.length?callback():replenish())})}()}},doParallel=function(fn){return function(){var args=Array.prototype.slice.call(arguments);return fn.apply(null,[async.each].concat(args))}},doParallelLimit=function(limit,fn){return function(){var args=Array.prototype.slice.call(arguments);return fn.apply(null,[_eachLimit(limit)].concat(args))}},doSeries=function(fn){return function(){var args=Array.prototype.slice.call(arguments);return fn.apply(null,[async.eachSeries].concat(args))}},_asyncMap=function(eachfn,arr,iterator,callback){var results=[];arr=_map(arr,function(x,i){return{index:i,value:x}}),eachfn(arr,function(x,callback){iterator(x.value,function(err,v){results[x.index]=v,callback(err)})},function(err){callback(err,results)})};async.map=doParallel(_asyncMap),async.mapSeries=doSeries(_asyncMap),async.mapLimit=function(arr,limit,iterator,callback){return _mapLimit(limit)(arr,iterator,callback)};var _mapLimit=function(limit){return doParallelLimit(limit,_asyncMap)};async.reduce=function(arr,memo,iterator,callback){async.eachSeries(arr,function(x,callback){iterator(memo,x,function(err,v){memo=v,callback(err)})},function(err){callback(err,memo)})},async.inject=async.reduce,async.foldl=async.reduce,async.reduceRight=function(arr,memo,iterator,callback){var reversed=_map(arr,function(x){return x}).reverse();async.reduce(reversed,memo,iterator,callback)},async.foldr=async.reduceRight;var _filter=function(eachfn,arr,iterator,callback){var results=[];arr=_map(arr,function(x,i){return{index:i,value:x}}),eachfn(arr,function(x,callback){iterator(x.value,function(v){v&&results.push(x),callback()})},function(err){callback(_map(results.sort(function(a,b){return a.index-b.index}),function(x){return x.value}))})};async.filter=doParallel(_filter),async.filterSeries=doSeries(_filter),async.select=async.filter,async.selectSeries=async.filterSeries;var _reject=function(eachfn,arr,iterator,callback){var results=[];arr=_map(arr,function(x,i){return{index:i,value:x}}),eachfn(arr,function(x,callback){iterator(x.value,function(v){v||results.push(x),callback()})},function(err){callback(_map(results.sort(function(a,b){return a.index-b.index}),function(x){return x.value}))})};async.reject=doParallel(_reject),async.rejectSeries=doSeries(_reject);var _detect=function(eachfn,arr,iterator,main_callback){eachfn(arr,function(x,callback){iterator(x,function(result){result?(main_callback(x),main_callback=function(){}):callback()})},function(err){main_callback()})};async.detect=doParallel(_detect),async.detectSeries=doSeries(_detect),async.some=function(arr,iterator,main_callback){async.each(arr,function(x,callback){iterator(x,function(v){v&&(main_callback(!0),main_callback=function(){}),callback()})},function(err){main_callback(!1)})},async.any=async.some,async.every=function(arr,iterator,main_callback){async.each(arr,function(x,callback){iterator(x,function(v){v||(main_callback(!1),main_callback=function(){}),callback()})},function(err){main_callback(!0)})},async.all=async.every,async.sortBy=function(arr,iterator,callback){async.map(arr,function(x,callback){iterator(x,function(err,criteria){err?callback(err):callback(null,{value:x,criteria:criteria})})},function(err,results){if(err)return callback(err);var fn=function(left,right){var a=left.criteria,b=right.criteria;return b>a?-1:a>b?1:0};callback(null,_map(results.sort(fn),function(x){return x.value}))})},async.auto=function(tasks,callback){callback=callback||function(){};var keys=_keys(tasks);if(!keys.length)return callback(null);var results={},listeners=[],addListener=function(fn){listeners.unshift(fn)},removeListener=function(fn){for(var i=0;i<listeners.length;i+=1)if(listeners[i]===fn)return void listeners.splice(i,1)},taskComplete=function(){_each(listeners.slice(0),function(fn){fn()})};addListener(function(){_keys(results).length===keys.length&&(callback(null,results),callback=function(){})}),_each(keys,function(k){var task=tasks[k]instanceof Function?[tasks[k]]:tasks[k],taskCallback=function(err){var args=Array.prototype.slice.call(arguments,1);if(args.length<=1&&(args=args[0]),err){var safeResults={};_each(_keys(results),function(rkey){safeResults[rkey]=results[rkey]}),safeResults[k]=args,callback(err,safeResults),callback=function(){}}else results[k]=args,async.setImmediate(taskComplete)},requires=task.slice(0,Math.abs(task.length-1))||[],ready=function(){return _reduce(requires,function(a,x){return a&&results.hasOwnProperty(x)},!0)&&!results.hasOwnProperty(k)};if(ready())task[task.length-1](taskCallback,results);else{var listener=function(){ready()&&(removeListener(listener),task[task.length-1](taskCallback,results))};addListener(listener)}})},async.waterfall=function(tasks,callback){if(callback=callback||function(){},tasks.constructor!==Array){var err=new Error("First argument to waterfall must be an array of functions");return callback(err)}if(!tasks.length)return callback();var wrapIterator=function(iterator){return function(err){if(err)callback.apply(null,arguments),callback=function(){};else{var args=Array.prototype.slice.call(arguments,1),next=iterator.next();args.push(next?wrapIterator(next):callback),async.setImmediate(function(){iterator.apply(null,args)})}}};wrapIterator(async.iterator(tasks))()};var _parallel=function(eachfn,tasks,callback){if(callback=callback||function(){},tasks.constructor===Array)eachfn.map(tasks,function(fn,callback){fn&&fn(function(err){var args=Array.prototype.slice.call(arguments,1);args.length<=1&&(args=args[0]),callback.call(null,err,args)})},callback);else{var results={};eachfn.each(_keys(tasks),function(k,callback){tasks[k](function(err){var args=Array.prototype.slice.call(arguments,1);args.length<=1&&(args=args[0]),results[k]=args,callback(err)})},function(err){callback(err,results)})}};async.parallel=function(tasks,callback){_parallel({map:async.map,each:async.each},tasks,callback)},async.parallelLimit=function(tasks,limit,callback){_parallel({map:_mapLimit(limit),each:_eachLimit(limit)},tasks,callback)},async.series=function(tasks,callback){if(callback=callback||function(){},tasks.constructor===Array)async.mapSeries(tasks,function(fn,callback){fn&&fn(function(err){var args=Array.prototype.slice.call(arguments,1);args.length<=1&&(args=args[0]),callback.call(null,err,args)})},callback);else{var results={};async.eachSeries(_keys(tasks),function(k,callback){tasks[k](function(err){var args=Array.prototype.slice.call(arguments,1);args.length<=1&&(args=args[0]),results[k]=args,callback(err)})},function(err){callback(err,results)})}},async.iterator=function(tasks){var makeCallback=function(index){var fn=function(){return tasks.length&&tasks[index].apply(null,arguments),fn.next()};return fn.next=function(){return index<tasks.length-1?makeCallback(index+1):null},fn};return makeCallback(0)},async.apply=function(fn){var args=Array.prototype.slice.call(arguments,1);return function(){return fn.apply(null,args.concat(Array.prototype.slice.call(arguments)))}};var _concat=function(eachfn,arr,fn,callback){var r=[];eachfn(arr,function(x,cb){fn(x,function(err,y){r=r.concat(y||[]),cb(err)})},function(err){callback(err,r)})};async.concat=doParallel(_concat),async.concatSeries=doSeries(_concat),async.whilst=function(test,iterator,callback){test()?iterator(function(err){return err?callback(err):void async.whilst(test,iterator,callback)}):callback()},async.doWhilst=function(iterator,test,callback){iterator(function(err){return err?callback(err):void(test()?async.doWhilst(iterator,test,callback):callback())})},async.until=function(test,iterator,callback){test()?callback():iterator(function(err){return err?callback(err):void async.until(test,iterator,callback)})},async.doUntil=function(iterator,test,callback){iterator(function(err){return err?callback(err):void(test()?callback():async.doUntil(iterator,test,callback))})},async.queue=function(worker,concurrency){function _insert(q,data,pos,callback){data.constructor!==Array&&(data=[data]),_each(data,function(task){var item={data:task,callback:"function"==typeof callback?callback:null};pos?q.tasks.unshift(item):q.tasks.push(item),q.saturated&&q.tasks.length===concurrency&&q.saturated(),async.setImmediate(q.process)})}void 0===concurrency&&(concurrency=1);var workers=0,q={tasks:[],concurrency:concurrency,saturated:null,empty:null,drain:null,push:function(data,callback){_insert(q,data,!1,callback)},unshift:function(data,callback){_insert(q,data,!0,callback)},process:function(){if(workers<q.concurrency&&q.tasks.length){var task=q.tasks.shift();q.empty&&0===q.tasks.length&&q.empty(),workers+=1;var next=function(){workers-=1,task.callback&&task.callback.apply(task,arguments),q.drain&&q.tasks.length+workers===0&&q.drain(),q.process()},cb=only_once(next);worker(task.data,cb)}},length:function(){return q.tasks.length},running:function(){return workers}};return q},async.cargo=function(worker,payload){var working=!1,tasks=[],cargo={tasks:tasks,payload:payload,saturated:null,empty:null,drain:null,push:function(data,callback){data.constructor!==Array&&(data=[data]),_each(data,function(task){tasks.push({data:task,callback:"function"==typeof callback?callback:null}),cargo.saturated&&tasks.length===payload&&cargo.saturated()}),async.setImmediate(cargo.process)},process:function process(){if(!working){if(0===tasks.length)return void(cargo.drain&&cargo.drain());var ts="number"==typeof payload?tasks.splice(0,payload):tasks.splice(0),ds=_map(ts,function(task){return task.data});cargo.empty&&cargo.empty(),working=!0,worker(ds,function(){working=!1;var args=arguments;_each(ts,function(data){data.callback&&data.callback.apply(null,args)}),process()})}},length:function(){return tasks.length},running:function(){return working}};return cargo};var _console_fn=function(name){return function(fn){var args=Array.prototype.slice.call(arguments,1);fn.apply(null,args.concat([function(err){var args=Array.prototype.slice.call(arguments,1);"undefined"!=typeof console&&(err?console.error&&console.error(err):console[name]&&_each(args,function(x){console[name](x)}))}]))}};async.log=_console_fn("log"),async.dir=_console_fn("dir"),async.memoize=function(fn,hasher){var memo={},queues={};hasher=hasher||function(x){return x};var memoized=function(){var args=Array.prototype.slice.call(arguments),callback=args.pop(),key=hasher.apply(null,args);key in memo?callback.apply(null,memo[key]):key in queues?queues[key].push(callback):(queues[key]=[callback],fn.apply(null,args.concat([function(){memo[key]=arguments;var q=queues[key];delete queues[key];for(var i=0,l=q.length;l>i;i++)q[i].apply(null,arguments)}])))};return memoized.memo=memo,memoized.unmemoized=fn,memoized},async.unmemoize=function(fn){return function(){return(fn.unmemoized||fn).apply(null,arguments)}},async.times=function(count,iterator,callback){for(var counter=[],i=0;count>i;i++)counter.push(i);return async.map(counter,iterator,callback)},async.timesSeries=function(count,iterator,callback){for(var counter=[],i=0;count>i;i++)counter.push(i);return async.mapSeries(counter,iterator,callback)},async.compose=function(){var fns=Array.prototype.reverse.call(arguments);return function(){var that=this,args=Array.prototype.slice.call(arguments),callback=args.pop();async.reduce(fns,args,function(newargs,fn,cb){fn.apply(that,newargs.concat([function(){var err=arguments[0],nextargs=Array.prototype.slice.call(arguments,1);cb(err,nextargs)}]))},function(err,results){callback.apply(that,[err].concat(results))})}};var _applyEach=function(eachfn,fns){var go=function(){var that=this,args=Array.prototype.slice.call(arguments),callback=args.pop();return eachfn(fns,function(fn,cb){fn.apply(that,args.concat([cb]))},callback)};if(arguments.length>2){var args=Array.prototype.slice.call(arguments,2);return go.apply(this,args)}return go};async.applyEach=doParallel(_applyEach),async.applyEachSeries=doSeries(_applyEach),async.forever=function(fn,callback){function next(err){if(err){if(callback)return callback(err);throw err}fn(next)}next()},"undefined"!=typeof define&&define.amd?define([],function(){return async}):"undefined"!=typeof module&&module.exports?module.exports=async:root.async=async}(),function($){function maybeCall(thing,ctx){return"function"==typeof thing?thing.call(ctx):thing}function isElementInDOM(ele){for(;ele=ele.parentNode;)if(ele==document)return!0;return!1}function Tipsy(element,options){this.$element=$(element),this.options=options,this.enabled=!0,this.fixTitle()}Tipsy.prototype={show:function(){var title=this.getTitle();if(title&&this.enabled){var $tip=this.tip();$tip.find(".tipsy-inner")[this.options.html?"html":"text"](title),$tip[0].className="tipsy",$tip.remove().css({top:0,left:0,visibility:"hidden",display:"block"}).prependTo(document.body);var tp,pos=$.extend({},this.$element.offset(),{width:this.$element[0].offsetWidth,height:this.$element[0].offsetHeight}),actualWidth=$tip[0].offsetWidth,actualHeight=$tip[0].offsetHeight,gravity=maybeCall(this.options.gravity,this.$element[0]);switch(gravity.charAt(0)){case"n":tp={top:pos.top+pos.height+this.options.offset,left:pos.left+pos.width/2-actualWidth/2};break;case"s":tp={top:pos.top-actualHeight-this.options.offset,left:pos.left+pos.width/2-actualWidth/2};break;case"e":tp={top:pos.top+pos.height/2-actualHeight/2,left:pos.left-actualWidth-this.options.offset};break;case"w":tp={top:pos.top+pos.height/2-actualHeight/2,left:pos.left+pos.width+this.options.offset}}2==gravity.length&&("w"==gravity.charAt(1)?tp.left=pos.left+pos.width/2-15:tp.left=pos.left+pos.width/2-actualWidth+15),$tip.css(tp).addClass("tipsy-"+gravity),$tip.find(".tipsy-arrow")[0].className="tipsy-arrow tipsy-arrow-"+gravity.charAt(0),this.options.className&&$tip.addClass(maybeCall(this.options.className,this.$element[0])),this.options.fade?$tip.stop().css({opacity:0,display:"block",visibility:"visible"}).animate({opacity:this.options.opacity}):$tip.css({visibility:"visible",opacity:this.options.opacity})}},hide:function(){this.options.fade?this.tip().stop().fadeOut(function(){$(this).remove()}):this.tip().remove()},fixTitle:function(){var $e=this.$element;($e.attr("title")||"string"!=typeof $e.attr("original-title"))&&$e.attr("original-title",$e.attr("title")||"").removeAttr("title")},getTitle:function(){var title,$e=this.$element,o=this.options;this.fixTitle();var title,o=this.options;return"string"==typeof o.title?title=$e.attr("title"==o.title?"original-title":o.title):"function"==typeof o.title&&(title=o.title.call($e[0])),title=(""+title).replace(/(^\s*|\s*$)/,""),title||o.fallback},tip:function(){return this.$tip||(this.$tip=$('<div class="tipsy"></div>').html('<div class="tipsy-arrow"></div><div class="tipsy-inner"></div>'),this.$tip.data("tipsy-pointee",this.$element[0])),this.$tip},validate:function(){this.$element[0].parentNode||(this.hide(),this.$element=null,this.options=null)},enable:function(){this.enabled=!0},disable:function(){this.enabled=!1},toggleEnabled:function(){this.enabled=!this.enabled}},$.fn.tipsy=function(options){function get(ele){var tipsy=$.data(ele,"tipsy");return tipsy||(tipsy=new Tipsy(ele,$.fn.tipsy.elementOptions(ele,options)),$.data(ele,"tipsy",tipsy)),tipsy}function enter(){var tipsy=get(this);tipsy.hoverState="in",0==options.delayIn?tipsy.show():(tipsy.fixTitle(),setTimeout(function(){"in"==tipsy.hoverState&&tipsy.show()},options.delayIn))}function leave(){var tipsy=get(this);tipsy.hoverState="out",0==options.delayOut?tipsy.hide():setTimeout(function(){"out"==tipsy.hoverState&&tipsy.hide()},options.delayOut)}if(options===!0)return this.data("tipsy");if("string"==typeof options){var tipsy=this.data("tipsy");return tipsy&&tipsy[options](),this}if(options=$.extend({},$.fn.tipsy.defaults,options),options.live||this.each(function(){get(this)}),"manual"!=options.trigger){var binder=options.live?"live":"bind",eventIn="hover"==options.trigger?"mouseenter":"focus",eventOut="hover"==options.trigger?"mouseleave":"blur";this[binder](eventIn,enter)[binder](eventOut,leave)}return this},$.fn.tipsy.defaults={className:null,delayIn:0,delayOut:0,fade:!1,fallback:"",gravity:"n",html:!1,live:!1,offset:0,opacity:.8,title:"title",trigger:"hover"},$.fn.tipsy.revalidate=function(){$(".tipsy").each(function(){var pointee=$.data(this,"tipsy-pointee");pointee&&isElementInDOM(pointee)||$(this).remove()})},$.fn.tipsy.elementOptions=function(ele,options){return $.metadata?$.extend({},options,$(ele).metadata()):options},$.fn.tipsy.autoNS=function(){return $(this).offset().top>$(document).scrollTop()+$(window).height()/2?"s":"n"},$.fn.tipsy.autoWE=function(){return $(this).offset().left>$(document).scrollLeft()+$(window).width()/2?"e":"w"},$.fn.tipsy.autoBounds=function(margin,prefer){return function(){var dir={ns:prefer[0],ew:prefer.length>1?prefer[1]:!1},boundTop=$(document).scrollTop()+margin,boundLeft=$(document).scrollLeft()+margin,$this=$(this);return $this.offset().top<boundTop&&(dir.ns="n"),$this.offset().left<boundLeft&&(dir.ew="w"),$(window).width()+$(document).scrollLeft()-$this.offset().left<margin&&(dir.ew="e"),$(window).height()+$(document).scrollTop()-$this.offset().top<margin&&(dir.ns="s"),dir.ns+(dir.ew?dir.ew:"")}}}(jQuery),function($){var current=null;$.kmodal=function(el,options){$.kmodal.close();var remove,target;if(this.$body=$("body"),this.options=$.extend({},$.kmodal.defaults,options),this.options.doFade=!isNaN(parseInt(this.options.fadeDuration,10)),el.is("a"))if(target=el.attr("href"),/^#/.test(target)){if(this.$elm=$(target),1!==this.$elm.length)return null;this.open()}else this.$elm=$("<div>"),this.$body.append(this.$elm),remove=function(event,modal){modal.elm.remove()},this.showSpinner(),el.trigger($.kmodal.AJAX_SEND),$.get(target).done(function(html){current&&(el.trigger($.kmodal.AJAX_SUCCESS),current.$elm.empty().append(html).on($.kmodal.CLOSE,remove),current.hideSpinner(),current.open(),el.trigger($.kmodal.AJAX_COMPLETE))}).fail(function(){el.trigger($.kmodal.AJAX_FAIL),current.hideSpinner(),el.trigger($.kmodal.AJAX_COMPLETE)});else this.$elm=el,this.$body.append(this.$elm),this.open()},$.kmodal.prototype={constructor:$.kmodal,open:function(){var m=this;this.options.doFade?(this.block(),setTimeout(function(){m.show()},this.options.fadeDuration*this.options.fadeDelay)):(this.block(),this.show()),this.options.escapeClose&&$(document).on("keydown.modal",function(event){27==event.which&&$.kmodal.close()}),this.options.clickClose&&this.blocker.click($.kmodal.close)},close:function(){this.unblock(),this.hide(),$(document).off("keydown.modal")},block:function(){var initialOpacity=this.options.doFade?0:this.options.opacity;this.$elm.trigger($.kmodal.BEFORE_BLOCK,[this._ctx()]),this.blocker=$('<div class="jquery-modal blocker"></div>').css({top:0,right:0,bottom:0,left:0,width:"100%",height:"100%",position:"fixed",zIndex:this.options.zIndex,background:this.options.overlay,opacity:initialOpacity}),this.$body.append(this.blocker),this.options.doFade&&this.blocker.animate({opacity:this.options.opacity},this.options.fadeDuration),this.$elm.trigger($.kmodal.BLOCK,[this._ctx()])},unblock:function(){this.options.doFade?this.blocker.fadeOut(this.options.fadeDuration,function(){$(this).remove()}):this.blocker.remove()},show:function(){this.$elm.trigger($.kmodal.BEFORE_OPEN,[this._ctx()]),this.options.showClose&&(this.closeButton=$('<a href="#close-modal" rel="modal:close" class="close-modal '+this.options.closeClass+'">'+this.options.closeText+"</a>"),this.$elm.append(this.closeButton)),this.$elm.addClass(this.options.modalClass+" current"),this.center(),this.options.doFade?this.$elm.fadeIn(this.options.fadeDuration):this.$elm.show(),this.$elm.trigger($.kmodal.OPEN,[this._ctx()])},hide:function(){this.$elm.trigger($.kmodal.BEFORE_CLOSE,[this._ctx()]),this.closeButton&&this.closeButton.remove(),this.$elm.removeClass("current"),this.options.doFade?this.$elm.fadeOut(this.options.fadeDuration):this.$elm.hide(),this.$elm.trigger($.kmodal.CLOSE,[this._ctx()])},showSpinner:function(){this.options.showSpinner&&(this.spinner=this.spinner||$('<div class="'+this.options.modalClass+'-spinner"></div>').append(this.options.spinnerHtml),this.$body.append(this.spinner),this.spinner.show())},hideSpinner:function(){this.spinner&&this.spinner.remove()},center:function(){this.$elm.css({position:"fixed",top:"50%",left:"50%",marginTop:-(this.$elm.outerHeight()/2),marginLeft:-(this.$elm.outerWidth()/2),zIndex:this.options.zIndex+1})},_ctx:function(){return{elm:this.$elm,blocker:this.blocker,options:this.options}}},$.kmodal.prototype.resize=$.kmodal.prototype.center,$.kmodal.close=function(event){if(current){event&&event.preventDefault(),current.close();var that=current.$elm;return current=null,that}},$.kmodal.resize=function(){current&&current.resize()},$.kmodal.isActive=function(){return current?!0:!1},$.kmodal.defaults={overlay:"#000",opacity:.75,zIndex:1,escapeClose:!0,clickClose:!0,closeText:"Close",closeClass:"",modalClass:"kraken-modal",spinnerHtml:null,showSpinner:!0,showClose:!0,fadeDuration:null,fadeDelay:1},$.kmodal.BEFORE_BLOCK="modal:before-block",$.kmodal.BLOCK="modal:block",$.kmodal.BEFORE_OPEN="modal:before-open",$.kmodal.OPEN="modal:open",$.kmodal.BEFORE_CLOSE="modal:before-close",$.kmodal.CLOSE="modal:close",$.kmodal.AJAX_SEND="modal:ajax:send",$.kmodal.AJAX_SUCCESS="modal:ajax:success",$.kmodal.AJAX_FAIL="modal:ajax:fail",$.kmodal.AJAX_COMPLETE="modal:ajax:complete",$.fn.kmodal=function(options){return 1===this.length&&(current=new $.kmodal(this,options)),this},$(document).on("click.modal",'a[rel="modal:close"]',$.kmodal.close),$(document).on("click.modal",'a[rel="modal:open"]',function(event){event.preventDefault(),$(this).kmodal()})}(jQuery),jQuery(document).ready(function($){var tipsySettings={gravity:"e",html:!0,trigger:"manual",className:function(){return"tipsy-"+$(this).data("id")},title:function(){return activeId=$(this).data("id"),$(this).attr("original-title")}};$(".krakenWhatsThis").tipsy({fade:!0,gravity:"w"}),$(".krakenError").tipsy({fade:!0,gravity:"e"});var data={action:"kraken_request"},errorTpl='<div class="krakenErrorWrap"><a class="krakenError">Failed! Hover here</a></div>',$btnApplyBulkAction=$("#doaction"),$btnApplyBulkAction2=$("#doaction2"),$topBulkActionDropdown=$(".tablenav.top .bulkactions select[name='action']"),$bottomBulkActionDropdown=$(".tablenav.bottom .bulkactions select[name='action2']"),requestSuccess=function(data,textStatus,jqXHR){var $button=$(this),$parent=$(this).closest(".kraken-wrap, .buttonWrap"),$cell=$(this).closest("td");if(data.html){$button.text("Image optimized");var originalSize=(data.type,data.original_size),$originalSizeColumn=$(this).parent().prev("td.original_size");$parent.fadeOut("fast",function(){$cell.find(".noSavings, .krakenErrorWrap").remove(),$cell.html(data.html),$cell.find(".kraken-item-details").tipsy(tipsySettings),$originalSizeColumn.html(originalSize),$parent.remove()})}else if(data.error){var $error=$(errorTpl).attr("title",data.error);$parent.closest("td").find(".krakenErrorWrap").remove(),$parent.after($error),$error.tipsy({fade:!0,gravity:"e"}),$button.text("Retry request").removeAttr("disabled").css({opacity:1})}},requestFail=function(jqXHR,textStatus,errorThrown){$(this).removeAttr("disabled")},requestComplete=function(jqXHR,textStatus,errorThrown){$(this).removeAttr("disabled"),$(this).parent().find(".krakenSpinner").css("display","none")},opts='<option value="kraken-bulk-lossy">Krak \'em all</option>';$topBulkActionDropdown.find("option:last-child").before(opts),$bottomBulkActionDropdown.find("option:last-child").before(opts);var getBulkImageData=function(){var $rows=$("tr[id^='post-']"),$row=null,postId=0,$krakBtn=null,btnData={},originalSize="",rv=[];return $rows.each(function(){$row=$(this),postId=this.id.replace(/^\D+/g,""),$row.find("input[type='checkbox'][value='"+postId+"']:checked").length&&($krakBtn=$row.find(".kraken_req"),$krakBtn.length&&(btnData=$krakBtn.data(),originalSize=$.trim($row.find("td.original_size").text()),btnData.originalSize=originalSize,rv.push(btnData)))}),rv},bulkModalOptions={zIndex:4,escapeClose:!0,clickClose:!1,closeText:"close",showClose:!1},renderBulkImageSummary=function(bulkImageData){var setting=kraken_settings.api_lossy,nImages=bulkImageData.length,header='<p class="krakenBulkHeader">Kraken Bulk Image Optimization <span class="close-kraken-bulk">&times;</span></p>',krakEmAll='<button class="kraken_req_bulk">Krak \'em all</button>',typeRadios='<div class="radiosWrap"><p>Choose optimization mode:</p><label><input type="radio" id="kraken-bulk-type-lossy" value="Lossy" name="kraken-bulk-type"/>Intelligent Lossy</label>&nbsp;&nbsp;&nbsp;<label><input type="radio" id="kraken-bulk-type-lossless" value="Lossless" name="kraken-bulk-type"/>Lossless</label></div>',$modal=$('<div id="kraken-bulk-modal" class="kraken-modal"></div>').html(header).append(typeRadios).append('<p class="the-following">The following <strong>'+nImages+'</strong> images will be optimized by Kraken.io using the <strong class="bulkSetting">'+setting+"</strong> setting:</p>").appendTo("body").kmodal(bulkModalOptions).bind($.kmodal.BEFORE_CLOSE,function(event,modal){}).bind($.kmodal.OPEN,function(event,modal){}).bind($.kmodal.CLOSE,function(event,modal){$("#kraken-bulk-modal").remove()}).css({top:"10px",marginTop:"40px"});"lossy"===setting?$("#kraken-bulk-type-lossy").attr("checked",!0):$("#kraken-bulk-type-lossless").attr("checked",!0),$bulkSettingSpan=$(".bulkSetting"),$("input[name='kraken-bulk-type']").change(function(){var text="kraken-bulk-type-lossy"===this.id?"lossy":"lossless";$bulkSettingSpan.text(text)}),$(".jquery-modal.blocker").click(function(e){return!1}),$("#menu-media ul.wp-submenu").css({"z-index":1});var $table=$('<table id="kraken-bulk"></table>'),$headerRow=$('<tr class="kraken-bulk-header"><td>File Name</td><td style="width:120px">Original Size</td><td style="width:120px">Kraken.io Stats</td></tr>');$table.append($headerRow),$.each(bulkImageData,function(index,element){$table.append('<tr class="kraken-item-row" data-krakenbulkid="'+element.id+'"><td class="kraken-bulk-filename">'+element.filename+'</td><td class="kraken-originalsize">'+element.originalSize+'</td><td class="kraken-krakedsize"><span class="krakenBulkSpinner hidden"></span></td></tr>')}),$modal.append($table).append(krakEmAll),$(".close-kraken-bulk").click(function(){$.kmodal.close()}),nImages||$(".kraken_req_bulk").attr("disabled",!0).css({opacity:.5})},bulkAction=function(bulkImageData){$bulkTable=$("#kraken-bulk");var jqxhr=null,q=async.queue(function(task,callback){var id=task.id,$row=(task.filename,$bulkTable.find("tr[data-krakenbulkid='"+id+"']")),$krakedSizeColumn=$row.find(".kraken-krakedsize"),$spinner=$krakedSizeColumn.find(".krakenBulkSpinner").css({display:"inline-block"}),$savingsPercentColumn=$row.find(".kraken-savingsPercent"),$savingsBytesColumn=$row.find(".kraken-savings");jqxhr=$.ajax({url:ajax_object.ajax_url,data:{action:"kraken_request",id:id,type:$("input[name='kraken-bulk-type']:checked").val().toLowerCase(),origin:"bulk_optimizer"},type:"post",dataType:"json",timeout:36e4}).done(function(data,textStatus,jqXHR){if(data.success&&"undefined"==typeof data.message){var originalSize=(data.type,data.original_size),savingsPercent=(data.html,data.savings_percent),savingsBytes=data.saved_bytes;$krakedSizeColumn.html(data.html),$krakedSizeColumn.find(".kraken-item-details").remove(),$savingsPercentColumn.text(savingsPercent),$savingsBytesColumn.text(savingsBytes);var $button=$("button[id='krakenid-"+id+"']"),$parent=$button.parent(),$cell=$button.closest("td"),$originalSizeColumn=$button.parent().prev("td.original_size");$parent.fadeOut("fast",function(){$cell.find(".noSavings, .krakenErrorWrap").remove(),$cell.empty().html(data.html),$cell.find(".kraken-item-details").tipsy(tipsySettings),$originalSizeColumn.html(originalSize),$parent.remove()})}else data.error&&"This image can not be optimized any further"===data.error&&$krakedSizeColumn.text("No savings found.")}).fail(function(){}).always(function(){$spinner.css({display:"none"}),callback()})},kraken_settings.bulk_async_limit);q.drain=function(){$(".kraken_req_bulk").removeAttr("disabled").css({opacity:1}).text("Done").unbind("click").click(function(){$.kmodal.close()})},q.push(bulkImageData,function(err){})};$btnApplyBulkAction.add($btnApplyBulkAction2).click(function(e){if("kraken-bulk-lossy"===$(this).prev("select").val()){e.preventDefault();var bulkImageData=getBulkImageData();renderBulkImageSummary(bulkImageData),$(".kraken_req_bulk").click(function(e){e.preventDefault(),$(this).attr("disabled",!0).css({opacity:.5}),bulkAction(bulkImageData)})}});var activeId=null;$(".kraken-item-details").tipsy(tipsySettings);$("body").on("click",".kraken-item-details",function(e){var id=$(this).data("id");return $(".tipsy").remove(),id==activeId?(activeId=null,void $(this).text("Show details")):($(".kraken-item-details").text("Show details"),$(this).tipsy("show"),void $(this).text("Hide details"))}),$("body").on("click",function(e){var $t=$(e.target);$t.hasClass("tipsy")||$t.closest(".tipsy").length||$t.hasClass("kraken-item-details")||(activeId=null,$(".kraken-item-details").text("Show details"),$(".tipsy").remove())}),$("body").on("click","small.krakenReset",function(e){e.preventDefault();var $resetButton=$(this),resetData={action:"kraken_reset"};resetData.id=$(this).data("id"),$row=$("#post-"+resetData.id).find(".kraked_size");var $spinner=$('<span class="resetSpinner"></span>');$resetButton.after($spinner);$.ajax({url:ajax_object.ajax_url,data:resetData,type:"post",dataType:"json",timeout:36e4
2
+ }).done(function(data,textStatus,jqXHR){"undefined"!==data.success&&($row.hide().html(data.html).fadeIn().prev(".original_size.column-original_size").html(data.original_size),$(".tipsy").remove())})}),$("body").on("click",".kraken-reset-all",function(e){e.preventDefault();var reset=confirm("This will immediately remove all Kraken metadata associated with your images. \n\nAre you sure you want to do this?");if(reset){var $resetButton=$(this);$resetButton.text("Resetting images, pleaes wait...").attr("disabled",!0);var resetData={action:"kraken_reset_all"},$spinner=$('<span class="resetSpinner"></span>');$resetButton.after($spinner);{$.ajax({url:ajax_object.ajax_url,data:resetData,type:"post",dataType:"json",timeout:36e4}).done(function(data,textStatus,jqXHR){$spinner.remove(),$resetButton.text("Your images have been reset.").removeAttr("disabled").removeClass("enabled")})}}}),$(".krakenAdvancedSettings h3").on("click",function(){var $rows=$(".kraken-advanced-settings"),$plusMinus=$(".kraken-plus-minus");$rows.is(":visible")?($rows.hide(),$plusMinus.removeClass("dashicons-arrow-down").addClass("dashicons-arrow-right")):($rows.show(),$plusMinus.removeClass("dashicons-arrow-right").addClass("dashicons-arrow-down"))}),$("body").on("click",".kraken_req",function(e){e.preventDefault();var $button=$(this),$parent=$(this).parent();data.id=$(this).data("id"),$button.text("Optimizing image...").attr("disabled",!0).css({opacity:.5}),$parent.find(".krakenSpinner").css("display","inline");$.ajax({url:ajax_object.ajax_url,data:data,type:"post",dataType:"json",timeout:36e4,context:$button}).done(requestSuccess).fail(requestFail).always(requestComplete)})});
 
kraken.php CHANGED
@@ -21,8 +21,8 @@
21
  * Plugin URI: http://wordpress.org/plugins/kraken-image-optimizer/
22
  * Description: This plugin allows you to optimize your WordPress images through the Kraken API, the world's most advanced image optimization solution.
23
  * Author: Karim Salman
24
- * Version: 2.0.0
25
- * Stable Tag: 2.0.0
26
  * Author URI: https://kraken.io
27
  * License GPL2
28
  */
@@ -41,7 +41,7 @@ if ( !class_exists( 'Wp_Kraken' ) ) {
41
 
42
  private $optimization_type = 'lossy';
43
 
44
- public static $kraken_plugin_version = '2.0.0';
45
 
46
  function __construct() {
47
  $plugin_dir_path = dirname( __FILE__ );
@@ -50,22 +50,37 @@ if ( !class_exists( 'Wp_Kraken' ) ) {
50
  $this->optimization_type = $this->kraken_settings['api_lossy'];
51
  add_action( 'admin_enqueue_scripts', array( &$this, 'my_enqueue' ) );
52
  add_action( 'wp_ajax_kraken_reset', array( &$this, 'kraken_media_library_reset' ) );
 
53
  add_action( 'wp_ajax_kraken_request', array( &$this, 'kraken_media_library_ajax_callback' ) );
54
  add_action( 'wp_ajax_kraken_reset_all', array( &$this, 'kraken_media_library_reset_all' ) );
55
  add_action( 'manage_media_custom_column', array( &$this, 'fill_media_columns' ), 10, 2 );
56
  add_filter( 'manage_media_columns', array( &$this, 'add_media_columns') );
57
  add_filter( 'plugin_action_links_' . plugin_basename(__FILE__), array( &$this, 'add_settings_link' ) );
 
58
  if ( ( !empty( $this->kraken_settings ) && !empty( $this->kraken_settings['auto_optimize'] ) ) || !isset( $this->kraken_settings['auto_optimize'] ) ) {
59
- add_filter( 'wp_generate_attachment_metadata', array( &$this, 'optimize_thumbnails') );
60
- add_action( 'add_attachment', array( &$this, 'kraken_media_uploader_callback' ) );
 
 
 
 
 
 
 
 
 
 
61
  }
62
- add_action( 'admin_menu', array( &$this, 'kraken_menu' ) );
63
  }
64
 
65
  function kraken_menu() {
66
  add_options_page( 'Kraken Image Optimizer Settings', 'Kraken.io', 'manage_options', 'wp-krakenio', array( &$this, 'kraken_settings_page' ) );
67
  }
68
 
 
 
 
69
 
70
  function add_settings_link ( $links ) {
71
  $mylinks = array(
@@ -74,9 +89,8 @@ if ( !class_exists( 'Wp_Kraken' ) ) {
74
  return array_merge( $links, $mylinks );
75
  }
76
 
 
77
 
78
- function kraken_settings_page() {
79
-
80
  if ( !empty( $_POST ) ) {
81
  $options = $_POST['_kraken_options'];
82
  $result = $this->validate_options( $options );
@@ -86,12 +100,20 @@ if ( !class_exists( 'Wp_Kraken' ) ) {
86
  $settings = get_option( '_kraken_options' );
87
  $lossy = isset( $settings['api_lossy'] ) ? $settings['api_lossy'] : 'lossy';
88
  $auto_optimize = isset( $settings['auto_optimize'] ) ? $settings['auto_optimize'] : 1;
89
-
90
  $api_key = isset( $settings['api_key'] ) ? $settings['api_key'] : '';
91
  $api_secret = isset( $settings['api_secret'] ) ? $settings['api_secret'] : '';
92
-
93
  $show_reset = isset( $settings['show_reset'] ) ? $settings['show_reset'] : 0;
94
  $bulk_async_limit = isset( $settings['bulk_async_limit'] ) ? $settings['bulk_async_limit'] : 4;
 
 
 
 
 
 
 
 
 
95
 
96
  $status = $this->get_api_status( $api_key, $api_secret );
97
 
@@ -138,47 +160,149 @@ if ( !class_exists( 'Wp_Kraken' ) ) {
138
  </td>
139
  </tr>
140
  <tr>
141
- <th scope="row">Optimization Type:</th>
 
 
 
 
 
 
142
  <td>
143
  <input type="radio" id="kraken_lossy" name="_kraken_options[api_lossy]" value="lossy" <?php checked( 'lossy', $lossy, true ); ?>/>
144
- <label for="kraken_lossy">Lossy</label>
145
  <input style="margin-left:10px;" type="radio" id="kraken_lossless" name="_kraken_options[api_lossy]" value="lossless" <?php checked( 'lossless', $lossy, true ) ?>/>
146
  <label for="kraken_lossless">Lossless</label>
147
  </td>
148
  </tr>
149
- <tr>
 
 
 
 
 
 
 
 
150
  <th scope="row">Automatically optimize uploads:</th>
151
  <td>
152
  <input type="checkbox" id="auto_optimize" name="_kraken_options[auto_optimize]" value="1" <?php checked( 1, $auto_optimize, true ); ?>/>
153
  </td>
154
- </tr>
155
- <tr>
156
- <th scope="row">API status:</th>
 
 
 
 
 
 
 
 
157
  <td>
158
- <?php echo $status_html ?>
159
  </td>
160
  </tr>
161
- <tr>
162
- <td class="krakenAdvancedSettings"><h3><span class="kraken-advanced-settings-label" title="Click to toggle advanced settings">Advanced Settings</span><span class="kraken-plus-minus dashicons dashicons-arrow-right"></span></h3></td>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
163
  </tr>
164
  <tr class="kraken-advanced-settings">
165
  <td colspan="2" class="krakenAdvancedSettingsDescription"><small>We recommend that you leave these settings at their default values</td>
166
  </tr>
167
- <tr class="kraken-advanced-settings">
168
- <th scope="row">
169
- Show metadata reset per image:&nbsp;
170
- <small class="krakenWhatsThis" title="Checking this option will add a Reset button in the Kraked Size column for each optimized image. Resetting an image will remove the Kraken.io metadata associated with it, effectively making your blog forget that it had been optimized in the first place, allowing further optimization in some cases. If an image has been optimized using the lossless setting, lossless optimization will not yield any greater savings. If in doubt, please contact support@kraken.io">What's this?</small>
171
- </th>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
172
  <td>
173
  <input type="checkbox" id="kraken_show_reset" name="_kraken_options[show_reset]" value="1" <?php checked( 1, $show_reset, true ); ?>/>
174
  &nbsp;&nbsp;&nbsp;&nbsp;<span class="kraken-reset-all enabled">Reset All Images</span>
175
  </td>
176
  </tr>
177
- <tr class="kraken-advanced-settings">
178
- <th scope="row">
179
- Bulk Concurrency:
180
- <small class="krakenWhatsThis" title="This settings defines how many images can be processed at the same time using the bulk optimizer. The recommended value is 4. For blogs on very small hosting plans, or with reduced connectivity, a lower number might be necessary to avoid hitting request limits.">what's this?</small>
181
- </th>
 
 
 
 
 
 
182
  <td>
183
  <select name="_kraken_options[bulk_async_limit]">
184
  <?php foreach ( range(1, 10) as $number ) { ?>
@@ -188,7 +312,15 @@ if ( !class_exists( 'Wp_Kraken' ) ) {
188
  <?php } ?>
189
  </select>
190
  </td>
191
- </tr>
 
 
 
 
 
 
 
 
192
  </tbody>
193
  </table>
194
  <input type="submit" name="kraken_save" id="kraken_save" class="button button-primary" value="Save All"/>
@@ -201,8 +333,18 @@ if ( !class_exists( 'Wp_Kraken' ) ) {
201
  $error = array();
202
  $valid['api_lossy'] = $input['api_lossy'];
203
  $valid['auto_optimize'] = isset( $input['auto_optimize'] )? 1 : 0;
 
 
 
 
 
 
 
204
  $valid['show_reset'] = isset( $input['show_reset'] ) ? 1 : 0;
205
  $valid['bulk_async_limit'] = isset( $input['bulk_async_limit'] ) ? $input['bulk_async_limit'] : 4;
 
 
 
206
 
207
  if ( $valid['show_reset'] ) {
208
  $valid['show_reset'] = $input['show_reset'];
@@ -240,6 +382,7 @@ if ( !class_exists( 'Wp_Kraken' ) ) {
240
  }
241
 
242
  function my_enqueue( $hook ) {
 
243
  if ( $hook == 'options-media.php' || $hook == 'upload.php' || $hook == 'settings_page_wp-krakenio' ) {
244
  wp_enqueue_script( 'jquery' );
245
  if ( KRAKEN_DEV_MODE === true ) {
@@ -271,152 +414,227 @@ if ( !class_exists( 'Wp_Kraken' ) ) {
271
  return false;
272
  }
273
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
274
  /**
275
  * Handles optimizing already-uploaded images in the Media Library
276
  */
277
  function kraken_media_library_ajax_callback() {
278
-
279
  $image_id = (int) $_POST['id'];
280
  $type = false;
 
281
  if ( isset( $_POST['type'] ) ) {
282
  $type = $_POST['type'];
 
283
  }
284
 
285
  $this->id = $image_id;
286
 
287
  if ( wp_attachment_is_image( $image_id ) ) {
288
 
289
- $image_path = get_attached_file( $image_id );
290
  $settings = $this->kraken_settings;
 
 
 
291
  $api_key = isset( $settings['api_key'] ) ? $settings['api_key'] : '';
292
  $api_secret = isset( $settings['api_secret'] ) ? $settings['api_secret'] : '';
293
 
294
- $status = $this->get_api_status( $api_key, $api_secret );
295
 
296
- if ( $status === false ) {
297
- $kv['error'] = 'There is a problem with your credentials. Please check them in the Kraken.io settings section of Media Settings, and try again.';
298
- update_post_meta( $image_id, '_kraken_size', $kv );
299
- echo json_encode( array( 'error' => $kv['error'] ) );
300
  exit;
301
  }
302
 
303
- if ( isset( $status['active'] ) && $status['active'] === true ) {
304
 
305
- } else {
306
- echo json_encode( array( 'error' => 'Your API is inactive. Please visit your account settings' ) );
307
- die();
308
- }
309
-
310
- $result = $this->optimize_image( $image_path, $type );
 
311
 
312
- $kv = array();
 
313
 
314
- if ( $result['success'] == true && !isset( $result['error'] ) ) {
 
 
315
 
316
- $kraked_url = $result['kraked_url'];
317
- $savings_percentage = (int) $result['saved_bytes'] / (int) $result['original_size'] * 100;
318
- $kv['original_size'] = self::pretty_kb( $result['original_size'] );
319
- $kv['kraked_size'] = self::pretty_kb( $result['kraked_size'] );
320
- $kv['saved_bytes'] = self::pretty_kb( $result['saved_bytes'] );
321
- $kv['savings_percent'] = round( $savings_percentage, 2 ) . '%';
322
- $kv['type'] = $result['type'];
323
- $kv['success'] = true;
324
- $kv['meta'] = wp_get_attachment_metadata( $image_id );
325
- $saved_bytes = (int) $kv['saved_bytes'];
326
 
327
- if ( $this->replace_image( $image_path, $result['kraked_url'] ) ) {
 
 
 
328
 
329
- // get metadata for thumbnails
330
- $image_data = wp_get_attachment_metadata( $image_id );
331
- $this->optimize_thumbnails( $image_data );
332
 
333
- // store kraked info to DB
334
- update_post_meta( $image_id, '_kraken_size', $kv );
 
335
 
336
- // krak thumbnails, store that data too. This can be unset when there are no thumbs
337
- $kraked_thumbs_data = get_post_meta( $image_id, '_kraked_thumbs', true );
338
- if ( !empty( $kraked_thumbs_data ) ) {
339
- $kv['thumbs_data'] = $kraked_thumbs_data;
340
- }
341
- $kv['html'] = $this->results_html( $image_id );
342
- echo json_encode( $kv );
343
- } else {
344
- echo json_encode( array( 'error' => 'Could not overwrite original file. Please ensure that your files are writable by plugins.' ) );
345
- exit;
346
- }
347
 
348
- } else {
 
349
 
350
- // error or no optimization
351
- if ( file_exists( $image_path ) ) {
 
 
 
 
352
 
353
- $kv['original_size'] = self::pretty_kb( filesize( $image_path ) );
354
- $kv['error'] = $result['error'];
355
- $kv['type'] = $result['type'];
 
 
 
 
356
 
357
- if ( $kv['error'] == 'This image can not be optimized any further' ) {
358
- $kv['kraked_size'] = 'No savings found';
359
- $kv['no_savings'] = true;
 
 
 
360
  }
 
 
 
 
 
 
361
 
362
- update_post_meta( $image_id, '_kraken_size', $kv );
 
363
 
364
- } else {
365
- // file not found
 
366
  }
367
- echo json_encode($result);
 
 
368
  }
369
  }
370
- die();
371
  }
372
 
 
 
 
373
  /**
374
  * Handles optimizing images uploaded through any of the media uploaders.
375
  */
376
  function kraken_media_uploader_callback( $image_id ) {
 
377
  $this->id = $image_id;
378
 
 
 
 
 
 
 
 
 
 
 
 
 
 
379
  if ( wp_attachment_is_image( $image_id ) ) {
380
 
381
- $settings = $this->kraken_settings;
382
- $type = $settings['api_lossy'];
383
  $image_path = get_attached_file( $image_id );
384
- $result = $this->optimize_image( $image_path, $type );
385
-
386
- if ( $result['success'] == true && !isset( $result['error'] ) ) {
387
-
388
- $kraked_url = $result['kraked_url'];
389
- $savings_percentage = (int) $result['saved_bytes'] / (int) $result['original_size'] * 100;
390
- $kv['original_size'] = self::pretty_kb( $result['original_size'] );
391
- $kv['kraked_size'] = self::pretty_kb( $result['kraked_size'] );
392
- $kv['saved_bytes'] = self::pretty_kb( $result['saved_bytes'] );
393
- $kv['savings_percent'] = round( $savings_percentage, 2 ) . '%';
394
- $kv['type'] = $result['type'];
395
- $kv['success'] = true;
396
- $kv['meta'] = wp_get_attachment_metadata( $image_id );
397
- $saved_bytes = (int) $kv['saved_bytes'];
398
-
399
- if ( $this->replace_image( $image_path, $kraked_url ) ) {
400
- update_post_meta( $image_id, '_kraken_size', $kv );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
401
  } else {
402
- // writing image failed
 
 
 
 
 
403
  }
 
404
 
405
  } else {
406
-
407
  // error or no optimization
408
  if ( file_exists( $image_path ) ) {
409
 
410
- $kv['original_size'] = self::pretty_kb( filesize( $image_path ) );
411
- $kv['error'] = $result['error'];
412
- $kv['type'] = $result['type'];
413
-
414
- if ( $kv['error'] == 'This image can not be optimized any further' ) {
415
- $kv['kraked_size'] = 'No savings found';
416
- $kv['no_savings'] = true;
417
- }
418
-
419
- update_post_meta( $image_id, '_kraken_size', $kv );
420
 
421
  } else {
422
  // file not found
@@ -428,11 +646,11 @@ if ( !class_exists( 'Wp_Kraken' ) ) {
428
  function kraken_media_library_reset() {
429
  $image_id = (int) $_POST['id'];
430
  $image_meta = get_post_meta( $image_id, '_kraken_size', true );
431
- $original_size = $image_meta['kraked_size'];
432
  delete_post_meta( $image_id, '_kraken_size' );
433
  delete_post_meta( $image_id, '_kraked_thumbs' );
434
  echo json_encode( array( 'success' => true, 'original_size' => $original_size, 'html' => $this->optimize_button_html( $image_id ) ) );
435
- die();
436
  }
437
 
438
  function kraken_media_library_reset_all() {
@@ -441,7 +659,7 @@ if ( !class_exists( 'Wp_Kraken' ) ) {
441
  delete_post_meta_by_key( '_kraken_size' );
442
  $result = json_encode( array( 'success' => true ) );
443
  echo $result;
444
- die();
445
  }
446
 
447
 
@@ -553,40 +771,189 @@ EOD;
553
  <?php
554
  }
555
 
556
-
557
  function add_media_columns( $columns ) {
558
  $columns['original_size'] = 'Original Size';
559
- $columns['kraked_size'] = 'Kraked Size';
560
  return $columns;
561
  }
562
 
563
- function results_html( $id ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
564
  $image_meta = get_post_meta( $id, '_kraken_size', true );
565
  $thumbs_meta = get_post_meta( $id, '_kraked_thumbs', true );
566
- $kraked_size = $image_meta['kraked_size'];
567
- $type = $image_meta['type'];
568
- $thumbs_count = count( $thumbs_meta );
569
- $savings_percentage = $image_meta['savings_percent'];
570
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
571
  ob_start();
572
  ?>
573
- <strong><?php echo $kraked_size; ?></strong>
 
 
574
  <br />
575
- <small>Type:&nbsp;<?php echo $type; ?></small>
 
 
576
  <br />
577
- <small>Savings:&nbsp;<?php echo $savings_percentage; ?></small>
578
- <?php if ( !empty( $thumbs_meta ) ) { ?>
 
579
  <br />
580
- <small><?php echo $thumbs_count; ?> thumbs optimized</small>
581
  <?php } ?>
 
 
 
 
582
  <?php if ( !empty( $this->kraken_settings['show_reset'] ) ) { ?>
583
  <br />
584
- <small
585
  class="krakenReset" data-id="<?php echo $id; ?>"
586
  title="Removes Kraken metadata associated with this image">
587
  Reset
588
  </small>
589
  <span class="krakenSpinner"></span>
 
590
  <?php } ?>
591
  <?php
592
  $html = ob_get_clean();
@@ -595,12 +962,21 @@ EOD;
595
 
596
  function fill_media_columns( $column_name, $id ) {
597
 
598
- $original_size = filesize( get_attached_file( $id ) );
599
- $original_size = self::pretty_kb( $original_size );
600
 
601
- $options = get_option( '_kraken_options' );
602
- $type = isset( $options['api_lossy'] ) ? $options['api_lossy'] : 'lossy';
603
 
 
 
 
 
 
 
 
 
 
604
 
605
  if ( strcmp( $column_name, 'original_size' ) === 0 ) {
606
  if ( wp_attachment_is_image( $id ) ) {
@@ -608,7 +984,13 @@ EOD;
608
  $meta = get_post_meta( $id, '_kraken_size', true );
609
 
610
  if ( isset( $meta['original_size'] ) ) {
611
- echo $meta['original_size'];
 
 
 
 
 
 
612
  } else {
613
  echo $original_size;
614
  }
@@ -616,19 +998,23 @@ EOD;
616
  echo $original_size;
617
  }
618
  } else if ( strcmp( $column_name, 'kraked_size' ) === 0 ) {
619
-
 
 
620
  if ( wp_attachment_is_image( $id ) ) {
621
 
622
- $meta = get_post_meta($id, '_kraken_size', true);
 
623
 
624
  // Is it optimized? Show some stats
625
- if ( isset( $meta['kraked_size'] ) && empty( $meta['no_savings'] ) ) {
626
- echo $this->results_html( $id );
 
 
 
627
 
628
  // Were there no savings, or was there an error?
629
  } else {
630
- $image_url = wp_get_attachment_url( $id );
631
- $filename = basename( $image_url );
632
  echo '<div class="buttonWrap"><button data-setting="' . $type . '" type="button" class="kraken_req" data-id="' . $id . '" id="krakenid-' . $id .'" data-filename="' . $filename . '" data-url="' . $image_url . '">Optimize This Image</button><span class="krakenSpinner"></span></div>';
633
  if ( !empty( $meta['no_savings'] ) ) {
634
  echo '<div class="noSavings"><strong>No savings found</strong><br /><small>Type:&nbsp;' . $meta['type'] . '</small></div>';
@@ -640,49 +1026,93 @@ EOD;
640
  } else {
641
  echo 'n/a';
642
  }
 
643
  }
644
  }
645
 
646
  function replace_image( $image_path, $kraked_url ) {
647
  $rv = false;
648
  $ch = curl_init( $kraked_url );
649
- curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
650
  curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, 0 );
651
- curl_setopt( $ch, CURLOPT_USERAGENT, 'WordPress/' . get_bloginfo('version') . ' KrakenPlugin/' . self::$kraken_plugin_version );
 
 
 
652
  $result = curl_exec( $ch );
653
- $rv = file_put_contents( $image_path, $result );
 
 
 
654
  return $rv !== false;
655
  }
656
 
657
- function optimize_image( $image_path, $type ) {
658
  $settings = $this->kraken_settings;
659
  $kraken = new Kraken( $settings['api_key'], $settings['api_secret'] );
660
 
661
  if ( !empty( $type ) ) {
662
  $lossy = $type === 'lossy';
663
  } else {
664
- $lossy = $settings['api_lossy'] === "lossy";
665
  }
666
 
667
  $params = array(
668
- "file" => $image_path,
669
- "wait" => true,
670
- "lossy" => $lossy,
671
- "origin" => "wp"
672
  );
673
 
674
- try {
675
- $data = $kraken->upload( $params );
676
- } catch (Exception $e) {
 
 
 
 
 
 
 
 
 
 
 
 
677
  }
678
 
679
- $data['type'] = !empty( $type ) ? $type : $settings['api_lossy'];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
680
 
 
 
 
 
 
 
 
681
  return $data;
682
  }
683
 
684
  function optimize_thumbnails( $image_data ) {
685
-
686
  $image_id = $this->id;
687
  if ( empty( $image_id ) ) {
688
  global $wpdb;
@@ -708,39 +1138,62 @@ EOD;
708
  }
709
 
710
  if ( !empty( $sizes ) ) {
711
-
712
  $thumb_path = '';
713
-
714
  $thumbs_optimized_store = array();
715
  $this_thumb = array();
716
 
717
  foreach ( $sizes as $key => $size ) {
718
 
719
  $thumb_path = $upload_full_path . '/' . $size['file'];
720
-
721
  if ( file_exists( $thumb_path ) !== false ) {
722
-
723
  $result = $this->optimize_image( $thumb_path, $this->optimization_type );
724
-
725
- if ( !empty($result) && isset($result['success']) && isset( $result['kraked_url'] ) ) {
726
- $kraked_url = $result["kraked_url"];
727
- if ( $this->replace_image( $thumb_path, $kraked_url ) ) {
728
- $this_thumb = array( 'thumb' => $key, 'file' => $size['file'], 'original_size' => $result['original_size'], 'kraked_size' => $result['kraked_size'], 'type' => $this->optimization_type );
729
- $thumbs_optimized_store [] = $this_thumb;
 
 
 
 
730
  }
 
 
731
  }
732
  }
733
  }
734
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
735
  if ( !empty( $thumbs_optimized_store ) ) {
736
  update_post_meta( $image_id, '_kraked_thumbs', $thumbs_optimized_store, false );
737
  }
738
  return $image_data;
739
  }
740
 
741
-
742
- static function pretty_kb( $bytes ) {
743
- return round( ( $bytes / 1024 ), 2 ) . ' kB';
 
744
  }
745
  }
746
  }
21
  * Plugin URI: http://wordpress.org/plugins/kraken-image-optimizer/
22
  * Description: This plugin allows you to optimize your WordPress images through the Kraken API, the world's most advanced image optimization solution.
23
  * Author: Karim Salman
24
+ * Version: 2.5.0
25
+ * Stable Tag: 2.5.0
26
  * Author URI: https://kraken.io
27
  * License GPL2
28
  */
41
 
42
  private $optimization_type = 'lossy';
43
 
44
+ public static $kraken_plugin_version = '2.5.0';
45
 
46
  function __construct() {
47
  $plugin_dir_path = dirname( __FILE__ );
50
  $this->optimization_type = $this->kraken_settings['api_lossy'];
51
  add_action( 'admin_enqueue_scripts', array( &$this, 'my_enqueue' ) );
52
  add_action( 'wp_ajax_kraken_reset', array( &$this, 'kraken_media_library_reset' ) );
53
+ add_action( 'wp_ajax_kraken_optimize', array( &$this, 'kraken_optimize' ) );
54
  add_action( 'wp_ajax_kraken_request', array( &$this, 'kraken_media_library_ajax_callback' ) );
55
  add_action( 'wp_ajax_kraken_reset_all', array( &$this, 'kraken_media_library_reset_all' ) );
56
  add_action( 'manage_media_custom_column', array( &$this, 'fill_media_columns' ), 10, 2 );
57
  add_filter( 'manage_media_columns', array( &$this, 'add_media_columns') );
58
  add_filter( 'plugin_action_links_' . plugin_basename(__FILE__), array( &$this, 'add_settings_link' ) );
59
+
60
  if ( ( !empty( $this->kraken_settings ) && !empty( $this->kraken_settings['auto_optimize'] ) ) || !isset( $this->kraken_settings['auto_optimize'] ) ) {
61
+ add_action( 'add_attachment', array( &$this, 'kraken_media_uploader_callback' ) );
62
+ add_filter( 'wp_generate_attachment_metadata', array( &$this, 'optimize_thumbnails' ) );
63
+ }
64
+ add_action( 'admin_menu', array( &$this, 'kraken_menu' ) );
65
+ }
66
+
67
+ function isApiActive() {
68
+ $settings = $this->kraken_settings;
69
+ $api_key = isset( $settings['api_key'] ) ? $settings['api_key'] : '';
70
+ $api_secret = isset( $settings['api_secret'] ) ? $settings['api_secret'] : '';
71
+ if ( empty( $api_key ) || empty( $api_secret) ) {
72
+ return false;
73
  }
74
+ return true;
75
  }
76
 
77
  function kraken_menu() {
78
  add_options_page( 'Kraken Image Optimizer Settings', 'Kraken.io', 'manage_options', 'wp-krakenio', array( &$this, 'kraken_settings_page' ) );
79
  }
80
 
81
+ function blog_kraker() {
82
+ add_management_page( 'Blog Kraker', 'Blog Kraker', 'manage_options', 'blog-kraker', array( &$this, 'show_blog_kraker' ) );
83
+ }
84
 
85
  function add_settings_link ( $links ) {
86
  $mylinks = array(
89
  return array_merge( $links, $mylinks );
90
  }
91
 
92
+ function kraken_settings_page() {
93
 
 
 
94
  if ( !empty( $_POST ) ) {
95
  $options = $_POST['_kraken_options'];
96
  $result = $this->validate_options( $options );
100
  $settings = get_option( '_kraken_options' );
101
  $lossy = isset( $settings['api_lossy'] ) ? $settings['api_lossy'] : 'lossy';
102
  $auto_optimize = isset( $settings['auto_optimize'] ) ? $settings['auto_optimize'] : 1;
103
+ $optimize_main_image = isset( $settings['optimize_main_image'] ) ? $settings['optimize_main_image'] : 1;
104
  $api_key = isset( $settings['api_key'] ) ? $settings['api_key'] : '';
105
  $api_secret = isset( $settings['api_secret'] ) ? $settings['api_secret'] : '';
 
106
  $show_reset = isset( $settings['show_reset'] ) ? $settings['show_reset'] : 0;
107
  $bulk_async_limit = isset( $settings['bulk_async_limit'] ) ? $settings['bulk_async_limit'] : 4;
108
+ $preserve_meta_date = isset( $settings['preserve_meta_date'] ) ? $settings['preserve_meta_date'] : 0;
109
+ $preserve_meta_copyright = isset( $settings['preserve_meta_copyright'] ) ? $settings['preserve_meta_copyright'] : 0;
110
+ $preserve_meta_geotag = isset( $settings['preserve_meta_geotag'] ) ? $settings['preserve_meta_geotag'] : 0;
111
+ $preserve_meta_orientation = isset( $settings['preserve_meta_orientation'] ) ? $settings['preserve_meta_orientation'] : 0;
112
+ $preserve_meta_profile = isset( $settings['preserve_meta_profile'] ) ? $settings['preserve_meta_profile'] : 0;
113
+ $auto_orient = isset( $settings['auto_orient'] ) ? $settings['auto_orient'] : 1;
114
+ $resize_width = isset( $settings['resize_width'] ) ? $settings['resize_width'] : 0;
115
+ $resize_height = isset( $settings['resize_height'] ) ? $settings['resize_height'] : 0;
116
+ $jpeg_quality = isset( $settings['jpeg_quality'] ) ? $settings['jpeg_quality'] : 0;
117
 
118
  $status = $this->get_api_status( $api_key, $api_secret );
119
 
160
  </td>
161
  </tr>
162
  <tr>
163
+ <th scope="row">API status:</th>
164
+ <td>
165
+ <?php echo $status_html ?>
166
+ </td>
167
+ </tr>
168
+ <tr class="with-tip">
169
+ <th scope="row">Optimization mode:</th>
170
  <td>
171
  <input type="radio" id="kraken_lossy" name="_kraken_options[api_lossy]" value="lossy" <?php checked( 'lossy', $lossy, true ); ?>/>
172
+ <label for="kraken_lossy">Intelligent Lossy</label>
173
  <input style="margin-left:10px;" type="radio" id="kraken_lossless" name="_kraken_options[api_lossy]" value="lossless" <?php checked( 'lossless', $lossy, true ) ?>/>
174
  <label for="kraken_lossless">Lossless</label>
175
  </td>
176
  </tr>
177
+ <tr class="tip">
178
+ <td colspan="2">
179
+ <div>
180
+ The <strong>Intelligent Lossy</strong> mode will yield the greatest savings without perceivable reducing the quality of your images, and so we recommend this setting to users.<br />
181
+ The <strong>Lossless</strong> mode will result in an unchanged image, however, will yield reduced savings as the image will not be recompressed.
182
+ </div>
183
+ </td>
184
+ </tr>
185
+ <tr class="with-tip">
186
  <th scope="row">Automatically optimize uploads:</th>
187
  <td>
188
  <input type="checkbox" id="auto_optimize" name="_kraken_options[auto_optimize]" value="1" <?php checked( 1, $auto_optimize, true ); ?>/>
189
  </td>
190
+ </tr>
191
+ <tr class="tip">
192
+ <td colspan="2">
193
+ <div>
194
+ Enabled by default. This setting causes images uploaded through the Media Uploader to be optimized on-the-fly.<br />
195
+ If you do not wish to do this, or wish to optimize images later, disable this setting by unchecking the box.
196
+ </div>
197
+ </td>
198
+ </tr>
199
+ <tr class="with-tip">
200
+ <th scope="row">Optimize main image:</th>
201
  <td>
202
+ <input type="checkbox" id="optimize_main_image" name="_kraken_options[optimize_main_image]" value="1" <?php checked( 1, $optimize_main_image, true ); ?>/>
203
  </td>
204
  </tr>
205
+ <tr class="tip">
206
+ <td colspan="2">
207
+ <div>
208
+ Enabled by default. This option causes the image uploaded by the user to get optimized, as well as all sizes generated by WordPress.<br />
209
+ Disabling this option results in faster uploading, since the main image is not sent to our system for optimization.<br />
210
+ Disable this option if you never use the "main" image upload in your posts, or speed of image uploading is an issue.
211
+ </div>
212
+ </td>
213
+ </tr>
214
+ <tr class="with-tip">
215
+ <th scope="row">Resize main image:</th>
216
+ <td>
217
+ Max Width (px):&nbsp;&nbsp;<input type="text" id="kraken_maximum_width" name="_kraken_options[resize_width]" value="<?php echo esc_attr( $resize_width ); ?>" style="width:50px;" />&nbsp;&nbsp;&nbsp;Max Height (px):&nbsp;<input type="text" id="kraken_maximum_height" name="_kraken_options[resize_height]" value="<?php echo esc_attr( $resize_height ); ?>" style="width:50px;" />
218
+ </td>
219
+ </tr>
220
+ <tr class="tip">
221
+ <td colspan="2">
222
+ <div>
223
+ You can restrict the maximum dimensions of image uploads by width and/or height.<br />
224
+ It is especially useful if you wish to prevent unnecessarily large photos with extremely high resolutions from being uploaded, for example, <br />
225
+ photos shot with a recent-model iPhone. Note: you can restrict the dimenions by width, height, or both. A value of zero disables.
226
+ </div>
227
+ </td>
228
+ </tr>
229
+ <tr class="with-tip">
230
+ <th scope="row">JPEG quality setting:</th>
231
+ <td>
232
+ <select name="_kraken_options[jpeg_quality]">
233
+ <?php $i = 0 ?>
234
+ <?php foreach ( range(100, 25) as $number ) { ?>
235
+ <?php if ( $i === 0 ) { ?>
236
+ <?php echo '<option value="0">Intelligent lossy (recommended)</option>'; ?>
237
+ <?php } ?>
238
+ <?php if ($i > 0) { ?>
239
+ <option value="<?php echo $number ?>" <?php selected( $jpeg_quality, $number, true); ?>>
240
+ <?php echo $number; ?>
241
+ <?php } ?>
242
+ </option>
243
+ <?php $i++ ?>
244
+ <?php } ?>
245
+ </select>
246
+ </td>
247
+ </tr>
248
+ <tr class="tip">
249
+ <td colspan="2">
250
+ <div>
251
+ Advanced users can force the quality of JPEG images to a discrete "q" value between 25 and 100 using this setting <br />
252
+ For example, forcing the quality to 60 or 70 might yield greater savings, but the resulting quality might be affected, depending on the image. <br />
253
+ We therefore recommend keeping the <strong>Intelligent Lossy</strong> setting, which will not allow a resulting image of unacceptable quality.<br />
254
+ This settings will be ignored when using the <strong>lossless</strong> optimization mode.
255
+ </div>
256
+ </td>
257
+ </tr>
258
+ <tr class="no-border">
259
+ <td class="krakenAdvancedSettings"><h3><span class="kraken-advanced-settings-label" title="Click to toggle advanced settings">Advanced Settings</span></h3></td>
260
  </tr>
261
  <tr class="kraken-advanced-settings">
262
  <td colspan="2" class="krakenAdvancedSettingsDescription"><small>We recommend that you leave these settings at their default values</td>
263
  </tr>
264
+ <tr class="kraken-advanced-settings">
265
+ <th scope="row">Preserve EXIF Metadata:</th>
266
+ <td>
267
+ <label for="preserve_meta_date"><input type="checkbox" id="preserve_meta_date" name="_kraken_options[preserve_meta_date]" value="1" <?php checked( 1, $preserve_meta_date, true ); ?>/>&nbsp;Date</label>&nbsp;&nbsp;&nbsp;&nbsp;
268
+ <label for="preserve_meta_copyright"><input type="checkbox" id="preserve_meta_copyright" name="_kraken_options[preserve_meta_copyright]" value="1" <?php checked( 1, $preserve_meta_copyright, true ); ?>/>&nbsp;Copyright</label>&nbsp;&nbsp;&nbsp;&nbsp;
269
+ <label for="preserve_meta_geotag"><input type="checkbox" id="preserve_meta_geotag" name="_kraken_options[preserve_meta_geotag]" value="1" <?php checked( 1, $preserve_meta_geotag, true ); ?>/>&nbsp;Geotag</label>&nbsp;&nbsp;&nbsp;&nbsp;
270
+ <label for="preserve_meta_orientation"><input type="checkbox" id="preserve_meta_orientation" name="_kraken_options[preserve_meta_orientation]" value="1" <?php checked( 1, $preserve_meta_orientation, true ); ?>/>&nbsp;Orientation</label>&nbsp;&nbsp;&nbsp;&nbsp;
271
+ <label for="preserve_meta_profile"><input type="checkbox" id="preserve_meta_profile" name="_kraken_options[preserve_meta_profile]" value="1" <?php checked( 1, $preserve_meta_profile, true ); ?>/>&nbsp;Profile</label>&nbsp;&nbsp;&nbsp;&nbsp;
272
+ </td>
273
+ </tr>
274
+ <tr class="kraken-advanced-settings with-tip">
275
+ <th scope="row">Automatically Orient Images:</th>
276
+ <td>
277
+ <input type="checkbox" id="auto_orient" name="_kraken_options[auto_orient]" value="1" <?php checked( 1, $auto_orient, true ); ?>/>
278
+ </td>
279
+ </tr>
280
+ <tr class="tip">
281
+ <td colspan="2">
282
+ <div>
283
+ This setting will rotate the JPEG image according to its <strong>Orientation</strong> EXIF metadata such that it will always be correctly displayed in Web Browsers.<br />
284
+ Enable this setting if many of your image uploads come from smart phones or digital cameras which set the orientation based on how they are held at the time of shooting.
285
+ </div>
286
+ </td>
287
+ </tr>
288
+ <tr class="kraken-advanced-settings with-tip">
289
+ <th scope="row">Show metadata reset per image:</th>
290
  <td>
291
  <input type="checkbox" id="kraken_show_reset" name="_kraken_options[show_reset]" value="1" <?php checked( 1, $show_reset, true ); ?>/>
292
  &nbsp;&nbsp;&nbsp;&nbsp;<span class="kraken-reset-all enabled">Reset All Images</span>
293
  </td>
294
  </tr>
295
+ <tr class="tip">
296
+ <td colspan="2">
297
+ <div>
298
+ Checking this option will add a Reset button in the "Show Details" popup in the Kraken Stats column for each optimized image.<br />
299
+ Resetting an image will remove the Kraken.io metadata associated with it, effectively making your blog forget that it had been optimized in the first place, allowing further optimization in some cases.<br />
300
+ If an image has been optimized using the lossless setting, lossless optimization will not yield any greater savings. If in doubt, please contact support@kraken.io
301
+ </div>
302
+ </td>
303
+ </tr>
304
+ <tr class="kraken-advanced-settings with-tip">
305
+ <th scope="row">Bulk Concurrency:</th>
306
  <td>
307
  <select name="_kraken_options[bulk_async_limit]">
308
  <?php foreach ( range(1, 10) as $number ) { ?>
312
  <?php } ?>
313
  </select>
314
  </td>
315
+ </tr>
316
+ <tr class="tip">
317
+ <td colspan="2">
318
+ <div>
319
+ This settings defines how many images can be processed at the same time using the bulk optimizer. The recommended (and default) value is 4. <br />
320
+ For blogs on very small hosting plans, or with reduced connectivity, a lower number might be necessary to avoid hitting request limits.
321
+ </div>
322
+ </td>
323
+ </tr>
324
  </tbody>
325
  </table>
326
  <input type="submit" name="kraken_save" id="kraken_save" class="button button-primary" value="Save All"/>
333
  $error = array();
334
  $valid['api_lossy'] = $input['api_lossy'];
335
  $valid['auto_optimize'] = isset( $input['auto_optimize'] )? 1 : 0;
336
+ $valid['optimize_main_image'] = isset( $input['optimize_main_image'] ) ? 1 : 0;
337
+ $valid['preserve_meta_date'] = isset( $input['preserve_meta_date'] ) ? $input['preserve_meta_date'] : 0;
338
+ $valid['preserve_meta_copyright'] = isset( $input['preserve_meta_copyright'] ) ? $input['preserve_meta_copyright'] : 0;
339
+ $valid['preserve_meta_geotag'] = isset( $input['preserve_meta_geotag'] ) ? $input['preserve_meta_geotag'] : 0;
340
+ $valid['preserve_meta_orientation'] = isset( $input['preserve_meta_orientation'] ) ? $input['preserve_meta_orientation'] : 0;
341
+ $valid['preserve_meta_profile'] = isset( $input['preserve_meta_profile'] ) ? $input['preserve_meta_profile'] : 0;
342
+ $valid['auto_orient'] = isset( $input['auto_orient'] ) ? $input['auto_orient'] : 0;
343
  $valid['show_reset'] = isset( $input['show_reset'] ) ? 1 : 0;
344
  $valid['bulk_async_limit'] = isset( $input['bulk_async_limit'] ) ? $input['bulk_async_limit'] : 4;
345
+ $valid['resize_width'] = isset( $input['resize_width'] ) ? (int) $input['resize_width'] : 0;
346
+ $valid['resize_height'] = isset( $input['resize_height'] ) ? (int) $input['resize_height'] : 0;
347
+ $valid['jpeg_quality'] = isset( $input['jpeg_quality'] ) ? (int) $input['jpeg_quality'] : 0;
348
 
349
  if ( $valid['show_reset'] ) {
350
  $valid['show_reset'] = $input['show_reset'];
382
  }
383
 
384
  function my_enqueue( $hook ) {
385
+
386
  if ( $hook == 'options-media.php' || $hook == 'upload.php' || $hook == 'settings_page_wp-krakenio' ) {
387
  wp_enqueue_script( 'jquery' );
388
  if ( KRAKEN_DEV_MODE === true ) {
414
  return false;
415
  }
416
 
417
+ /**
418
+ * Converts an deserialized API result array into an array
419
+ * which this plugin will consume
420
+ */
421
+ function get_result_arr( $result, $image_id ) {
422
+ $rv = array();
423
+ $rv['original_size'] = $result['original_size'];
424
+ $rv['kraked_size'] = $result['kraked_size'];
425
+ $rv['saved_bytes'] = $result['saved_bytes'];
426
+ $savings_percentage = $result['saved_bytes'] / $result['original_size'] * 100;
427
+ $rv['savings_percent'] = round( $savings_percentage, 2 ) . '%';
428
+ $rv['type'] = $result['type'];
429
+ if ( !empty( $result['kraked_width'] ) && !empty( $result['kraked_height'] ) ) {
430
+ $rv['kraked_width'] = $result['kraked_width'];
431
+ $rv['kraked_height'] = $result['kraked_height'];
432
+ }
433
+ $rv['success'] = $result['success'];
434
+ $rv['meta'] = wp_get_attachment_metadata( $image_id );
435
+ return $rv;
436
+ }
437
+
438
+
439
  /**
440
  * Handles optimizing already-uploaded images in the Media Library
441
  */
442
  function kraken_media_library_ajax_callback() {
443
+
444
  $image_id = (int) $_POST['id'];
445
  $type = false;
446
+
447
  if ( isset( $_POST['type'] ) ) {
448
  $type = $_POST['type'];
449
+ $this->optimization_type = $type;
450
  }
451
 
452
  $this->id = $image_id;
453
 
454
  if ( wp_attachment_is_image( $image_id ) ) {
455
 
 
456
  $settings = $this->kraken_settings;
457
+
458
+ $image_path = get_attached_file( $image_id );
459
+ $optimize_main_image = !empty( $settings['optimize_main_image'] );
460
  $api_key = isset( $settings['api_key'] ) ? $settings['api_key'] : '';
461
  $api_secret = isset( $settings['api_secret'] ) ? $settings['api_secret'] : '';
462
 
463
+ $data = array();
464
 
465
+ if ( empty( $api_key ) && empty( $api_secret ) ) {
466
+ $data['error'] = 'There is a problem with your credentials. Please check them in the Kraken.io settings section of Media Settings, and try again.';
467
+ update_post_meta( $image_id, '_kraken_size', $data );
468
+ echo json_encode( array( 'error' => $data['error'] ) );
469
  exit;
470
  }
471
 
472
+ if ( $optimize_main_image ) {
473
 
474
+ // check if thumbs already optimized
475
+ $thumbs_optimized = false;
476
+ $kraked_thumbs_data = get_post_meta( $image_id, '_kraked_thumbs', true );
477
+
478
+ if ( !empty ( $kraked_thumbs_data ) ) {
479
+ $thumbs_optimized = true;
480
+ }
481
 
482
+ // get metadata for thumbnails
483
+ $image_data = wp_get_attachment_metadata( $image_id );
484
 
485
+ if ( !$thumbs_optimized ) {
486
+ $this->optimize_thumbnails( $image_data );
487
+ } else {
488
 
489
+ // re-optimize thumbs if mode has changed
490
+ $kraked_thumbs_mode = $kraked_thumbs_data[0]['type'];
491
+ if ( strcmp( $kraked_thumbs_mode, $this->optimization_type ) !== 0 ) {
492
+ wp_generate_attachment_metadata( $image_id, $image_path );
493
+ $this->optimize_thumbnails( $image_data );
494
+ }
495
+ }
 
 
 
496
 
497
+ $resize = false;
498
+ if ( !empty( $settings['resize_width'] ) || !empty( $settings['resize_height'] ) ) {
499
+ $resize = true;
500
+ }
501
 
502
+ $api_result = $this->optimize_image( $image_path, $type, $resize );
 
 
503
 
504
+ if ( !empty( $api_result ) && !empty( $api_result['success'] ) ) {
505
+ $data = $this->get_result_arr( $api_result, $image_id );
506
+ if ( $this->replace_image( $image_path, $api_result['kraked_url'] ) ) {
507
 
508
+ if ( !empty( $data['kraked_width'] ) && !empty( $data['kraked_height'] ) ) {
509
+ $image_data = wp_get_attachment_metadata( $image_id );
510
+ $image_data['width'] = $data['kraked_width'];
511
+ $image_data['height'] = $data['kraked_height'];
512
+ wp_update_attachment_metadata( $image_id, $image_data );
513
+ }
 
 
 
 
 
514
 
515
+ // store kraked info to DB
516
+ update_post_meta( $image_id, '_kraken_size', $data );
517
 
518
+ // krak thumbnails, store that data too. This can be unset when there are no thumbs
519
+ $kraked_thumbs_data = get_post_meta( $image_id, '_kraked_thumbs', true );
520
+ if ( !empty( $kraked_thumbs_data ) ) {
521
+ $data['thumbs_data'] = $kraked_thumbs_data;
522
+ $data['success'] = true;
523
+ }
524
 
525
+ $data['html'] = $this->generate_stats_summary( $image_id );
526
+ echo json_encode( $data );
527
+
528
+ } else {
529
+ echo json_encode( array( 'error' => 'Could not overwrite original file. Please ensure that your files are writable by plugins.' ) );
530
+ exit;
531
+ }
532
 
533
+ } else {
534
+ // error or no optimization
535
+ if ( file_exists( $image_path ) ) {
536
+ update_post_meta( $image_id, '_kraken_size', $data );
537
+ } else {
538
+ // file not found
539
  }
540
+ echo json_encode( array( 'error' => $api_result['message'], '' ) );
541
+ }
542
+ } else {
543
+ // get metadata for thumbnails
544
+ $image_data = wp_get_attachment_metadata( $image_id );
545
+ $this->optimize_thumbnails( $image_data );
546
 
547
+ // krak thumbnails, store that data too. This can be unset when there are no thumbs
548
+ $kraked_thumbs_data = get_post_meta( $image_id, '_kraked_thumbs', true );
549
 
550
+ if ( !empty( $kraked_thumbs_data ) ) {
551
+ $data['thumbs_data'] = $kraked_thumbs_data;
552
+ $data['success'] = true;
553
  }
554
+ $data['html'] = $this->generate_stats_summary( $image_id );
555
+
556
+ echo json_encode( $data );
557
  }
558
  }
559
+ wp_die();
560
  }
561
 
562
+
563
+ function is_successful( $response ) {}
564
+
565
  /**
566
  * Handles optimizing images uploaded through any of the media uploaders.
567
  */
568
  function kraken_media_uploader_callback( $image_id ) {
569
+
570
  $this->id = $image_id;
571
 
572
+ if ( !$this->kraken_settings['optimize_main_image'] ) {
573
+ return;
574
+ }
575
+
576
+ $settings = $this->kraken_settings;
577
+ $type = $settings['api_lossy'];
578
+
579
+ if ( !$this->isApiActive() ) {
580
+ remove_filter( 'wp_generate_attachment_metadata', array( &$this, 'optimize_thumbnails') );
581
+ remove_action( 'add_attachment', array( &$this, 'kraken_media_uploader_callback' ) );
582
+ return;
583
+ }
584
+
585
  if ( wp_attachment_is_image( $image_id ) ) {
586
 
 
 
587
  $image_path = get_attached_file( $image_id );
588
+ $image_backup_path = $image_path . '_kraken_' . md5( $image_path );
589
+ $backup_created = false;
590
+
591
+ if ( copy( $image_path, $image_backup_path ) ) {
592
+ $backup_created = true;
593
+ }
594
+
595
+ $resize = false;
596
+ if ( !empty( $settings['resize_width'] ) || !empty( $settings['resize_height'] ) ) {
597
+ $resize = true;
598
+ }
599
+
600
+ // optimize backup image
601
+ if ( $backup_created ) {
602
+ $api_result = $this->optimize_image( $image_backup_path, $type, $resize );
603
+ } else {
604
+ $api_result = $this->optimize_image( $image_path, $type, $resize );
605
+ }
606
+
607
+ $data = array();
608
+
609
+ if ( !empty( $api_result ) && !empty( $api_result['success'] ) ) {
610
+ $data = $this->get_result_arr( $api_result, $image_id );
611
+
612
+ if ( $backup_created ) {
613
+ $data['optimized_backup_file'] = $image_backup_path;
614
+ if ( $data['saved_bytes'] > 0 ) {
615
+ if ( $this->replace_image( $image_backup_path, $api_result['kraked_url'] ) ) {
616
+ } else {
617
+ error_log('Kraken.io: Could not replace local image with optimized image.');
618
+ }
619
+ }
620
  } else {
621
+ if ( $data['saved_bytes'] > 0 ) {
622
+ if ( $this->replace_image( $image_path, $api_result['kraked_url'] ) ) {
623
+ } else {
624
+ error_log('Kraken.io: Could not replace local image with optimized image.');
625
+ }
626
+ }
627
  }
628
+ update_post_meta( $image_id, '_kraken_size', $data );
629
 
630
  } else {
 
631
  // error or no optimization
632
  if ( file_exists( $image_path ) ) {
633
 
634
+ $data['original_size'] = filesize( $image_path );
635
+ $data['error'] = $api_result['message'];
636
+ $data['type'] = $api_result['type'];
637
+ update_post_meta( $image_id, '_kraken_size', $data );
 
 
 
 
 
 
638
 
639
  } else {
640
  // file not found
646
  function kraken_media_library_reset() {
647
  $image_id = (int) $_POST['id'];
648
  $image_meta = get_post_meta( $image_id, '_kraken_size', true );
649
+ $original_size = self::formatBytes( filesize( get_attached_file( $image_id ) ) );
650
  delete_post_meta( $image_id, '_kraken_size' );
651
  delete_post_meta( $image_id, '_kraked_thumbs' );
652
  echo json_encode( array( 'success' => true, 'original_size' => $original_size, 'html' => $this->optimize_button_html( $image_id ) ) );
653
+ wp_die();
654
  }
655
 
656
  function kraken_media_library_reset_all() {
659
  delete_post_meta_by_key( '_kraken_size' );
660
  $result = json_encode( array( 'success' => true ) );
661
  echo $result;
662
+ wp_die();
663
  }
664
 
665
 
771
  <?php
772
  }
773
 
 
774
  function add_media_columns( $columns ) {
775
  $columns['original_size'] = 'Original Size';
776
+ $columns['kraked_size'] = 'Kraken.io Stats';
777
  return $columns;
778
  }
779
 
780
+
781
+ static function KBStringToBytes( $str ) {
782
+ $temp = floatVal( $str );
783
+ $rv = false;
784
+ if ( 0 == $temp ) {
785
+ $rv = '0 bytes';
786
+ } else {
787
+ $rv = self::formatBytes( ceil( floatval( $str) * 1024 ) );
788
+ }
789
+ return $rv;
790
+ }
791
+
792
+
793
+ static function calculate_savings( $meta ) {
794
+
795
+ if ( isset( $meta['original_size'] ) ) {
796
+
797
+ $saved_bytes = isset( $meta['saved_bytes'] ) ? $meta['saved_bytes'] : '';
798
+ $savings_percentage = $meta['savings_percent'];
799
+
800
+ // convert old data format, where applicable
801
+ if ( stripos( $saved_bytes, 'kb' ) !== false ) {
802
+ $saved_bytes = self::KBStringToBytes( $saved_bytes );
803
+ } else {
804
+ if ( !$saved_bytes ) {
805
+ $saved_bytes = '0 bytes';
806
+ } else {
807
+ $saved_bytes = self::formatBytes( $saved_bytes );
808
+ }
809
+ }
810
+
811
+ return array(
812
+ 'saved_bytes' => $saved_bytes,
813
+ 'savings_percentage' => $savings_percentage
814
+ );
815
+
816
+ } else if ( !empty( $meta ) ) {
817
+ $thumbs_count = count( $meta );
818
+ $total_thumb_byte_savings = 0;
819
+ $total_thumb_size = 0;
820
+ $thumbs_savings_percentage = '';
821
+ $total_thumbs_savings = '';
822
+
823
+ foreach ( $meta as $k => $v ) {
824
+ $total_thumb_size += $v['original_size'];
825
+ $thumb_byte_savings = $v['original_size'] - $v['kraked_size'];
826
+ $total_thumb_byte_savings += $thumb_byte_savings;
827
+ }
828
+
829
+ $thumbs_savings_percentage = round( ( $total_thumb_byte_savings / $total_thumb_size * 100 ), 2 ) . '%';
830
+ if ( $total_thumb_byte_savings ) {
831
+ $total_thumbs_savings = self::formatBytes( $total_thumb_byte_savings );
832
+ } else {
833
+ $total_thumbs_savings = '0 bytes';
834
+ }
835
+ return array(
836
+ 'savings_percentage' => $thumbs_savings_percentage,
837
+ 'total_savings' => $total_thumbs_savings
838
+ );
839
+ }
840
+ }
841
+
842
+ function generate_stats_summary( $id ) {
843
  $image_meta = get_post_meta( $id, '_kraken_size', true );
844
  $thumbs_meta = get_post_meta( $id, '_kraked_thumbs', true );
 
 
 
 
845
 
846
+ $total_original_size = 0;
847
+ $total_kraked_size = 0;
848
+ $total_saved_bytes = 0;
849
+
850
+ $total_savings_percentage = 0;
851
+
852
+ // crap for backward compat
853
+ if ( isset( $image_meta['original_size'] ) ) {
854
+
855
+ $original_size = $image_meta['original_size'];
856
+
857
+ if ( stripos( $original_size, 'kb' ) !== false ) {
858
+ $total_original_size = ceil( floatval( $original_size ) * 1024 );
859
+ } else {
860
+ $total_original_size = (int) $original_size;
861
+ }
862
+
863
+ if ( isset( $image_meta['saved_bytes'] ) ) {
864
+ $saved_bytes = $image_meta['saved_bytes'];
865
+ if ( is_string( $saved_bytes ) ) {
866
+ $total_saved_bytes = (int) ceil( floatval( $saved_bytes ) * 1024 );
867
+ } else {
868
+ $total_saved_bytes = $saved_bytes;
869
+ }
870
+ }
871
+
872
+ $total_kraked_size = $total_original_size - $total_saved_bytes;
873
+ }
874
+
875
+ if ( !empty( $thumbs_meta ) ) {
876
+ $thumb_saved_bytes = 0;
877
+ $total_thumb_byte_savings = 0;
878
+ $total_thumb_size = 0;
879
+
880
+ foreach ( $thumbs_meta as $k => $v ) {
881
+ $total_original_size += $v['original_size'];
882
+ $thumb_saved_bytes = $v['original_size'] - $v['kraked_size'];
883
+ $total_saved_bytes += $thumb_saved_bytes;
884
+ }
885
+
886
+ }
887
+ $total_savings_percentage = round( ( $total_saved_bytes / $total_original_size * 100 ), 2 ) . '%';
888
+ $summary_string = '';
889
+ if ( !$total_saved_bytes ) {
890
+ $summary_string = 'No savings';
891
+ } else {
892
+ $total_savings = self::formatBytes( $total_saved_bytes );
893
+ $detailed_results_html = $this->results_html( $id );
894
+ $summary_string = '<div class="kraken-result-wrap">' . "Saved $total_savings_percentage ($total_savings)";
895
+ $summary_string .= '<br /><small class="kraken-item-details" data-id="' . $id . '" original-title="' . htmlspecialchars($detailed_results_html) .'">Show details</small></div>';
896
+ }
897
+ return $summary_string;
898
+ }
899
+
900
+ function results_html( $id ) {
901
+
902
+ $settings = $this->kraken_settings;
903
+ $optimize_main_image = !empty( $settings['optimize_main_image'] );
904
+
905
+ // get meta data for main post and thumbs
906
+ $image_meta = get_post_meta( $id, '_kraken_size', true );
907
+ $thumbs_meta = get_post_meta( $id, '_kraked_thumbs', true );
908
+ $main_image_optimized = !empty( $image_meta ) && isset( $image_meta['type'] );
909
+ $thumbs_optimized = !empty( $thumbs_meta ) && count( $thumbs_meta ) && isset( $thumbs_meta[0]['type'] );
910
+
911
+ $type = '';
912
+ $kraked_size = '';
913
+ $savings_percentage = '';
914
+
915
+ if ( $main_image_optimized ) {
916
+ $type = $image_meta['type'];
917
+ $kraked_size = isset( $image_meta['kraked_size'] ) ? $image_meta['kraked_size'] : '';
918
+ $savings_percentage = $image_meta['savings_percent'];
919
+ $main_image_kraked_stats = self::calculate_savings( $image_meta );
920
+ }
921
+
922
+ if ( $thumbs_optimized ) {
923
+ $type = $thumbs_meta[0]['type'];
924
+ $thumbs_kraked_stats = self::calculate_savings( $thumbs_meta );
925
+ $thumbs_count = count( $thumbs_meta );
926
+ }
927
+
928
  ob_start();
929
  ?>
930
+ <?php if ( $main_image_optimized ) { ?>
931
+ <div class="kraken_detailed_results_wrap">
932
+ <span class=""><strong>Main image savings:</strong></span>
933
  <br />
934
+ <span style="display:inline-block;margin-bottom:5px"><?php echo $main_image_kraked_stats['saved_bytes']; ?> (<?php echo $main_image_kraked_stats['savings_percentage']; ?> saved)</span>
935
+ <?php } ?>
936
+ <?php if ( $main_image_optimized && $thumbs_optimized ) { ?>
937
  <br />
938
+ <?php } ?>
939
+ <?php if ( $thumbs_optimized ) { ?>
940
+ <span><strong>Savings on <?php echo $thumbs_count; ?> thumbnails:</strong></span>
941
  <br />
942
+ <span style="display:inline-block;margin-bottom:5px"><?php echo $thumbs_kraked_stats['total_savings']; ?> (<?php echo $thumbs_kraked_stats['savings_percentage']; ?> saved)</span>
943
  <?php } ?>
944
+ <br />
945
+ <span><strong>Optimization mode:</strong></span>
946
+ <br />
947
+ <span><?php echo ucfirst($type); ?></span>
948
  <?php if ( !empty( $this->kraken_settings['show_reset'] ) ) { ?>
949
  <br />
950
+ <small
951
  class="krakenReset" data-id="<?php echo $id; ?>"
952
  title="Removes Kraken metadata associated with this image">
953
  Reset
954
  </small>
955
  <span class="krakenSpinner"></span>
956
+ </div>
957
  <?php } ?>
958
  <?php
959
  $html = ob_get_clean();
962
 
963
  function fill_media_columns( $column_name, $id ) {
964
 
965
+ $settings = $this->kraken_settings;
966
+ $optimize_main_image = !empty( $settings['optimize_main_image'] );
967
 
968
+ $file = get_attached_file( $id );
969
+ $original_size = filesize( $file );
970
 
971
+ // handle the case where file does not exist
972
+ if ( $original_size === 0 || $original_size === false ) {
973
+ echo '0 bytes';
974
+ return;
975
+ } else {
976
+ $original_size = self::formatBytes( $original_size );
977
+ }
978
+
979
+ $type = isset( $settings['api_lossy'] ) ? $settings['api_lossy'] : 'lossy';
980
 
981
  if ( strcmp( $column_name, 'original_size' ) === 0 ) {
982
  if ( wp_attachment_is_image( $id ) ) {
984
  $meta = get_post_meta( $id, '_kraken_size', true );
985
 
986
  if ( isset( $meta['original_size'] ) ) {
987
+
988
+ if ( stripos( $meta['original_size'], 'kb' ) !== false ) {
989
+ echo self::formatBytes( ceil( floatval( $meta['original_size']) * 1024 ) );
990
+ } else {
991
+ echo self::formatBytes( $meta['original_size'] );
992
+ }
993
+
994
  } else {
995
  echo $original_size;
996
  }
998
  echo $original_size;
999
  }
1000
  } else if ( strcmp( $column_name, 'kraked_size' ) === 0 ) {
1001
+ echo '<div class="kraken-wrap">';
1002
+ $image_url = wp_get_attachment_url( $id );
1003
+ $filename = basename( $image_url );
1004
  if ( wp_attachment_is_image( $id ) ) {
1005
 
1006
+ $meta = get_post_meta( $id, '_kraken_size', true );
1007
+ $thumbs_meta = get_post_meta( $id, '_kraked_thumbs', true );
1008
 
1009
  // Is it optimized? Show some stats
1010
+ if ( ( isset( $meta['kraked_size'] ) && empty( $meta['no_savings'] ) ) || !empty( $thumbs_meta ) ) {
1011
+ if ( !isset( $meta['kraked_size'] ) && $optimize_main_image ) {
1012
+ echo '<div class="buttonWrap"><button data-setting="' . $type . '" type="button" class="kraken_req" data-id="' . $id . '" id="krakenid-' . $id .'" data-filename="' . $filename . '" data-url="' . $image_url . '">Optimize Main Image</button><span class="krakenSpinner"></span></div>';
1013
+ }
1014
+ echo $this->generate_stats_summary( $id );
1015
 
1016
  // Were there no savings, or was there an error?
1017
  } else {
 
 
1018
  echo '<div class="buttonWrap"><button data-setting="' . $type . '" type="button" class="kraken_req" data-id="' . $id . '" id="krakenid-' . $id .'" data-filename="' . $filename . '" data-url="' . $image_url . '">Optimize This Image</button><span class="krakenSpinner"></span></div>';
1019
  if ( !empty( $meta['no_savings'] ) ) {
1020
  echo '<div class="noSavings"><strong>No savings found</strong><br /><small>Type:&nbsp;' . $meta['type'] . '</small></div>';
1026
  } else {
1027
  echo 'n/a';
1028
  }
1029
+ echo '</div>';
1030
  }
1031
  }
1032
 
1033
  function replace_image( $image_path, $kraked_url ) {
1034
  $rv = false;
1035
  $ch = curl_init( $kraked_url );
1036
+ curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
1037
  curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, 0 );
1038
+ curl_setopt( $ch, CURLOPT_SSL_VERIFYHOST, 0 );
1039
+ curl_setopt( $ch, CURLOPT_CONNECTTIMEOUT, 0 );
1040
+ curl_setopt( $ch, CURLOPT_TIMEOUT, 120 );
1041
+ curl_setopt( $ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.85 Safari/537.36' );
1042
  $result = curl_exec( $ch );
1043
+
1044
+ if ( $result ) {
1045
+ $rv = file_put_contents( $image_path, $result );
1046
+ }
1047
  return $rv !== false;
1048
  }
1049
 
1050
+ function optimize_image( $image_path, $type, $resize = false ) {
1051
  $settings = $this->kraken_settings;
1052
  $kraken = new Kraken( $settings['api_key'], $settings['api_secret'] );
1053
 
1054
  if ( !empty( $type ) ) {
1055
  $lossy = $type === 'lossy';
1056
  } else {
1057
+ $lossy = $settings['api_lossy'] === 'lossy';
1058
  }
1059
 
1060
  $params = array(
1061
+ 'file' => $image_path,
1062
+ 'wait' => true,
1063
+ 'lossy' => $lossy,
1064
+ 'origin' => 'wp'
1065
  );
1066
 
1067
+ $preserve_meta_arr = [];
1068
+ if ( $settings['preserve_meta_date'] ) {
1069
+ $preserve_meta_arr[] = 'date';
1070
+ }
1071
+ if ( $settings['preserve_meta_copyright'] ) {
1072
+ $preserve_meta_arr[] = 'copyright';
1073
+ }
1074
+ if ( $settings['preserve_meta_geotag'] ) {
1075
+ $preserve_meta_arr[] = 'geotag';
1076
+ }
1077
+ if ( $settings['preserve_meta_orientation'] ) {
1078
+ $preserve_meta_arr[] = 'orientation';
1079
+ }
1080
+ if ( $settings['preserve_meta_profile'] ) {
1081
+ $preserve_meta_arr[] = 'profile';
1082
  }
1083
 
1084
+ if ( count( $preserve_meta_arr ) ) {
1085
+ $params['preserve_meta'] = $preserve_meta_arr;
1086
+ }
1087
+
1088
+ if ( $settings['auto_orient'] ) {
1089
+ $params['auto_orient'] = true;
1090
+ }
1091
+
1092
+ if ( $resize ) {
1093
+ $width = (int) $settings['resize_width'];
1094
+ $height = (int) $settings['resize_height'];
1095
+ if ( $width && $height ) {
1096
+ $params['resize'] = array('strategy' => 'auto', 'width' => $width, 'height' => $height, 'enhance' => true );
1097
+ } elseif ( $width && !$height ) {
1098
+ $params['resize'] = array('strategy' => 'landscape', 'width' => $width, 'enhance' => true );
1099
+ } elseif ( $height && !$width ) {
1100
+ $params['resize'] = array('strategy' => 'portrait', 'height' => $height, 'enhance' => true );
1101
+ }
1102
+ }
1103
 
1104
+ if ( isset( $settings['jpeg_quality'] ) && $settings['jpeg_quality'] > 0 ) {
1105
+ $params['quality'] = (int) $settings['jpeg_quality'];
1106
+ }
1107
+
1108
+ set_time_limit(400);
1109
+ $data = $kraken->upload( $params );
1110
+ $data['type'] = !empty( $type ) ? $type : $settings['api_lossy'];
1111
  return $data;
1112
  }
1113
 
1114
  function optimize_thumbnails( $image_data ) {
1115
+
1116
  $image_id = $this->id;
1117
  if ( empty( $image_id ) ) {
1118
  global $wpdb;
1138
  }
1139
 
1140
  if ( !empty( $sizes ) ) {
 
1141
  $thumb_path = '';
 
1142
  $thumbs_optimized_store = array();
1143
  $this_thumb = array();
1144
 
1145
  foreach ( $sizes as $key => $size ) {
1146
 
1147
  $thumb_path = $upload_full_path . '/' . $size['file'];
1148
+
1149
  if ( file_exists( $thumb_path ) !== false ) {
 
1150
  $result = $this->optimize_image( $thumb_path, $this->optimization_type );
1151
+ if ( !empty( $result ) && isset( $result['success'] ) && isset( $result['kraked_url'] ) ) {
1152
+ $kraked_url = $result['kraked_url'];
1153
+ if ( (int) $result['saved_bytes'] !== 0 ) {
1154
+ if ( $this->replace_image( $thumb_path, $kraked_url ) ) {
1155
+ $this_thumb = array( 'thumb' => $key, 'file' => $size['file'], 'original_size' => $result['original_size'], 'kraked_size' => $result['kraked_size'], 'type' => $this->optimization_type );
1156
+ $thumbs_optimized_store [] = $this_thumb;
1157
+ }
1158
+ } else {
1159
+ $this_thumb = array( 'thumb' => $key, 'file' => $size['file'], 'original_size' => $result['original_size'], 'kraked_size' => $result['original_size'], 'type' => $this->optimization_type );
1160
+ $thumbs_optimized_store [] = $this_thumb;
1161
  }
1162
+ } else {
1163
+ return $image_data;
1164
  }
1165
  }
1166
  }
1167
  }
1168
+
1169
+ $kraken_meta = get_post_meta( $image_id, '_kraken_size', true );
1170
+ $image_backup_path = isset( $kraken_meta['optimized_backup_file'] ) ? $kraken_meta['optimized_backup_file'] : '';
1171
+
1172
+ if ( $image_backup_path ) {
1173
+ $original_image_path = get_attached_file( $image_id );
1174
+ if ( copy( $image_backup_path, $original_image_path ) ) {
1175
+ unlink( $image_backup_path );
1176
+ unset( $kraken_meta['optimized_backup_file'] );
1177
+ update_post_meta( $image_id, '_kraken_size', $kraken_meta );
1178
+ }
1179
+ }
1180
+
1181
+ // when resizing has taken place via API, update the post metadata accordingly
1182
+ if ( !empty( $kraken_meta['kraked_width'] ) && !empty( $kraken_meta['kraked_height'] ) ) {
1183
+ $image_data['width'] = $kraken_meta['kraked_width'];
1184
+ $image_data['height'] = $kraken_meta['kraked_height'];
1185
+ }
1186
+
1187
  if ( !empty( $thumbs_optimized_store ) ) {
1188
  update_post_meta( $image_id, '_kraked_thumbs', $thumbs_optimized_store, false );
1189
  }
1190
  return $image_data;
1191
  }
1192
 
1193
+ static function formatBytes( $size, $precision = 2 ) {
1194
+ $base = log( $size, 1024 );
1195
+ $suffixes = array( ' bytes', 'KB', 'MB', 'GB', 'TB' );
1196
+ return round( pow( 1024, $base - floor( $base ) ), $precision ) . $suffixes[floor( $base )];
1197
  }
1198
  }
1199
  }
lib/Kraken.php CHANGED
@@ -1,13 +1,10 @@
1
  <?php
2
 
3
- class Kraken
4
- {
5
-
6
  protected $auth = array();
7
- public static $kraken_plugin_version = '2.0.0';
8
 
9
- public function __construct($key = '', $secret = '')
10
- {
11
  $this->auth = array(
12
  "auth" => array(
13
  "api_key" => $key,
@@ -16,95 +13,93 @@ class Kraken
16
  );
17
  }
18
 
19
- public function url($opts = array())
20
- {
21
  $data = json_encode(array_merge($this->auth, $opts));
22
- $response = self::request($data, "https://api.kraken.io/v1/url");
23
 
24
  return $response;
25
  }
26
 
27
- public function upload($opts = array())
28
- {
29
- if (!isset($opts['file']))
30
- {
31
  return array(
32
  "success" => false,
33
  "error" => "File parameter was not provided"
34
  );
35
  }
36
 
37
- if (preg_match("/\/\//i", $opts['file']))
38
- {
39
  $opts['url'] = $opts['file'];
40
  unset($opts['file']);
 
41
  return $this->url($opts);
42
  }
43
 
44
- if (!file_exists($opts['file']))
45
- {
46
  return array(
47
  "success" => false,
48
- "error" => "File `" . $opts['file'] . "` does not exist"
49
  );
50
  }
51
 
52
- if (function_exists('curl_file_create')) {
53
- $file = curl_file_create($opts['file'], 'image/jpeg', $opts['file']);
54
  } else {
55
- $file = sprintf('@%s', $opts['file']);
56
  }
57
 
58
  unset($opts['file']);
59
 
60
  $data = array_merge(array(
61
  "file" => $file,
62
- "data" => json_encode(array_merge(
63
- $this->auth, $opts
64
- ))
65
  ));
66
-
67
- $response = self::request($data, "https://api.kraken.io/v1/upload");
68
 
69
  return $response;
70
  }
71
 
72
- public function status()
73
- {
74
  $data = array('auth' => array(
75
  'api_key' => $this->auth['auth']['api_key'],
76
  'api_secret' => $this->auth['auth']['api_secret']
77
  ));
78
- $response = self::request(json_encode($data), "https://api.kraken.io/user_status");
79
-
80
  return $response;
81
  }
82
 
83
- private function request($data, $url)
84
- {
85
- $curl = curl_init();
86
-
87
- curl_setopt($curl, CURLOPT_URL, $url);
 
 
 
 
 
 
 
88
  curl_setopt($curl, CURLOPT_POST, 1);
89
  curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
90
  curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
91
  curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 0);
92
  curl_setopt($curl, CURLOPT_TIMEOUT, 400);
93
  curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0);
94
- curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0);
95
- curl_setopt($curl, CURLOPT_USERAGENT, 'WordPress/' . get_bloginfo('version') . ' KrakenPlugin/' . self::$kraken_plugin_version);
96
- curl_setopt($curl, CURLOPT_FAILONERROR, 1);
97
 
98
  $response = json_decode(curl_exec($curl), true);
99
  $error = curl_errno($curl);
100
 
 
 
 
 
 
 
 
 
101
  curl_close($curl);
102
-
103
- if ($error > 0) {
104
- throw new RuntimeException(sprintf('cURL returned with the following error code: "%s"', $error));
105
- }
106
-
107
  return $response;
108
  }
109
-
110
- }
1
  <?php
2
 
3
+ class Kraken {
 
 
4
  protected $auth = array();
5
+ public static $kraken_plugin_version = '2.5.0';
6
 
7
+ public function __construct($key = '', $secret = '') {
 
8
  $this->auth = array(
9
  "auth" => array(
10
  "api_key" => $key,
13
  );
14
  }
15
 
16
+ public function url($opts = array()) {
 
17
  $data = json_encode(array_merge($this->auth, $opts));
18
+ $response = self::request($data, 'https://api.kraken.io/v1/url', 'url');
19
 
20
  return $response;
21
  }
22
 
23
+ public function upload($opts = array()) {
24
+ if (!isset($opts['file'])) {
 
 
25
  return array(
26
  "success" => false,
27
  "error" => "File parameter was not provided"
28
  );
29
  }
30
 
31
+ if (preg_match("/\/\//i", $opts['file'])) {
 
32
  $opts['url'] = $opts['file'];
33
  unset($opts['file']);
34
+
35
  return $this->url($opts);
36
  }
37
 
38
+ if (!file_exists($opts['file'])) {
 
39
  return array(
40
  "success" => false,
41
+ "error" => 'File `' . $opts['file'] . '` does not exist'
42
  );
43
  }
44
 
45
+ if (class_exists('CURLFile')) {
46
+ $file = new CURLFile($opts['file']);
47
  } else {
48
+ $file = '@' . $opts['file'];
49
  }
50
 
51
  unset($opts['file']);
52
 
53
  $data = array_merge(array(
54
  "file" => $file,
55
+ "data" => json_encode(array_merge($this->auth, $opts))
 
 
56
  ));
57
+ $response = self::request($data, 'https://api.kraken.io/v1/upload', 'upload');
 
58
 
59
  return $response;
60
  }
61
 
62
+ public function status() {
 
63
  $data = array('auth' => array(
64
  'api_key' => $this->auth['auth']['api_key'],
65
  'api_secret' => $this->auth['auth']['api_secret']
66
  ));
67
+ $response = self::request(json_encode($data), 'https://api.kraken.io/user_status', 'url');
 
68
  return $response;
69
  }
70
 
71
+ private function request($data, $url, $type) {
72
+ $curl = curl_init($url);
73
+
74
+ if ($type === 'url') {
75
+ curl_setopt($curl, CURLOPT_HTTPHEADER, array(
76
+ 'Content-Type: application/json'
77
+ ));
78
+ }
79
+
80
+ // Force continue-100 from server
81
+ curl_setopt($curl, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.85 Safari/537.36');
82
+ curl_setopt($curl, CURLOPT_HTTPHEADER, array('Expect:'));
83
  curl_setopt($curl, CURLOPT_POST, 1);
84
  curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
85
  curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
86
  curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 0);
87
  curl_setopt($curl, CURLOPT_TIMEOUT, 400);
88
  curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0);
89
+ curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0);
 
 
90
 
91
  $response = json_decode(curl_exec($curl), true);
92
  $error = curl_errno($curl);
93
 
94
+ if ($response === null) {
95
+ $error_code = (int) curl_error($curl);
96
+ $response = array (
97
+ "success" => false,
98
+ "error" => 'cURL Error: ' . $error_code,
99
+ "code" => $error_code
100
+ );
101
+ }
102
  curl_close($curl);
 
 
 
 
 
103
  return $response;
104
  }
105
+ }
 
readme.txt CHANGED
@@ -1,19 +1,19 @@
1
  === Kraken Image Optimizer ===
2
  Contributors: karim79
3
- Tags: Image Optimizer, Image Optimiser, Optimize, Optimise, Images, Media, Performance, SEO, faster loading times, smushit, smush.it, compress, kraken-image-optimizer, tinypng, tinyjpeg, pngquant, jpegmini, ewww, pagespeed, pagespeed insights, sitespeed, optimize gif, optimize jpeg, optimize png, optimize animated gif, svg, improve pagerank, gtmetrix speed test
4
  Requires at least: 3.0.1
5
- Tested up to: 4.2
6
  Donate link: https://kraken.io
7
- Stable tag: 2.0.0
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
10
 
11
 
12
- This plugin allows you to optimize your WordPress images through the Kraken API, the world's most advanced image optimization solution.
13
 
14
  == Description ==
15
 
16
- This plugin allows you to optimize new and existing Wordpress image uploads through [Kraken Image Optimizer's](https://kraken.io "Kraken Image Optimizer") API. Both lossless and intelligent lossy optimization modes are supported. Supported filetypes are JPEG, PNG and GIF. Maximum filesize limit is 16 MB. For more details, including detailed documentation and plans and pricing, please visit [Kraken.io](https://kraken.io "Kraken Image Optimizer").
17
 
18
  > **Get your FREE account with us**
19
 
@@ -30,6 +30,10 @@ This plugin allows you to optimize new and existing Wordpress image uploads thro
30
  = About the plugin =
31
  * You can use your Kraken API key and secret on as many sites/blogs as you like. We have no per-site license.
32
  * All images uploaded throught the media uploader are optimized on-the-fly. All generated thumbnails are optimized too.
 
 
 
 
33
  * All images already present in the media library can be optimized individually, or using the Bulk Action menu "Krak 'em all" feature.
34
  * This plugin does not require any root or command-line access. No compilation and installation of any binaries is necessary.
35
  * All optimization is carried out by sending images to Kraken.io's infrastructure, and pulling the optimized files to your Wordpress installation.
@@ -52,12 +56,6 @@ Once you have obtained your credentials, from your Wordpress admin, go to the Kr
52
 
53
  For advanced users, there is a third party WordPress Command Line Interface (CLI) tool to allow image optimization from the command line, or by using cron. For details, visit: https://github.com/tillkruss/wp-cli-kraken
54
 
55
- = Features on the way =
56
- * Optimize images directly to Amazon S3.
57
- * Optimize entire media library in one click.
58
- * Optimize your currently active theme.
59
- * WordPress Multisite support.
60
-
61
  Please send bug reports, problems, feature requests and so on to support (at) Kraken dot io, or directly to the author of this plugin.
62
 
63
  = Connect with Kraken.io =
@@ -65,6 +63,7 @@ Please send bug reports, problems, feature requests and so on to support (at) Kr
65
  * [Twitter](https://twitter.com/KrakenIO "@KrakenIO")
66
  * [Google+](https://plus.google.com/107209047753760492207/ "Google+")
67
  * [Facebook](https://www.facebook.com/krakenio "Kraken Image Optimizer")
 
68
 
69
  == Installation ==
70
 
@@ -102,9 +101,17 @@ Yes, of course they will. Our plugin simply replaces the image files on your blo
102
 
103
  You will need to switch the Media Library from the Thumbnail view to the List view. In the "Kraked Size" column, you will then see the "Optimize This Image" button for unoptimized images, or the results of the optimization where the image has already been optimized by our plugin.
104
 
105
-
106
  == Changelog ==
107
 
 
 
 
 
 
 
 
 
 
108
  = 2.0.0 =
109
  * Please read! Kraken.io settings have now moved to an own section (Settings->Kraken.io), in order to reduce clutter in Media Settings, and to accomodate new features on the way.
110
  * Advanced settings grouped in "Advanced Settings" section of settings page.
1
  === Kraken Image Optimizer ===
2
  Contributors: karim79
3
+ Tags: Image Optimizer, Image Optimiser, Optimize, Optimise, Images, Media, Performance, SEO, faster loading times, smushit, smush.it, compress, kraken-image-optimizer, tinypng, tinyjpeg, pngquant, jpegmini, ewww, pagespeed, pagespeed insights, sitespeed, optimize gif, optimize jpeg, optimize png, optimize animated gif, svg, improve pagerank, gtmetrix speed test, EXIF, image resize
4
  Requires at least: 3.0.1
5
+ Tested up to: 4.4.2
6
  Donate link: https://kraken.io
7
+ Stable tag: 2.5.0
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
10
 
11
 
12
+ This plugin allows you to optimize your WordPress images through the Kraken API, the world's most advanced image optimization and resizing API.
13
 
14
  == Description ==
15
 
16
+ This plugin allows you to optimize and resize new and existing Wordpress image uploads through [Kraken Image Optimizer's](https://kraken.io "Kraken Image Optimizer") API. Both lossless and intelligent lossy optimization modes are supported. Supported filetypes are JPEG, PNG and GIF (including animated). Maximum filesize limit is 32 MB. For more details, including detailed documentation and plans and pricing, please visit [Kraken.io](https://kraken.io "Kraken Image Optimizer"). Even when using Kraken.io's lossy optimization, our system goes the extra mile to ensure that the results are of high quality, every time. You can just install the plugin and stop worrying.
17
 
18
  > **Get your FREE account with us**
19
 
30
  = About the plugin =
31
  * You can use your Kraken API key and secret on as many sites/blogs as you like. We have no per-site license.
32
  * All images uploaded throught the media uploader are optimized on-the-fly. All generated thumbnails are optimized too.
33
+ * The main image upload can be optionally resized - this is useful for preventing user uploads with unnecessarily large dimensions. You can specify the maximum width and/or height in Kraken.io->Settings.
34
+ * When restricting the maximum dimensions of the main image using the resizing feature, the resulting image is **enhanced** using various advanced techniques, to help prevent downsample artifacts and "haloing" and produce a sharper result.
35
+ * You can optionally preserve one or more of the Date, Copyright, Geotag, Orientation, Profile EXIF metadata tags.
36
+ * Images can be automatically oriented according to their EXIF Orientation value - no need to manually rotate images.
37
  * All images already present in the media library can be optimized individually, or using the Bulk Action menu "Krak 'em all" feature.
38
  * This plugin does not require any root or command-line access. No compilation and installation of any binaries is necessary.
39
  * All optimization is carried out by sending images to Kraken.io's infrastructure, and pulling the optimized files to your Wordpress installation.
56
 
57
  For advanced users, there is a third party WordPress Command Line Interface (CLI) tool to allow image optimization from the command line, or by using cron. For details, visit: https://github.com/tillkruss/wp-cli-kraken
58
 
 
 
 
 
 
 
59
  Please send bug reports, problems, feature requests and so on to support (at) Kraken dot io, or directly to the author of this plugin.
60
 
61
  = Connect with Kraken.io =
63
  * [Twitter](https://twitter.com/KrakenIO "@KrakenIO")
64
  * [Google+](https://plus.google.com/107209047753760492207/ "Google+")
65
  * [Facebook](https://www.facebook.com/krakenio "Kraken Image Optimizer")
66
+ * [Github](https://github.com/kraken-io "Kraken.io on Github")
67
 
68
  == Installation ==
69
 
101
 
102
  You will need to switch the Media Library from the Thumbnail view to the List view. In the "Kraked Size" column, you will then see the "Optimize This Image" button for unoptimized images, or the results of the optimization where the image has already been optimized by our plugin.
103
 
 
104
  == Changelog ==
105
 
106
+ = 2.5.0 =
107
+ * Ability to disable optimization of main image, allowing faster uploads from Media Library. You can optimize the main image later from within your Media Library.
108
+ * Ability to restrict the maximum dimensions of image uploads (resizing), by width and/or height.
109
+ * When using resize feature, resized images are enhanced for sharper results using various advanced techniques.
110
+ * Ability to force JPEG quality to a discrete "quality" value, for greater savings if you know what you're doing.
111
+ * Ability to preserve certain EXIF metadata tags, including Date, Copyright, Orientation, Geotag and Profile.
112
+ * Ability to automatically orient images according to their Orientation EXIF metadata.
113
+ * Improvements and simplifications to interface elements and Kraken.io Settings page.
114
+
115
  = 2.0.0 =
116
  * Please read! Kraken.io settings have now moved to an own section (Settings->Kraken.io), in order to reduce clutter in Media Settings, and to accomodate new features on the way.
117
  * Advanced settings grouped in "Advanced Settings" section of settings page.