Version Description
- Custom folders optimization
- NextGen galleries optimization
Download this release
Release Info
Developer | ShortPixel |
Plugin | ShortPixel Image Optimizer |
Version | 4.0.0 |
Comparing to | |
See all releases |
Code changes from version 3.3.8 to 4.0.0
- class/db/shortpixel-custom-meta-dao.php +421 -0
- class/db/shortpixel-db.php +9 -0
- class/db/shortpixel-meta-facade.php +344 -0
- class/db/shortpixel-nextgen-adapter.php +33 -0
- class/db/wp-shortpixel-db.php +76 -0
- class/db/wp-shortpixel-media-library-adapter.php +165 -0
- class/model/shortpixel-entity.php +19 -0
- class/model/shortpixel-folder.php +198 -0
- class/model/shortpixel-meta.php +251 -0
- class/model/sp-file-rights-exception.php +6 -0
- class/shortpixel-tools.php +42 -0
- class/view/shortpixel-list-table.php +180 -0
- class/view/shortpixel_view.php +971 -0
- readme.txt +18 -25
- {css → res/css}/short-pixel.css +188 -13
- res/css/sp-file-tree.css +259 -0
- {img → res/img}/arrow.png +0 -0
- res/img/exclamation-big.png +0 -0
- res/img/file-tree/application.png +0 -0
- res/img/file-tree/code.png +0 -0
- res/img/file-tree/css.png +0 -0
- res/img/file-tree/db.png +0 -0
- res/img/file-tree/directory-lock.png +0 -0
- res/img/file-tree/directory.png +0 -0
- res/img/file-tree/doc.png +0 -0
- res/img/file-tree/file-lock.png +0 -0
- res/img/file-tree/file.png +0 -0
- res/img/file-tree/film.png +0 -0
- res/img/file-tree/flash.png +0 -0
- res/img/file-tree/folder_open.png +0 -0
- res/img/file-tree/html.png +0 -0
- res/img/file-tree/java.png +0 -0
- res/img/file-tree/linux.png +0 -0
- res/img/file-tree/music.png +0 -0
- res/img/file-tree/pdf.png +0 -0
- res/img/file-tree/php.png +0 -0
- res/img/file-tree/picture.png +0 -0
- res/img/file-tree/ppt.png +0 -0
- res/img/file-tree/psd.png +0 -0
- res/img/file-tree/ruby.png +0 -0
- res/img/file-tree/script.png +0 -0
- res/img/file-tree/spinner.gif +0 -0
- res/img/file-tree/txt.png +0 -0
- res/img/file-tree/xls.png +0 -0
- res/img/file-tree/zip.png +0 -0
- res/img/info-icon.png +0 -0
- {img → res/img}/loading-dark-big.gif +0 -0
- {img → res/img}/loading-dark.gif +0 -0
- {img → res/img}/loading.gif +0 -0
- res/img/logo-pdf.png +0 -0
- res/img/robo-slider.png +0 -0
- {img → res/img}/shortpixel-alert.png +0 -0
- {img → res/img}/shortpixel.png +0 -0
- {img → res/img}/slider.png +0 -0
- {img → res/img}/stars.png +0 -0
- res/js/jquery.knob.js +805 -0
- res/js/jquery.tooltip.js +207 -0
- {js → res/js}/short-pixel.js +238 -65
- res/js/sp-file-tree.js +213 -0
- shortpixel-debug.php +47 -0
- shortpixel_api.php +271 -200
- shortpixel_queue.php +142 -131
- shortpixel_view.php +1 -1
- wp-shortpixel-req.php +36 -0
- wp-shortpixel-settings.php +55 -16
- wp-shortpixel.php +840 -507
class/db/shortpixel-custom-meta-dao.php
ADDED
@@ -0,0 +1,421 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class ShortPixelCustomMetaDao {
|
4 |
+
const META_VERSION = 1;
|
5 |
+
private $db;
|
6 |
+
|
7 |
+
private static $fields = array(
|
8 |
+
ShortPixelMeta::TABLE_SUFFIX => array(
|
9 |
+
"folder_id" => "d",
|
10 |
+
"path" => "s",
|
11 |
+
"name" => "s",
|
12 |
+
"compression_type" => "d",
|
13 |
+
"compressed_size" => "d",
|
14 |
+
"keep_exif" => "d",
|
15 |
+
"cmyk2rgb" => "d",
|
16 |
+
"resize" => "d",
|
17 |
+
"resize_width" => "d",
|
18 |
+
"resize_height" => "d",
|
19 |
+
"backup" => "d",
|
20 |
+
"status" => "d",
|
21 |
+
"retries" => "d",
|
22 |
+
"message" => "s",
|
23 |
+
"ext_meta_id" => "d" //this is nggPid for now
|
24 |
+
),
|
25 |
+
ShortPixelFolder::TABLE_SUFFIX => array(
|
26 |
+
"path" => "s",
|
27 |
+
"file_count" => "d",
|
28 |
+
"status" => "d",
|
29 |
+
"ts_updated" => "s",
|
30 |
+
"ts_created" => "s",
|
31 |
+
)
|
32 |
+
);
|
33 |
+
|
34 |
+
public function __construct($db) {
|
35 |
+
$this->db = $db;
|
36 |
+
}
|
37 |
+
|
38 |
+
public static function getCreateFolderTableSQL($tablePrefix, $charsetCollate) {
|
39 |
+
return "CREATE TABLE {$tablePrefix}shortpixel_folders (
|
40 |
+
id mediumint(9) NOT NULL AUTO_INCREMENT,
|
41 |
+
path varchar(512),
|
42 |
+
name varchar(64),
|
43 |
+
path_md5 char(32),
|
44 |
+
file_count int,
|
45 |
+
status tinyint DEFAULT 0,
|
46 |
+
ts_updated timestamp,
|
47 |
+
ts_created timestamp,
|
48 |
+
UNIQUE KEY id (id)
|
49 |
+
) $charsetCollate;";
|
50 |
+
// UNIQUE INDEX spf_path_md5 (path_md5)
|
51 |
+
}
|
52 |
+
|
53 |
+
public static function getCreateMetaTableSQL($tablePrefix, $charsetCollate) {
|
54 |
+
return "CREATE TABLE {$tablePrefix}shortpixel_meta (
|
55 |
+
id mediumint(10) NOT NULL AUTO_INCREMENT,
|
56 |
+
folder_id mediumint(9) NOT NULL,
|
57 |
+
ext_meta_id int(10),
|
58 |
+
path varchar(512),
|
59 |
+
name varchar(64),
|
60 |
+
path_md5 char(32),
|
61 |
+
compressed_size int(10) NOT NULL DEFAULT 0,
|
62 |
+
compression_type tinyint,
|
63 |
+
keep_exif tinyint,
|
64 |
+
cmyk2rgb tinyint,
|
65 |
+
resize tinyint,
|
66 |
+
resize_width smallint,
|
67 |
+
resize_height smallint,
|
68 |
+
backup tinyint,
|
69 |
+
status tinyint DEFAULT 0,
|
70 |
+
retries tinyint DEFAULT 0,
|
71 |
+
message varchar(255),
|
72 |
+
ts_added timestamp,
|
73 |
+
ts_optimized timestamp,
|
74 |
+
UNIQUE KEY sp_id (id)
|
75 |
+
) $charsetCollate;";
|
76 |
+
//UNIQUE INDEX sp_path_md5 (path_md5),
|
77 |
+
//FOREIGN KEY fk_shortpixel_meta_folder(folder_id) REFERENCES {$tablePrefix}shortpixel_folders(id)
|
78 |
+
}
|
79 |
+
|
80 |
+
private function addIfMissing($type, $table, $key, $field, $fkTable = null, $fkField = null) {
|
81 |
+
$hasIndexSql = "select count(*) hasIndex from information_schema.statistics where table_name = '%s' and index_name = '%s' and table_schema = database()";
|
82 |
+
$createIndexSql = "ALTER TABLE %s ADD UNIQUE INDEX %s (%s)";
|
83 |
+
$createFkSql = "ALTER TABLE %s ADD FOREIGN KEY %s(%s) REFERENCES %s(%s)";
|
84 |
+
$hasIndex = $this->db->query(sprintf($hasIndexSql, $table, $key));
|
85 |
+
if($hasIndex[0]->hasIndex == 0){
|
86 |
+
if($type == "UNIQUE INDEX"){
|
87 |
+
$this->db->query(sprintf($createIndexSql, $table, $key, $field));
|
88 |
+
} else {
|
89 |
+
$this->db->query(sprintf($createFkSql, $table, $key, $field, $fkTable, $fkField));
|
90 |
+
}
|
91 |
+
return true;
|
92 |
+
}
|
93 |
+
return false;
|
94 |
+
}
|
95 |
+
|
96 |
+
public function tablesExist() {
|
97 |
+
$hasTablesSql = "SELECT COUNT(1) tableCount FROM information_schema.tables WHERE table_schema='{$wpdb->dbname}' "
|
98 |
+
. "AND table_name='{$wpdb->prefix}shortpixel_meta' OR table_name='{$wpdb->prefix}shortpixel_folders'";
|
99 |
+
$hasTables = $this->db->query(sprintf($this->db->getPrefix()."shortpixel_meta", "fk_shortpixel_meta_folder"));
|
100 |
+
if($hasTables[0]->tableCount == 2){
|
101 |
+
return true;
|
102 |
+
}
|
103 |
+
return false;
|
104 |
+
|
105 |
+
}
|
106 |
+
|
107 |
+
public function createUpdateShortPixelTables() {
|
108 |
+
$res = $this->db->createUpdateSchema(array(
|
109 |
+
self::getCreateFolderTableSQL($this->db->getPrefix(), $this->db->getCharsetCollate()),
|
110 |
+
self::getCreateMetaTableSQL($this->db->getPrefix(), $this->db->getCharsetCollate())
|
111 |
+
));
|
112 |
+
// Set up indexes, not handled well by WP DBDelta
|
113 |
+
$this->addIfMissing("UNIQUE INDEX", $this->db->getPrefix()."shortpixel_folders", "spf_path_md5", "path_md5");
|
114 |
+
$this->addIfMissing("UNIQUE INDEX", $this->db->getPrefix()."shortpixel_meta", "sp_path_md5", "path_md5");
|
115 |
+
$this->addIfMissing("FOREIGN KEY", $this->db->getPrefix()."shortpixel_meta", "fk_shortpixel_meta_folder", "folder_id",
|
116 |
+
$this->db->getPrefix()."shortpixel_folders", "id");
|
117 |
+
}
|
118 |
+
|
119 |
+
public function getFolders($deleted = false) {
|
120 |
+
$sql = "SELECT * FROM {$this->db->getPrefix()}shortpixel_folders" . ($deleted ? "" : " WHERE status <> -1");
|
121 |
+
$rows = $this->db->query($sql);
|
122 |
+
$folders = array();
|
123 |
+
foreach($rows as $row) {
|
124 |
+
$folders[] = new ShortPixelFolder($row);
|
125 |
+
}
|
126 |
+
return $folders;
|
127 |
+
}
|
128 |
+
|
129 |
+
public function getFolder($path, $deleted = false) {
|
130 |
+
$sql = "SELECT * FROM {$this->db->getPrefix()}shortpixel_folders" . ($deleted ? "" : " WHERE path = %s AND status <> -1");
|
131 |
+
$rows = $this->db->query($sql, array($path));
|
132 |
+
$folders = array();
|
133 |
+
foreach($rows as $row) {
|
134 |
+
return new ShortPixelFolder($row);
|
135 |
+
}
|
136 |
+
return false;
|
137 |
+
}
|
138 |
+
|
139 |
+
public function hasFoldersTable() {
|
140 |
+
global $wpdb;
|
141 |
+
$foldersTable = $wpdb->get_results("SELECT COUNT(1) hasFoldersTable FROM information_schema.tables WHERE table_schema='{$wpdb->dbname}' AND table_name='{$wpdb->prefix}shortpixel_folders'");
|
142 |
+
if(isset($foldersTable[0]->hasFoldersTable) && $foldersTable[0]->hasFoldersTable > 0) {
|
143 |
+
return true;
|
144 |
+
}
|
145 |
+
return false;
|
146 |
+
}
|
147 |
+
|
148 |
+
public function addFolder($folder, $fileCount = 0) {
|
149 |
+
//$sql = "INSERT INTO {$this->db->getPrefix()}shortpixel_folders (path, file_count, ts_created) values (%s, %d, now())";
|
150 |
+
//$this->db->query($sql, array($folder, $fileCount));
|
151 |
+
return $this->db->insert($this->db->getPrefix().'shortpixel_folders',
|
152 |
+
array("path" => $folder, "path_md5" => md5($folder), "file_count" => $fileCount, "ts_updated" => date("Y-m-d H:i:s")),
|
153 |
+
array("path" => "%s", "path_md5" => "%s", "file_count" => "%d", "ts_updated" => "%s"));
|
154 |
+
}
|
155 |
+
|
156 |
+
public function updateFolder($folder, $newPath, $status = 0, $fileCount = 0) {
|
157 |
+
$sql = "UPDATE {$this->db->getPrefix()}shortpixel_folders SET path = %s, path_md5 = %s, file_count = %d, ts_updated = %s, status = %d WHERE path = %s";
|
158 |
+
$this->db->query($sql, array($newPath, md5($newPath), $fileCount, date("Y-m-d H:i:s"), $status, $folder));
|
159 |
+
$sql2 = "SELECT id FROM {$this->db->getPrefix()}shortpixel_folders WHERE path = %s";
|
160 |
+
$res = $this->db->query($sql2, array($folder));
|
161 |
+
if(is_array($res)) {
|
162 |
+
return $res[0]->id;
|
163 |
+
}
|
164 |
+
else return -1;
|
165 |
+
}
|
166 |
+
|
167 |
+
public function removeFolder($folderPath) {
|
168 |
+
$sql = "SELECT id FROM {$this->db->getPrefix()}shortpixel_folders WHERE path = %s";
|
169 |
+
$row = $this->db->query($sql, array($folderPath));
|
170 |
+
if(!isset($row[0]->id)) return false;
|
171 |
+
$id = $row[0]->id;
|
172 |
+
$sql = "UPDATE {$this->db->getPrefix()}shortpixel_folders SET status = -1 WHERE id = %d";
|
173 |
+
$this->db->query($sql, array($id));
|
174 |
+
|
175 |
+
$this->db->hideErrors();
|
176 |
+
$sql = "DELETE FROM {$this->db->getPrefix()}shortpixel_meta WHERE folder_id = %d AND status <> 1 AND status <> 2";
|
177 |
+
@$this->db->query($sql, array($id));
|
178 |
+
$sql = "DELETE FROM {$this->db->getPrefix()}shortpixel_folders WHERE path = %s";
|
179 |
+
@$this->db->query($sql, array($folderPath));
|
180 |
+
$this->db->restoreErrors();
|
181 |
+
}
|
182 |
+
|
183 |
+
public function newFolderFromPath($path, $uploadPath, $rootPath) {
|
184 |
+
WpShortPixelDb::checkCustomTables(); // check if custom tables are created, if not, create them
|
185 |
+
$addedFolder = ShortPixelFolder::checkFolder($path, $uploadPath);
|
186 |
+
if($this->getFolder($addedFolder)) {
|
187 |
+
return "Folder already added.";
|
188 |
+
}
|
189 |
+
if(strpos($addedFolder, $rootPath) !== 0) {
|
190 |
+
|
191 |
+
return( "The $addedFolder folder cannot be processed as it's not inside the root path of your website.");
|
192 |
+
}
|
193 |
+
$folder = new ShortPixelFolder(array("path" => $addedFolder));
|
194 |
+
try {
|
195 |
+
$folder->setFileCount($folder->countFiles());
|
196 |
+
} catch(SpFileRightsException $ex) {
|
197 |
+
return $ex->getMessage();
|
198 |
+
}
|
199 |
+
if(ShortPixelMetaFacade::isMediaSubfolder($folder->getPath())) {
|
200 |
+
return "This folder contains Media Library images. To optimize Media Library images please go to <a href='upload.php?mode=list'>Media Library list view</a> or to <a href='upload.php?page=wp-short-pixel-bulk'>SortPixel Bulk page</a>.";
|
201 |
+
}
|
202 |
+
$folderMsg = $this->saveFolder($folder);
|
203 |
+
if(!$folder->getId()) {
|
204 |
+
throw new Exception("Inserted folder doesn't have an ID!");
|
205 |
+
}
|
206 |
+
//die(var_dump($folder));
|
207 |
+
if(!$folderMsg) {
|
208 |
+
$fileList = $folder->getFileList();
|
209 |
+
$this->batchInsertImages($fileList, $folder->getId());
|
210 |
+
}
|
211 |
+
return $folderMsg;
|
212 |
+
|
213 |
+
}
|
214 |
+
/**
|
215 |
+
*
|
216 |
+
* @param type $path
|
217 |
+
* @return false if saved OK, error message otherwise.
|
218 |
+
*/
|
219 |
+
public function saveFolder(&$folder) {
|
220 |
+
$addedPath = $folder->getPath();
|
221 |
+
if($addedPath) {
|
222 |
+
//first check if it does contain the Backups Folder - we don't allow that
|
223 |
+
if(ShortPixelFolder::checkFolderIsSubfolder(SP_BACKUP_FOLDER, $addedPath)) {
|
224 |
+
return "This folder contains the ShortPixel Backups. Please select a different folder.";
|
225 |
+
}
|
226 |
+
$customFolderPaths = array_map(function($item){return $item->getPath();}, $this->getFolders());
|
227 |
+
$allFolders = $this->getFolders(true);
|
228 |
+
$customAllFolderPaths = array_map(function($item){return $item->getPath();}, $allFolders);
|
229 |
+
$parent = ShortPixelFolder::checkFolderIsSubfolder($addedPath, $customFolderPaths);
|
230 |
+
if(!$parent){
|
231 |
+
$sub = ShortPixelFolder::checkFolderIsParent($addedPath, $customAllFolderPaths);
|
232 |
+
if($sub) {
|
233 |
+
$id = $this->updateFolder($sub, $addedPath, 0, $folder->getFileCount());
|
234 |
+
} else {
|
235 |
+
$id = $this->addFolder($addedPath, $folder->getFileCount());
|
236 |
+
}
|
237 |
+
$folder->setId($id);
|
238 |
+
return false;
|
239 |
+
} else {
|
240 |
+
foreach($allFolders as $fld) {
|
241 |
+
if($fld->getPath() == $parent) {
|
242 |
+
$folder->setPath($parent);
|
243 |
+
$folder->setId($fld->getId());
|
244 |
+
}
|
245 |
+
}
|
246 |
+
//var_dump($allFolders);
|
247 |
+
return "Folder already included in {$parent}.";
|
248 |
+
}
|
249 |
+
} else {
|
250 |
+
return "Folder does not exist.";
|
251 |
+
}
|
252 |
+
}
|
253 |
+
|
254 |
+
protected function metaToParams($meta) {
|
255 |
+
$params = $types = array();
|
256 |
+
foreach(self::$fields[ShortPixelMeta::TABLE_SUFFIX] as $key=>$type) {
|
257 |
+
$getter = "get" . ShortPixelTools::snakeToCamel($key);
|
258 |
+
if(!method_exists($meta, $getter)) {
|
259 |
+
throw new Exception("Bad fields list in ShortPixelCustomMetaDao::metaToParams");
|
260 |
+
}
|
261 |
+
$val = $meta->$getter();
|
262 |
+
if($val !== null) {
|
263 |
+
$params[$key] = $val;
|
264 |
+
$types[] = "%" . $type;
|
265 |
+
}
|
266 |
+
}
|
267 |
+
return (object)array("params" => $params, "types" => $types);
|
268 |
+
}
|
269 |
+
public function addImage($meta) {
|
270 |
+
$p = $this->metaToParams($meta);
|
271 |
+
$id = $this->db->insert($this->db->getPrefix().'shortpixel_meta', $p->params, $p->types);
|
272 |
+
return $id;
|
273 |
+
}
|
274 |
+
|
275 |
+
public function batchInsertImages($pathsFile, $folderId) {
|
276 |
+
$pathsFileHandle = fopen($pathsFile, 'r');
|
277 |
+
|
278 |
+
$values = ''; $inserted = 0;
|
279 |
+
$sql = "INSERT IGNORE INTO {$this->db->getPrefix()}shortpixel_meta(folder_id, path, name, path_md5, status) VALUES ";
|
280 |
+
for ($i = 0; ($path = fgets($pathsFileHandle)) !== false; $i++) {
|
281 |
+
$pathParts = explode(DIRECTORY_SEPARATOR, trim($path));
|
282 |
+
$namePrep = $this->db->prepare("%s",$pathParts[count($pathParts) - 1]);
|
283 |
+
$values .= (strlen($values) ? ", ": "") . "(" . $folderId . ", ". $this->db->prepare("%s", trim($path)) . ", ". $namePrep .", '". md5($path) ."', 0)";
|
284 |
+
if($i % 1000 == 999) {
|
285 |
+
$id = $this->db->query($sql . $values);
|
286 |
+
$values = '';
|
287 |
+
$inserted++;
|
288 |
+
}
|
289 |
+
}
|
290 |
+
if($values) {
|
291 |
+
$id = $this->db->query($sql . $values);
|
292 |
+
}
|
293 |
+
fclose($pathsFileHandle);
|
294 |
+
unlink($pathsFile);
|
295 |
+
return $inserted;
|
296 |
+
}
|
297 |
+
|
298 |
+
public function getPaginatedMetas($hasNextGen, $count, $page, $orderby = false, $order = false) {
|
299 |
+
$sql = "SELECT sm.id, sm.name, sm.path folder, "
|
300 |
+
. ($hasNextGen ? "CASE WHEN ng.gid IS NOT NULL THEN 'NextGen' ELSE 'Custom' END media_type, " : "'Custom' media_type, ")
|
301 |
+
. "sm.status, sm.compression_type, sm.keep_exif, sm.cmyk2rgb, sm.resize, sm.resize_width, sm.resize_height, sm.message "
|
302 |
+
. "FROM {$this->db->getPrefix()}shortpixel_meta sm "
|
303 |
+
. "INNER JOIN {$this->db->getPrefix()}shortpixel_folders sf on sm.folder_id = sf.id "
|
304 |
+
. ($hasNextGen ? "LEFT JOIN {$this->db->getPrefix()}ngg_gallery ng on sf.path = ng.path " : " ")
|
305 |
+
. "WHERE sf.status <> -1 "
|
306 |
+
. ($orderby ? "ORDER BY $orderby $order " : "")
|
307 |
+
. "LIMIT $count OFFSET " . ($page - 1) * $count;
|
308 |
+
|
309 |
+
//die($sql);
|
310 |
+
return $this->db->query($sql);
|
311 |
+
}
|
312 |
+
|
313 |
+
public function getPendingMetas($count) {
|
314 |
+
return $this->db->query("SELECT sm.id from {$this->db->getPrefix()}shortpixel_meta sm "
|
315 |
+
. "INNER JOIN {$this->db->getPrefix()}shortpixel_folders sf on sm.folder_id = sf.id "
|
316 |
+
. "WHERE sf.status <> -1 AND ( sm.status = 0 OR sm.status = 1 OR (sm.status <> 2 AND sm.retries < 3)) "
|
317 |
+
. "ORDER BY ts_added DESC LIMIT $count");
|
318 |
+
}
|
319 |
+
|
320 |
+
public function getFolderOptimizationStatus($folderId) {
|
321 |
+
$res = $this->db->query("SELECT SUM(CASE WHEN sm.status = 2 THEN 1 ELSE 0 END) Optimized, SUM(CASE WHEN sm.status = 1 THEN 1 ELSE 0 END) Pending, "
|
322 |
+
. "SUM(CASE WHEN sm.status = 0 THEN 1 ELSE 0 END) Waiting, SUM(CASE WHEN sm.status < 0 THEN 1 ELSE 0 END) Failed, count(*) Total "
|
323 |
+
. "FROM {$this->db->getPrefix()}shortpixel_meta sm "
|
324 |
+
. "INNER JOIN {$this->db->getPrefix()}shortpixel_folders sf on sm.folder_id = sf.id "
|
325 |
+
. "WHERE sf.id = $folderId");
|
326 |
+
return $res[0];
|
327 |
+
}
|
328 |
+
|
329 |
+
public function getPendingMetaCount() {
|
330 |
+
$res = $this->db->query("SELECT COUNT(sm.id) recCount from {$this->db->getPrefix()}shortpixel_meta sm "
|
331 |
+
. "INNER JOIN {$this->db->getPrefix()}shortpixel_folders sf on sm.folder_id = sf.id "
|
332 |
+
. "WHERE sf.status <> -1 AND ( sm.status = 0 OR sm.status = 1 )");
|
333 |
+
return isset($res[0]->recCount) ? $res[0]->recCount : null;
|
334 |
+
}
|
335 |
+
|
336 |
+
public function getCustomMetaCount() {
|
337 |
+
$sql = "SELECT COUNT(sm.id) recCount FROM {$this->db->getPrefix()}shortpixel_meta sm "
|
338 |
+
. "INNER JOIN {$this->db->getPrefix()}shortpixel_folders sf on sm.folder_id = sf.id "
|
339 |
+
. "WHERE sf.status <> -1";
|
340 |
+
$res = $this->db->query($sql);
|
341 |
+
return isset($res[0]->recCount) ? $res[0]->recCount : 0;
|
342 |
+
}
|
343 |
+
|
344 |
+
public function getMeta($id, $deleted = false) {
|
345 |
+
$sql = "SELECT * FROM {$this->db->getPrefix()}shortpixel_meta WHERE id = %d " . ($deleted ? "" : " AND status <> -1");
|
346 |
+
$rows = $this->db->query($sql, array($id));
|
347 |
+
foreach($rows as $row) {
|
348 |
+
$meta = new ShortPixelMeta($row);
|
349 |
+
if($meta->getPath()) {
|
350 |
+
$meta->setWebPath(ShortPixelMetaFacade::filenameToContentRelative($meta->getPath()));
|
351 |
+
}
|
352 |
+
//die(var_dump($meta)."ZA META");
|
353 |
+
return $meta;
|
354 |
+
}
|
355 |
+
return null;
|
356 |
+
}
|
357 |
+
|
358 |
+
public function getMetaForPath($path, $deleted = false) {
|
359 |
+
$sql = "SELECT * FROM {$this->db->getPrefix()}shortpixel_meta WHERE path = %s " . ($deleted ? "" : " AND status <> -1");
|
360 |
+
$rows = $this->db->query($sql, array($path));
|
361 |
+
foreach($rows as $row) {
|
362 |
+
return new ShortPixelMeta($row);
|
363 |
+
}
|
364 |
+
return null;
|
365 |
+
}
|
366 |
+
|
367 |
+
public function update($meta) {
|
368 |
+
$metaClass = get_class($meta);
|
369 |
+
$sql = "UPDATE {$this->db->getPrefix()}shortpixel_" . $metaClass::TABLE_SUFFIX . " SET ";
|
370 |
+
foreach(self::$fields[$metaClass::TABLE_SUFFIX] as $field => $type) {
|
371 |
+
$getter = "get" . ShortPixelTools::snakeToCamel($field);
|
372 |
+
$val = $meta->$getter();
|
373 |
+
if($meta->$getter() !== null) {
|
374 |
+
$sql .= " {$field} = %{$type},"; $params[] = $val;
|
375 |
+
}
|
376 |
+
}
|
377 |
+
|
378 |
+
if(substr($sql, -1) != ',') {
|
379 |
+
return; //no fields added;
|
380 |
+
}
|
381 |
+
|
382 |
+
$sql = rtrim($sql, ",");
|
383 |
+
$sql .= " WHERE id = %d";
|
384 |
+
$params[] = $meta->getId();
|
385 |
+
$this->db->query($sql, $params);
|
386 |
+
}
|
387 |
+
|
388 |
+
public function delete($meta) {
|
389 |
+
$metaClass = get_class($meta);
|
390 |
+
$sql = "DELETE FROM {$this->db->getPrefix()}shortpixel_" . $metaClass::TABLE_SUFFIX . " WHERE id = %d";
|
391 |
+
$this->db->query($sql, array($meta->getId()));
|
392 |
+
}
|
393 |
+
|
394 |
+
public function countAllProcessableFiles() {
|
395 |
+
$sql = "SELECT count(*) totalFiles, sum(CASE WHEN status = 2 THEN 1 ELSE 0 END) totalProcessedFiles,"
|
396 |
+
." sum(CASE WHEN status = 2 AND compression_type = 1 THEN 1 ELSE 0 END) totalProcLossyFiles,"
|
397 |
+
." sum(CASE WHEN status = 2 AND compression_type = 0 THEN 1 ELSE 0 END) totalProcLosslessFiles"
|
398 |
+
." FROM {$this->db->getPrefix()}shortpixel_meta WHERE status <> -1";
|
399 |
+
$rows = $this->db->query($sql);
|
400 |
+
|
401 |
+
$filesWithErrors = array();
|
402 |
+
$sql = "SELECT id, name, path, message FROM {$this->db->getPrefix()}shortpixel_meta WHERE status < -1 AND retries >= 3 LIMIT 30";
|
403 |
+
$failRows = $this->db->query($sql);
|
404 |
+
$filesWithErrors = array();
|
405 |
+
foreach($failRows as $failLine) {
|
406 |
+
$filesWithErrors['C-' . $failLine->id] = array('Name' => $failLine->name, 'Message' => $failLine->message, 'Path' => $failLine->path);
|
407 |
+
}
|
408 |
+
|
409 |
+
return array("totalFiles" => $rows[0]->totalFiles, "mainFiles" => $rows[0]->totalFiles,
|
410 |
+
"totalProcessedFiles" => $rows[0]->totalProcessedFiles, "mainProcessedFiles" => $rows[0]->totalProcessedFiles,
|
411 |
+
"totalProcLossyFiles" => $rows[0]->totalProcLossyFiles, "mainProcLossyFiles" => $rows[0]->totalProcLossyFiles,
|
412 |
+
"totalProcLosslessFiles" => $rows[0]->totalProcLosslessFiles, "mainProcLosslessFiles" => $rows[0]->totalProcLosslessFiles,
|
413 |
+
"totalCustomFiles" => $rows[0]->totalFiles, "mainCustomFiles" => $rows[0]->totalFiles,
|
414 |
+
"totalProcessedCustomFiles" => $rows[0]->totalProcessedFiles, "mainProcessedCustomFiles" => $rows[0]->totalProcessedFiles,
|
415 |
+
"totalProcLossyCustomFiles" => $rows[0]->totalProcLossyFiles, "mainProcLossyCustomFiles" => $rows[0]->totalProcLossyFiles,
|
416 |
+
"totalProcLosslessCustomFiles" => $rows[0]->totalProcLosslessFiles, "mainProcLosslessCustomFiles" => $rows[0]->totalProcLosslessFiles,
|
417 |
+
"filesWithErrors" => $filesWithErrors
|
418 |
+
);
|
419 |
+
|
420 |
+
}
|
421 |
+
}
|
class/db/shortpixel-db.php
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
interface ShortPixelDb {
|
4 |
+
|
5 |
+
public static function createUpdateSchema($tableDefinitions);
|
6 |
+
public function getPrefix();
|
7 |
+
public function query($sql);
|
8 |
+
public function getCharsetCollate();
|
9 |
+
}
|
class/db/shortpixel-meta-facade.php
ADDED
@@ -0,0 +1,344 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class ShortPixelMetaFacade {
|
4 |
+
const MEDIA_LIBRARY_TYPE = 1;
|
5 |
+
const CUSTOM_TYPE = 2;
|
6 |
+
|
7 |
+
private $ID;
|
8 |
+
private $type;
|
9 |
+
private $meta;
|
10 |
+
private $spMetaDao;
|
11 |
+
private $rawMeta;
|
12 |
+
|
13 |
+
public function __construct($ID) {
|
14 |
+
if(strpos($ID, 'C-') === 0) {
|
15 |
+
$this->ID = substr($ID, 2);
|
16 |
+
$this->type = self::CUSTOM_TYPE;
|
17 |
+
} else {
|
18 |
+
$this->ID = $ID;
|
19 |
+
$this->type = self::MEDIA_LIBRARY_TYPE;
|
20 |
+
}
|
21 |
+
$this->spMetaDao = new ShortPixelCustomMetaDao(new WpShortPixelDb());
|
22 |
+
}
|
23 |
+
|
24 |
+
function setRawMeta($rawMeta) {
|
25 |
+
if($this->type == self::MEDIA_LIBRARY_TYPE) {
|
26 |
+
$this->rawMeta = $rawMeta;
|
27 |
+
$this->meta = self::rawMetaToMeta($this->ID, $rawMeta);
|
28 |
+
}
|
29 |
+
}
|
30 |
+
|
31 |
+
function getMeta($refresh = false) {
|
32 |
+
if($refresh || !isset($this->meta)) {
|
33 |
+
if($this->type == self::CUSTOM_TYPE) {
|
34 |
+
$this->meta = $this->spMetaDao->getMeta($this->ID);
|
35 |
+
} else {
|
36 |
+
$rawMeta = wp_get_attachment_metadata($this->ID);
|
37 |
+
$this->meta = self::rawMetaToMeta($this->ID, $rawMeta);
|
38 |
+
$this->rawMeta = $rawMeta;
|
39 |
+
}
|
40 |
+
}
|
41 |
+
return $this->meta;
|
42 |
+
}
|
43 |
+
|
44 |
+
private static function rawMetaToMeta($ID, $rawMeta) {
|
45 |
+
return new ShortPixelMeta(array(
|
46 |
+
"id" => $ID,
|
47 |
+
"path" => get_attached_file($ID),
|
48 |
+
"webPath" => (isset($rawMeta["file"]) ? $rawMeta["file"] : null),
|
49 |
+
"thumbs" => (isset($rawMeta["sizes"]) ? $rawMeta["sizes"] : array()),
|
50 |
+
"message" =>(isset($rawMeta["ShortPixelImprovement"]) ? $rawMeta["ShortPixelImprovement"] : null),
|
51 |
+
"compressionType" =>(isset($rawMeta["ShortPixel"]["type"]) ? ($rawMeta["ShortPixel"]["type"] == "lossy" ? 1 : 0) : null),
|
52 |
+
"thumbsOpt" =>(isset($rawMeta["ShortPixel"]["thumbsOpt"]) ? $rawMeta["ShortPixel"]["thumbsOpt"] : null),
|
53 |
+
"thumbsTodo" =>(isset($rawMeta["ShortPixel"]["thumbsTodo"]) ? $rawMeta["ShortPixel"]["thumbsTodo"] : false),
|
54 |
+
"backup" => !isset($rawMeta['ShortPixel']['NoBackup']),
|
55 |
+
"status" => (!isset($rawMeta["ShortPixel"]) ? 0
|
56 |
+
: (isset($rawMeta["ShortPixelImprovement"]) && is_numeric($rawMeta["ShortPixelImprovement"]) ? 2
|
57 |
+
: (isset($rawMeta["ShortPixel"]["WaitingProcessing"]) ? 1
|
58 |
+
: -500))),
|
59 |
+
"retries" =>(isset($rawMeta["ShortPixel"]["retries"]) ? $rawMeta["ShortPixel"]["retries"] : 0),
|
60 |
+
));
|
61 |
+
}
|
62 |
+
|
63 |
+
function check() {
|
64 |
+
if($this->type == self::CUSTOM_TYPE) {
|
65 |
+
$this->meta = $this->spMetaDao->getMeta($this->ID);
|
66 |
+
return $this->meta;
|
67 |
+
} else {
|
68 |
+
return wp_get_attachment_url($this->ID);
|
69 |
+
}
|
70 |
+
}
|
71 |
+
|
72 |
+
function updateMeta($newMeta = null) {
|
73 |
+
if($newMeta) {
|
74 |
+
$this->meta = $newMeta;
|
75 |
+
}
|
76 |
+
if($this->type == self::CUSTOM_TYPE) {
|
77 |
+
$this->spMetaDao->update($this->meta);
|
78 |
+
if($this->meta->getExtMetaId()) {
|
79 |
+
ShortPixelNextGenAdapter::updateImageSize($this->meta->getExtMetaId(), $this->meta->getPath());
|
80 |
+
}
|
81 |
+
}
|
82 |
+
elseif($this->type == ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE) {
|
83 |
+
//TODO vezi daca nu mai bine mutam asta in Facade - acolo unde actualizam meta, in updateMeta
|
84 |
+
$duplicates = ShortPixelMetaFacade::getWPMLDuplicates($this->ID);
|
85 |
+
foreach($duplicates as $_ID) {
|
86 |
+
$rawMeta = wp_get_attachment_metadata($_ID);
|
87 |
+
if(!is_array($rawMeta)) {
|
88 |
+
$rawMeta = array("previous_meta" => $rawMeta, 'ShortPixel' => array());
|
89 |
+
}
|
90 |
+
$rawMeta['ShortPixel']['type'] = ($newMeta->getCompressionType() == 1 ? "lossy" : "lossless");
|
91 |
+
$rawMeta['ShortPixel']['exifKept'] = $newMeta->getKeepExif();
|
92 |
+
$rawMeta['ShortPixel']['date'] = date("Y-m-d", strtotime($newMeta->getTsOptimized()));
|
93 |
+
//thumbs were processed if settings or if they were explicitely requested
|
94 |
+
$rawMeta['ShortPixel']['thumbsOpt'] = $newMeta->getThumbsOpt();
|
95 |
+
//if thumbsTodo - this means there was an explicit request to process thumbs for an image that was previously processed without
|
96 |
+
// don't update the ShortPixelImprovement ratio as this is only calculated based on main image
|
97 |
+
if($newMeta->getThumbsTodo()) {
|
98 |
+
$rawMeta['ShortPixel']['thumbsTodo'] = true;
|
99 |
+
} else {
|
100 |
+
$rawMeta['ShortPixelImprovement'] = "".round($newMeta->getImprovementPercent(),2);
|
101 |
+
unset($rawMeta['ShortPixel']['thumbsTodo']);
|
102 |
+
}
|
103 |
+
if($newMeta->getActualWidth() && $newMeta->getActualHeight()) {
|
104 |
+
$rawMeta['width'] = $newMeta->getActualWidth();
|
105 |
+
$rawMeta['height'] = $newMeta->getActualHeight();
|
106 |
+
}
|
107 |
+
if(!$newMeta->getBackup()) {
|
108 |
+
$rawMeta['ShortPixel']['NoBackup'] = true;
|
109 |
+
}
|
110 |
+
if($newMeta->getStatus() !== 1) {
|
111 |
+
unset($rawMeta['ShortPixel']['WaitingProcessing']);
|
112 |
+
}
|
113 |
+
wp_update_attachment_metadata($this->ID, $rawMeta);
|
114 |
+
}
|
115 |
+
}
|
116 |
+
}
|
117 |
+
|
118 |
+
function deleteMeta() {
|
119 |
+
if($this->type == self::CUSTOM_TYPE) {
|
120 |
+
throw new Exception("Not implemented 1");
|
121 |
+
} else {
|
122 |
+
unset($this->rawMeta['ShortPixel']);
|
123 |
+
wp_update_attachment_metadata($this->ID, $this->rawMeta);
|
124 |
+
}
|
125 |
+
}
|
126 |
+
|
127 |
+
function incrementRetries($count = 1) {
|
128 |
+
if($this->type == self::CUSTOM_TYPE) {
|
129 |
+
$this->meta->setRetries($this->meta->getRetries() + $count);
|
130 |
+
$this->updateMeta();
|
131 |
+
} else {
|
132 |
+
$this->rawMeta['ShortPixel']['Retries'] = isset($this->rawMeta['ShortPixel']['Retries']) ? $this->rawMeta['ShortPixel']['Retries'] + $count : $count;
|
133 |
+
$this->meta->setRetries($this->rawMeta['ShortPixel']['Retries']);
|
134 |
+
wp_update_attachment_metadata($this->ID, $this->rawMeta);
|
135 |
+
}
|
136 |
+
}
|
137 |
+
|
138 |
+
function setWaitingProcessing($status = true) {
|
139 |
+
if($status) {
|
140 |
+
$this->meta->setStatus(1);
|
141 |
+
}
|
142 |
+
if($this->type == self::CUSTOM_TYPE) {
|
143 |
+
$this->updateMeta();
|
144 |
+
} else {
|
145 |
+
if($status) {
|
146 |
+
$this->rawMeta['ShortPixel']['WaitingProcessing'] = true;
|
147 |
+
} else {
|
148 |
+
unset($this->rawMeta['ShortPixel']['WaitingProcessing']);
|
149 |
+
}
|
150 |
+
wp_update_attachment_metadata($this->ID, $this->rawMeta);
|
151 |
+
}
|
152 |
+
}
|
153 |
+
|
154 |
+
function setError($errorCode, $errorMessage) {
|
155 |
+
$this->meta->setMessage('Error: <i>' . $errorMessage . '</i>');
|
156 |
+
$this->meta->setStatus($errorCode);
|
157 |
+
if($this->type == self::CUSTOM_TYPE) {
|
158 |
+
if($errorCode == ShortPixelAPI::ERR_FILE_NOT_FOUND) {
|
159 |
+
$this->spMetaDao->delete($this->meta);
|
160 |
+
} else {
|
161 |
+
$this->spMetaDao->update($this->meta);
|
162 |
+
}
|
163 |
+
} else {
|
164 |
+
$this->rawMeta['ShortPixelImprovement'] = $this->meta->getMessage();
|
165 |
+
unset($this->rawMeta['ShortPixel']['WaitingProcessing']);
|
166 |
+
wp_update_attachment_metadata($this->ID, $this->rawMeta);
|
167 |
+
}
|
168 |
+
}
|
169 |
+
|
170 |
+
public function getURLsAndPATHs($processThumbnails, $onlyThumbs = false) {
|
171 |
+
if($this->type == self::CUSTOM_TYPE) {
|
172 |
+
$meta = $this->getMeta();
|
173 |
+
$urlList[] = str_replace(get_home_path(), network_site_url("/"), $meta->getPath());
|
174 |
+
$filePaths[] = $meta->getPath();
|
175 |
+
return array("URLs" => $urlList, "PATHs" => $filePaths);
|
176 |
+
} else {
|
177 |
+
if ( !parse_url(WP_CONTENT_URL, PHP_URL_SCHEME) ) {//no absolute URLs used -> we implement a hack
|
178 |
+
$url = get_site_url() . wp_get_attachment_url($this->ID);//get the file URL
|
179 |
+
}
|
180 |
+
else {
|
181 |
+
$url = wp_get_attachment_url($this->ID);//get the file URL
|
182 |
+
}
|
183 |
+
$urlList[] = $url;
|
184 |
+
$path = get_attached_file($this->ID);//get the full file PATH
|
185 |
+
$filePath[] = $path;
|
186 |
+
|
187 |
+
$meta = $this->getMeta();
|
188 |
+
$sizes = $meta->getThumbs();
|
189 |
+
|
190 |
+
//it is NOT a PDF file and thumbs are processable
|
191 |
+
if ( strtolower(substr($filePath[0],strrpos($filePath[0], ".")+1)) != "pdf"
|
192 |
+
&& ($processThumbnails || $onlyThumbs)
|
193 |
+
&& count($sizes))
|
194 |
+
{
|
195 |
+
foreach( $sizes as $thumbnailInfo ) {
|
196 |
+
$urlList[] = str_replace(ShortPixelAPI::MB_basename($urlList[0]), $thumbnailInfo['file'], $url);
|
197 |
+
$filePath[] = str_replace(ShortPixelAPI::MB_basename($filePath[0]), $thumbnailInfo['file'], $path);
|
198 |
+
}
|
199 |
+
}
|
200 |
+
if(!count($sizes)) {
|
201 |
+
WPShortPixel::log("getURLsAndPATHs: no meta sizes for ID " . $this->ID . " : " . json_encode($this->rawMeta));
|
202 |
+
}
|
203 |
+
|
204 |
+
if($onlyThumbs) { //remove the main image
|
205 |
+
array_shift($urlList);
|
206 |
+
array_shift($filePath);
|
207 |
+
}
|
208 |
+
}
|
209 |
+
return array("URLs" => $urlList, "PATHs" => $filePath);
|
210 |
+
}
|
211 |
+
|
212 |
+
public static function getWPMLDuplicates( $id ) {
|
213 |
+
global $wpdb;
|
214 |
+
|
215 |
+
$parentId = get_post_meta ($id, '_icl_lang_duplicate_of', true );
|
216 |
+
if($parentId) $id = $parentId;
|
217 |
+
|
218 |
+
$duplicates = $wpdb->get_col( $wpdb->prepare( "
|
219 |
+
SELECT pm.post_id FROM {$wpdb->postmeta} pm
|
220 |
+
WHERE pm.meta_value = %s AND pm.meta_key = '_icl_lang_duplicate_of'
|
221 |
+
", $id ) );
|
222 |
+
|
223 |
+
if(!in_array($id, $duplicates)) $duplicates[] = $id;
|
224 |
+
|
225 |
+
$transTable = $wpdb->get_results("SELECT COUNT(1) hasTransTable FROM information_schema.tables WHERE table_schema='{$wpdb->dbname}' AND table_name='{$wpdb->prefix}icl_translations'");
|
226 |
+
if(isset($transTable[0]->hasTransTable) && $transTable[0]->hasTransTable > 0) {
|
227 |
+
$transGroupId = $wpdb->get_results("SELECT trid FROM {$wpdb->prefix}icl_translations WHERE element_id = {$id}");
|
228 |
+
if(count($transGroupId)) {
|
229 |
+
$transGroup = $wpdb->get_results("SELECT element_id FROM {$wpdb->prefix}icl_translations WHERE trid = " . $transGroupId[0]->trid);
|
230 |
+
foreach($transGroup as $trans) {
|
231 |
+
$duplicates[] = $trans->element_id;
|
232 |
+
}
|
233 |
+
}
|
234 |
+
}
|
235 |
+
return array_unique($duplicates);
|
236 |
+
}
|
237 |
+
|
238 |
+
public static function pathToWebPath($path) {
|
239 |
+
//$upl = wp_upload_dir();
|
240 |
+
//return str_replace($upl["basedir"], $upl["baseurl"], $path);
|
241 |
+
return str_replace(get_home_path(), site_url()."/", $path);
|
242 |
+
}
|
243 |
+
|
244 |
+
public static function pathToContentRelative($path) {
|
245 |
+
//$upl = wp_upload_dir();
|
246 |
+
$pathParts = explode(DIRECTORY_SEPARATOR, $path);
|
247 |
+
unset($pathParts[count($pathParts) - 1]);
|
248 |
+
$path = implode(DIRECTORY_SEPARATOR, $pathParts);
|
249 |
+
return str_replace(WP_CONTENT_DIR . "/", "", $path);
|
250 |
+
}
|
251 |
+
|
252 |
+
public static function filenameToContentRelative($path) {
|
253 |
+
return str_replace(WP_CONTENT_DIR . DIRECTORY_SEPARATOR, "", $path);
|
254 |
+
}
|
255 |
+
|
256 |
+
public static function getMaxMediaId() {
|
257 |
+
global $wpdb;
|
258 |
+
$queryMax = "SELECT max(post_id) as QueryID FROM " . $wpdb->prefix . "postmeta";
|
259 |
+
$resultQuery = $wpdb->get_results($queryMax);
|
260 |
+
return $resultQuery[0]->QueryID;
|
261 |
+
}
|
262 |
+
|
263 |
+
public static function getMinMediaId() {
|
264 |
+
global $wpdb;
|
265 |
+
$queryMax = "SELECT min(post_id) as QueryID FROM " . $wpdb->prefix . "postmeta";
|
266 |
+
$resultQuery = $wpdb->get_results($queryMax);
|
267 |
+
return $resultQuery[0]->QueryID;
|
268 |
+
}
|
269 |
+
|
270 |
+
public static function isCustomQueuedId($id) {
|
271 |
+
return substr($id, 0, 2) == "C-";
|
272 |
+
}
|
273 |
+
|
274 |
+
public static function stripQueuedIdType($id) {
|
275 |
+
return substr($id, 2);
|
276 |
+
}
|
277 |
+
|
278 |
+
public function getQueuedId() {
|
279 |
+
return self::queuedId($this->type, $this->ID);
|
280 |
+
}
|
281 |
+
|
282 |
+
public static function queuedId($type, $id) {
|
283 |
+
return ($type == self::CUSTOM_TYPE ? "C-" : "") . $id;
|
284 |
+
}
|
285 |
+
|
286 |
+
function getId() {
|
287 |
+
return $this->ID;
|
288 |
+
}
|
289 |
+
|
290 |
+
function getType() {
|
291 |
+
return $this->type;
|
292 |
+
}
|
293 |
+
|
294 |
+
function setId($ID) {
|
295 |
+
$this->ID = $ID;
|
296 |
+
}
|
297 |
+
|
298 |
+
function setType($type) {
|
299 |
+
$this->type = $type;
|
300 |
+
}
|
301 |
+
|
302 |
+
function getRawMeta() {
|
303 |
+
return $this->rawMeta;
|
304 |
+
}
|
305 |
+
|
306 |
+
/**
|
307 |
+
* return subdir for that particular attached file - if it's media library then last 3 path items, otherwise substract the uploads path
|
308 |
+
* Has trailing directory separator (/)
|
309 |
+
* @param type $file
|
310 |
+
* @return string
|
311 |
+
*/
|
312 |
+
static public function returnSubDir($file, $type)
|
313 |
+
{
|
314 |
+
if(strstr($file, WP_CONTENT_DIR . DIRECTORY_SEPARATOR)) {
|
315 |
+
$path = str_replace( WP_CONTENT_DIR . DIRECTORY_SEPARATOR, "", $file);
|
316 |
+
} else {
|
317 |
+
$path = (substr($file, 1));
|
318 |
+
}
|
319 |
+
$pathArr = explode(DIRECTORY_SEPARATOR, $path);
|
320 |
+
unset($pathArr[count($pathArr) - 1]);
|
321 |
+
return implode(DIRECTORY_SEPARATOR, $pathArr) . DIRECTORY_SEPARATOR;
|
322 |
+
}
|
323 |
+
|
324 |
+
public static function isMediaSubfolder($path) {
|
325 |
+
$uploadDir = wp_upload_dir();
|
326 |
+
$uploadBase = $uploadDir["basedir"];
|
327 |
+
$uploadPath = $uploadDir["path"];
|
328 |
+
//contains the current media upload path
|
329 |
+
if(ShortPixelFolder::checkFolderIsSubfolder($uploadPath, $path)) {
|
330 |
+
return true;
|
331 |
+
}
|
332 |
+
//contains one of the year subfolders of the media library
|
333 |
+
if(strpos($path, $uploadPath) == 0) {
|
334 |
+
$pathArr = explode(DIRECTORY_SEPARATOR, str_replace($uploadBase . DIRECTORY_SEPARATOR, "", $path));
|
335 |
+
if( count($pathArr) >= 1
|
336 |
+
&& is_numeric($pathArr[0]) && $pathArr[0] > 1900 && $pathArr[0] < 2100 //contains the year subfolder
|
337 |
+
&& ( count($pathArr) == 1 //if there is another subfolder then it's the month subfolder
|
338 |
+
|| (is_numeric($pathArr[1]) && $pathArr[1] > 0 && $pathArr[1] < 13) )) {
|
339 |
+
return true;
|
340 |
+
}
|
341 |
+
}
|
342 |
+
return false;
|
343 |
+
}
|
344 |
+
}
|
class/db/shortpixel-nextgen-adapter.php
ADDED
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class ShortPixelNextGenAdapter {
|
4 |
+
public static function getGalleries () {
|
5 |
+
global $wpdb;
|
6 |
+
return array_map(function($item){return $item->path;}, $wpdb->get_results("SELECT path FROM {$wpdb->prefix}ngg_gallery"));
|
7 |
+
|
8 |
+
}
|
9 |
+
|
10 |
+
public static function hasNextGen() {
|
11 |
+
global $wpdb;
|
12 |
+
$nggTable = $wpdb->get_results("SELECT COUNT(1) hasNggTable FROM information_schema.tables WHERE table_schema='{$wpdb->dbname}' AND table_name='{$wpdb->prefix}ngg_gallery'");
|
13 |
+
if(isset($nggTable[0]->hasNggTable) && $nggTable[0]->hasNggTable > 0) {
|
14 |
+
return true;
|
15 |
+
}
|
16 |
+
return false;
|
17 |
+
}
|
18 |
+
|
19 |
+
public static function getImageAbspath($image) {
|
20 |
+
$storage = C_Gallery_Storage::get_instance();
|
21 |
+
return $storage->get_image_abspath($image);
|
22 |
+
}
|
23 |
+
|
24 |
+
public static function updateImageSize($nggId, $path) {
|
25 |
+
$mapper = C_Image_Mapper::get_instance();
|
26 |
+
$image = $mapper->find($nggId);
|
27 |
+
$dimensions = getimagesize(self::getImageAbspath($image));
|
28 |
+
$size_meta = array('width' => $dimensions[0], 'height' => $dimensions[1]);
|
29 |
+
$image->meta_data = array_merge($image->meta_data, $size_meta);
|
30 |
+
$image->meta_data['full'] = $size_meta;
|
31 |
+
$mapper->save($image);
|
32 |
+
}
|
33 |
+
}
|
class/db/wp-shortpixel-db.php
ADDED
@@ -0,0 +1,76 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class WpShortPixelDb implements ShortPixelDb {
|
4 |
+
|
5 |
+
protected $prefix;
|
6 |
+
protected $defaultShowErrors;
|
7 |
+
|
8 |
+
public function __construct($prefix = null) {
|
9 |
+
$this->prefix = $prefix;
|
10 |
+
}
|
11 |
+
|
12 |
+
public static function createUpdateSchema($tableDefinitions) {
|
13 |
+
require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
|
14 |
+
$res = array();
|
15 |
+
foreach($tableDefinitions as $tableDef) {
|
16 |
+
array_merge($res, dbDelta( $tableDef ));
|
17 |
+
}
|
18 |
+
return $res;
|
19 |
+
}
|
20 |
+
|
21 |
+
public static function checkCustomTables() {
|
22 |
+
global $wpdb;
|
23 |
+
if(function_exists("is_multisite") && is_multisite()) {
|
24 |
+
$sites = wp_get_sites();
|
25 |
+
foreach($sites as $site) {
|
26 |
+
$prefix = $wpdb->get_blog_prefix($site['blog_id']);
|
27 |
+
$spMetaDao = new ShortPixelCustomMetaDao(new WpShortPixelDb($prefix));
|
28 |
+
$spMetaDao->createUpdateShortPixelTables();
|
29 |
+
}
|
30 |
+
|
31 |
+
} else {
|
32 |
+
$spMetaDao = new ShortPixelCustomMetaDao(new WpShortPixelDb());
|
33 |
+
$spMetaDao->createUpdateShortPixelTables();
|
34 |
+
}
|
35 |
+
}
|
36 |
+
|
37 |
+
public function getCharsetCollate() {
|
38 |
+
global $wpdb;
|
39 |
+
return $wpdb->get_charset_collate();
|
40 |
+
}
|
41 |
+
|
42 |
+
public function getPrefix() {
|
43 |
+
global $wpdb;
|
44 |
+
return $this->prefix ? $this->prefix : $wpdb->prefix;
|
45 |
+
}
|
46 |
+
|
47 |
+
public function query($sql, $params = false) {
|
48 |
+
global $wpdb;
|
49 |
+
if($params) {
|
50 |
+
$sql = $wpdb->prepare($sql, $params);
|
51 |
+
}
|
52 |
+
return $wpdb->get_results($sql);
|
53 |
+
}
|
54 |
+
|
55 |
+
public function insert($table, $params, $format = null) {
|
56 |
+
global $wpdb;
|
57 |
+
$wpdb->insert($table, $params, $format);
|
58 |
+
return $wpdb->insert_id;
|
59 |
+
}
|
60 |
+
|
61 |
+
public function prepare($query, $args) {
|
62 |
+
global $wpdb;
|
63 |
+
return $wpdb->prepare($query, $args);
|
64 |
+
}
|
65 |
+
|
66 |
+
public function hideErrors() {
|
67 |
+
global $wpdb;
|
68 |
+
$this->defaultShowErrors = $wpdb->show_errors;
|
69 |
+
$wpdb->show_errors = false;
|
70 |
+
}
|
71 |
+
|
72 |
+
public function restoreErrors() {
|
73 |
+
global $wpdb;
|
74 |
+
$wpdb->show_errors = $this->defaultShowErrors;
|
75 |
+
}
|
76 |
+
}
|
class/db/wp-shortpixel-media-library-adapter.php
ADDED
@@ -0,0 +1,165 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class WpShortPixelMediaLbraryAdapter {
|
4 |
+
|
5 |
+
//count all the processable files in media library (while limiting the results to max 10000)
|
6 |
+
public static function countAllProcessableFiles($maxId = PHP_INT_MAX, $minId = 0){
|
7 |
+
global $wpdb;
|
8 |
+
|
9 |
+
$totalFiles = $mainFiles = $processedMainFiles = $processedTotalFiles =
|
10 |
+
$procLossyMainFiles = $procLossyTotalFiles = $procLosslessMainFiles = $procLosslessTotalFiles = $procUndefMainFiles = $procUndefTotalFiles = $mainUnprocessedThumbs = 0;
|
11 |
+
$filesMap = $processedFilesMap = array();
|
12 |
+
$limit = self::getOptimalChunkSize();
|
13 |
+
$pointer = 0;
|
14 |
+
$filesWithErrors = array();
|
15 |
+
|
16 |
+
//count all the files, main and thumbs
|
17 |
+
while ( 1 ) {
|
18 |
+
$ids = self::getPostIdsChunk($minId, $maxId, $pointer, $limit);
|
19 |
+
if($ids === null) {
|
20 |
+
break; //we parsed all the results
|
21 |
+
}
|
22 |
+
elseif(count($ids) == 0) {
|
23 |
+
$pointer += $limit;
|
24 |
+
continue;
|
25 |
+
}
|
26 |
+
|
27 |
+
$filesList= $wpdb->get_results("SELECT * FROM " . $wpdb->prefix . "postmeta
|
28 |
+
WHERE post_id IN (" . implode(',', $ids) . ")
|
29 |
+
AND ( meta_key = '_wp_attached_file' OR meta_key = '_wp_attachment_metadata' )");
|
30 |
+
|
31 |
+
foreach ( $filesList as $file )
|
32 |
+
{
|
33 |
+
if ( $file->meta_key == "_wp_attached_file" )
|
34 |
+
{//count pdf files only
|
35 |
+
$extension = substr($file->meta_value, strrpos($file->meta_value,".") + 1 );
|
36 |
+
if ( $extension == "pdf" && !isset($filesMap[$file->meta_value]))
|
37 |
+
{
|
38 |
+
$totalFiles++;
|
39 |
+
$mainFiles++;
|
40 |
+
$filesMap[$file->meta_value] = 1;
|
41 |
+
}
|
42 |
+
}
|
43 |
+
else //_wp_attachment_metadata
|
44 |
+
{
|
45 |
+
$attachment = unserialize($file->meta_value);
|
46 |
+
//processable
|
47 |
+
$isProcessable = false;
|
48 |
+
if(isset($attachment['file']) && !isset($filesMap[$attachment['file']]) && WPShortPixel::isProcessablePath($attachment['file'])){
|
49 |
+
$isProcessable = true;
|
50 |
+
if ( isset($attachment['sizes']) ) {
|
51 |
+
$totalFiles += count($attachment['sizes']);
|
52 |
+
}
|
53 |
+
if ( isset($attachment['file']) )
|
54 |
+
{
|
55 |
+
$totalFiles++;
|
56 |
+
$mainFiles++;
|
57 |
+
$filesMap[$attachment['file']] = 1;
|
58 |
+
}
|
59 |
+
}
|
60 |
+
//processed
|
61 |
+
if (isset($attachment['ShortPixelImprovement'])
|
62 |
+
&& ($attachment['ShortPixelImprovement'] > 0 || $attachment['ShortPixelImprovement'] === 0.0 || $attachment['ShortPixelImprovement'] === "0")
|
63 |
+
//for PDFs there is no file field so just let it pass.
|
64 |
+
&& (!isset($attachment['file']) || !isset($processedFilesMap[$attachment['file']])) ) {
|
65 |
+
|
66 |
+
//add main file to counts
|
67 |
+
$processedMainFiles++;
|
68 |
+
$processedTotalFiles++;
|
69 |
+
$type = isset($attachment['ShortPixel']['type']) ? $attachment['ShortPixel']['type'] : null;
|
70 |
+
if($type == 'lossy') {
|
71 |
+
$procLossyMainFiles++;
|
72 |
+
$procLossyTotalFiles++;
|
73 |
+
} elseif($type == 'lossless') {
|
74 |
+
$procLosslessMainFiles++;
|
75 |
+
$procLosslessTotalFiles++;
|
76 |
+
} else {
|
77 |
+
$procUndefMainFiles++;
|
78 |
+
$procUndefTotalFiles++;
|
79 |
+
}
|
80 |
+
|
81 |
+
//get the thumbs processed for that attachment
|
82 |
+
$thumbs = $allThumbs = 0;
|
83 |
+
if ( isset($attachment['ShortPixel']['thumbsOpt']) ) {
|
84 |
+
$thumbs = $attachment['ShortPixel']['thumbsOpt'];
|
85 |
+
}
|
86 |
+
elseif ( isset($attachment['sizes']) ) {
|
87 |
+
$thumbs = count($attachment['sizes']);
|
88 |
+
}
|
89 |
+
if ( isset($attachment['sizes']) && count($attachment['sizes']) > $thumbs) {
|
90 |
+
$mainUnprocessedThumbs++;
|
91 |
+
}
|
92 |
+
|
93 |
+
//increment with thumbs processed
|
94 |
+
$processedTotalFiles += $thumbs;
|
95 |
+
if($type == 'lossy') {
|
96 |
+
$procLossyTotalFiles += $thumbs;
|
97 |
+
} else {
|
98 |
+
$procLosslessTotalFiles += $thumbs;
|
99 |
+
}
|
100 |
+
|
101 |
+
if ( isset($attachment['file']) ) {
|
102 |
+
$processedFilesMap[$attachment['file']] = 1;
|
103 |
+
}
|
104 |
+
}
|
105 |
+
elseif($isProcessable && isset($attachment['ShortPixelImprovement']) && count($filesWithErrors) < 50) {
|
106 |
+
$filePath = explode("/", $attachment["file"]);
|
107 |
+
$name = is_array($filePath)? $filePath[count($filePath) - 1] : $file->post_id;
|
108 |
+
$filesWithErrors[$file->post_id] = array('Name' => $name, 'Message' => $attachment['ShortPixelImprovement']);
|
109 |
+
}
|
110 |
+
|
111 |
+
}
|
112 |
+
}
|
113 |
+
unset($filesList);
|
114 |
+
$pointer += $limit;
|
115 |
+
|
116 |
+
}//end while
|
117 |
+
|
118 |
+
return array("totalFiles" => $totalFiles, "mainFiles" => $mainFiles,
|
119 |
+
"totalProcessedFiles" => $processedTotalFiles, "mainProcessedFiles" => $processedMainFiles,
|
120 |
+
"totalProcLossyFiles" => $procLossyTotalFiles, "mainProcLossyFiles" => $procLossyMainFiles,
|
121 |
+
"totalProcLosslessFiles" => $procLosslessTotalFiles, "mainProcLosslessFiles" => $procLosslessMainFiles,
|
122 |
+
"totalMlFiles" => $totalFiles, "mainMlFiles" => $mainFiles,
|
123 |
+
"totalProcessedMlFiles" => $processedTotalFiles, "mainProcessedMlFiles" => $processedMainFiles,
|
124 |
+
"totalProcLossyMlFiles" => $procLossyTotalFiles, "mainProcLossyMlFiles" => $procLossyMainFiles,
|
125 |
+
"totalProcLosslessMlFiles" => $procLosslessTotalFiles, "mainProcLosslessMlFiles" => $procLosslessMainFiles,
|
126 |
+
"totalProcUndefMlFiles" => $procUndefTotalFiles, "mainProcUndefMlFiles" => $procUndefMainFiles,
|
127 |
+
"mainUnprocessedThumbs" => $mainUnprocessedThumbs,
|
128 |
+
"filesWithErrors" => $filesWithErrors
|
129 |
+
);
|
130 |
+
}
|
131 |
+
|
132 |
+
protected static function getOptimalChunkSize() {
|
133 |
+
global $wpdb;
|
134 |
+
$cnt = $wpdb->get_results("SELECT count(*) posts FROM " . $wpdb->prefix . "posts");
|
135 |
+
$posts = isset($cnt) && count($cnt) > 0 ? $cnt[0]->posts : 0;
|
136 |
+
if($posts > 100000) {
|
137 |
+
return 20000;
|
138 |
+
} elseif ($posts > 50000) {
|
139 |
+
return 5000;
|
140 |
+
} elseif($posts > 10000) {
|
141 |
+
return 2000;
|
142 |
+
} else {
|
143 |
+
return 500;
|
144 |
+
}
|
145 |
+
}
|
146 |
+
|
147 |
+
protected static function getPostIdsChunk($minId, $maxId, $pointer, $limit) {
|
148 |
+
global $wpdb;
|
149 |
+
|
150 |
+
$ids = array();
|
151 |
+
$idList = $wpdb->get_results("SELECT ID, post_mime_type FROM " . $wpdb->prefix . "posts
|
152 |
+
WHERE ( ID <= $maxId AND ID > $minId )
|
153 |
+
LIMIT $pointer,$limit");
|
154 |
+
if ( empty($idList) ) {
|
155 |
+
return null;
|
156 |
+
}
|
157 |
+
foreach($idList as $item) {
|
158 |
+
if($item->post_mime_type != '') {
|
159 |
+
$ids[] = $item->ID;
|
160 |
+
}
|
161 |
+
}
|
162 |
+
return $ids;
|
163 |
+
}
|
164 |
+
|
165 |
+
}
|
class/model/shortpixel-entity.php
ADDED
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class ShortPixelEntity{
|
4 |
+
public function __construct($data) {
|
5 |
+
if(is_object($data)) {
|
6 |
+
$dataArr = get_object_vars($data);
|
7 |
+
} elseif(is_array($data)) {
|
8 |
+
$dataArr = $data;
|
9 |
+
} else {
|
10 |
+
return;
|
11 |
+
}
|
12 |
+
foreach($dataArr as $key => $val) {
|
13 |
+
$setter = 'set' . ShortPixelTools::snakeToCamel($key);
|
14 |
+
if(method_exists($this, $setter)) {
|
15 |
+
$this->$setter($val);
|
16 |
+
}
|
17 |
+
}
|
18 |
+
}
|
19 |
+
}
|
class/model/shortpixel-folder.php
ADDED
@@ -0,0 +1,198 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class ShortPixelFolder extends ShortPixelEntity{
|
4 |
+
const META_VERSION = 1;
|
5 |
+
|
6 |
+
protected $id;
|
7 |
+
protected $path;
|
8 |
+
protected $type;
|
9 |
+
protected $status;
|
10 |
+
protected $fileCount;
|
11 |
+
protected $tsCreated;
|
12 |
+
protected $tsUpdated;
|
13 |
+
|
14 |
+
const TABLE_SUFFIX = 'folders';
|
15 |
+
|
16 |
+
public function __construct($data) {
|
17 |
+
parent::__construct($data);
|
18 |
+
}
|
19 |
+
|
20 |
+
public static function checkFolder($folder, $base) {
|
21 |
+
if(substr($folder, 0, 1) !== DIRECTORY_SEPARATOR) {
|
22 |
+
$folder = DIRECTORY_SEPARATOR . $folder;
|
23 |
+
}
|
24 |
+
if(is_dir($folder)) {
|
25 |
+
return realpath($folder);
|
26 |
+
} elseif(is_dir($base . $folder)) {
|
27 |
+
return realpath($base . $folder);
|
28 |
+
}
|
29 |
+
return false;
|
30 |
+
}
|
31 |
+
|
32 |
+
/**
|
33 |
+
* returns the first from parents that is a parent folder of $folder
|
34 |
+
* @param type $folder
|
35 |
+
* @param type $parents
|
36 |
+
* @return parent if found, false otherwise
|
37 |
+
*/
|
38 |
+
public static function checkFolderIsSubfolder($folder, $parents) {
|
39 |
+
if(!is_array($parents)) {
|
40 |
+
$parents = array($parents);
|
41 |
+
}
|
42 |
+
foreach($parents as $parent) {
|
43 |
+
if(strpos($folder, $parent) === 0 && (strlen($parent) == strlen($folder) || substr($folder, strlen($parent), 1) == DIRECTORY_SEPARATOR)) {
|
44 |
+
return $parent;
|
45 |
+
}
|
46 |
+
}
|
47 |
+
return false;
|
48 |
+
}
|
49 |
+
|
50 |
+
/**
|
51 |
+
* finds the first from the subfolders that has the folder as parent
|
52 |
+
* @param type $folder
|
53 |
+
* @param type $subfolders
|
54 |
+
* @return subfolder if found, false otherwise
|
55 |
+
*/
|
56 |
+
public static function checkFolderIsParent($folder, $subfolders) {
|
57 |
+
if(!is_array($subfolders)) {
|
58 |
+
$subfolders[] = $subfolders;
|
59 |
+
}
|
60 |
+
foreach($subfolders as $sub) {
|
61 |
+
if(strpos($sub, $folder) === 0 && (strlen($folder) == strlen($sub) || substr($sub, strlen($folder) - 1, 1) == DIRECTORY_SEPARATOR)) {
|
62 |
+
return $sub;
|
63 |
+
}
|
64 |
+
}
|
65 |
+
return false;
|
66 |
+
}
|
67 |
+
|
68 |
+
public function countFiles($path = null) {
|
69 |
+
$size = 0;
|
70 |
+
$path = $path ? $path : $this->getPath();
|
71 |
+
if($path == null) {
|
72 |
+
return 0;
|
73 |
+
}
|
74 |
+
$ignore = array('.','..');
|
75 |
+
if(!is_writable($path)) {
|
76 |
+
throw new SpFileRightsException("Folder " . $path . " is not writeable. Please check permissions and try again.");
|
77 |
+
}
|
78 |
+
$files = scandir($path);
|
79 |
+
foreach($files as $t) {
|
80 |
+
$tpath = rtrim($path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $t;
|
81 |
+
if(in_array($t, $ignore)) continue;
|
82 |
+
if (is_dir($tpath)) {
|
83 |
+
$size += $this->countFiles($tpath);
|
84 |
+
} elseif(in_array(pathinfo($t, PATHINFO_EXTENSION), WPShortPixel::$PROCESSABLE_EXTENSIONS)) {
|
85 |
+
$size++;
|
86 |
+
}
|
87 |
+
}
|
88 |
+
return $size;
|
89 |
+
}
|
90 |
+
|
91 |
+
public function getFileList($onlyNewerThan = 0) {
|
92 |
+
$upl = wp_upload_dir();
|
93 |
+
$fileListPath = tempnam($upl["basedir"] . DIRECTORY_SEPARATOR, 'sp_');
|
94 |
+
$fileHandle = fopen($fileListPath, 'w+');
|
95 |
+
self::getFileListRecursive($this->getPath(), $fileHandle, $onlyNewerThan);
|
96 |
+
fclose($fileHandle);
|
97 |
+
return $fileListPath;
|
98 |
+
}
|
99 |
+
|
100 |
+
protected static function getFileListRecursive($path, $fileHandle, $onlyNewerThan) {
|
101 |
+
$ignore = array('.','..');
|
102 |
+
$files = scandir($path);
|
103 |
+
$add = (filemtime($path) > $onlyNewerThan);
|
104 |
+
/*
|
105 |
+
if($add && $onlyNewerThan) {
|
106 |
+
echo("<br> FOLDER UPDATED: " . $path);
|
107 |
+
}
|
108 |
+
*/
|
109 |
+
foreach($files as $t) {
|
110 |
+
if(in_array($t, $ignore)) continue;
|
111 |
+
$tpath = rtrim($path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $t;
|
112 |
+
if (is_dir($tpath)) {
|
113 |
+
self::getFileListRecursive($tpath, $fileHandle, $onlyNewerThan);
|
114 |
+
} elseif($add && in_array(pathinfo($t, PATHINFO_EXTENSION), WPShortPixel::$PROCESSABLE_EXTENSIONS)) {
|
115 |
+
fwrite($fileHandle, $tpath . "\n");
|
116 |
+
}
|
117 |
+
}
|
118 |
+
}
|
119 |
+
|
120 |
+
public function getFolderContentsChangeDate() {
|
121 |
+
return self::getFolderContentsChangeDateRecursive($this->getPath(), 0, time($this->getTsUpdated()));
|
122 |
+
}
|
123 |
+
|
124 |
+
protected static function getFolderContentsChangeDateRecursive($path, $mtime, $refMtime) {
|
125 |
+
$ignore = array('.','..');
|
126 |
+
if(!is_writable($path)) {
|
127 |
+
throw new SpFileRightsException("Folder " . $path . " is not writeable. Please check permissions and try again.");
|
128 |
+
}
|
129 |
+
$files = scandir($path);
|
130 |
+
$mtime = max($mtime, filemtime($path));
|
131 |
+
foreach($files as $t) {
|
132 |
+
if(in_array($t, $ignore)) continue;
|
133 |
+
$tpath = rtrim($path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $t;
|
134 |
+
if (is_dir($tpath)) {
|
135 |
+
$mtime = max($mtime, filemtime($tpath));
|
136 |
+
self::getFolderContentsChangeDateRecursive($tpath, $mtime, $refMtime);
|
137 |
+
}
|
138 |
+
}
|
139 |
+
return $mtime;
|
140 |
+
}
|
141 |
+
|
142 |
+
function getId() {
|
143 |
+
return $this->id;
|
144 |
+
}
|
145 |
+
|
146 |
+
function getPath() {
|
147 |
+
return $this->path;
|
148 |
+
}
|
149 |
+
|
150 |
+
function getTsCreated() {
|
151 |
+
return $this->tsCreated;
|
152 |
+
}
|
153 |
+
|
154 |
+
function getTsUpdated() {
|
155 |
+
return $this->tsUpdated;
|
156 |
+
}
|
157 |
+
|
158 |
+
function setId($id) {
|
159 |
+
$this->id = $id;
|
160 |
+
}
|
161 |
+
|
162 |
+
function setPath($path) {
|
163 |
+
$this->path = $path;
|
164 |
+
}
|
165 |
+
|
166 |
+
function getType() {
|
167 |
+
return $this->type;
|
168 |
+
}
|
169 |
+
|
170 |
+
function setType($type) {
|
171 |
+
$this->type = $type;
|
172 |
+
}
|
173 |
+
|
174 |
+
function getStatus() {
|
175 |
+
return $this->status;
|
176 |
+
}
|
177 |
+
|
178 |
+
function setStatus($status) {
|
179 |
+
$this->status = $status;
|
180 |
+
}
|
181 |
+
|
182 |
+
function getFileCount() {
|
183 |
+
return $this->fileCount;
|
184 |
+
}
|
185 |
+
|
186 |
+
function setFileCount($fileCount) {
|
187 |
+
$this->fileCount = $fileCount;
|
188 |
+
}
|
189 |
+
|
190 |
+
function setTsCreated($tsCreated) {
|
191 |
+
$this->tsCreated = $tsCreated;
|
192 |
+
}
|
193 |
+
|
194 |
+
function setTsUpdated($tsUpdated) {
|
195 |
+
$this->tsUpdated = $tsUpdated;
|
196 |
+
}
|
197 |
+
|
198 |
+
}
|
class/model/shortpixel-meta.php
ADDED
@@ -0,0 +1,251 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class ShortPixelMeta extends ShortPixelEntity{
|
4 |
+
const META_VERSION = 1;
|
5 |
+
|
6 |
+
protected $id;
|
7 |
+
protected $folderId;
|
8 |
+
protected $extMetaId;
|
9 |
+
protected $path;
|
10 |
+
protected $name;
|
11 |
+
protected $webPath;
|
12 |
+
protected $compressionType;
|
13 |
+
protected $compressedSize;
|
14 |
+
protected $thumbsOpt;
|
15 |
+
protected $thumbsTodo;
|
16 |
+
protected $keepExif;
|
17 |
+
protected $cmyk2rgb;
|
18 |
+
protected $resize;
|
19 |
+
protected $resizeWidth;
|
20 |
+
protected $resizeHeight;
|
21 |
+
protected $actualWidth;
|
22 |
+
protected $actualHeight;
|
23 |
+
protected $backup;
|
24 |
+
protected $status; //0 waiting, 1 pending, 2 success, -x errors
|
25 |
+
protected $retries;
|
26 |
+
protected $message;
|
27 |
+
protected $tsAdded;
|
28 |
+
protected $tsOptimized;
|
29 |
+
protected $thumbs;
|
30 |
+
|
31 |
+
const TABLE_SUFFIX = 'meta';
|
32 |
+
|
33 |
+
public function __construct($data = array()) {
|
34 |
+
parent::__construct($data);
|
35 |
+
}
|
36 |
+
|
37 |
+
/**
|
38 |
+
* @return meta string to be embedded into the image
|
39 |
+
*/
|
40 |
+
public function getCompressedMeta() {
|
41 |
+
//To be implemented
|
42 |
+
return base64_encode("Not now John.");
|
43 |
+
}
|
44 |
+
|
45 |
+
function getImprovementPercent() {
|
46 |
+
if(is_numeric($this->message)) {
|
47 |
+
return round($this->message,2);
|
48 |
+
}
|
49 |
+
return 0;
|
50 |
+
}
|
51 |
+
|
52 |
+
function getId() {
|
53 |
+
return $this->id;
|
54 |
+
}
|
55 |
+
|
56 |
+
function getPath() {
|
57 |
+
return $this->path;
|
58 |
+
}
|
59 |
+
function getWebPath() {
|
60 |
+
return $this->webPath;
|
61 |
+
}
|
62 |
+
|
63 |
+
function setWebPath($webPath) {
|
64 |
+
$this->webPath = $webPath;
|
65 |
+
}
|
66 |
+
|
67 |
+
function getPathMd5() {
|
68 |
+
return md5($this->path);
|
69 |
+
}
|
70 |
+
|
71 |
+
function getFolderId() {
|
72 |
+
return $this->folderId;
|
73 |
+
}
|
74 |
+
|
75 |
+
function setFolderId($folderId) {
|
76 |
+
$this->folderId = $folderId;
|
77 |
+
}
|
78 |
+
|
79 |
+
function getExtMetaId() {
|
80 |
+
return $this->extMetaId;
|
81 |
+
}
|
82 |
+
|
83 |
+
function setExtMetaId($extMetaId) {
|
84 |
+
$this->extMetaId = $extMetaId;
|
85 |
+
}
|
86 |
+
|
87 |
+
function getCompressionType() {
|
88 |
+
return $this->compressionType;
|
89 |
+
}
|
90 |
+
|
91 |
+
function getKeepExif() {
|
92 |
+
return $this->keepExif;
|
93 |
+
}
|
94 |
+
|
95 |
+
function getBackup() {
|
96 |
+
return $this->backup;
|
97 |
+
}
|
98 |
+
|
99 |
+
function getTsOptimized() {
|
100 |
+
return $this->tsOptimized;
|
101 |
+
}
|
102 |
+
|
103 |
+
function setId($id) {
|
104 |
+
$this->id = $id;
|
105 |
+
}
|
106 |
+
|
107 |
+
function setPath($path) {
|
108 |
+
$this->path = $path;
|
109 |
+
}
|
110 |
+
|
111 |
+
function getName() {
|
112 |
+
return $this->name;
|
113 |
+
}
|
114 |
+
|
115 |
+
function getCompressedSize() {
|
116 |
+
return $this->compressedSize;
|
117 |
+
}
|
118 |
+
|
119 |
+
function setName($name) {
|
120 |
+
$this->name = $name;
|
121 |
+
}
|
122 |
+
|
123 |
+
function setCompressedSize($compressedSize) {
|
124 |
+
$this->compressedSize = $compressedSize;
|
125 |
+
}
|
126 |
+
|
127 |
+
function setCompressionType($compressionType) {
|
128 |
+
$this->compressionType = $compressionType;
|
129 |
+
}
|
130 |
+
|
131 |
+
function getThumbsOpt() {
|
132 |
+
return $this->thumbsOpt;
|
133 |
+
}
|
134 |
+
|
135 |
+
function setThumbsOpt($thumbsOpt) {
|
136 |
+
$this->thumbsOpt = $thumbsOpt;
|
137 |
+
}
|
138 |
+
|
139 |
+
function getThumbsTodo() {
|
140 |
+
return $this->thumbsTodo;
|
141 |
+
}
|
142 |
+
|
143 |
+
function setThumbsTodo($thumbsTodo) {
|
144 |
+
$this->thumbsTodo = $thumbsTodo;
|
145 |
+
}
|
146 |
+
|
147 |
+
function setKeepExif($keepExif) {
|
148 |
+
$this->keepExif = $keepExif;
|
149 |
+
}
|
150 |
+
|
151 |
+
function setBackup($backup) {
|
152 |
+
$this->backup = $backup;
|
153 |
+
}
|
154 |
+
|
155 |
+
function setTsOptimized($tsOptimized) {
|
156 |
+
$this->tsOptimized = $tsOptimized;
|
157 |
+
}
|
158 |
+
|
159 |
+
function getTsAdded() {
|
160 |
+
return $this->tsAdded;
|
161 |
+
}
|
162 |
+
|
163 |
+
function setTsAdded($tsAdded) {
|
164 |
+
$this->tsAdded = $tsAdded;
|
165 |
+
}
|
166 |
+
|
167 |
+
function getCmyk2rgb() {
|
168 |
+
return $this->cmyk2rgb;
|
169 |
+
}
|
170 |
+
|
171 |
+
function getResize() {
|
172 |
+
return $this->resize;
|
173 |
+
}
|
174 |
+
|
175 |
+
function getResizeWidth() {
|
176 |
+
return $this->resizeWidth;
|
177 |
+
}
|
178 |
+
|
179 |
+
function getResizeHeight() {
|
180 |
+
return $this->resizeHeight;
|
181 |
+
}
|
182 |
+
|
183 |
+
function getActualWidth() {
|
184 |
+
return $this->actualWidth;
|
185 |
+
}
|
186 |
+
|
187 |
+
function getActualHeight() {
|
188 |
+
return $this->actualHeight;
|
189 |
+
}
|
190 |
+
|
191 |
+
function setActualWidth($actualWidth) {
|
192 |
+
$this->actualWidth = $actualWidth;
|
193 |
+
}
|
194 |
+
|
195 |
+
function setActualHeight($actualHeight) {
|
196 |
+
$this->actualHeight = $actualHeight;
|
197 |
+
}
|
198 |
+
|
199 |
+
function setCmyk2rgb($cmyk2rgb) {
|
200 |
+
$this->cmyk2rgb = $cmyk2rgb;
|
201 |
+
}
|
202 |
+
|
203 |
+
function setResize($resize) {
|
204 |
+
$this->resize = $resize;
|
205 |
+
}
|
206 |
+
|
207 |
+
function setResizeWidth($resizeWidth) {
|
208 |
+
$this->resizeWidth = $resizeWidth;
|
209 |
+
}
|
210 |
+
|
211 |
+
function setResizeHeight($resizeHeight) {
|
212 |
+
$this->resizeHeight = $resizeHeight;
|
213 |
+
}
|
214 |
+
|
215 |
+
function getStatus() {
|
216 |
+
return $this->status;
|
217 |
+
}
|
218 |
+
|
219 |
+
function getMessage() {
|
220 |
+
return $this->message;
|
221 |
+
}
|
222 |
+
|
223 |
+
function getRetries() {
|
224 |
+
return $this->retries;
|
225 |
+
}
|
226 |
+
|
227 |
+
function setRetries($retries) {
|
228 |
+
$this->retries = $retries;
|
229 |
+
}
|
230 |
+
|
231 |
+
function setStatus($status) {
|
232 |
+
$this->status = $status;
|
233 |
+
}
|
234 |
+
|
235 |
+
function setMessage($message) {
|
236 |
+
$this->message = $message;
|
237 |
+
}
|
238 |
+
|
239 |
+
function getType() {
|
240 |
+
return (isset($this->folderId) ? ShortPixelMetaFacade::CUSTOM_TYPE : ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE);
|
241 |
+
}
|
242 |
+
|
243 |
+
function getThumbs() {
|
244 |
+
return $this->thumbs;
|
245 |
+
}
|
246 |
+
|
247 |
+
function setThumbs($thumbs) {
|
248 |
+
$this->thumbs = $thumbs;
|
249 |
+
}
|
250 |
+
|
251 |
+
}
|
class/model/sp-file-rights-exception.php
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class SpFileRightsException extends Exception {
|
4 |
+
|
5 |
+
}
|
6 |
+
|
class/shortpixel-tools.php
ADDED
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class ShortPixelTools {
|
4 |
+
public static function parseJSON($data) {
|
5 |
+
if ( function_exists('json_decode') ) {
|
6 |
+
$data = json_decode( $data );
|
7 |
+
} else {
|
8 |
+
require_once( 'JSON/JSON.php' );
|
9 |
+
$json = new Services_JSON( );
|
10 |
+
$data = $json->decode( $data );
|
11 |
+
}
|
12 |
+
return $data;
|
13 |
+
}
|
14 |
+
|
15 |
+
public static function snakeToCamel($snake_case) {
|
16 |
+
return str_replace(' ', '', ucwords(str_replace('_', ' ', $snake_case)));
|
17 |
+
}
|
18 |
+
|
19 |
+
public static function requestIsFrontendAjax()
|
20 |
+
{
|
21 |
+
$script_filename = isset($_SERVER['SCRIPT_FILENAME']) ? $_SERVER['SCRIPT_FILENAME'] : '';
|
22 |
+
|
23 |
+
//Try to figure out if frontend AJAX request... If we are DOING_AJAX; let's look closer
|
24 |
+
if((defined('DOING_AJAX') && DOING_AJAX))
|
25 |
+
{
|
26 |
+
//From wp-includes/functions.php, wp_get_referer() function.
|
27 |
+
//Required to fix: https://core.trac.wordpress.org/ticket/25294
|
28 |
+
$ref = '';
|
29 |
+
if ( ! empty( $_REQUEST['_wp_http_referer'] ) ) {
|
30 |
+
$ref = wp_unslash( $_REQUEST['_wp_http_referer'] );
|
31 |
+
} elseif ( ! empty( $_SERVER['HTTP_REFERER'] ) ) {
|
32 |
+
$ref = wp_unslash( $_SERVER['HTTP_REFERER'] );
|
33 |
+
}
|
34 |
+
//If referer does not contain admin URL and we are using the admin-ajax.php endpoint, this is likely a frontend AJAX request
|
35 |
+
if(((strpos($ref, admin_url()) === false) && (basename($script_filename) === 'admin-ajax.php')))
|
36 |
+
return true;
|
37 |
+
}
|
38 |
+
|
39 |
+
//If no checks triggered, we end up here - not an AJAX request.
|
40 |
+
return false;
|
41 |
+
}
|
42 |
+
}
|
class/view/shortpixel-list-table.php
ADDED
@@ -0,0 +1,180 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
if( ! class_exists( 'WP_List_Table' ) ) {
|
4 |
+
require_once( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' );
|
5 |
+
}
|
6 |
+
|
7 |
+
class ShortPixelListTable extends WP_List_Table {
|
8 |
+
|
9 |
+
protected $ctrl;
|
10 |
+
protected $spMetaDao;
|
11 |
+
protected $hasNextGen;
|
12 |
+
|
13 |
+
public function __construct($ctrl, $spMetaDao, $hasNextGen) {
|
14 |
+
parent::__construct( [
|
15 |
+
'singular' => 'Image', //singular name of the listed records
|
16 |
+
'plural' => 'Images', //plural name of the listed records
|
17 |
+
'ajax' => false //should this table support ajax?
|
18 |
+
] );
|
19 |
+
$this->ctrl = $ctrl;
|
20 |
+
$this->spMetaDao = $spMetaDao;
|
21 |
+
$this->hasNextGen = $hasNextGen;
|
22 |
+
}
|
23 |
+
|
24 |
+
// define the columns to display, the syntax is 'internal name' => 'display name'
|
25 |
+
function get_columns() {
|
26 |
+
$columns = array();
|
27 |
+
|
28 |
+
//pe viitor. $columns['cb'] = '<input type="checkbox" />';
|
29 |
+
$columns['name'] = 'Filename';
|
30 |
+
$columns['folder'] = 'Folder';
|
31 |
+
$columns['media_type'] = 'Type';
|
32 |
+
$columns['status'] = 'Status';
|
33 |
+
$columns['options'] = 'Options';
|
34 |
+
//$columns = apply_filters('shortpixel_list_columns', $columns);
|
35 |
+
|
36 |
+
return $columns;
|
37 |
+
}
|
38 |
+
|
39 |
+
function column_cb( $item ) {
|
40 |
+
return sprintf('<input type="checkbox" name="bulk-optimize[]" value="%s" />', $item->id);
|
41 |
+
}
|
42 |
+
|
43 |
+
function column_default( $item, $column_name ) {
|
44 |
+
switch( $column_name ) {
|
45 |
+
case 'name':
|
46 |
+
$title = '<a href="" title="'.$item->folder.'"><strong>' . $item->name . '</strong></a>';
|
47 |
+
|
48 |
+
$actions = array();
|
49 |
+
if($item->status <= 1) {
|
50 |
+
// create the image web path
|
51 |
+
$actions = [
|
52 |
+
'optimize' => sprintf( '<a href="?page=%s&action=%s&image=%s&_wpnonce=%s">' . ($item->status == 0 ? 'Optimize' : 'Retry') . '</a>',
|
53 |
+
esc_attr( $_REQUEST['page'] ), 'optimize', absint( $item->id ), wp_create_nonce( 'sp_optimize_image' ) )
|
54 |
+
];
|
55 |
+
}
|
56 |
+
$url = ShortPixelMetaFacade::pathToWebPath($item->folder);
|
57 |
+
$actions['view'] = sprintf( '<a href="%s" target="_blank">View</a>', $url );
|
58 |
+
$title = $title . $this->row_actions( $actions );
|
59 |
+
return $title;
|
60 |
+
case 'folder':
|
61 |
+
return ShortPixelMetaFacade::pathToContentRelative($item->folder);
|
62 |
+
case 'status':
|
63 |
+
switch($item->status) {
|
64 |
+
case 2: $msg = 0 + $item->message == 0 ? "Bonus processing" : "Reduced by " . $item->message . "%" . (0 + $item->message < 5 ? "<br>Bonus processing." : "");
|
65 |
+
break;
|
66 |
+
case 1: $msg = "Pending";
|
67 |
+
break;
|
68 |
+
case 0: $msg = "Waiting";
|
69 |
+
break;
|
70 |
+
default:
|
71 |
+
if($item->status < 0) {
|
72 |
+
$msg = $item->message . "(code: " . $item->status . ")";
|
73 |
+
} else {
|
74 |
+
$msg = "";
|
75 |
+
}
|
76 |
+
}
|
77 |
+
return "<div id='sp-cust-msg-C-" . $item->id . "'>" . $msg . "</div>";
|
78 |
+
break;
|
79 |
+
case 'options':
|
80 |
+
return ($item->compression_type == 1 ? "Lossy" : "Lossless")
|
81 |
+
. ($item->keep_exif == 1 ? "": ", Keep EXIF")
|
82 |
+
. ($item->cmyk2rgb ? "": ", Preserve CMYK");
|
83 |
+
case 'media_type':
|
84 |
+
return $item->$column_name;
|
85 |
+
default:
|
86 |
+
return print_r( $item, true ) ; //Show the whole array for troubleshooting purposes
|
87 |
+
}
|
88 |
+
}
|
89 |
+
|
90 |
+
public function no_items() {
|
91 |
+
echo('No images avaliable. Go to <a href="options-general.php?page=wp-shortpixel#adv-settings">Advanced Settings</a> to configure additional folders to be optimized.');
|
92 |
+
}
|
93 |
+
|
94 |
+
/**
|
95 |
+
* Columns to make sortable.
|
96 |
+
*
|
97 |
+
* @return array
|
98 |
+
*/
|
99 |
+
public function get_sortable_columns() {
|
100 |
+
$sortable_columns = array(
|
101 |
+
'name' => array( 'name', true ),
|
102 |
+
'folder' => array( 'folder', true ),
|
103 |
+
'status' => array( 'status', false )
|
104 |
+
);
|
105 |
+
|
106 |
+
return $sortable_columns;
|
107 |
+
}
|
108 |
+
|
109 |
+
/**
|
110 |
+
* Handles data query and filter, sorting, and pagination.
|
111 |
+
*/
|
112 |
+
public function prepare_items() {
|
113 |
+
|
114 |
+
$this->_column_headers = $this->get_column_info();
|
115 |
+
|
116 |
+
$this->_column_headers[0] = $this->get_columns();
|
117 |
+
|
118 |
+
/** Process actions */
|
119 |
+
$this->process_actions();
|
120 |
+
|
121 |
+
$perPage = $this->get_items_per_page( 'images_per_page', 20 );
|
122 |
+
$currentPage = $this->get_pagenum();
|
123 |
+
$total_items = $this->record_count();
|
124 |
+
|
125 |
+
$this->set_pagination_args( [
|
126 |
+
'total_items' => $total_items, //WE have to calculate the total number of items
|
127 |
+
'per_page' => $perPage //WE have to determine how many items to show on a page
|
128 |
+
] );
|
129 |
+
|
130 |
+
$orderby = ( ! empty( $_GET['orderby'] ) ) ? $_GET['orderby'] : 'ts_added';
|
131 |
+
// If no order, default to asc
|
132 |
+
$order = ( ! empty($_GET['order'] ) ) ? $_GET['order'] : 'desc';
|
133 |
+
|
134 |
+
$this->items = $this->spMetaDao->getPaginatedMetas($this->hasNextGen, $perPage, $currentPage, $orderby, $order);
|
135 |
+
return $this->items;
|
136 |
+
}
|
137 |
+
|
138 |
+
public function record_count() {
|
139 |
+
return $this->spMetaDao->getCustomMetaCount();
|
140 |
+
}
|
141 |
+
|
142 |
+
public function action_optimize_image( $id ) {
|
143 |
+
$this->ctrl->optimizeCustomImage($id);
|
144 |
+
}
|
145 |
+
|
146 |
+
public function process_actions() {
|
147 |
+
|
148 |
+
//Detect when a bulk action is being triggered...
|
149 |
+
if ('optimize' === $this->current_action()) {
|
150 |
+
|
151 |
+
// In our file that handles the request, verify the nonce.
|
152 |
+
$nonce = esc_attr($_REQUEST['_wpnonce']);
|
153 |
+
|
154 |
+
if (!wp_verify_nonce($nonce, 'sp_optimize_image')) {
|
155 |
+
die('Error.');
|
156 |
+
} else {
|
157 |
+
$this->action_optimize_image(absint($_GET['image']));
|
158 |
+
|
159 |
+
wp_redirect(esc_url(add_query_arg()));
|
160 |
+
exit;
|
161 |
+
}
|
162 |
+
}
|
163 |
+
|
164 |
+
// If the delete bulk action is triggered
|
165 |
+
if (( isset($_POST['action']) && $_POST['action'] == 'bulk-optimize' ) || ( isset($_POST['action2']) && $_POST['action2'] == 'bulk-optimize' )
|
166 |
+
) {
|
167 |
+
|
168 |
+
$optimize_ids = esc_sql($_POST['bulk-optimize']);
|
169 |
+
|
170 |
+
// loop over the array of record IDs and delete them
|
171 |
+
foreach ($optimize_ids as $id) {
|
172 |
+
$this->action_optimize_image($id);
|
173 |
+
}
|
174 |
+
|
175 |
+
wp_redirect(esc_url(add_query_arg()));
|
176 |
+
exit;
|
177 |
+
}
|
178 |
+
}
|
179 |
+
|
180 |
+
}
|
class/view/shortpixel_view.php
ADDED
@@ -0,0 +1,971 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class ShortPixelView {
|
4 |
+
|
5 |
+
private $ctrl;
|
6 |
+
|
7 |
+
public function __construct($controller) {
|
8 |
+
$this->ctrl = $controller;
|
9 |
+
}
|
10 |
+
|
11 |
+
//handling older
|
12 |
+
public function ShortPixelView($controller) {
|
13 |
+
$this->__construct($controller);
|
14 |
+
}
|
15 |
+
|
16 |
+
public function displayQuotaExceededAlert($quotaData)
|
17 |
+
{ ?>
|
18 |
+
<br/>
|
19 |
+
<div class="wrap sp-quota-exceeded-alert">
|
20 |
+
<h3>Quota Exceeded</h3>
|
21 |
+
<p>The plugin has optimized <strong><?php echo(number_format($quotaData['APICallsMadeNumeric'] + $quotaData['APICallsMadeOneTimeNumeric']));?> images</strong> and stopped because it reached the available quota limit.
|
22 |
+
<?php if($quotaData['totalProcessedFiles'] < $quotaData['totalFiles']) { ?>
|
23 |
+
<strong><?php echo(number_format($quotaData['mainFiles'] - $quotaData['mainProcessedFiles']));?> images and
|
24 |
+
<?php echo(number_format(($quotaData['totalFiles'] - $quotaData['mainFiles']) - ($quotaData['totalProcessedFiles'] - $quotaData['mainProcessedFiles'])));?> thumbnails</strong> are not yet optimized by ShortPixel.
|
25 |
+
<?php } ?></p>
|
26 |
+
<div> <!-- style='float:right;margin-top:20px;'> -->
|
27 |
+
<a class='button button-primary' href='https://shortpixel.com/login/<?php echo($this->ctrl->getApiKey());?>' target='_blank'>Upgrade</a>
|
28 |
+
<input type='button' name='checkQuota' class='button' value='Confirm New Quota' onclick="javascript:window.location.reload();">
|
29 |
+
</div>
|
30 |
+
<!-- <p>It’s simple to upgrade, just <a href='https://shortpixel.com/login/<?php echo($this->ctrl->getApiKey());?>' target='_blank'>log into your account</a> and see the available options.
|
31 |
+
You can immediately start processing 5,000 images/month for $4,99, choose another plan that suits you or <a href='https://shortpixel.com/contact' target='_blank'>contact us</a> for larger compression needs.</p> -->
|
32 |
+
<p>Get more image credits by referring ShortPixel to your friends! <a href="https://shortpixel.com/login/<?php echo($this->ctrl->getApiKey());?>/tell-a-friend" target="_blank">Check your account</a> for your unique referral link. For each user that joins, you will receive +100 additional image credits/month.</p>
|
33 |
+
|
34 |
+
</div> <?php
|
35 |
+
}
|
36 |
+
|
37 |
+
public static function displayApiKeyAlert()
|
38 |
+
{ ?>
|
39 |
+
<p>In order to start the optimization process, you need to validate your API Key in the <a href="options-general.php?page=wp-shortpixel">ShortPixel Settings</a> page in your WordPress Admin.</p>
|
40 |
+
<p>If you don’t have an API Key, you can get one delivered to your inbox, for free.</p>
|
41 |
+
<p>Please <a href="https://shortpixel.com/wp-apikey" target="_blank">sign up</a> to get your API key.</p>
|
42 |
+
<?php
|
43 |
+
}
|
44 |
+
|
45 |
+
public static function displayActivationNotice($when = 'activate') { ?>
|
46 |
+
<div class='notice notice-warning' id='short-pixel-notice-<?php echo($when);?>'>
|
47 |
+
<?php if($when != 'activate') { ?>
|
48 |
+
<div style="float:right;"><a href="javascript:dismissShortPixelNotice('<?php echo($when);?>')" class="button" style="margin-top:10px;">Dismiss</a></div>
|
49 |
+
<?php } ?>
|
50 |
+
<h3>ShortPixel Optimization</h3> <?php
|
51 |
+
switch($when) {
|
52 |
+
case '2h' :
|
53 |
+
echo "Action needed. Please <a href='https://shortpixel.com/wp-apikey' target='_blank'>get your API key</a> to activate your ShortPixel plugin.<BR><BR>";
|
54 |
+
break;
|
55 |
+
case '3d':
|
56 |
+
echo "Your image gallery is not optimized. It takes 2 minutes to <a href='https://shortpixel.com/wp-apikey' target='_blank'>get your API key</a> and activate your ShortPixel plugin.<BR><BR>";
|
57 |
+
break;
|
58 |
+
case 'activate':
|
59 |
+
self::displayApiKeyAlert();
|
60 |
+
break;
|
61 |
+
}
|
62 |
+
?>
|
63 |
+
</div>
|
64 |
+
<?php
|
65 |
+
}
|
66 |
+
|
67 |
+
public function displayBulkProcessingForm($quotaData, $thumbsProcessedCount, $under5PercentCount, $bulkRan,
|
68 |
+
$averageCompression, $filesOptimized, $savedSpace, $percent, $customCount) {
|
69 |
+
?>
|
70 |
+
<div class="wrap short-pixel-bulk-page">
|
71 |
+
<h1>Bulk Image Optimization by ShortPixel</h1>
|
72 |
+
<?php
|
73 |
+
if ( !$bulkRan ) {
|
74 |
+
?>
|
75 |
+
<div class="notice notice-info sp-floating-block sp-full-width">
|
76 |
+
<form class='start' action='' method='POST' id='startBulk'>
|
77 |
+
<input type='hidden' id='mainToProcess' value='<?php echo($quotaData['mainFiles'] - $quotaData['mainProcessedFiles']);?>'/>
|
78 |
+
<input type='hidden' id='totalToProcess' value='<?php echo($quotaData['totalFiles'] - $quotaData['totalProcessedFiles']);?>'/>
|
79 |
+
<div class="bulk-stats-container">
|
80 |
+
<h3 style='margin-top:0;'>Your media library</h3>
|
81 |
+
<div class="bulk-label">Original images</div>
|
82 |
+
<div class="bulk-val"><?php echo(number_format($quotaData['mainMlFiles']));?></div><br>
|
83 |
+
<div class="bulk-label">Smaller thumbnails</div>
|
84 |
+
<div class="bulk-val"><?php echo(number_format($quotaData['totalMlFiles'] - $quotaData['mainMlFiles']));?></div>
|
85 |
+
<div style='width:165px; display:inline-block; padding-left: 5px'>
|
86 |
+
<input type='checkbox' id='thumbnails' name='thumbnails' onclick='ShortPixel.checkThumbsUpdTotal(this)' <?php echo($this->ctrl->processThumbnails() ? "checked":"");?>> Include thumbnails
|
87 |
+
</div><br>
|
88 |
+
<?php if($quotaData["totalProcessedMlFiles"] > 0) { ?>
|
89 |
+
<div class="bulk-label bulk-total">Total images</div>
|
90 |
+
<div class="bulk-val bulk-total"><?php echo(number_format($quotaData['totalMlFiles']));?></div>
|
91 |
+
<br><div class="bulk-label">Already optimized originals</div>
|
92 |
+
<div class="bulk-val"><?php echo(number_format($quotaData['mainProcessedMlFiles']));?></div><br>
|
93 |
+
<div class="bulk-label">Already optimized thumbnails</div>
|
94 |
+
<div class="bulk-val"><?php echo(number_format($quotaData['totalProcessedMlFiles'] - $quotaData['mainProcessedMlFiles']));?></div><br>
|
95 |
+
<?php } ?>
|
96 |
+
<div class="bulk-label bulk-total">Total to be optimized</div>
|
97 |
+
<div class="bulk-val bulk-total" id='displayTotal'><?php echo(number_format($quotaData['totalMlFiles'] - $quotaData['totalProcessedMlFiles']));?></div>
|
98 |
+
|
99 |
+
<?php if($customCount > 0) { ?>
|
100 |
+
<h3 style='margin-bottom:10px;'>Your custom folders</h3>
|
101 |
+
<div class="bulk-label bulk-total">Total to be optimized</div>
|
102 |
+
<div class="bulk-val bulk-total" id='displayTotal'><?php echo(number_format($customCount));?></div>
|
103 |
+
<?php } ?>
|
104 |
+
</div>
|
105 |
+
<?php if($quotaData['totalFiles'] - $quotaData['totalProcessedFiles'] + $customCount > 0) { ?>
|
106 |
+
<div class="bulk-play">
|
107 |
+
<input type='hidden' name='bulkProcess' id='bulkProcess' value='Start Optimizing'/>
|
108 |
+
<a href='javascript:void(0);' onclick="document.getElementById('startBulk').submit();" class='button'>
|
109 |
+
<div style="width: 320px">
|
110 |
+
<div class="bulk-btn-img" class="bulk-btn-img">
|
111 |
+
<img src='<?php echo(plugins_url( 'shortpixel-image-optimiser/res/img/robo-slider.png' ));?>'/>
|
112 |
+
</div>
|
113 |
+
<div class="bulk-btn-txt">
|
114 |
+
<span class="label">Start Optimizing</span><br>
|
115 |
+
<span class='total'><?php echo(number_format($quotaData['totalFiles'] - $quotaData['totalProcessedFiles']));?></span> images
|
116 |
+
</div>
|
117 |
+
<div class="bulk-btn-img" class="bulk-btn-img">
|
118 |
+
<img src='<?php echo(plugins_url( 'shortpixel-image-optimiser/res/img/arrow.png' ));?>'/>
|
119 |
+
</div>
|
120 |
+
</div>
|
121 |
+
</a>
|
122 |
+
</div>
|
123 |
+
<?php } else {?>
|
124 |
+
<div class="bulk-play bulk-nothing-optimize">
|
125 |
+
Nothing to optimize! The images that you add to Media Gallery will be automatically optimized after upload.
|
126 |
+
</div>
|
127 |
+
<?php } ?>
|
128 |
+
</form>
|
129 |
+
</div>
|
130 |
+
<?php if($quotaData['totalFiles'] - $quotaData['totalProcessedFiles'] > 0) { ?>
|
131 |
+
<div class='shortpixel-clearfix'></div>
|
132 |
+
<div class="bulk-wide">
|
133 |
+
<h3 style='font-size: 1.1em; font-weight: bold;'>After you start the bulk process, in order for the optimization to run, you must keep this page open and your computer running. If you close the page for whatever reason, just turn back to it and the bulk process will resume.</h3>
|
134 |
+
</div>
|
135 |
+
<?php } ?>
|
136 |
+
<div class='shortpixel-clearfix'></div>
|
137 |
+
<div class="bulk-text-container">
|
138 |
+
<h3>What are Thumbnails?</h3>
|
139 |
+
<p>Thumbnails are smaller images usually generated by your WP theme. Most themes generate between 3 and 6 thumbnails for each Media Library image.</p>
|
140 |
+
<p>The thumbnails also generate traffic on your website pages and they influence your website's speed.</p>
|
141 |
+
<p>It's highly recommended that you include thumbnails in the optimization as well.</p>
|
142 |
+
</div>
|
143 |
+
<div class="bulk-text-container" style="padding-right:0">
|
144 |
+
<h3>How does it work?</h3>
|
145 |
+
<p>The plugin processes images starting with the newest ones you uploaded in your Media Library.</p>
|
146 |
+
<p>You will be able to pause the process anytime.</p>
|
147 |
+
<p><?php echo($this->ctrl->backupImages() ? "<p>Your original images will be stored in a separate back-up folder.</p>" : "");?></p>
|
148 |
+
<p>You can watch the images being processed live, right here, after you start optimizing.</p>
|
149 |
+
</div>
|
150 |
+
<?php
|
151 |
+
} elseif($percent) // bulk is paused
|
152 |
+
{ ?>
|
153 |
+
<?php echo($this->displayBulkProgressBar(false, $percent, "", $quotaData['APICallsRemaining'], $this->ctrl->getAverageCompression(), 1, $customCount));?>
|
154 |
+
<p>Please see below the optimization status so far:</p>
|
155 |
+
<?php $this->displayBulkStats($quotaData['totalProcessedFiles'], $quotaData['mainProcessedFiles'], $under5PercentCount, $averageCompression, $savedSpace);?>
|
156 |
+
<?php if($quotaData['totalProcessedFiles'] < $quotaData['totalFiles']) { ?>
|
157 |
+
<p><?php echo(number_format($quotaData['mainFiles'] - $quotaData['mainProcessedFiles']));?> images and
|
158 |
+
<?php echo(number_format(($quotaData['totalFiles'] - $quotaData['mainFiles']) - ($quotaData['totalProcessedFiles'] - $quotaData['mainProcessedFiles'])));
|
159 |
+
?> thumbnails are not yet optimized by ShortPixel.</p>
|
160 |
+
<?php } ?>
|
161 |
+
<p>You can continue optimizing your Media Gallery from where you left, by clicking the Resume processing button. Already optimized images will not be reprocessed.</p>
|
162 |
+
<?php
|
163 |
+
} else { ?>
|
164 |
+
<div class="sp-container">
|
165 |
+
<div class='notice notice-success sp-floating-block sp-single-width' style="height: 80px;overflow:hidden;">
|
166 |
+
<div style='float:left;margin:5px 20px 5px 0'><img src="<?php echo(plugins_url( 'shortpixel-image-optimiser/res/img/slider.png' ));?>"></div>
|
167 |
+
<div class="sp-bulk-summary">
|
168 |
+
<input type="text" value="<?php echo("" . round($averageCompression))?>" id="sp-total-optimization-dial" class="dial">
|
169 |
+
</div>
|
170 |
+
<p style="margin-top:4px;">
|
171 |
+
<span style="font-size:1.2em;font-weight:bold">Congratulations!</span><br>Your media library has been successfully optimized!
|
172 |
+
<span class="sp-bulk-summary"><a href='javascript:void(0);'>Summary</a></span>
|
173 |
+
</p>
|
174 |
+
</div>
|
175 |
+
<div class='notice notice-success sp-floating-block sp-single-width' style="height: 80px;overflow:hidden;padding-right: 0;">
|
176 |
+
<div style="float:left; margin-top:-5px">
|
177 |
+
<p style='margin-bottom: -2px; font-weight: bold;'>
|
178 |
+
Share your optimization results:
|
179 |
+
</p>
|
180 |
+
<div style='display:inline-block; margin: 16px 16px 6px 0;float:left'>
|
181 |
+
<div id="fb-root"></div>
|
182 |
+
<script>
|
183 |
+
(function(d, s, id) {
|
184 |
+
var js, fjs = d.getElementsByTagName(s)[0];
|
185 |
+
if (d.getElementById(id)) return;
|
186 |
+
js = d.createElement(s); js.id = id;
|
187 |
+
js.src = "//connect.facebook.net/ro_RO/sdk.js#xfbml=1&version=v2.6";
|
188 |
+
fjs.parentNode.insertBefore(js, fjs);
|
189 |
+
}(document, 'script', 'facebook-jssdk'));
|
190 |
+
</script>
|
191 |
+
<div style="float:left;width:240px;">
|
192 |
+
<div class="fb-like" data-href="https://www.facebook.com/ShortPixel" data-width="260" data-layout="button_count" data-action="like" data-show-faces="true" data-share="true"></div>
|
193 |
+
</div>
|
194 |
+
<div style="float:left;margin:-7px 0 0 10px">
|
195 |
+
<a href="https://twitter.com/share" class="twitter-share-button" data-url="https://shortpixel.com"
|
196 |
+
data-text="I just optimized my images<?php echo(0+$averageCompression>20 ? " by ".round($averageCompression) ."%" : "");?><?php echo(false && (0+$savedSpace>0) ? " saving $savedSpace" : "");?> with @ShortPixel, a great plugin for increasing #WordPress page speed:" data-size='large'>Tweet</a>
|
197 |
+
</div>
|
198 |
+
<script>
|
199 |
+
jQuery(function() {
|
200 |
+
jQuery("#sp-total-optimization-dial").val("<?php echo("" . round($averageCompression))?>");
|
201 |
+
ShortPixel.percentDial("#sp-total-optimization-dial", 60);
|
202 |
+
|
203 |
+
jQuery(".sp-bulk-summary").tooltip({
|
204 |
+
tooltipSource: "inline",
|
205 |
+
tooltipSourceID: "#sp-bulk-stats"
|
206 |
+
});
|
207 |
+
});
|
208 |
+
!function(d,s,id){//Just optimized my site with ShortPixel image optimization plugin
|
209 |
+
var js,
|
210 |
+
fjs=d.getElementsByTagName(s)[0],
|
211 |
+
p=/^http:/.test(d.location)?'http':'https';
|
212 |
+
if(!d.getElementById(id)){js=d.createElement(s);
|
213 |
+
js.id=id;js.src=p+'://platform.twitter.com/widgets.js';
|
214 |
+
fjs.parentNode.insertBefore(js,fjs);}}(document, 'script', 'twitter-wjs');
|
215 |
+
</script>
|
216 |
+
</div>
|
217 |
+
</div>
|
218 |
+
<?php if(0+$averageCompression>30) {?>
|
219 |
+
<div class='shortpixel-rate-us' style='float:left;padding-top:0'>
|
220 |
+
<a href="https://wordpress.org/support/view/plugin-reviews/shortpixel-image-optimiser?rate=5#postform" target="_blank">
|
221 |
+
<span>
|
222 |
+
Please rate us!
|
223 |
+
</span><br><img src="<?php echo(plugins_url( 'shortpixel-image-optimiser/res/img/stars.png' ));?>">
|
224 |
+
</a>
|
225 |
+
</div>
|
226 |
+
<?php } ?>
|
227 |
+
</div>
|
228 |
+
<div id="sp-bulk-stats" style="display:none">
|
229 |
+
<?php $this->displayBulkStats($quotaData['totalProcessedFiles'], $quotaData['mainProcessedFiles'], $under5PercentCount, $averageCompression, $savedSpace);?>
|
230 |
+
</div>
|
231 |
+
</div>
|
232 |
+
<p>Go to the ShortPixel <a href='<?php echo(get_admin_url());?>options-general.php?page=wp-shortpixel#stats'>Stats</a> and see all your websites' optimized stats. Download your detailed <a href="https://api.shortpixel.com/v2/report.php?key=<?php echo($this->ctrl->getApiKey());?>">Optimization Report</a> to check your image optimization statistics for the last 40 days.</p>
|
233 |
+
<?php
|
234 |
+
$failed = $this->ctrl->getPrioQ()->getFailed();
|
235 |
+
if(count($failed)) { ?>
|
236 |
+
<div class="bulk-progress" style="margin-bottom: 15px">
|
237 |
+
<p>
|
238 |
+
The following images could not be processed because of their limited write rights. This usually happens if you have changed your hosting provider. Please restart the optimization process after you granted write rights to all the files below.
|
239 |
+
</p>
|
240 |
+
<?php $this->displayFailed($failed); ?>
|
241 |
+
</div>
|
242 |
+
<?php } ?>
|
243 |
+
<div class="bulk-progress notice notice-info sp-floating-block sp-double-width">
|
244 |
+
<?php
|
245 |
+
$todo = $reopt = false;
|
246 |
+
if($quotaData['totalProcessedFiles'] < $quotaData['totalFiles']) {
|
247 |
+
$todo = true;
|
248 |
+
$mainNotProcessed = $quotaData['mainFiles'] - $quotaData['mainProcessedFiles'];
|
249 |
+
$thumbsNotProcessed = ($quotaData['totalFiles'] - $quotaData['mainFiles']) - ($quotaData['totalProcessedFiles'] - $quotaData['mainProcessedFiles']);
|
250 |
+
?>
|
251 |
+
<p>
|
252 |
+
<?php echo($mainNotProcessed ? number_format($mainNotProcessed) . " images" : "");?>
|
253 |
+
<?php echo($mainNotProcessed && $thumbsNotProcessed ? " and" : "");?>
|
254 |
+
<?php echo($thumbsNotProcessed ? number_format($thumbsNotProcessed) . " thumbnails" : "");?> are not yet optimized by ShortPixel.
|
255 |
+
<?php if (count($quotaData['filesWithErrors'])) { ?>
|
256 |
+
Some have errors:
|
257 |
+
<?php foreach($quotaData['filesWithErrors'] as $id => $data) {
|
258 |
+
if(ShortPixelMetaFacade::isCustomQueuedId($id)) {
|
259 |
+
echo('<a href="'.trailingslashit(network_site_url("/")) . 'wp-content/' . ShortPixelMetaFacade::filenameToContentRelative($data['Path']).'" title="'.$data['Message'].'" target="_blank">'.$data['Name'].'</a>, ');
|
260 |
+
} else {
|
261 |
+
echo('<a href="post.php?post='.$id.'&action=edit" title="'.$data['Message'].'">'.$data['Name'].'</a>, ');
|
262 |
+
}
|
263 |
+
} ?>
|
264 |
+
<?php } ?>
|
265 |
+
</p>
|
266 |
+
<?php }
|
267 |
+
$settings = $this->ctrl->getSettings();
|
268 |
+
$optType = $settings->compressionType == '1' ? 'lossy' : 'lossless';
|
269 |
+
$otherType = $settings->compressionType == '1' ? 'lossless' : 'lossy';
|
270 |
+
if( !$this->ctrl->backupFolderIsEmpty()
|
271 |
+
&& ( ($quotaData['totalProcLossyFiles'] > 0 && $settings->compressionType == 0)
|
272 |
+
|| ($quotaData['totalProcLosslessFiles'] > 0 && $settings->compressionType == 1)))
|
273 |
+
{
|
274 |
+
$todo = $reopt = true;
|
275 |
+
$statType = $settings->compressionType == '1' ? 'Lossless' : 'Lossy';
|
276 |
+
$thumbsCount = $quotaData['totalProc'.$statType.'Files'] - $quotaData['mainProc'.$statType.'Files'];
|
277 |
+
?>
|
278 |
+
<p id="with-thumbs" <?php echo(!$settings->processThumbnails ? 'style="display:none;"' : "");?>>
|
279 |
+
<?php echo(number_format($quotaData['mainProc'.$statType.'Files']));?> images and
|
280 |
+
<?php echo(number_format($quotaData['totalProc'.$statType.'Files'] - $quotaData['mainProc'.$statType.'Files']));?> thumbnails were optimized
|
281 |
+
<strong>
|
282 |
+
<?php echo($otherType);?>
|
283 |
+
</strong>. You can re-optimize
|
284 |
+
<strong>
|
285 |
+
<?php echo($optType);?>
|
286 |
+
</strong> the ones that have backup.
|
287 |
+
</p>
|
288 |
+
<p id="without-thumbs" <?php echo($settings->processThumbnails ? 'style="display:none;"' : "");?>>
|
289 |
+
<?php echo(number_format($quotaData['mainProc'.$statType.'Files']));?> images are optimized
|
290 |
+
<strong>
|
291 |
+
<?php echo($otherType);?>
|
292 |
+
</strong>. You can re-optimize
|
293 |
+
<strong>
|
294 |
+
<?php echo($optType);?>
|
295 |
+
</strong> the ones that have backup.
|
296 |
+
<?php echo($thumbsCount ? number_format($thumbsCount) . ' thumbnails will be restored to originals.' : '');?>
|
297 |
+
</p>
|
298 |
+
<?php
|
299 |
+
} ?>
|
300 |
+
<p>Restart the optimization process for <?php echo($todo ? 'these images' : 'new images added to your library');?> by clicking the button below.
|
301 |
+
Already <strong><?php echo($todo ? ($optType) : '');?></strong> optimized images will not be reprocessed.
|
302 |
+
<?php if($reopt) { ?>
|
303 |
+
<br>Please note that reoptimizing images as <strong>lossy/lossless</strong> may use additional credits. <a href="http://blog.shortpixel.com/the-all-new-re-optimization-functions-in-shortpixel/" target="_blank">More info</a>
|
304 |
+
<?php } ?>
|
305 |
+
</p>
|
306 |
+
<form action='' method='POST' >
|
307 |
+
<input type='checkbox' id='bulk-thumbnails' name='thumbnails' <?php echo($this->ctrl->processThumbnails() ? "checked":"");?> onchange="ShortPixel.onBulkThumbsCheck(this)"> Include thumbnails<br><br>
|
308 |
+
<input type='submit' name='bulkProcess' id='bulkProcess' class='button button-primary' value='Restart Optimizing'>
|
309 |
+
</form>
|
310 |
+
</div>
|
311 |
+
<?php } ?>
|
312 |
+
</div>
|
313 |
+
<?php
|
314 |
+
}
|
315 |
+
|
316 |
+
public function displayBulkProcessingRunning($percent, $message, $remainingQuota, $averageCompression, $type) {
|
317 |
+
?>
|
318 |
+
<div class="wrap short-pixel-bulk-page">
|
319 |
+
<h1>Bulk Image Optimization by ShortPixel</h1>
|
320 |
+
<?php $this->displayBulkProgressBar(true, $percent, $message, $remainingQuota, $averageCompression, $type);?>
|
321 |
+
<div class="sp-floating-block notice bulk-notices-parent">
|
322 |
+
<div class="bulk-notice-container">
|
323 |
+
<div class="bulk-notice-msg bulk-lengthy">
|
324 |
+
<img src="<?php echo(plugins_url( 'shortpixel-image-optimiser/res/img/loading-dark-big.gif' ));?>">
|
325 |
+
Lengthy operation in progress:<br>
|
326 |
+
Optimizing image <a href="#" data-href="<?php echo(get_admin_url());?>/post.php?post=__ID__&action=edit" target="_blank">lala.png</a>
|
327 |
+
</div>
|
328 |
+
<div class="bulk-notice-msg bulk-error" id="bulk-error-template">
|
329 |
+
<div style="float: right; margin-top: -4px; margin-right: -8px;">
|
330 |
+
<a href="javascript:void(0);" onclick="ShortPixel.removeBulkMsg(this)" style='color: #c32525;'>✖</a>
|
331 |
+
</div>
|
332 |
+
<img src="<?php echo(plugins_url( 'shortpixel-image-optimiser/res/img/exclamation-big.png' ));?>">
|
333 |
+
<span class="sp-err-title">Error processing file:<br></span>
|
334 |
+
<span class="sp-err-content"><?php echo $message; ?></span> <a class="sp-post-link" href="<?php echo(get_admin_url());?>/post.php?post=__ID__&action=edit" target="_blank">lala.png</a>
|
335 |
+
</div>
|
336 |
+
</div>
|
337 |
+
</div>
|
338 |
+
<div class="bulk-progress bulk-slider-container notice notice-info sp-floating-block sp-full-width">
|
339 |
+
<div class="short-pixel-block-title"><span>Just optimized:</span><span class="filename"></span></div>
|
340 |
+
<div class="bulk-slider">
|
341 |
+
<div class="bulk-slide" id="empty-slide">
|
342 |
+
<div class="bulk-slide-images">
|
343 |
+
<div class="img-original">
|
344 |
+
<div><img class="bulk-img-orig" src=""></div>
|
345 |
+
<div>Original image</div>
|
346 |
+
</div>
|
347 |
+
<div class="img-optimized">
|
348 |
+
<div><img class="bulk-img-opt" src=""></div>
|
349 |
+
<div>Optimized image</div>
|
350 |
+
</div>
|
351 |
+
</div>
|
352 |
+
<div class="img-info">
|
353 |
+
<div style="font-size: 14px; line-height: 10px; margin-bottom:16px;">Optimized by:</div>
|
354 |
+
<span class="bulk-opt-percent"></span>
|
355 |
+
</div>
|
356 |
+
</div>
|
357 |
+
</div>
|
358 |
+
</div>
|
359 |
+
</div>
|
360 |
+
<?php
|
361 |
+
}
|
362 |
+
|
363 |
+
public function displayBulkProgressBar($running, $percent, $message, $remainingQuota, $averageCompression, $type = 1, $customPending = false) {
|
364 |
+
$percentBefore = $percentAfter = '';
|
365 |
+
if($percent > 24) {
|
366 |
+
$percentBefore = $percent . "%";
|
367 |
+
} else {
|
368 |
+
$percentAfter = $percent . "%";
|
369 |
+
}
|
370 |
+
?>
|
371 |
+
<div class="notice notice-info bulk-progress sp-floating-block sp-full-width">
|
372 |
+
<div style="float:right">
|
373 |
+
<?php if(false) { ?>
|
374 |
+
<div class="bulk-progress-indicator">
|
375 |
+
<div style="margin-bottom:5px">Remaining credits</div>
|
376 |
+
<div style="margin-top:22px;margin-bottom: 5px;font-size:2em;font-weight: bold;"><?php echo(number_format($remainingQuota))?></div>
|
377 |
+
<div>images</div>
|
378 |
+
</div>
|
379 |
+
<?php } ?>
|
380 |
+
<div class="bulk-progress-indicator">
|
381 |
+
<div style="margin-bottom:5px">Average reduction</div>
|
382 |
+
<div id="sp-avg-optimization"><input type="text" id="sp-avg-optimization-dial" value="<?php echo("" . round($averageCompression))?>" class="dial"></div>
|
383 |
+
<script>
|
384 |
+
jQuery(function() {
|
385 |
+
ShortPixel.percentDial("#sp-avg-optimization-dial", 60);
|
386 |
+
});
|
387 |
+
</script>
|
388 |
+
</div>
|
389 |
+
</div>
|
390 |
+
<?php if($running) { ?>
|
391 |
+
<h2><?php echo($type & 1 ? "Media Library " : "") ?><?php echo($type & 3 == 3 ? "and " : "") ?><?php echo($type & 2 ? "Custom folders " : "") ?>optimization in progress ...</h2>
|
392 |
+
<p style="margin: 0 0 18px;">Bulk optimization has started.<br>
|
393 |
+
This process will take some time, depending on the number of images in your library. In the meantime, you can continue using
|
394 |
+
the admin as usual, <a href='<?php echo(get_admin_url());?>' target='_blank'>in a different browser window or tab</a>.<br>
|
395 |
+
However, <strong>if you close this window, the bulk processing will pause</strong> until you open the media gallery or the ShortPixel bulk page again.
|
396 |
+
</p>
|
397 |
+
<?php } else { ?>
|
398 |
+
<h2>Media Library <?php ($type & 2 ? "and Custom folders " : "") ?>optimization paused</h2>
|
399 |
+
<p style="margin: 0 0 50px;">Bulk processing is paused until you resume the optimization process.</p>
|
400 |
+
<?php }?>
|
401 |
+
<div id="bulk-progress" class="progress" >
|
402 |
+
<div class="progress-img" style="left: <?php echo($percent);?>%;">
|
403 |
+
<img src="<?php echo(plugins_url( 'shortpixel-image-optimiser/res/img/slider.png' ));?>">
|
404 |
+
<span><?php echo($percentAfter);?></span>
|
405 |
+
</div>
|
406 |
+
<div class="progress-left" style="width: <?php echo($percent);?>%"><?php echo($percentBefore);?></div>
|
407 |
+
</div>
|
408 |
+
<div class="bulk-estimate">
|
409 |
+
<?php echo($message);?>
|
410 |
+
</div>
|
411 |
+
<?php if (true || ($type & 1)) { //now we display the action buttons always when a type of bulk is running ?>
|
412 |
+
<form action='' method='POST' style="display:inline;">
|
413 |
+
<input type="submit" class="button button-primary bulk-cancel" onclick="clearBulkProcessor();"
|
414 |
+
name="bulkProcessStop" value="Stop" style="margin-left:10px"/>
|
415 |
+
<input type="submit" class="button button-primary bulk-cancel" onclick="clearBulkProcessor();"
|
416 |
+
name="<?php echo($running ? "bulkProcessPause" : "bulkProcessResume");?>" value="<?php echo($running ? "Pause" : "Resume processing");?>"/>
|
417 |
+
<?php if(!$running && $customPending) {?>
|
418 |
+
<input type="submit" class="button button-primary bulk-cancel" onclick="clearBulkProcessor();"
|
419 |
+
name="skipToCustom" value="Only custom folders" title="Process only the custom folders, skipping the Media Library" style="margin-right:10px"/>
|
420 |
+
<?php }?>
|
421 |
+
</form>
|
422 |
+
<?php } else { ?>
|
423 |
+
<a href="options-general.php?page=wp-shortpixel" class="button button-primary bulk-cancel" style="margin-left:10px">Manage custom folders</a>
|
424 |
+
<?php }?>
|
425 |
+
</div>
|
426 |
+
<?php
|
427 |
+
}
|
428 |
+
|
429 |
+
public function displayBulkStats($totalOptimized, $mainOptimized, $under5PercentCount, $averageCompression, $savedSpace) {?>
|
430 |
+
<div class="bulk-progress bulk-stats">
|
431 |
+
<div class="label">Processed Images and PDFs:</div><div class="stat-value"><?php echo(number_format($mainOptimized));?></div><br>
|
432 |
+
<div class="label">Processed Thumbnails:</div><div class="stat-value"><?php echo(number_format($totalOptimized - $mainOptimized));?></div><br>
|
433 |
+
<div class="label totals">Total files processed:</div><div class="stat-value"><?php echo(number_format($totalOptimized));?></div><br>
|
434 |
+
<div class="label totals">Minus files with <5% optimization (free):</div><div class="stat-value"><?php echo(number_format($under5PercentCount));?></div><br><br>
|
435 |
+
<div class="label totals">Used quota:</div><div class="stat-value"><?php echo(number_format($totalOptimized - $under5PercentCount));?></div><br>
|
436 |
+
<br>
|
437 |
+
<div class="label">Average optimization:</div><div class="stat-value"><?php echo($averageCompression);?>%</div><br>
|
438 |
+
<div class="label">Saved space:</div><div class="stat-value"><?php echo($savedSpace);?></div>
|
439 |
+
</div>
|
440 |
+
<?php
|
441 |
+
}
|
442 |
+
|
443 |
+
public function displayFailed($failed) {
|
444 |
+
?>
|
445 |
+
<div class="bulk-progress bulk-stats">
|
446 |
+
<?php foreach($failed as $fail) {
|
447 |
+
if($fail->type == ShortPixelMetaFacade::CUSTOM_TYPE) {
|
448 |
+
$meta = $fail->meta;
|
449 |
+
?> <div class="label"><a href="<?php echo(trailingslashit(network_site_url("/")) . "wp-content/" . $fail->meta->getWebPath());?>"><?php echo(substr($fail->meta->getName(), 0, 80));?> - ID: C-<?php echo($fail->id);?></a></div><br/>
|
450 |
+
<?php } else {
|
451 |
+
$meta = wp_get_attachment_metadata($fail);
|
452 |
+
?> <div class="label"><a href="/wp-admin/post.php?post=<?php echo($fail->id);?>&action=edit"><?php echo(substr($fail->meta["file"], 0, 80));?> - ID: <?php echo($fail->id);?></a></div><br/>
|
453 |
+
<?php }
|
454 |
+
}?>
|
455 |
+
</div>
|
456 |
+
<?php
|
457 |
+
}
|
458 |
+
|
459 |
+
function displaySettings($showApiKey, $editApiKey, $quotaData, $notice, $resources = null, $averageCompression = null, $savedSpace = null, $savedBandwidth = null,
|
460 |
+
$remainingImages = null, $totalCallsMade = null, $fileCount = null, $backupFolderSize = null,
|
461 |
+
$customFolders = null, $folderMsg = false, $addedFolder = false, $showAdvanced = false) {
|
462 |
+
//wp_enqueue_script('jquery.idTabs.js', plugins_url('/js/jquery.idTabs.js',__FILE__) );
|
463 |
+
?>
|
464 |
+
<h1>ShortPixel Plugin Settings</h1>
|
465 |
+
<p style="font-size:18px">
|
466 |
+
<a href="https://shortpixel.com/<?php echo($this->ctrl->getVerifiedKey() ? "login/".$this->ctrl->getApiKey() : "pricing");?>" target="_blank" style="font-size:18px">
|
467 |
+
Upgrade now
|
468 |
+
</a> |
|
469 |
+
<a href="https://shortpixel.com/contact/<?php echo($this->ctrl->getEncryptedData());?>" target="_blank" style="font-size:18px">Support </a>
|
470 |
+
</p>
|
471 |
+
<?php if($notice !== null) { ?>
|
472 |
+
<br/>
|
473 |
+
<div style="background-color: #fff; border-left: 4px solid <?php echo($notice['status'] == 'error' ? '#ff0000' : ($notice['status'] == 'warn' ? '#FFC800' : '#7ad03a'));?>; box-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.1); padding: 1px 12px;;width: 95%">
|
474 |
+
<p><?php echo($notice['msg']);?></p>
|
475 |
+
</div>
|
476 |
+
<?php } ?>
|
477 |
+
<?php if($folderMsg) { ?>
|
478 |
+
<br/>
|
479 |
+
<div style="background-color: #fff; border-left: 4px solid #ff0000; box-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.1); padding: 1px 12px;;width: 95%">
|
480 |
+
<p><?php echo($folderMsg);?></p>
|
481 |
+
</div>
|
482 |
+
<?php } ?>
|
483 |
+
|
484 |
+
<article id="shortpixel-settings-tabs" class="sp-tabs">
|
485 |
+
<form name='wp_shortpixel_options' action='options-general.php?page=wp-shortpixel&noheader=true' method='post' id='wp_shortpixel_options'>
|
486 |
+
<section <?php echo($showAdvanced ? "" : "class='sel-tab'");?> id="tab-settings">
|
487 |
+
<h2><a class='tab-link' href='javascript:void(0);' data-id="tab-settings">General</a></h2>
|
488 |
+
<?php $this->displaySettingsForm($showApiKey, $editApiKey, $quotaData);?>
|
489 |
+
</section>
|
490 |
+
<section <?php echo($showAdvanced ? "class='sel-tab'" : "");?> id="tab-adv-settings">
|
491 |
+
<h2><a class='tab-link' href='javascript:void(0);' data-id="tab-adv-settings">Advanced</a></h2>
|
492 |
+
<?php $this->displayAdvancedSettingsForm($customFolders, $addedFolder);?>
|
493 |
+
</section>
|
494 |
+
</form><span style="display:none"> </span><?php //the span is a trick to keep the sections ordered as nth-child in styles: 1,2,3,4 (otherwise the third section would be nth-child(2) too, because of the form)
|
495 |
+
if($averageCompression !== null) {?>
|
496 |
+
<section id="tab-stats">
|
497 |
+
<h2><a class='tab-link' href='javascript:void(0);' data-id="tab-stats">Statistics</a></h2>
|
498 |
+
<?php
|
499 |
+
$this->displaySettingsStats($quotaData, $averageCompression, $savedSpace, $savedBandwidth,
|
500 |
+
$remainingImages, $totalCallsMade, $fileCount, $backupFolderSize);?>
|
501 |
+
</section>
|
502 |
+
<?php }
|
503 |
+
if($resources !== null) {?>
|
504 |
+
<section id="tab-resources">
|
505 |
+
<h2><a class='tab-link' href='javascript:void(0);' data-id="tab-resources">WP Resources</a></h2>
|
506 |
+
<?php echo((isset($resources['body']) ? $resources['body'] : "Please reload"));?>
|
507 |
+
</section>
|
508 |
+
<?php } ?>
|
509 |
+
</article>
|
510 |
+
<script>
|
511 |
+
jQuery(document).ready(function () {
|
512 |
+
ShortPixel.adjustSettingsTabs();
|
513 |
+
|
514 |
+
if(window.location.hash) {
|
515 |
+
var target = 'tab-' + window.location.hash.substring(window.location.hash.indexOf("#")+1)
|
516 |
+
ShortPixel.switchSettingsTab(target);
|
517 |
+
}
|
518 |
+
jQuery("article.sp-tabs a.tab-link").click(function(){ShortPixel.switchSettingsTab(jQuery(this).data("id"))});
|
519 |
+
});
|
520 |
+
</script>
|
521 |
+
<?php
|
522 |
+
}
|
523 |
+
|
524 |
+
public function displaySettingsForm($showApiKey, $editApiKey, $quotaData) {
|
525 |
+
$settings = $this->ctrl->getSettings();
|
526 |
+
$checked = ($this->ctrl->processThumbnails() ? 'checked' : '');
|
527 |
+
$checkedBackupImages = ($this->ctrl->backupImages() ? 'checked' : '');
|
528 |
+
$cmyk2rgb = ($this->ctrl->getCMYKtoRGBconversion() ? 'checked' : '');
|
529 |
+
$removeExif = ($settings->keepExif ? '' : 'checked');
|
530 |
+
$resize = ($this->ctrl->getResizeImages() ? 'checked' : '');
|
531 |
+
$resizeDisabled = ($this->ctrl->getResizeImages() ? '' : 'disabled');
|
532 |
+
$minSizes = $this->ctrl->getMaxIntermediateImageSize();
|
533 |
+
$thumbnailsToProcess = isset($quotaData['totalFiles']) ? ($quotaData['totalFiles'] - $quotaData['mainFiles']) - ($quotaData['totalProcessedFiles'] - $quotaData['mainProcessedFiles']) : 0;
|
534 |
+
?>
|
535 |
+
<div class="wp-shortpixel-options">
|
536 |
+
<?php if($this->ctrl->getVerifiedKey()) { ?>
|
537 |
+
<p>New images uploaded to the Media Library will be optimized automatically.<br/>If you have existing images you would like to optimize, you can use the <a href="<?php echo(get_admin_url());?>upload.php?page=wp-short-pixel-bulk">Bulk Optimization Tool</a>.</p>
|
538 |
+
<?php } else {
|
539 |
+
if($showApiKey) {?>
|
540 |
+
<h3>Step 1:</h3>
|
541 |
+
<p style='font-size: 14px'>If you don't have an API Key, <a href="https://shortpixel.com/wp-apikey<?php echo( $this->ctrl->getAffiliateSufix() );?>" target="_blank">sign up here.</a> It's free and it only takes one minute, we promise!</p>
|
542 |
+
<h3>Step 2:</h3>
|
543 |
+
<p style='font-size: 14px'>Please enter here the API Key you received by email and press Validate.</p>
|
544 |
+
<?php }
|
545 |
+
}?>
|
546 |
+
<table class="form-table">
|
547 |
+
<tbody>
|
548 |
+
<tr>
|
549 |
+
<th scope="row"><label for="key">API Key:</label></th>
|
550 |
+
<td>
|
551 |
+
<?php
|
552 |
+
$canValidate = false;
|
553 |
+
if($showApiKey) {
|
554 |
+
$canValidate = true;?>
|
555 |
+
<input name="key" type="text" id="key" value="<?php echo( $this->ctrl->getApiKey() );?>"
|
556 |
+
class="regular-text" <?php echo($editApiKey ? "" : 'disabled') ?>>
|
557 |
+
<?php } elseif(defined("SHORTPIXEL_API_KEY")) {
|
558 |
+
$canValidate = true;?>
|
559 |
+
<input name="key" type="text" id="key" disabled="true" placeholder="Multisite API Key" class="regular-text">
|
560 |
+
<?php } ?>
|
561 |
+
<input type="hidden" name="validate" id="valid" value=""/>
|
562 |
+
<button type="button" id="validate" class="button button-primary" title="Validate the provided API key"
|
563 |
+
onclick="validateKey()" <?php echo $canValidate ? "" : "disabled"?>>Validate</button>
|
564 |
+
<?php if($showApiKey && !$editApiKey) { ?>
|
565 |
+
<p class="settings-info">Key defined in wp-config.php.</p>
|
566 |
+
<?php } ?>
|
567 |
+
|
568 |
+
</td>
|
569 |
+
</tr>
|
570 |
+
<?php if (!$this->ctrl->getVerifiedKey()) { //if invalid key we display the link to the API Key ?>
|
571 |
+
</tbody>
|
572 |
+
</table>
|
573 |
+
<?php } else { //if valid key we display the rest of the options ?>
|
574 |
+
<tr>
|
575 |
+
<th scope="row">
|
576 |
+
<label for="compressionType">Compression type:</label>
|
577 |
+
</th>
|
578 |
+
<td>
|
579 |
+
<input type="radio" name="compressionType" value="1" <?php echo( $this->ctrl->getCompressionType() == 1 ? "checked" : "" );?>>Lossy (recommended)</br>
|
580 |
+
<p class="settings-info"> <b>Lossy compression: </b>lossy has a better compression rate than lossless compression.</br>The resulting image is identical with the original to the human eye. You can run a test for free
|
581 |
+
<a href="https://shortpixel.com/online-image-compression" target="_blank">here</a>.</p></br>
|
582 |
+
<input type="radio" name="compressionType" value="0" <?php echo( $this->ctrl->getCompressionType() != 1 ? "checked" : "" );?>>Lossless
|
583 |
+
<p class="settings-info"><b>Lossless compression: </b> the shrunk image will be identical with the original and smaller in size.</br>In some rare cases you will need to use
|
584 |
+
this type of compression. Some technical drawings or images from vector graphics are possible situations.</p>
|
585 |
+
</td>
|
586 |
+
</tr>
|
587 |
+
</tbody>
|
588 |
+
</table>
|
589 |
+
<table class="form-table">
|
590 |
+
<tbody>
|
591 |
+
<tr>
|
592 |
+
<th scope="row"><label for="thumbnails">Also include thumbnails:</label></th>
|
593 |
+
<td><input name="thumbnails" type="checkbox" id="thumbnails" <?php echo( $checked );?>> Apply compression also to
|
594 |
+
<strong>image thumbnails.</strong> <?php echo($thumbnailsToProcess ? "(" . number_format($thumbnailsToProcess) . " thumbnails to optimize)" : "");?>
|
595 |
+
<p class="settings-info">It is highly recommended that you optimize the thumbnails as they are usually the images most viewed by end users and can generate most traffic.<br>Please note that thumbnails count up to your total quota.</p>
|
596 |
+
</td>
|
597 |
+
</tr>
|
598 |
+
<tr>
|
599 |
+
<th scope="row"><label for="backupImages">Image backup</label></th>
|
600 |
+
<td>
|
601 |
+
<input name="backupImages" type="checkbox" id="backupImages" <?php echo( $checkedBackupImages );?>> Save and keep a backup of your original images in a separate folder.
|
602 |
+
<p class="settings-info">You <strong>need to have backup active</strong> in order to be able to restore images to originals or to convert from Lossy to Lossless and back.</p>
|
603 |
+
</td>
|
604 |
+
</tr>
|
605 |
+
<tr>
|
606 |
+
<th scope="row"><label for="cmyk2rgb">CMYK to RGB conversion</label></th>
|
607 |
+
<td>
|
608 |
+
<input name="cmyk2rgb" type="checkbox" id="cmyk2rgb" <?php echo( $cmyk2rgb );?>>Adjust your images for computer and mobile screen display.
|
609 |
+
<p class="settings-info">Images for the web only need RGB format and converting them from CMYK to RGB makes them smaller.</p>
|
610 |
+
</td>
|
611 |
+
</tr>
|
612 |
+
<tr>
|
613 |
+
<th scope="row"><label for="removeExif">Remove EXIF</label></th>
|
614 |
+
<td>
|
615 |
+
<input name="removeExif" type="checkbox" id="removeExif" <?php echo( $removeExif );?>>Remove the EXIF tag of the image (recommended).
|
616 |
+
<p class="settings-info"> EXIF is a set of various pieces of information that are automatically embedded into the image upon creation. This can include GPS position, camera manufacturer, date and time, etc.
|
617 |
+
Unless you really need that data to be preserved, we recommend removing it as it can lead to <a href="http://blog.shortpixel.com/how-much-smaller-can-be-images-without-exif-icc" target="_blank">better compression rates</a>.</p>
|
618 |
+
</td>
|
619 |
+
</tr>
|
620 |
+
<tr>
|
621 |
+
<th scope="row"><label for="resize">Resize large images</label></th>
|
622 |
+
<td>
|
623 |
+
<input name="resize" type="checkbox" id="resize" <?php echo( $resize );?>> to maximum
|
624 |
+
<input type="text" name="width" id="width" style="width:70px" value="<?php echo( max($this->ctrl->getResizeWidth(), min(1024, $minSizes['width'])) );?>" <?php echo( $resizeDisabled );?>/> pixels wide ×
|
625 |
+
<input type="text" name="height" id="height" style="width:70px" value="<?php echo( max($this->ctrl->getResizeHeight(), min(1024, $minSizes['height'])) );?>" <?php echo( $resizeDisabled );?>/> pixels high (original aspect ratio is preserved)
|
626 |
+
<p class="settings-info"> Recommended for large photos, like the ones taken with your phone. Saved space can go up to 80% or more after resizing.<br/>
|
627 |
+
The new resolution should not be less than your largest thumbnail size, which is <?php echo($minSizes['width']);?> × <?php echo($minSizes['height']);?> pixels,
|
628 |
+
or, if you have a Retina images plugin, <?php echo(2 * $minSizes['width']);?> × <?php echo(2 * $minSizes['height']);?> pixels.<br>
|
629 |
+
The resize keeps the aspect ratio and is done so that the resulting image will be resized to no less than the configured sizes. For example, if you set the resize dimensions at 1000x1200, an image of 2000x3000px will be resized to 1000x1500px while an image of 3000x2000px will be resized to 1800x1200px</p>
|
630 |
+
</td>
|
631 |
+
</tr>
|
632 |
+
</tbody>
|
633 |
+
</table>
|
634 |
+
<p class="submit">
|
635 |
+
<input type="submit" name="save" id="save" class="button button-primary" title="Save Changes" value="Save Changes">
|
636 |
+
<input type="submit" name="save" id="bulk" class="button button-primary" title="Save and go to the Bulk Processing page" value="Save and Go to Bulk Process">
|
637 |
+
</p>
|
638 |
+
</div>
|
639 |
+
<?php }
|
640 |
+
}
|
641 |
+
|
642 |
+
public function displayAdvancedSettingsForm($customFolders = false, $addedFolder = false) {
|
643 |
+
$settings = $this->ctrl->getSettings();
|
644 |
+
$minSizes = $this->ctrl->getMaxIntermediateImageSize();
|
645 |
+
$hasNextGen = $this->ctrl->hasNextGen();
|
646 |
+
$frontBootstrap = ($settings->frontBootstrap ? 'checked' : '');
|
647 |
+
$includeNextGen = ($settings->includeNextGen ? 'checked' : '');
|
648 |
+
?>
|
649 |
+
<div class="wp-shortpixel-options">
|
650 |
+
<?php if(!$this->ctrl->getVerifiedKey()) { ?>
|
651 |
+
<p>Please enter your API key in the General tab first.</p>
|
652 |
+
<?php } else { //if valid key we display the rest of the options ?>
|
653 |
+
<table class="form-table">
|
654 |
+
<tbody>
|
655 |
+
<tr>
|
656 |
+
<th scope="row"><label for="resize">Additional media folders</label></th>
|
657 |
+
<td>
|
658 |
+
<?php if($customFolders) { ?>
|
659 |
+
<table class="shortpixel-folders-list">
|
660 |
+
<tr style="font-weight: bold;">
|
661 |
+
<td>Folder name</td>
|
662 |
+
<td>Type &<br>Status</td>
|
663 |
+
<td>Files</td>
|
664 |
+
<td>Last change</td>
|
665 |
+
<td></td>
|
666 |
+
</tr>
|
667 |
+
<?php foreach($customFolders as $folder) {
|
668 |
+
$typ = $folder->getType();
|
669 |
+
$typ = $typ ? $typ . "<br>" : "";
|
670 |
+
$stat = $this->ctrl->getSpMetaDao()->getFolderOptimizationStatus($folder->getId());
|
671 |
+
$cnt = $folder->getFileCount();
|
672 |
+
$st = ($cnt == 0
|
673 |
+
? "Empty"
|
674 |
+
: ($stat->Total == $stat->Optimized
|
675 |
+
? "Optimized"
|
676 |
+
: ($stat->Optimized + $stat->Pending > 0 ? "Pending" : "Waiting")));
|
677 |
+
$err = $stat->Failed > 0 && !$st == "Empty" ? " ({$stat->Failed} failed)" : "";
|
678 |
+
$action = ($st == "Optimized" || $st == "Empty" ? "monitoring" : "optimizing");
|
679 |
+
$fullStat = $st == "Empty" ? "" : "Optimized: " . $stat->Optimized . ", Pending: " . $stat->Pending . ", Waiting: " . $stat->Waiting . ", Failed: " . $stat->Failed;
|
680 |
+
?>
|
681 |
+
<tr>
|
682 |
+
<td>
|
683 |
+
<?php echo($folder->getPath()); ?>
|
684 |
+
</td>
|
685 |
+
<td>
|
686 |
+
<?php if(!($st == "Empty")) { ?>
|
687 |
+
<a href="javascript:none();" title="<?php echo $fullStat; ?>" style="text-decoration: none;">
|
688 |
+
<img src='<?php echo(plugins_url( 'shortpixel-image-optimiser/res/img/info-icon.png' ));?>' style="margin-bottom: -2px;"/>
|
689 |
+
</a> <?php } echo($typ.$st.$err); ?>
|
690 |
+
|
691 |
+
</td>
|
692 |
+
<td>
|
693 |
+
<?php echo($cnt); ?> files
|
694 |
+
</td>
|
695 |
+
<td>
|
696 |
+
<?php echo($folder->getTsUpdated()); ?>
|
697 |
+
</td>
|
698 |
+
<td>
|
699 |
+
<input type="button" class="button remove-folder-button" data-value="<?php echo($folder->getPath()); ?>" title="Stop <?php echo($action . " " . $folder->getPath()); ?>" value="Stop <?php echo $action;?>">
|
700 |
+
</td>
|
701 |
+
</tr>
|
702 |
+
<?php }?>
|
703 |
+
</table>
|
704 |
+
<?php } ?>
|
705 |
+
<input type="hidden" name="removeFolder" id="removeFolder"/>
|
706 |
+
<input type="text" name="addCustomFolderView" id="addCustomFolderView" class="regular-text" value="<?php echo($addedFolder);?>" disabled style="width: 50em;max-width: 70%;">
|
707 |
+
<input type="hidden" name="addCustomFolder" id="addCustomFolder" value="<?php echo($addedFolder);?>"/>
|
708 |
+
<input type="hidden" id="customFolderBase" value="<?php echo $this->ctrl->getCustomFolderBase(); ?>">
|
709 |
+
<a class="button button-primary select-folder-button" title="Select the images folder on your server" href="javascript:void(0);">Select ... </a>
|
710 |
+
<input type="submit" name="saveAdv" id="saveAdvAddFolder" class="button button-primary" title="Add Folder" value="Add Folder">
|
711 |
+
<p class="settings-info"> Use the Select... button to select folders from <i>wp-content</i>. ShortPixel will optimize images and PDFs from the specified folders and their subfolders. The optimization status for each image or PDF in these folders can be seen in the <a href="upload.php?page=wp-short-pixel-custom">Other Media list</a>, under the Media menu.</p>
|
712 |
+
<div class="sp-folder-picker-shade">
|
713 |
+
<div class="sp-folder-picker-popup">
|
714 |
+
<div class="sp-folder-picker-title">Select the images folder</div>
|
715 |
+
<div class="sp-folder-picker"></div>
|
716 |
+
<input type="button" class="button button-info select-folder-cancel" value="Cancel" style="margin-right: 30px;">
|
717 |
+
<input type="button" class="button button-primary select-folder" value="Select">
|
718 |
+
</div>
|
719 |
+
</div>
|
720 |
+
<script>
|
721 |
+
jQuery(document).ready(function () {
|
722 |
+
ShortPixel.initFolderSelector();
|
723 |
+
});
|
724 |
+
</script>
|
725 |
+
</td>
|
726 |
+
</tr>
|
727 |
+
<?php if($hasNextGen) { ?>
|
728 |
+
<tr>
|
729 |
+
<th scope="row"><label for="resize">Optimize NextGen galleries</label></th>
|
730 |
+
<td>
|
731 |
+
<input name="nextGen" type="checkbox" id="resize" <?php echo( $includeNextGen );?>> Optimize NextGen galleries.
|
732 |
+
<p class="settings-info">Check this to add all your current NextGen galleries to the custom folders list and to also have all the future NextGen galleries and images optimized automatically by ShortPixel.</p>
|
733 |
+
</td>
|
734 |
+
</tr>
|
735 |
+
<?php } ?>
|
736 |
+
<tr>
|
737 |
+
<th scope="row"><label for="authentication">HTTP AUTH credentials</label></th>
|
738 |
+
<td>
|
739 |
+
<input name="siteAuthUser" type="text" id="siteAuthUser" value="<?php echo( $settings->siteAuthUser );?>" class="regular-text" placeholder="User"><br>
|
740 |
+
<input name="siteAuthPass" type="text" id="siteAuthPass" value="<?php echo( $settings->siteAuthPass );?>" class="regular-text" placeholder="Password">
|
741 |
+
<p class="settings-info"> Only fill in these fields if your site (front-end) is not publicly accessible and visitors need a user/pass to connect to it. If you don't know what is this then just <strong>leave the fields empty</strong>.</p>
|
742 |
+
</td>
|
743 |
+
</tr>
|
744 |
+
<tr>
|
745 |
+
<th scope="row"><label for="resize">Process in front-end</label></th>
|
746 |
+
<td>
|
747 |
+
<input name="frontBootstrap" type="checkbox" id="resize" <?php echo( $frontBootstrap );?>> Automatically optimize images added by users in front end.
|
748 |
+
<p class="settings-info">Check this if you have users that add images or PDF documents from custom forms in the front-end. This could increase the load on your server if you have a lot of users simultaneously connected.</p>
|
749 |
+
</td>
|
750 |
+
</tr>
|
751 |
+
</tbody>
|
752 |
+
</table>
|
753 |
+
<p class="submit">
|
754 |
+
<input type="submit" name="saveAdv" id="saveAdv" class="button button-primary" title="Save Changes" value="Save Changes">
|
755 |
+
<input type="submit" name="saveAdv" id="bulkAdvGo" class="button button-primary" title="Save and go to the Bulk Processing page" value="Save and Go to Bulk Process">
|
756 |
+
</p>
|
757 |
+
</div>
|
758 |
+
<script>
|
759 |
+
var rad = document.wp_shortpixel_options.compressionType;
|
760 |
+
var prev = null;
|
761 |
+
var minWidth = Math.min(1024, <?php echo($minSizes['width']);?>),
|
762 |
+
minHeight = Math.min(1024, <?php echo($minSizes['height']);?>);
|
763 |
+
for(var i = 0; i < rad.length; i++) {
|
764 |
+
rad[i].onclick = function() {
|
765 |
+
|
766 |
+
if(this !== prev) {
|
767 |
+
prev = this;
|
768 |
+
}
|
769 |
+
alert('This type of optimization will apply to new uploaded images.\nImages that were already processed will not be re-optimized unless you restart the bulk process.');
|
770 |
+
};
|
771 |
+
}
|
772 |
+
function enableResize(elm) {
|
773 |
+
if(jQuery(elm).is(':checked')) {
|
774 |
+
jQuery("#width,#height").removeAttr("disabled");
|
775 |
+
} else {
|
776 |
+
jQuery("#width,#height").attr("disabled", "disabled");
|
777 |
+
}
|
778 |
+
}
|
779 |
+
enableResize("#resize");
|
780 |
+
jQuery("#resize").change(function(){ enableResize(this) });
|
781 |
+
jQuery("#width").blur(function(){
|
782 |
+
jQuery(this).val(Math.max(minWidth, parseInt(jQuery(this).val())));
|
783 |
+
});
|
784 |
+
jQuery("#height").blur(function(){
|
785 |
+
jQuery(this).val(Math.max(minHeight, parseInt(jQuery(this).val())));
|
786 |
+
});
|
787 |
+
jQuery("input.remove-folder-button").click(function(){
|
788 |
+
var path = jQuery(this).data("value");
|
789 |
+
var r = confirm("Are you sure you want to stop optimizing the folder " + path + "?");
|
790 |
+
if (r == true) {
|
791 |
+
jQuery("#removeFolder").val(path);
|
792 |
+
jQuery('#wp_shortpixel_options').submit();
|
793 |
+
}
|
794 |
+
});
|
795 |
+
</script>
|
796 |
+
<?php } ?>
|
797 |
+
<script>
|
798 |
+
function validateKey(){
|
799 |
+
jQuery('#valid').val('validate');
|
800 |
+
jQuery('#wp_shortpixel_options').submit();
|
801 |
+
}
|
802 |
+
jQuery("#key").keypress(function(e) {
|
803 |
+
if(e.which == 13) {
|
804 |
+
jQuery('#valid').val('validate');
|
805 |
+
}
|
806 |
+
});
|
807 |
+
</script>
|
808 |
+
<?php
|
809 |
+
}
|
810 |
+
|
811 |
+
function displaySettingsStats($quotaData, $averageCompression, $savedSpace, $savedBandwidth,
|
812 |
+
$remainingImages, $totalCallsMade, $fileCount, $backupFolderSize) { ?>
|
813 |
+
<a id="facts"></a>
|
814 |
+
<h3>Your ShortPixel Stats</h3>
|
815 |
+
<table class="form-table">
|
816 |
+
<tbody>
|
817 |
+
<tr>
|
818 |
+
<th scope="row"><label for="averagCompression">Average compression of your files:</label></th>
|
819 |
+
<td><?php echo($averageCompression);?>%</td>
|
820 |
+
</tr>
|
821 |
+
<tr>
|
822 |
+
<th scope="row"><label for="savedSpace">Saved disk space by ShortPixel</label></th>
|
823 |
+
<td><?php echo($savedSpace);?></td>
|
824 |
+
</tr>
|
825 |
+
<tr>
|
826 |
+
<th scope="row"><label for="savedBandwidth">Bandwith* saved with ShortPixel:</label></th>
|
827 |
+
<td><?php echo($savedBandwidth);?></td>
|
828 |
+
</tr>
|
829 |
+
</tbody>
|
830 |
+
</table>
|
831 |
+
|
832 |
+
<p style="padding-top: 0px; color: #818181;" >* Saved bandwidth is calculated at 10,000 impressions/image</p>
|
833 |
+
|
834 |
+
<h3>Your ShortPixel Plan</h3>
|
835 |
+
<table class="form-table">
|
836 |
+
<tbody>
|
837 |
+
<tr>
|
838 |
+
<th scope="row" bgcolor="#ffffff"><label for="apiQuota">Your ShortPixel plan</label></th>
|
839 |
+
<td bgcolor="#ffffff">
|
840 |
+
<?php echo($quotaData['APICallsQuota']);?>/month, renews in <?php echo(floor(30 + (strtotime($quotaData['APILastRenewalDate']) - time()) / 86400));?> days, on <?php echo(date('M d, Y', strtotime($quotaData['APILastRenewalDate']. ' + 30 days')));?> ( <a href="https://shortpixel.com/login/<?php echo($this->ctrl->getApiKey());?>" target="_blank">Need More? See the options available</a> )<br/>
|
841 |
+
<a href="https://shortpixel.com/login/<?php echo($this->ctrl->getApiKey());?>/tell-a-friend" target="_blank">Join our friend referral system</a> to win more credits. For each user that joins, you receive +100 images credits/month.
|
842 |
+
</td>
|
843 |
+
</tr>
|
844 |
+
<tr>
|
845 |
+
<th scope="row"><label for="usedQUota">One time credits:</label></th>
|
846 |
+
<td><?php echo( number_format($quotaData['APICallsQuotaOneTimeNumeric']));?></td>
|
847 |
+
</tr>
|
848 |
+
<tr>
|
849 |
+
<th scope="row"><label for="usedQUota">Number of images processed this month:</label></th>
|
850 |
+
<td><?php echo($totalCallsMade);?> (<a href="https://api.shortpixel.com/v2/report.php?key=<?php echo($this->ctrl->getApiKey());?>" target="_blank">see report</a>)</td>
|
851 |
+
</tr>
|
852 |
+
<tr>
|
853 |
+
<th scope="row"><label for="remainingImages">Remaining** images in your plan: </label></th>
|
854 |
+
<td><?php echo($remainingImages);?> images</td>
|
855 |
+
</tr>
|
856 |
+
</tbody>
|
857 |
+
</table>
|
858 |
+
|
859 |
+
<p style="padding-top: 0px; color: #818181;" >** Increase your image quota by <a href="https://shortpixel.com/login/<?php echo($this->ctrl->getApiKey());?>" target="_blank">upgrading your ShortPixel plan.</a></p>
|
860 |
+
|
861 |
+
<table class="form-table">
|
862 |
+
<tbody>
|
863 |
+
<tr>
|
864 |
+
<th scope="row"><label for="totalFiles">Total number of processed files:</label></th>
|
865 |
+
<td><?php echo($fileCount);?></td>
|
866 |
+
</tr>
|
867 |
+
<?php if($this->ctrl->backupImages()) { ?>
|
868 |
+
<tr>
|
869 |
+
<th scope="row"><label for="sizeBackup">Original images are stored in a backup folder. Your backup folder size is now:</label></th>
|
870 |
+
<td>
|
871 |
+
<form action="" method="POST">
|
872 |
+
<?php echo($backupFolderSize);?>
|
873 |
+
<input type="submit" style="margin-left: 15px; vertical-align: middle;" class="button button-secondary" name="emptyBackup" value="Empty backups"/>
|
874 |
+
</form>
|
875 |
+
</td>
|
876 |
+
</tr>
|
877 |
+
<?php } ?>
|
878 |
+
</tbody>
|
879 |
+
</table>
|
880 |
+
<div style="display:none">
|
881 |
+
|
882 |
+
</div>
|
883 |
+
<?php
|
884 |
+
}
|
885 |
+
|
886 |
+
public function renderCustomColumn($id, $data){ ?>
|
887 |
+
<div id='sp-msg-<?php echo($id);?>' class='column-wp-shortPixel'>
|
888 |
+
<?php switch($data['status']) {
|
889 |
+
case 'n/a': ?>
|
890 |
+
Optimization N/A <?php
|
891 |
+
break;
|
892 |
+
case 'notFound': ?>
|
893 |
+
Image does not exist. <?php
|
894 |
+
break;
|
895 |
+
case 'invalidKey':
|
896 |
+
if(defined("SHORTPIXEL_API_KEY")) { // multisite key - need to be validated on each site but it's not invalid
|
897 |
+
?> Please <a href="options-general.php?page=wp-shortpixel">go to Settings</a> to validate the API Key. <?php
|
898 |
+
} else {
|
899 |
+
?> Invalid API Key. <a href="options-general.php?page=wp-shortpixel">Check your Settings</a> <?php
|
900 |
+
}
|
901 |
+
break;
|
902 |
+
case 'quotaExceeded':
|
903 |
+
echo($this->getQuotaExceededHTML(isset($data['message']) ? $data['message'] : ''));
|
904 |
+
break;
|
905 |
+
case 'optimizeNow':
|
906 |
+
echo($data['message']);
|
907 |
+
if($data['showActions']) { ?>
|
908 |
+
<a class='button button-smaller button-primary' href="javascript:manualOptimization('<?php echo($id)?>')">Optimize now</a>
|
909 |
+
<?php }
|
910 |
+
if(isset($data['thumbsTotal']) && $data['thumbsTotal'] > 0) {
|
911 |
+
echo("<br>+" . $data['thumbsTotal'] . " thumbnails");
|
912 |
+
}
|
913 |
+
break;
|
914 |
+
case 'retry': ?>
|
915 |
+
<?php echo($data['message'])?> <a class='button button-smaller button-primary' href="javascript:manualOptimization('<?php echo($id)?>')">Retry</a> <?php
|
916 |
+
break;
|
917 |
+
case 'pdfOptimized':
|
918 |
+
case 'imgOptimized':
|
919 |
+
$this->renderListCell($id, $data['showActions'],
|
920 |
+
!$data['thumbsOpt'] && $data['thumbsTotal'], $data['thumbsTotal'], $data['backup'], $data['type'],
|
921 |
+
$this->getSuccessText($data['percent'],$data['bonus'],$data['type'],$data['thumbsOpt'],$data['thumbsTotal']));
|
922 |
+
break;
|
923 |
+
}
|
924 |
+
//die(var_dump($data));
|
925 |
+
?>
|
926 |
+
</div>
|
927 |
+
<?php
|
928 |
+
}
|
929 |
+
|
930 |
+
public function getSuccessText($percent, $bonus, $type, $thumbsOpt = 0, $thumbsTotal = 0) {
|
931 |
+
return ($percent ? 'Reduced by ' . $percent . '% ' : '')
|
932 |
+
.(!$bonus ? ' ('.$type.')':'')
|
933 |
+
.($bonus && $percent ? '<br>' : '')
|
934 |
+
.($bonus ? 'Bonus processing' : '')
|
935 |
+
.($bonus ? ' ('.$type.')':'') . '<br>'
|
936 |
+
.($thumbsOpt ? "+" . $thumbsOpt . ($thumbsTotal > $thumbsOpt ? " of ".$thumbsTotal : '') . " thumbnails optimized" : '');
|
937 |
+
}
|
938 |
+
|
939 |
+
public function renderListCell($id, $showActions, $optimizeThumbs, $thumbsTotal, $backup, $type, $message) {
|
940 |
+
if($showActions) { ?>
|
941 |
+
<div class='sp-column-actions'>
|
942 |
+
<?php if($optimizeThumbs) { ?>
|
943 |
+
<a class='button button-smaller button-primary' href="javascript:optimizeThumbs(<?php echo($id)?>);">
|
944 |
+
Optimize <?php echo($thumbsTotal);?> thumbnails
|
945 |
+
</a>
|
946 |
+
<?php }
|
947 |
+
if($backup) {
|
948 |
+
if($type) {
|
949 |
+
$invType = $type == 'lossy' ? 'lossless' : 'lossy'; ?>
|
950 |
+
<a class='button button-smaller' href="javascript:reoptimize('<?php echo($id)?>', '<?php echo($invType)?>');" title="Reoptimize from the backed-up image">
|
951 |
+
Re-optimize <?php echo($invType)?>
|
952 |
+
</a><?php
|
953 |
+
} ?>
|
954 |
+
<a class='button button-smaller' href="admin.php?action=shortpixel_restore_backup&attachment_ID=<?php echo($id)?>">
|
955 |
+
Restore backup
|
956 |
+
</a>
|
957 |
+
<?php } ?>
|
958 |
+
</div>
|
959 |
+
<?php } ?>
|
960 |
+
<div class='sp-column-info'>
|
961 |
+
<?php echo($message);?>
|
962 |
+
</div> <?php
|
963 |
+
}
|
964 |
+
|
965 |
+
public function getQuotaExceededHTML($message = '') {
|
966 |
+
return "<div class='sp-column-actions' style='width:110px;'>
|
967 |
+
<a class='button button-smaller button-primary' href='https://shortpixel.com/login/". $this->ctrl->getApiKey() . "' target='_blank'>Extend Quota</a>
|
968 |
+
<a class='button button-smaller' href='admin.php?action=shortpixel_check_quota'>Check Quota</a></div>
|
969 |
+
<div class='sp-column-info'>" . $message . " Quota Exceeded.</div>";
|
970 |
+
}
|
971 |
+
}
|
readme.txt
CHANGED
@@ -5,24 +5,28 @@ Tags: image optimizer, image optimization, compress pdf, compress jpeg, compress
|
|
5 |
|
6 |
Requires at least: 3.2.0
|
7 |
Tested up to: 4.6
|
8 |
-
Stable tag:
|
9 |
License: GPLv2 or later
|
10 |
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
11 |
|
12 |
-
Easy-to-use, lightweight plugin that optimizes images & PDFs. Make your website faster, keeping the images’ high quality. WooCommerce compatible
|
13 |
|
14 |
== Description ==
|
15 |
|
16 |
ShortPixel makes your website load faster by resizing/rescaling and then compressing the images. Optimized images mean better user experience, better PageSpeed Insights results, better Google PageRank (SEO) and more visitors. Both lossy and lossless <a rel="friend" href="https://shortpixel.com" target="_blank">image compression</a> available for all common image types (JPG, PNG and GIF), plus PDF files.
|
17 |
|
18 |
-
|
|
|
|
|
|
|
|
|
19 |
|
20 |
**How does it work?**
|
21 |
|
22 |
* choose your favorite settings like lossy/lossless, keep/remove EXIF, backup, optimize thumbs, etc.
|
23 |
* all your current pics can be easily scaled and optimized with a single click via our **bulk optimization** page.
|
24 |
* new images are automatically resized and compressed in the cloud right after they are uploaded.
|
25 |
-
* smaller images will start being served from your website once they
|
26 |
|
27 |
It's that easy indeed.
|
28 |
|
@@ -32,9 +36,10 @@ You can try a **live demo** <a href="https://addendio.com/try-plugin/?slug=short
|
|
32 |
|
33 |
**Why use ShortPixel to optimize your images? Here are some of the features:**
|
34 |
|
35 |
-
* **24h support** directly from the developers
|
36 |
* compress JPG, PNG, GIF (still and animated) images and PDF documents
|
37 |
* optimize thumbnails as well as featured images
|
|
|
38 |
* featured images can be rescaled before being optimized. **No need for additional plugins** like Imsanity
|
39 |
* CMYK to RGB conversion
|
40 |
* skip already optimized images
|
@@ -78,9 +83,10 @@ We will continue to purchase this software for any site we develop with a lot of
|
|
78 |
|
79 |
**New features coming soon:**
|
80 |
|
81 |
-
*
|
82 |
-
* support
|
83 |
-
*
|
|
|
84 |
|
85 |
|
86 |
**Get in touch!**
|
@@ -91,7 +97,7 @@ We will continue to purchase this software for any site we develop with a lot of
|
|
91 |
* Facebook <a href="https://www.facebook.com/ShortPixel" target="_blank">https://www.facebook.com/ShortPixel</a>
|
92 |
* LinkedIn <a href="https://www.linkedin.com/company/shortpixel" target="_blank">https://www.linkedin.com/company/shortpixel</a>
|
93 |
|
94 |
-
**Keywords:** picture, optimization, image editor, pngout, upload speed, shortpixel, compression, jpegmini, webp, lossless, cwebp, media, jpegtran, image, image optimisation, image optimization, shrink, picture, photo, optimize photos, compress, performance, tinypng, crunch, pngquant, attachment, optimize, pictures, fast, images, image files, image quality, lossy, upload, kraken, resize, seo, smushit, optipng, kraken image optimizer, ewww, photo optimization, gifsicle, image optimizer, images, krakenio, png, gmagick, image optimize, pdf, pdf optimisation, pdf optimization, optimize pdf, optimise pdf, shrink pdf, jpg, jpeg, jpg optimisation, jpg optimization, optimize jpg, optimise jpg, shrink jpg, gif, animated gif, optimize gif, optimise gif, optimizer, optimiser, compresion, optimization, cruncher, image cruncher, compress png, compress jpg, compress jpeg, compress pdf, faster loading times, image optimiser, improve pagerank, optimise, optimize animated gif, optimise jpeg, optimize jpeg, optimize png, optimise png, optimise pdf, optimize pdf, tinyjpg, short pixel, shortpixel, woocommerce compatible, wpml compatible, smush, imsanity, scale, wp smush, compress images, pdf compression, optimize images, shrink jpeg, compressor, faster website, google pagerank, imagify, prizm, optimus, zara, improve page speed, PageSpeed Insights, sitespeed, smaller images, tinyjpeg, wordpress compression, wordPress image tool, reduce image size, bandwidth, pics, keep exif, remove exif, speed up site, speed up website, compress thumbnails, optimize thumbnails
|
95 |
|
96 |
|
97 |
== Installation ==
|
@@ -193,23 +199,10 @@ The ShortPixel team is here to help. <a href="https://shortpixel.com/contact">Co
|
|
193 |
|
194 |
== Changelog ==
|
195 |
|
196 |
-
=
|
197 |
|
198 |
-
*
|
199 |
-
*
|
200 |
-
|
201 |
-
= 3.3.7 =
|
202 |
-
|
203 |
-
* Solve CSS compatibility issue with WPEstate
|
204 |
-
* PHP 7 compatibility
|
205 |
-
|
206 |
-
= 3.3.6 =
|
207 |
-
|
208 |
-
* When quota exceeded, download the images that are already processed on the server
|
209 |
-
|
210 |
-
= 3.3.5 =
|
211 |
-
|
212 |
-
* fix the size problem of the settings tabs when not yet activated
|
213 |
|
214 |
= 3.3.4 =
|
215 |
|
5 |
|
6 |
Requires at least: 3.2.0
|
7 |
Tested up to: 4.6
|
8 |
+
Stable tag: 4.0.0
|
9 |
License: GPLv2 or later
|
10 |
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
11 |
|
12 |
+
Easy-to-use, lightweight plugin that optimizes images & PDFs. Make your website faster, keeping the images’ high quality. WooCommerce compatible
|
13 |
|
14 |
== Description ==
|
15 |
|
16 |
ShortPixel makes your website load faster by resizing/rescaling and then compressing the images. Optimized images mean better user experience, better PageSpeed Insights results, better Google PageRank (SEO) and more visitors. Both lossy and lossless <a rel="friend" href="https://shortpixel.com" target="_blank">image compression</a> available for all common image types (JPG, PNG and GIF), plus PDF files.
|
17 |
|
18 |
+
**Compatible with**
|
19 |
+
* any image gallery (including NextGEN)
|
20 |
+
* any slider
|
21 |
+
* Woo Commerce plugin
|
22 |
+
ShortPixel is also able to optimize any images regardless of where they are located on disk (e.g. theme specific icons, logos, images).
|
23 |
|
24 |
**How does it work?**
|
25 |
|
26 |
* choose your favorite settings like lossy/lossless, keep/remove EXIF, backup, optimize thumbs, etc.
|
27 |
* all your current pics can be easily scaled and optimized with a single click via our **bulk optimization** page.
|
28 |
* new images are automatically resized and compressed in the cloud right after they are uploaded.
|
29 |
+
* smaller images will start being served from your website once they are optimized
|
30 |
|
31 |
It's that easy indeed.
|
32 |
|
36 |
|
37 |
**Why use ShortPixel to optimize your images? Here are some of the features:**
|
38 |
|
39 |
+
* **24h support** (24/7) directly from the developers
|
40 |
* compress JPG, PNG, GIF (still and animated) images and PDF documents
|
41 |
* optimize thumbnails as well as featured images
|
42 |
+
* ability to optimize any image on your site including images in NextGEN Gallery and any other image gallery or slider
|
43 |
* featured images can be rescaled before being optimized. **No need for additional plugins** like Imsanity
|
44 |
* CMYK to RGB conversion
|
45 |
* skip already optimized images
|
83 |
|
84 |
**New features coming soon:**
|
85 |
|
86 |
+
* new resize options
|
87 |
+
* WebP support
|
88 |
+
* Retina optimiziation and support
|
89 |
+
* mass restore for backed-up images.
|
90 |
|
91 |
|
92 |
**Get in touch!**
|
97 |
* Facebook <a href="https://www.facebook.com/ShortPixel" target="_blank">https://www.facebook.com/ShortPixel</a>
|
98 |
* LinkedIn <a href="https://www.linkedin.com/company/shortpixel" target="_blank">https://www.linkedin.com/company/shortpixel</a>
|
99 |
|
100 |
+
**Keywords:** picture, optimization, image editor, pngout, upload speed, shortpixel, compression, nextgen jpegmini, webp, lossless, cwebp, media, jpegtran, image, image optimisation, image optimization, shrink, picture, photo, optimize photos, compress, performance, tinypng, crunch, pngquant, attachment, optimize, pictures, fast, images, image files, image quality, lossy, upload, kraken, resize, seo, smushit, optipng, kraken image optimizer, ewww, photo optimization, gifsicle, image optimizer, images, krakenio, png, gmagick, image optimize, pdf, pdf optimisation, pdf optimization, optimize pdf, optimise pdf, shrink pdf, jpg, jpeg, jpg optimisation, jpg optimization, optimize jpg, optimise jpg, shrink jpg, gif, animated gif, optimize gif, optimise gif, optimizer, optimiser, compresion, optimization, cruncher, image cruncher, compress png, compress jpg, compress jpeg, compress pdf, faster loading times, image optimiser, improve pagerank, optimise, optimize animated gif, optimise jpeg, optimize jpeg, optimize png, optimise png, optimise pdf, optimize pdf, tinyjpg, short pixel, shortpixel, woocommerce compatible, wpml compatible, smush, imsanity, scale, wp smush, compress images, pdf compression, optimize images, shrink jpeg, compressor, faster website, google pagerank, imagify, prizm, optimus, zara, improve page speed, PageSpeed Insights, sitespeed, smaller images, tinyjpeg, wordpress compression, wordPress image tool, reduce image size, bandwidth, pics, keep exif, remove exif, speed up site, speed up website, compress thumbnails, optimize thumbnails
|
101 |
|
102 |
|
103 |
== Installation ==
|
199 |
|
200 |
== Changelog ==
|
201 |
|
202 |
+
= 4.0.0 =
|
203 |
|
204 |
+
* Custom folders optimization
|
205 |
+
* NextGen galleries optimization
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
206 |
|
207 |
= 3.3.4 =
|
208 |
|
{css → res/css}/short-pixel.css
RENAMED
@@ -1,18 +1,109 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
div.shortpixel-rate-us {
|
2 |
display:inline-block;
|
3 |
-
margin-left:
|
4 |
vertical-align: top;
|
5 |
font-weight: bold;
|
6 |
-
padding-top: 5px;
|
7 |
}
|
8 |
div.shortpixel-rate-us > a {
|
9 |
vertical-align: middle;
|
10 |
-
padding:
|
|
|
|
|
11 |
}
|
12 |
-
div.shortpixel-rate-us > a >
|
13 |
display: inline-block;
|
14 |
vertical-align: top;
|
15 |
-
margin-top:
|
16 |
}
|
17 |
div.shortpixel-rate-us > a > img {
|
18 |
padding-top: 7px;
|
@@ -82,7 +173,7 @@ li.shortpixel-hide {
|
|
82 |
width:98%;
|
83 |
background-color:white;
|
84 |
padding:10px 10px 0;
|
85 |
-
margin-top: 2em
|
86 |
}
|
87 |
|
88 |
.bulk-stats-container{
|
@@ -132,6 +223,14 @@ li.shortpixel-hide {
|
|
132 |
float:left;
|
133 |
margin-bottom:20px;
|
134 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
135 |
.wp-core-ui .bulk-play a.button{
|
136 |
height:60px;
|
137 |
margin-top: 27px;
|
@@ -172,7 +271,7 @@ li.shortpixel-hide {
|
|
172 |
.bulk-progress {
|
173 |
padding: 20px 32px 17px;
|
174 |
background-color: #ffffff;
|
175 |
-
border: 1px dotted #c4c2c2
|
176 |
}
|
177 |
.bulk-progress.bulk-stats > div{
|
178 |
display:inline-block;
|
@@ -230,19 +329,39 @@ li.shortpixel-hide {
|
|
230 |
}
|
231 |
.short-pixel-block-title {
|
232 |
font-size: 22px;
|
|
|
233 |
margin-bottom: 15px;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
234 |
}
|
235 |
.bulk-slider-container {
|
236 |
margin-top: 20px;
|
237 |
-
|
238 |
-
|
239 |
}
|
240 |
.bulk-slider-container h2{
|
241 |
margin-bottom: 15px;
|
242 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
243 |
.bulk-slider .bulk-slide {
|
244 |
-
position: absolute
|
245 |
-
|
|
|
|
|
|
|
246 |
}
|
247 |
.bulk-slider .img-original,
|
248 |
.bulk-slider .img-optimized{
|
@@ -264,6 +383,12 @@ li.shortpixel-hide {
|
|
264 |
vertical-align: top;
|
265 |
font-size: 48px;
|
266 |
max-width: 150px;
|
|
|
|
|
|
|
|
|
|
|
|
|
267 |
}
|
268 |
p.settings-info {
|
269 |
padding-top: 0px;
|
@@ -276,7 +401,7 @@ article.sp-tabs {
|
|
276 |
position: relative;
|
277 |
display: block;
|
278 |
width: 100%;
|
279 |
-
height:
|
280 |
margin: 2em auto;
|
281 |
}
|
282 |
article.sp-tabs section {
|
@@ -284,7 +409,7 @@ article.sp-tabs section {
|
|
284 |
display: block;
|
285 |
top: 1.8em;
|
286 |
left: 0;
|
287 |
-
height:
|
288 |
width:94%;
|
289 |
padding: 10px 20px;
|
290 |
background-color: #ddd;
|
@@ -315,6 +440,9 @@ article.sp-tabs section:nth-child(2) h2 {
|
|
315 |
article.sp-tabs section:nth-child(3) h2 {
|
316 |
left: 374px;
|
317 |
}
|
|
|
|
|
|
|
318 |
article.sp-tabs section h2 a {
|
319 |
display: block;
|
320 |
width: 100%;
|
@@ -355,3 +483,50 @@ section#tab-resources .text-center {
|
|
355 |
section#tab-resources p {
|
356 |
font-size: 16px;
|
357 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
div.fb-like {
|
2 |
+
transform: scale(1.3);
|
3 |
+
-ms-transform: scale(1.3);
|
4 |
+
-webkit-transform: scale(1.3);
|
5 |
+
-o-transform: scale(1.3);
|
6 |
+
-moz-transform: scale(1.3);
|
7 |
+
transform-origin: bottom left;
|
8 |
+
-ms-transform-origin: bottom left;
|
9 |
+
-webkit-transform-origin: bottom left;
|
10 |
+
-moz-transform-origin: bottom left;
|
11 |
+
-webkit-transform-origin: bottom left;
|
12 |
+
}
|
13 |
+
div.short-pixel-bulk-page input.dial {
|
14 |
+
font-size: 16px !important;
|
15 |
+
}
|
16 |
+
div.short-pixel-bulk-page h1 {
|
17 |
+
margin-bottom:20px;
|
18 |
+
}
|
19 |
+
div.bulk-progress h2 {
|
20 |
+
margin-top:0;
|
21 |
+
margin-bottom: 10px;
|
22 |
+
}
|
23 |
+
div.bulk-progress .bulk-progress-indicator {
|
24 |
+
display: inline-block;
|
25 |
+
text-align: center;
|
26 |
+
padding: 0 10px;
|
27 |
+
margin-left: 10px;
|
28 |
+
float: left;
|
29 |
+
height: 90px;
|
30 |
+
overflow: hidden;
|
31 |
+
border: 1px solid #1CAECB;
|
32 |
+
}
|
33 |
+
div.wrap.short-pixel-bulk-page .bulk-notice-container {
|
34 |
+
margin-top: 15px;
|
35 |
+
position: absolute;
|
36 |
+
}
|
37 |
+
div.wrap.short-pixel-bulk-page .bulk-notice-container .bulk-notice-msg {
|
38 |
+
text-align: center;
|
39 |
+
margin: 10px 0 0 32px;
|
40 |
+
overflow: hidden;
|
41 |
+
border: 1px solid #1CAECB;
|
42 |
+
background-color: #9ddbe0;
|
43 |
+
border-radius: 5px;
|
44 |
+
padding: 7px 10px 10px;
|
45 |
+
display: none;
|
46 |
+
max-width: 600px;
|
47 |
+
}
|
48 |
+
div.wrap.short-pixel-bulk-page .bulk-notice-container .bulk-notice-msg.bulk-error {
|
49 |
+
border: 1px solid #c32525;
|
50 |
+
background-color: #ff969d;
|
51 |
+
}
|
52 |
+
div.wrap.short-pixel-bulk-page .bulk-notice-msg img {
|
53 |
+
float:left;
|
54 |
+
margin-top:3px;
|
55 |
+
margin-right: 5px;
|
56 |
+
}
|
57 |
+
div.sp-bulk-summary {
|
58 |
+
float:right;
|
59 |
+
margin:8px 5px 3px 20px;
|
60 |
+
}
|
61 |
+
input.dial {
|
62 |
+
box-shadow: none;
|
63 |
+
}
|
64 |
+
.shortpixel-table .column-filename {
|
65 |
+
max-width: 32em;
|
66 |
+
width: 40%;
|
67 |
+
}
|
68 |
+
.shortpixel-table .column-folder {
|
69 |
+
max-width: 20em;
|
70 |
+
width: 20%;
|
71 |
+
}
|
72 |
+
.shortpixel-table .column-media_type {
|
73 |
+
max-width: 8em;
|
74 |
+
width: 10%;
|
75 |
+
}
|
76 |
+
.shortpixel-table .column-status {
|
77 |
+
max-width: 16em;
|
78 |
+
width: 15%;
|
79 |
+
}
|
80 |
+
.shortpixel-table .column-options {
|
81 |
+
max-width: 16em;
|
82 |
+
width: 15%;
|
83 |
+
}
|
84 |
+
|
85 |
+
.form-table table.shortpixel-folders-list tr {
|
86 |
+
background-color: #eee;
|
87 |
+
}
|
88 |
+
.form-table table.shortpixel-folders-list td {
|
89 |
+
padding: 5px 10px;
|
90 |
+
}
|
91 |
div.shortpixel-rate-us {
|
92 |
display:inline-block;
|
93 |
+
margin-left: 10px;
|
94 |
vertical-align: top;
|
95 |
font-weight: bold;
|
|
|
96 |
}
|
97 |
div.shortpixel-rate-us > a {
|
98 |
vertical-align: middle;
|
99 |
+
padding: 1px 5px 0;
|
100 |
+
text-align:center;
|
101 |
+
display: inline-block;
|
102 |
}
|
103 |
+
div.shortpixel-rate-us > a > span {
|
104 |
display: inline-block;
|
105 |
vertical-align: top;
|
106 |
+
margin-top: 5px;
|
107 |
}
|
108 |
div.shortpixel-rate-us > a > img {
|
109 |
padding-top: 7px;
|
173 |
width:98%;
|
174 |
background-color:white;
|
175 |
padding:10px 10px 0;
|
176 |
+
/*margin-top: 2em;*/
|
177 |
}
|
178 |
|
179 |
.bulk-stats-container{
|
223 |
float:left;
|
224 |
margin-bottom:20px;
|
225 |
}
|
226 |
+
.wp-core-ui .bulk-play.bulk-nothing-optimize {
|
227 |
+
font-weight: bold;
|
228 |
+
color: #0080b2;
|
229 |
+
border: 1px solid;
|
230 |
+
border-radius: 5px;
|
231 |
+
margin-top: 60px;
|
232 |
+
padding: 5px 12px;
|
233 |
+
}
|
234 |
.wp-core-ui .bulk-play a.button{
|
235 |
height:60px;
|
236 |
margin-top: 27px;
|
271 |
.bulk-progress {
|
272 |
padding: 20px 32px 17px;
|
273 |
background-color: #ffffff;
|
274 |
+
/*border: 1px dotted #c4c2c2;*/
|
275 |
}
|
276 |
.bulk-progress.bulk-stats > div{
|
277 |
display:inline-block;
|
329 |
}
|
330 |
.short-pixel-block-title {
|
331 |
font-size: 22px;
|
332 |
+
font-weight: bold;
|
333 |
margin-bottom: 15px;
|
334 |
+
text-align: center;
|
335 |
+
margin-bottom: 30px;
|
336 |
+
}
|
337 |
+
.sp-floating-block.bulk-slider-container {
|
338 |
+
display: none;
|
339 |
+
}
|
340 |
+
.sp-floating-block.notice.bulk-notices-parent {
|
341 |
+
padding: 0;
|
342 |
+
margin: 0;
|
343 |
}
|
344 |
.bulk-slider-container {
|
345 |
margin-top: 20px;
|
346 |
+
min-height: 300px;
|
347 |
+
overflow: hidden;
|
348 |
}
|
349 |
.bulk-slider-container h2{
|
350 |
margin-bottom: 15px;
|
351 |
}
|
352 |
+
.bulk-slider-container span.filename {
|
353 |
+
font-weight: normal;
|
354 |
+
}
|
355 |
+
.bulk-slider {
|
356 |
+
display: table;
|
357 |
+
margin: 0 auto;
|
358 |
+
}
|
359 |
.bulk-slider .bulk-slide {
|
360 |
+
/*position: absolute;*/
|
361 |
+
margin: 0 auto;
|
362 |
+
padding-left: 120px;
|
363 |
+
display: inline-block;
|
364 |
+
font-weight: bold;
|
365 |
}
|
366 |
.bulk-slider .img-original,
|
367 |
.bulk-slider .img-optimized{
|
383 |
vertical-align: top;
|
384 |
font-size: 48px;
|
385 |
max-width: 150px;
|
386 |
+
padding: 10px 0 0 20px;
|
387 |
+
}
|
388 |
+
.bulk-slide-images {
|
389 |
+
display: inline-block;
|
390 |
+
border: 1px solid #1CAECB;
|
391 |
+
padding: 15px 0 0 20px;
|
392 |
}
|
393 |
p.settings-info {
|
394 |
padding-top: 0px;
|
401 |
position: relative;
|
402 |
display: block;
|
403 |
width: 100%;
|
404 |
+
height: 1100px;
|
405 |
margin: 2em auto;
|
406 |
}
|
407 |
article.sp-tabs section {
|
409 |
display: block;
|
410 |
top: 1.8em;
|
411 |
left: 0;
|
412 |
+
height: 1100px;
|
413 |
width:94%;
|
414 |
padding: 10px 20px;
|
415 |
background-color: #ddd;
|
440 |
article.sp-tabs section:nth-child(3) h2 {
|
441 |
left: 374px;
|
442 |
}
|
443 |
+
article.sp-tabs section:nth-child(4) h2 {
|
444 |
+
left: 556px;
|
445 |
+
}
|
446 |
article.sp-tabs section h2 a {
|
447 |
display: block;
|
448 |
width: 100%;
|
483 |
section#tab-resources p {
|
484 |
font-size: 16px;
|
485 |
}
|
486 |
+
|
487 |
+
/* ShortPixel columns layout */
|
488 |
+
.wrap.short-pixel-bulk-page {
|
489 |
+
margin-right: 0;
|
490 |
+
}
|
491 |
+
.sp-container {
|
492 |
+
overflow: hidden;
|
493 |
+
display:block;
|
494 |
+
width:100%;
|
495 |
+
}
|
496 |
+
.sp-floating-block {
|
497 |
+
overflow: hidden;
|
498 |
+
display:inline-block;
|
499 |
+
float: left;
|
500 |
+
margin-right: 1.1% !important;
|
501 |
+
}
|
502 |
+
.sp-full-width {
|
503 |
+
width: 98.8%;
|
504 |
+
box-sizing: border-box;
|
505 |
+
}
|
506 |
+
.sp-double-width {
|
507 |
+
width: 65.52%;
|
508 |
+
box-sizing: border-box;
|
509 |
+
}
|
510 |
+
.sp-single-width {
|
511 |
+
width: 32.23%;
|
512 |
+
box-sizing: border-box;
|
513 |
+
}
|
514 |
+
@media(max-width: 1759px) {
|
515 |
+
.sp-floating-block {
|
516 |
+
margin-right: 1.3% !important;
|
517 |
+
}
|
518 |
+
.sp-double-width, .sp-full-width {
|
519 |
+
width: 98.65%;
|
520 |
+
}
|
521 |
+
.sp-single-width {
|
522 |
+
width: 48.7%;
|
523 |
+
}
|
524 |
+
}
|
525 |
+
@media(max-width: 1249px) {
|
526 |
+
.sp-floating-block {
|
527 |
+
margin-right: 2% !important;
|
528 |
+
}
|
529 |
+
.sp-double-width, .sp-full-width, .sp-single-width {
|
530 |
+
width: 97%;
|
531 |
+
}
|
532 |
+
}
|
res/css/sp-file-tree.css
ADDED
@@ -0,0 +1,259 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
div.sp-folder-picker-shade {
|
2 |
+
display: none; /* Hidden by default */
|
3 |
+
position: fixed; /* Stay in place */
|
4 |
+
z-index: 10; /* Sit on top */
|
5 |
+
left: 0;
|
6 |
+
top: 0;
|
7 |
+
width: 100%; /* Full width */
|
8 |
+
height: 100%; /* Full height */
|
9 |
+
overflow: auto; /* Enable scroll if needed */
|
10 |
+
background-color: rgb(0,0,0); /* Fallback color */
|
11 |
+
background-color: rgba(0,0,0,0.4); /* Black w/ opacity */
|
12 |
+
}
|
13 |
+
div.sp-folder-picker-popup {
|
14 |
+
background-color: #fefefe;
|
15 |
+
margin: 15% auto; /* 15% from the top and centered */
|
16 |
+
padding: 20px;
|
17 |
+
border: 1px solid #888;
|
18 |
+
width: 30%; /* Could be more or less, depending on screen size */
|
19 |
+
min-width: 300px; /* Could be more or less, depending on screen size */
|
20 |
+
}
|
21 |
+
div.sp-folder-picker-title {
|
22 |
+
font-size: 1.4em;
|
23 |
+
}
|
24 |
+
div.sp-folder-picker {
|
25 |
+
margin: 20px 0; /* 15% from the top and centered */
|
26 |
+
border: 1px solid #888;
|
27 |
+
max-height: 400px;
|
28 |
+
overflow: auto;}
|
29 |
+
|
30 |
+
UL.jqueryFileTree LI.directory.selected {
|
31 |
+
background-color: #209fd2;
|
32 |
+
}
|
33 |
+
|
34 |
+
UL.jqueryFileTree {
|
35 |
+
font-family: Verdana, sans-serif;
|
36 |
+
font-size: 11px;
|
37 |
+
line-height: 18px;
|
38 |
+
padding: 0;
|
39 |
+
margin: 0;
|
40 |
+
display: none;
|
41 |
+
}
|
42 |
+
UL.jqueryFileTree LI {
|
43 |
+
list-style: none;
|
44 |
+
padding: 0;
|
45 |
+
padding-left: 20px;
|
46 |
+
margin: 0;
|
47 |
+
white-space: nowrap;
|
48 |
+
}
|
49 |
+
UL.jqueryFileTree LI.directory {
|
50 |
+
background: url(../img/file-tree/directory.png) left top no-repeat;
|
51 |
+
}
|
52 |
+
UL.jqueryFileTree LI.directory-locked {
|
53 |
+
background: url(../img/file-tree/directory-lock.png) left top no-repeat;
|
54 |
+
}
|
55 |
+
UL.jqueryFileTree LI.expanded {
|
56 |
+
background: url(../img/file-tree/folder_open.png) left top no-repeat;
|
57 |
+
}
|
58 |
+
UL.jqueryFileTree LI.file {
|
59 |
+
background: url(../img/file-tree/file.png) left top no-repeat;
|
60 |
+
}
|
61 |
+
UL.jqueryFileTree LI.file-locked {
|
62 |
+
background: url(../img/file-tree/file-lock.png) left top no-repeat !important;
|
63 |
+
}
|
64 |
+
UL.jqueryFileTree LI.wait {
|
65 |
+
background: url(../img/file-tree/spinner.gif) left top no-repeat;
|
66 |
+
}
|
67 |
+
UL.jqueryFileTree LI.selected > a {
|
68 |
+
font-weight: bold;
|
69 |
+
}
|
70 |
+
UL.jqueryFileTree LI.ext_3gp {
|
71 |
+
background: url(../img/file-tree/film.png) left top no-repeat;
|
72 |
+
}
|
73 |
+
UL.jqueryFileTree LI.ext_afp {
|
74 |
+
background: url(../img/file-tree/code.png) left top no-repeat;
|
75 |
+
}
|
76 |
+
UL.jqueryFileTree LI.ext_afpa {
|
77 |
+
background: url(../img/file-tree/code.png) left top no-repeat;
|
78 |
+
}
|
79 |
+
UL.jqueryFileTree LI.ext_asp {
|
80 |
+
background: url(../img/file-tree/code.png) left top no-repeat;
|
81 |
+
}
|
82 |
+
UL.jqueryFileTree LI.ext_aspx {
|
83 |
+
background: url(../img/file-tree/code.png) left top no-repeat;
|
84 |
+
}
|
85 |
+
UL.jqueryFileTree LI.ext_avi {
|
86 |
+
background: url(../img/file-tree/film.png) left top no-repeat;
|
87 |
+
}
|
88 |
+
UL.jqueryFileTree LI.ext_bat {
|
89 |
+
background: url(../img/file-tree/application.png) left top no-repeat;
|
90 |
+
}
|
91 |
+
UL.jqueryFileTree LI.ext_bmp {
|
92 |
+
background: url(../img/file-tree/picture.png) left top no-repeat;
|
93 |
+
}
|
94 |
+
UL.jqueryFileTree LI.ext_c {
|
95 |
+
background: url(../img/file-tree/code.png) left top no-repeat;
|
96 |
+
}
|
97 |
+
UL.jqueryFileTree LI.ext_cfm {
|
98 |
+
background: url(../img/file-tree/code.png) left top no-repeat;
|
99 |
+
}
|
100 |
+
UL.jqueryFileTree LI.ext_cgi {
|
101 |
+
background: url(../img/file-tree/code.png) left top no-repeat;
|
102 |
+
}
|
103 |
+
UL.jqueryFileTree LI.ext_com {
|
104 |
+
background: url(../img/file-tree/application.png) left top no-repeat;
|
105 |
+
}
|
106 |
+
UL.jqueryFileTree LI.ext_cpp {
|
107 |
+
background: url(../img/file-tree/code.png) left top no-repeat;
|
108 |
+
}
|
109 |
+
UL.jqueryFileTree LI.ext_css {
|
110 |
+
background: url(../img/file-tree/css.png) left top no-repeat;
|
111 |
+
}
|
112 |
+
UL.jqueryFileTree LI.ext_doc {
|
113 |
+
background: url(../img/file-tree/doc.png) left top no-repeat;
|
114 |
+
}
|
115 |
+
UL.jqueryFileTree LI.ext_exe {
|
116 |
+
background: url(../img/file-tree/application.png) left top no-repeat;
|
117 |
+
}
|
118 |
+
UL.jqueryFileTree LI.ext_gif {
|
119 |
+
background: url(../img/file-tree/picture.png) left top no-repeat;
|
120 |
+
}
|
121 |
+
UL.jqueryFileTree LI.ext_fla {
|
122 |
+
background: url(../img/file-tree/flash.png) left top no-repeat;
|
123 |
+
}
|
124 |
+
UL.jqueryFileTree LI.ext_h {
|
125 |
+
background: url(../img/file-tree/code.png) left top no-repeat;
|
126 |
+
}
|
127 |
+
UL.jqueryFileTree LI.ext_htm {
|
128 |
+
background: url(../img/file-tree/html.png) left top no-repeat;
|
129 |
+
}
|
130 |
+
UL.jqueryFileTree LI.ext_html {
|
131 |
+
background: url(../img/file-tree/html.png) left top no-repeat;
|
132 |
+
}
|
133 |
+
UL.jqueryFileTree LI.ext_jar {
|
134 |
+
background: url(../img/file-tree/java.png) left top no-repeat;
|
135 |
+
}
|
136 |
+
UL.jqueryFileTree LI.ext_jpg {
|
137 |
+
background: url(../img/file-tree/picture.png) left top no-repeat;
|
138 |
+
}
|
139 |
+
UL.jqueryFileTree LI.ext_jpeg {
|
140 |
+
background: url(../img/file-tree/picture.png) left top no-repeat;
|
141 |
+
}
|
142 |
+
UL.jqueryFileTree LI.ext_js {
|
143 |
+
background: url(../img/file-tree/script.png) left top no-repeat;
|
144 |
+
}
|
145 |
+
UL.jqueryFileTree LI.ext_lasso {
|
146 |
+
background: url(../img/file-tree/code.png) left top no-repeat;
|
147 |
+
}
|
148 |
+
UL.jqueryFileTree LI.ext_log {
|
149 |
+
background: url(../img/file-tree/txt.png) left top no-repeat;
|
150 |
+
}
|
151 |
+
UL.jqueryFileTree LI.ext_m4p {
|
152 |
+
background: url(../img/file-tree/music.png) left top no-repeat;
|
153 |
+
}
|
154 |
+
UL.jqueryFileTree LI.ext_mov {
|
155 |
+
background: url(../img/file-tree/film.png) left top no-repeat;
|
156 |
+
}
|
157 |
+
UL.jqueryFileTree LI.ext_mp3 {
|
158 |
+
background: url(../img/file-tree/music.png) left top no-repeat;
|
159 |
+
}
|
160 |
+
UL.jqueryFileTree LI.ext_mp4 {
|
161 |
+
background: url(../img/file-tree/film.png) left top no-repeat;
|
162 |
+
}
|
163 |
+
UL.jqueryFileTree LI.ext_mpg {
|
164 |
+
background: url(../img/file-tree/film.png) left top no-repeat;
|
165 |
+
}
|
166 |
+
UL.jqueryFileTree LI.ext_mpeg {
|
167 |
+
background: url(../img/file-tree/film.png) left top no-repeat;
|
168 |
+
}
|
169 |
+
UL.jqueryFileTree LI.ext_ogg {
|
170 |
+
background: url(../img/file-tree/music.png) left top no-repeat;
|
171 |
+
}
|
172 |
+
UL.jqueryFileTree LI.ext_ogv {
|
173 |
+
background: url(../img/file-tree/film.png) left top no-repeat;
|
174 |
+
}
|
175 |
+
UL.jqueryFileTree LI.ext_pcx {
|
176 |
+
background: url(../img/file-tree/picture.png) left top no-repeat;
|
177 |
+
}
|
178 |
+
UL.jqueryFileTree LI.ext_pdf {
|
179 |
+
background: url(../img/file-tree/pdf.png) left top no-repeat;
|
180 |
+
}
|
181 |
+
UL.jqueryFileTree LI.ext_php {
|
182 |
+
background: url(../img/file-tree/php.png) left top no-repeat;
|
183 |
+
}
|
184 |
+
UL.jqueryFileTree LI.ext_png {
|
185 |
+
background: url(../img/file-tree/picture.png) left top no-repeat;
|
186 |
+
}
|
187 |
+
UL.jqueryFileTree LI.ext_ppt {
|
188 |
+
background: url(../img/file-tree/ppt.png) left top no-repeat;
|
189 |
+
}
|
190 |
+
UL.jqueryFileTree LI.ext_psd {
|
191 |
+
background: url(../img/file-tree/psd.png) left top no-repeat;
|
192 |
+
}
|
193 |
+
UL.jqueryFileTree LI.ext_pl {
|
194 |
+
background: url(../img/file-tree/script.png) left top no-repeat;
|
195 |
+
}
|
196 |
+
UL.jqueryFileTree LI.ext_py {
|
197 |
+
background: url(../img/file-tree/script.png) left top no-repeat;
|
198 |
+
}
|
199 |
+
UL.jqueryFileTree LI.ext_rb {
|
200 |
+
background: url(../img/file-tree/ruby.png) left top no-repeat;
|
201 |
+
}
|
202 |
+
UL.jqueryFileTree LI.ext_rbx {
|
203 |
+
background: url(../img/file-tree/ruby.png) left top no-repeat;
|
204 |
+
}
|
205 |
+
UL.jqueryFileTree LI.ext_rhtml {
|
206 |
+
background: url(../img/file-tree/ruby.png) left top no-repeat;
|
207 |
+
}
|
208 |
+
UL.jqueryFileTree LI.ext_rpm {
|
209 |
+
background: url(../img/file-tree/linux.png) left top no-repeat;
|
210 |
+
}
|
211 |
+
UL.jqueryFileTree LI.ext_ruby {
|
212 |
+
background: url(../img/file-tree/ruby.png) left top no-repeat;
|
213 |
+
}
|
214 |
+
UL.jqueryFileTree LI.ext_sql {
|
215 |
+
background: url(../img/file-tree/db.png) left top no-repeat;
|
216 |
+
}
|
217 |
+
UL.jqueryFileTree LI.ext_swf {
|
218 |
+
background: url(../img/file-tree/flash.png) left top no-repeat;
|
219 |
+
}
|
220 |
+
UL.jqueryFileTree LI.ext_tif {
|
221 |
+
background: url(../img/file-tree/picture.png) left top no-repeat;
|
222 |
+
}
|
223 |
+
UL.jqueryFileTree LI.ext_tiff {
|
224 |
+
background: url(../img/file-tree/picture.png) left top no-repeat;
|
225 |
+
}
|
226 |
+
UL.jqueryFileTree LI.ext_txt {
|
227 |
+
background: url(../img/file-tree/txt.png) left top no-repeat;
|
228 |
+
}
|
229 |
+
UL.jqueryFileTree LI.ext_vb {
|
230 |
+
background: url(../img/file-tree/code.png) left top no-repeat;
|
231 |
+
}
|
232 |
+
UL.jqueryFileTree LI.ext_wav {
|
233 |
+
background: url(../img/file-tree/music.png) left top no-repeat;
|
234 |
+
}
|
235 |
+
UL.jqueryFileTree LI.ext_webm {
|
236 |
+
background: url(../img/file-tree/film.png) left top no-repeat;
|
237 |
+
}
|
238 |
+
UL.jqueryFileTree LI.ext_wmv {
|
239 |
+
background: url(../img/file-tree/film.png) left top no-repeat;
|
240 |
+
}
|
241 |
+
UL.jqueryFileTree LI.ext_xls {
|
242 |
+
background: url(../img/file-tree/xls.png) left top no-repeat;
|
243 |
+
}
|
244 |
+
UL.jqueryFileTree LI.ext_xml {
|
245 |
+
background: url(../img/file-tree/code.png) left top no-repeat;
|
246 |
+
}
|
247 |
+
UL.jqueryFileTree LI.ext_zip {
|
248 |
+
background: url(../img/file-tree/zip.png) left top no-repeat;
|
249 |
+
}
|
250 |
+
UL.jqueryFileTree A {
|
251 |
+
color: #333;
|
252 |
+
text-decoration: none;
|
253 |
+
display: inline-block;
|
254 |
+
padding: 0 2px;
|
255 |
+
cursor: pointer;
|
256 |
+
}
|
257 |
+
UL.jqueryFileTree A:hover {
|
258 |
+
background: #BDF;
|
259 |
+
}
|
{img → res/img}/arrow.png
RENAMED
File without changes
|
res/img/exclamation-big.png
ADDED
Binary file
|
res/img/file-tree/application.png
ADDED
Binary file
|
res/img/file-tree/code.png
ADDED
Binary file
|
res/img/file-tree/css.png
ADDED
Binary file
|
res/img/file-tree/db.png
ADDED
Binary file
|
res/img/file-tree/directory-lock.png
ADDED
Binary file
|
res/img/file-tree/directory.png
ADDED
Binary file
|
res/img/file-tree/doc.png
ADDED
Binary file
|
res/img/file-tree/file-lock.png
ADDED
Binary file
|
res/img/file-tree/file.png
ADDED
Binary file
|
res/img/file-tree/film.png
ADDED
Binary file
|
res/img/file-tree/flash.png
ADDED
Binary file
|
res/img/file-tree/folder_open.png
ADDED
Binary file
|
res/img/file-tree/html.png
ADDED
Binary file
|
res/img/file-tree/java.png
ADDED
Binary file
|
res/img/file-tree/linux.png
ADDED
Binary file
|
res/img/file-tree/music.png
ADDED
Binary file
|
res/img/file-tree/pdf.png
ADDED
Binary file
|
res/img/file-tree/php.png
ADDED
Binary file
|
res/img/file-tree/picture.png
ADDED
Binary file
|
res/img/file-tree/ppt.png
ADDED
Binary file
|
res/img/file-tree/psd.png
ADDED
Binary file
|
res/img/file-tree/ruby.png
ADDED
Binary file
|
res/img/file-tree/script.png
ADDED
Binary file
|
res/img/file-tree/spinner.gif
ADDED
Binary file
|
res/img/file-tree/txt.png
ADDED
Binary file
|
res/img/file-tree/xls.png
ADDED
Binary file
|
res/img/file-tree/zip.png
ADDED
Binary file
|
res/img/info-icon.png
ADDED
Binary file
|
{img → res/img}/loading-dark-big.gif
RENAMED
File without changes
|
{img → res/img}/loading-dark.gif
RENAMED
File without changes
|
{img → res/img}/loading.gif
RENAMED
File without changes
|
res/img/logo-pdf.png
ADDED
Binary file
|
res/img/robo-slider.png
ADDED
Binary file
|
{img → res/img}/shortpixel-alert.png
RENAMED
File without changes
|
{img → res/img}/shortpixel.png
RENAMED
File without changes
|
{img → res/img}/slider.png
RENAMED
File without changes
|
{img → res/img}/stars.png
RENAMED
File without changes
|
res/js/jquery.knob.js
ADDED
@@ -0,0 +1,805 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*!jQuery Knob*/
|
2 |
+
/**
|
3 |
+
* Downward compatible, touchable dial
|
4 |
+
*
|
5 |
+
* Version: 1.2.12
|
6 |
+
* Requires: jQuery v1.7+
|
7 |
+
*
|
8 |
+
* Copyright (c) 2012 Anthony Terrien
|
9 |
+
* Under MIT License (http://www.opensource.org/licenses/mit-license.php)
|
10 |
+
*
|
11 |
+
* Thanks to vor, eskimoblood, spiffistan, FabrizioC
|
12 |
+
*/
|
13 |
+
(function (factory) {
|
14 |
+
if (typeof exports === 'object') {
|
15 |
+
// CommonJS
|
16 |
+
module.exports = factory(require('jquery'));
|
17 |
+
} else if (typeof define === 'function' && define.amd) {
|
18 |
+
// AMD. Register as an anonymous module.
|
19 |
+
define(['jquery'], factory);
|
20 |
+
} else {
|
21 |
+
// Browser globals
|
22 |
+
factory(jQuery);
|
23 |
+
}
|
24 |
+
}(function ($) {
|
25 |
+
|
26 |
+
/**
|
27 |
+
* Kontrol library
|
28 |
+
*/
|
29 |
+
"use strict";
|
30 |
+
|
31 |
+
/**
|
32 |
+
* Definition of globals and core
|
33 |
+
*/
|
34 |
+
var k = {}, // kontrol
|
35 |
+
max = Math.max,
|
36 |
+
min = Math.min;
|
37 |
+
|
38 |
+
k.c = {};
|
39 |
+
k.c.d = $(document);
|
40 |
+
k.c.t = function (e) {
|
41 |
+
return e.originalEvent.touches.length - 1;
|
42 |
+
};
|
43 |
+
|
44 |
+
/**
|
45 |
+
* Kontrol Object
|
46 |
+
*
|
47 |
+
* Definition of an abstract UI control
|
48 |
+
*
|
49 |
+
* Each concrete component must call this one.
|
50 |
+
* <code>
|
51 |
+
* k.o.call(this);
|
52 |
+
* </code>
|
53 |
+
*/
|
54 |
+
k.o = function () {
|
55 |
+
var s = this;
|
56 |
+
|
57 |
+
this.o = null; // array of options
|
58 |
+
this.$ = null; // jQuery wrapped element
|
59 |
+
this.i = null; // mixed HTMLInputElement or array of HTMLInputElement
|
60 |
+
this.g = null; // deprecated 2D graphics context for 'pre-rendering'
|
61 |
+
this.v = null; // value ; mixed array or integer
|
62 |
+
this.cv = null; // change value ; not commited value
|
63 |
+
this.x = 0; // canvas x position
|
64 |
+
this.y = 0; // canvas y position
|
65 |
+
this.w = 0; // canvas width
|
66 |
+
this.h = 0; // canvas height
|
67 |
+
this.$c = null; // jQuery canvas element
|
68 |
+
this.c = null; // rendered canvas context
|
69 |
+
this.t = 0; // touches index
|
70 |
+
this.isInit = false;
|
71 |
+
this.fgColor = null; // main color
|
72 |
+
this.pColor = null; // previous color
|
73 |
+
this.dH = null; // draw hook
|
74 |
+
this.cH = null; // change hook
|
75 |
+
this.eH = null; // cancel hook
|
76 |
+
this.rH = null; // release hook
|
77 |
+
this.scale = 1; // scale factor
|
78 |
+
this.relative = false;
|
79 |
+
this.relativeWidth = false;
|
80 |
+
this.relativeHeight = false;
|
81 |
+
this.$div = null; // component div
|
82 |
+
|
83 |
+
this.run = function () {
|
84 |
+
var cf = function (e, conf) {
|
85 |
+
var k;
|
86 |
+
for (k in conf) {
|
87 |
+
s.o[k] = conf[k];
|
88 |
+
}
|
89 |
+
s._carve().init();
|
90 |
+
s._configure()
|
91 |
+
._draw();
|
92 |
+
};
|
93 |
+
|
94 |
+
if (this.$.data('kontroled')) return;
|
95 |
+
this.$.data('kontroled', true);
|
96 |
+
|
97 |
+
this.extend();
|
98 |
+
this.o = $.extend({
|
99 |
+
// Config
|
100 |
+
min: this.$.data('min') !== undefined ? this.$.data('min') : 0,
|
101 |
+
max: this.$.data('max') !== undefined ? this.$.data('max') : 100,
|
102 |
+
stopper: true,
|
103 |
+
readOnly: this.$.data('readonly') || (this.$.attr('readonly') === 'readonly'),
|
104 |
+
|
105 |
+
// UI
|
106 |
+
cursor: this.$.data('cursor') === true && 30
|
107 |
+
|| this.$.data('cursor') || 0,
|
108 |
+
thickness: this.$.data('thickness')
|
109 |
+
&& Math.max(Math.min(this.$.data('thickness'), 1), 0.01)
|
110 |
+
|| 0.35,
|
111 |
+
lineCap: this.$.data('linecap') || 'butt',
|
112 |
+
width: this.$.data('width') || 200,
|
113 |
+
height: this.$.data('height') || 200,
|
114 |
+
displayInput: this.$.data('displayinput') == null || this.$.data('displayinput'),
|
115 |
+
displayPrevious: this.$.data('displayprevious'),
|
116 |
+
fgColor: this.$.data('fgcolor') || '#87CEEB',
|
117 |
+
inputColor: this.$.data('inputcolor'),
|
118 |
+
font: this.$.data('font') || 'Arial',
|
119 |
+
fontWeight: this.$.data('font-weight') || 'bold',
|
120 |
+
inline: false,
|
121 |
+
step: this.$.data('step') || 1,
|
122 |
+
rotation: this.$.data('rotation'),
|
123 |
+
|
124 |
+
// Hooks
|
125 |
+
draw: null, // function () {}
|
126 |
+
change: null, // function (value) {}
|
127 |
+
cancel: null, // function () {}
|
128 |
+
release: null, // function (value) {}
|
129 |
+
|
130 |
+
// Output formatting, allows to add unit: %, ms ...
|
131 |
+
format: function(v) {
|
132 |
+
return v;
|
133 |
+
},
|
134 |
+
parse: function (v) {
|
135 |
+
return parseFloat(v);
|
136 |
+
}
|
137 |
+
}, this.o
|
138 |
+
);
|
139 |
+
|
140 |
+
// finalize options
|
141 |
+
this.o.flip = this.o.rotation === 'anticlockwise' || this.o.rotation === 'acw';
|
142 |
+
if (!this.o.inputColor) {
|
143 |
+
this.o.inputColor = this.o.fgColor;
|
144 |
+
}
|
145 |
+
|
146 |
+
// routing value
|
147 |
+
if (this.$.is('fieldset')) {
|
148 |
+
|
149 |
+
// fieldset = array of integer
|
150 |
+
this.v = {};
|
151 |
+
this.i = this.$.find('input');
|
152 |
+
this.i.each(function(k) {
|
153 |
+
var $this = $(this);
|
154 |
+
s.i[k] = $this;
|
155 |
+
s.v[k] = s.o.parse($this.val());
|
156 |
+
|
157 |
+
$this.bind(
|
158 |
+
'change blur',
|
159 |
+
function () {
|
160 |
+
var val = {};
|
161 |
+
val[k] = $this.val();
|
162 |
+
s.val(s._validate(val));
|
163 |
+
}
|
164 |
+
);
|
165 |
+
});
|
166 |
+
this.$.find('legend').remove();
|
167 |
+
} else {
|
168 |
+
|
169 |
+
// input = integer
|
170 |
+
this.i = this.$;
|
171 |
+
this.v = this.o.parse(this.$.val());
|
172 |
+
this.v === '' && (this.v = this.o.min);
|
173 |
+
this.$.bind(
|
174 |
+
'change blur',
|
175 |
+
function () {
|
176 |
+
s.val(s._validate(s.o.parse(s.$.val())));
|
177 |
+
}
|
178 |
+
);
|
179 |
+
|
180 |
+
}
|
181 |
+
|
182 |
+
!this.o.displayInput && this.$.hide();
|
183 |
+
|
184 |
+
// adds needed DOM elements (canvas, div)
|
185 |
+
this.$c = $(document.createElement('canvas')).attr({
|
186 |
+
width: this.o.width,
|
187 |
+
height: this.o.height
|
188 |
+
});
|
189 |
+
|
190 |
+
// wraps all elements in a div
|
191 |
+
// add to DOM before Canvas init is triggered
|
192 |
+
this.$div = $('<div style="'
|
193 |
+
+ (this.o.inline ? 'display:inline;' : '')
|
194 |
+
+ 'width:' + this.o.width + 'px;height:' + this.o.height + 'px;'
|
195 |
+
+ '"></div>');
|
196 |
+
|
197 |
+
this.$.wrap(this.$div).before(this.$c);
|
198 |
+
this.$div = this.$.parent();
|
199 |
+
|
200 |
+
if (typeof G_vmlCanvasManager !== 'undefined') {
|
201 |
+
G_vmlCanvasManager.initElement(this.$c[0]);
|
202 |
+
}
|
203 |
+
|
204 |
+
this.c = this.$c[0].getContext ? this.$c[0].getContext('2d') : null;
|
205 |
+
|
206 |
+
if (!this.c) {
|
207 |
+
throw {
|
208 |
+
name: "CanvasNotSupportedException",
|
209 |
+
message: "Canvas not supported. Please use excanvas on IE8.0.",
|
210 |
+
toString: function(){return this.name + ": " + this.message}
|
211 |
+
}
|
212 |
+
}
|
213 |
+
|
214 |
+
// hdpi support
|
215 |
+
this.scale = (window.devicePixelRatio || 1) / (
|
216 |
+
this.c.webkitBackingStorePixelRatio ||
|
217 |
+
this.c.mozBackingStorePixelRatio ||
|
218 |
+
this.c.msBackingStorePixelRatio ||
|
219 |
+
this.c.oBackingStorePixelRatio ||
|
220 |
+
this.c.backingStorePixelRatio || 1
|
221 |
+
);
|
222 |
+
|
223 |
+
// detects relative width / height
|
224 |
+
this.relativeWidth = this.o.width % 1 !== 0
|
225 |
+
&& this.o.width.indexOf('%');
|
226 |
+
this.relativeHeight = this.o.height % 1 !== 0
|
227 |
+
&& this.o.height.indexOf('%');
|
228 |
+
this.relative = this.relativeWidth || this.relativeHeight;
|
229 |
+
|
230 |
+
// computes size and carves the component
|
231 |
+
this._carve();
|
232 |
+
|
233 |
+
// prepares props for transaction
|
234 |
+
if (this.v instanceof Object) {
|
235 |
+
this.cv = {};
|
236 |
+
this.copy(this.v, this.cv);
|
237 |
+
} else {
|
238 |
+
this.cv = this.v;
|
239 |
+
}
|
240 |
+
|
241 |
+
// binds configure event
|
242 |
+
this.$
|
243 |
+
.bind("configure", cf)
|
244 |
+
.parent()
|
245 |
+
.bind("configure", cf);
|
246 |
+
|
247 |
+
// finalize init
|
248 |
+
this._listen()
|
249 |
+
._configure()
|
250 |
+
._xy()
|
251 |
+
.init();
|
252 |
+
|
253 |
+
this.isInit = true;
|
254 |
+
|
255 |
+
this.$.val(this.o.format(this.v));
|
256 |
+
this._draw();
|
257 |
+
|
258 |
+
return this;
|
259 |
+
};
|
260 |
+
|
261 |
+
this._carve = function() {
|
262 |
+
if (this.relative) {
|
263 |
+
var w = this.relativeWidth ?
|
264 |
+
this.$div.parent().width() *
|
265 |
+
parseInt(this.o.width) / 100
|
266 |
+
: this.$div.parent().width(),
|
267 |
+
h = this.relativeHeight ?
|
268 |
+
this.$div.parent().height() *
|
269 |
+
parseInt(this.o.height) / 100
|
270 |
+
: this.$div.parent().height();
|
271 |
+
|
272 |
+
// apply relative
|
273 |
+
this.w = this.h = Math.min(w, h);
|
274 |
+
} else {
|
275 |
+
this.w = this.o.width;
|
276 |
+
this.h = this.o.height;
|
277 |
+
}
|
278 |
+
|
279 |
+
// finalize div
|
280 |
+
this.$div.css({
|
281 |
+
'width': this.w + 'px',
|
282 |
+
'height': this.h + 'px'
|
283 |
+
});
|
284 |
+
|
285 |
+
// finalize canvas with computed width
|
286 |
+
this.$c.attr({
|
287 |
+
width: this.w,
|
288 |
+
height: this.h
|
289 |
+
});
|
290 |
+
|
291 |
+
// scaling
|
292 |
+
if (this.scale !== 1) {
|
293 |
+
this.$c[0].width = this.$c[0].width * this.scale;
|
294 |
+
this.$c[0].height = this.$c[0].height * this.scale;
|
295 |
+
this.$c.width(this.w);
|
296 |
+
this.$c.height(this.h);
|
297 |
+
}
|
298 |
+
|
299 |
+
return this;
|
300 |
+
};
|
301 |
+
|
302 |
+
this._draw = function () {
|
303 |
+
|
304 |
+
// canvas pre-rendering
|
305 |
+
var d = true;
|
306 |
+
|
307 |
+
s.g = s.c;
|
308 |
+
|
309 |
+
s.clear();
|
310 |
+
|
311 |
+
s.dH && (d = s.dH());
|
312 |
+
|
313 |
+
d !== false && s.draw();
|
314 |
+
};
|
315 |
+
|
316 |
+
this._touch = function (e) {
|
317 |
+
var touchMove = function (e) {
|
318 |
+
var v = s.xy2val(
|
319 |
+
e.originalEvent.touches[s.t].pageX,
|
320 |
+
e.originalEvent.touches[s.t].pageY
|
321 |
+
);
|
322 |
+
|
323 |
+
if (v == s.cv) return;
|
324 |
+
|
325 |
+
if (s.cH && s.cH(v) === false) return;
|
326 |
+
|
327 |
+
s.change(s._validate(v));
|
328 |
+
s._draw();
|
329 |
+
};
|
330 |
+
|
331 |
+
// get touches index
|
332 |
+
this.t = k.c.t(e);
|
333 |
+
|
334 |
+
// First touch
|
335 |
+
touchMove(e);
|
336 |
+
|
337 |
+
// Touch events listeners
|
338 |
+
k.c.d
|
339 |
+
.bind("touchmove.k", touchMove)
|
340 |
+
.bind(
|
341 |
+
"touchend.k",
|
342 |
+
function () {
|
343 |
+
k.c.d.unbind('touchmove.k touchend.k');
|
344 |
+
s.val(s.cv);
|
345 |
+
}
|
346 |
+
);
|
347 |
+
|
348 |
+
return this;
|
349 |
+
};
|
350 |
+
|
351 |
+
this._mouse = function (e) {
|
352 |
+
var mouseMove = function (e) {
|
353 |
+
var v = s.xy2val(e.pageX, e.pageY);
|
354 |
+
|
355 |
+
if (v == s.cv) return;
|
356 |
+
|
357 |
+
if (s.cH && (s.cH(v) === false)) return;
|
358 |
+
|
359 |
+
s.change(s._validate(v));
|
360 |
+
s._draw();
|
361 |
+
};
|
362 |
+
|
363 |
+
// First click
|
364 |
+
mouseMove(e);
|
365 |
+
|
366 |
+
// Mouse events listeners
|
367 |
+
k.c.d
|
368 |
+
.bind("mousemove.k", mouseMove)
|
369 |
+
.bind(
|
370 |
+
// Escape key cancel current change
|
371 |
+
"keyup.k",
|
372 |
+
function (e) {
|
373 |
+
if (e.keyCode === 27) {
|
374 |
+
k.c.d.unbind("mouseup.k mousemove.k keyup.k");
|
375 |
+
|
376 |
+
if (s.eH && s.eH() === false)
|
377 |
+
return;
|
378 |
+
|
379 |
+
s.cancel();
|
380 |
+
}
|
381 |
+
}
|
382 |
+
)
|
383 |
+
.bind(
|
384 |
+
"mouseup.k",
|
385 |
+
function (e) {
|
386 |
+
k.c.d.unbind('mousemove.k mouseup.k keyup.k');
|
387 |
+
s.val(s.cv);
|
388 |
+
}
|
389 |
+
);
|
390 |
+
|
391 |
+
return this;
|
392 |
+
};
|
393 |
+
|
394 |
+
this._xy = function () {
|
395 |
+
var o = this.$c.offset();
|
396 |
+
this.x = o.left;
|
397 |
+
this.y = o.top;
|
398 |
+
|
399 |
+
return this;
|
400 |
+
};
|
401 |
+
|
402 |
+
this._listen = function () {
|
403 |
+
if (!this.o.readOnly) {
|
404 |
+
this.$c
|
405 |
+
.bind(
|
406 |
+
"mousedown",
|
407 |
+
function (e) {
|
408 |
+
e.preventDefault();
|
409 |
+
s._xy()._mouse(e);
|
410 |
+
}
|
411 |
+
)
|
412 |
+
.bind(
|
413 |
+
"touchstart",
|
414 |
+
function (e) {
|
415 |
+
e.preventDefault();
|
416 |
+
s._xy()._touch(e);
|
417 |
+
}
|
418 |
+
);
|
419 |
+
|
420 |
+
this.listen();
|
421 |
+
} else {
|
422 |
+
this.$.attr('readonly', 'readonly');
|
423 |
+
}
|
424 |
+
|
425 |
+
if (this.relative) {
|
426 |
+
$(window).resize(function() {
|
427 |
+
s._carve().init();
|
428 |
+
s._draw();
|
429 |
+
});
|
430 |
+
}
|
431 |
+
|
432 |
+
return this;
|
433 |
+
};
|
434 |
+
|
435 |
+
this._configure = function () {
|
436 |
+
|
437 |
+
// Hooks
|
438 |
+
if (this.o.draw) this.dH = this.o.draw;
|
439 |
+
if (this.o.change) this.cH = this.o.change;
|
440 |
+
if (this.o.cancel) this.eH = this.o.cancel;
|
441 |
+
if (this.o.release) this.rH = this.o.release;
|
442 |
+
|
443 |
+
if (this.o.displayPrevious) {
|
444 |
+
this.pColor = this.h2rgba(this.o.fgColor, "0.4");
|
445 |
+
this.fgColor = this.h2rgba(this.o.fgColor, "0.6");
|
446 |
+
} else {
|
447 |
+
this.fgColor = this.o.fgColor;
|
448 |
+
}
|
449 |
+
|
450 |
+
return this;
|
451 |
+
};
|
452 |
+
|
453 |
+
this._clear = function () {
|
454 |
+
this.$c[0].width = this.$c[0].width;
|
455 |
+
};
|
456 |
+
|
457 |
+
this._validate = function (v) {
|
458 |
+
var val = (~~ (((v < 0) ? -0.5 : 0.5) + (v/this.o.step))) * this.o.step;
|
459 |
+
return Math.round(val * 100) / 100;
|
460 |
+
};
|
461 |
+
|
462 |
+
// Abstract methods
|
463 |
+
this.listen = function () {}; // on start, one time
|
464 |
+
this.extend = function () {}; // each time configure triggered
|
465 |
+
this.init = function () {}; // each time configure triggered
|
466 |
+
this.change = function (v) {}; // on change
|
467 |
+
this.val = function (v) {}; // on release
|
468 |
+
this.xy2val = function (x, y) {}; //
|
469 |
+
this.draw = function () {}; // on change / on release
|
470 |
+
this.clear = function () { this._clear(); };
|
471 |
+
|
472 |
+
// Utils
|
473 |
+
this.h2rgba = function (h, a) {
|
474 |
+
var rgb;
|
475 |
+
h = h.substring(1,7);
|
476 |
+
rgb = [
|
477 |
+
parseInt(h.substring(0,2), 16),
|
478 |
+
parseInt(h.substring(2,4), 16),
|
479 |
+
parseInt(h.substring(4,6), 16)
|
480 |
+
];
|
481 |
+
|
482 |
+
return "rgba(" + rgb[0] + "," + rgb[1] + "," + rgb[2] + "," + a + ")";
|
483 |
+
};
|
484 |
+
|
485 |
+
this.copy = function (f, t) {
|
486 |
+
for (var i in f) {
|
487 |
+
t[i] = f[i];
|
488 |
+
}
|
489 |
+
};
|
490 |
+
};
|
491 |
+
|
492 |
+
|
493 |
+
/**
|
494 |
+
* k.Dial
|
495 |
+
*/
|
496 |
+
k.Dial = function () {
|
497 |
+
k.o.call(this);
|
498 |
+
|
499 |
+
this.startAngle = null;
|
500 |
+
this.xy = null;
|
501 |
+
this.radius = null;
|
502 |
+
this.lineWidth = null;
|
503 |
+
this.cursorExt = null;
|
504 |
+
this.w2 = null;
|
505 |
+
this.PI2 = 2*Math.PI;
|
506 |
+
|
507 |
+
this.extend = function () {
|
508 |
+
this.o = $.extend({
|
509 |
+
bgColor: this.$.data('bgcolor') || '#EEEEEE',
|
510 |
+
angleOffset: this.$.data('angleoffset') || 0,
|
511 |
+
angleArc: this.$.data('anglearc') || 360,
|
512 |
+
inline: true
|
513 |
+
}, this.o);
|
514 |
+
};
|
515 |
+
|
516 |
+
this.val = function (v, triggerRelease) {
|
517 |
+
if (null != v) {
|
518 |
+
|
519 |
+
// reverse format
|
520 |
+
v = this.o.parse(v);
|
521 |
+
|
522 |
+
if (triggerRelease !== false
|
523 |
+
&& v != this.v
|
524 |
+
&& this.rH
|
525 |
+
&& this.rH(v) === false) { return; }
|
526 |
+
|
527 |
+
this.cv = this.o.stopper ? max(min(v, this.o.max), this.o.min) : v;
|
528 |
+
this.v = this.cv;
|
529 |
+
this.$.val(this.o.format(this.v));
|
530 |
+
this._draw();
|
531 |
+
} else {
|
532 |
+
return this.v;
|
533 |
+
}
|
534 |
+
};
|
535 |
+
|
536 |
+
this.xy2val = function (x, y) {
|
537 |
+
var a, ret;
|
538 |
+
|
539 |
+
a = Math.atan2(
|
540 |
+
x - (this.x + this.w2),
|
541 |
+
- (y - this.y - this.w2)
|
542 |
+
) - this.angleOffset;
|
543 |
+
|
544 |
+
if (this.o.flip) {
|
545 |
+
a = this.angleArc - a - this.PI2;
|
546 |
+
}
|
547 |
+
|
548 |
+
if (this.angleArc != this.PI2 && (a < 0) && (a > -0.5)) {
|
549 |
+
|
550 |
+
// if isset angleArc option, set to min if .5 under min
|
551 |
+
a = 0;
|
552 |
+
} else if (a < 0) {
|
553 |
+
a += this.PI2;
|
554 |
+
}
|
555 |
+
|
556 |
+
ret = (a * (this.o.max - this.o.min) / this.angleArc) + this.o.min;
|
557 |
+
|
558 |
+
this.o.stopper && (ret = max(min(ret, this.o.max), this.o.min));
|
559 |
+
|
560 |
+
return ret;
|
561 |
+
};
|
562 |
+
|
563 |
+
this.listen = function () {
|
564 |
+
|
565 |
+
// bind MouseWheel
|
566 |
+
var s = this, mwTimerStop,
|
567 |
+
mwTimerRelease,
|
568 |
+
mw = function (e) {
|
569 |
+
e.preventDefault();
|
570 |
+
|
571 |
+
var ori = e.originalEvent,
|
572 |
+
deltaX = ori.detail || ori.wheelDeltaX,
|
573 |
+
deltaY = ori.detail || ori.wheelDeltaY,
|
574 |
+
v = s._validate(s.o.parse(s.$.val()))
|
575 |
+
+ (
|
576 |
+
deltaX > 0 || deltaY > 0
|
577 |
+
? s.o.step
|
578 |
+
: deltaX < 0 || deltaY < 0 ? -s.o.step : 0
|
579 |
+
);
|
580 |
+
|
581 |
+
v = max(min(v, s.o.max), s.o.min);
|
582 |
+
|
583 |
+
s.val(v, false);
|
584 |
+
|
585 |
+
if (s.rH) {
|
586 |
+
// Handle mousewheel stop
|
587 |
+
clearTimeout(mwTimerStop);
|
588 |
+
mwTimerStop = setTimeout(function () {
|
589 |
+
s.rH(v);
|
590 |
+
mwTimerStop = null;
|
591 |
+
}, 100);
|
592 |
+
|
593 |
+
// Handle mousewheel releases
|
594 |
+
if (!mwTimerRelease) {
|
595 |
+
mwTimerRelease = setTimeout(function () {
|
596 |
+
if (mwTimerStop)
|
597 |
+
s.rH(v);
|
598 |
+
mwTimerRelease = null;
|
599 |
+
}, 200);
|
600 |
+
}
|
601 |
+
}
|
602 |
+
},
|
603 |
+
kval,
|
604 |
+
to,
|
605 |
+
m = 1,
|
606 |
+
kv = {
|
607 |
+
37: -s.o.step,
|
608 |
+
38: s.o.step,
|
609 |
+
39: s.o.step,
|
610 |
+
40: -s.o.step
|
611 |
+
};
|
612 |
+
|
613 |
+
this.$
|
614 |
+
.bind(
|
615 |
+
"keydown",
|
616 |
+
function (e) {
|
617 |
+
var kc = e.keyCode;
|
618 |
+
|
619 |
+
// numpad support
|
620 |
+
if (kc >= 96 && kc <= 105) {
|
621 |
+
kc = e.keyCode = kc - 48;
|
622 |
+
}
|
623 |
+
|
624 |
+
kval = parseInt(String.fromCharCode(kc));
|
625 |
+
|
626 |
+
if (isNaN(kval)) {
|
627 |
+
(kc !== 13) // enter
|
628 |
+
&& kc !== 8 // bs
|
629 |
+
&& kc !== 9 // tab
|
630 |
+
&& kc !== 189 // -
|
631 |
+
&& (kc !== 190
|
632 |
+
|| s.$.val().match(/\./)) // . allowed once
|
633 |
+
&& e.preventDefault();
|
634 |
+
|
635 |
+
// arrows
|
636 |
+
if ($.inArray(kc,[37,38,39,40]) > -1) {
|
637 |
+
e.preventDefault();
|
638 |
+
|
639 |
+
var v = s.o.parse(s.$.val()) + kv[kc] * m;
|
640 |
+
s.o.stopper && (v = max(min(v, s.o.max), s.o.min));
|
641 |
+
|
642 |
+
s.change(s._validate(v));
|
643 |
+
s._draw();
|
644 |
+
|
645 |
+
// long time keydown speed-up
|
646 |
+
to = window.setTimeout(function () {
|
647 |
+
m *= 2;
|
648 |
+
}, 30);
|
649 |
+
}
|
650 |
+
}
|
651 |
+
}
|
652 |
+
)
|
653 |
+
.bind(
|
654 |
+
"keyup",
|
655 |
+
function (e) {
|
656 |
+
if (isNaN(kval)) {
|
657 |
+
if (to) {
|
658 |
+
window.clearTimeout(to);
|
659 |
+
to = null;
|
660 |
+
m = 1;
|
661 |
+
s.val(s.$.val());
|
662 |
+
}
|
663 |
+
} else {
|
664 |
+
// kval postcond
|
665 |
+
(s.$.val() > s.o.max && s.$.val(s.o.max))
|
666 |
+
|| (s.$.val() < s.o.min && s.$.val(s.o.min));
|
667 |
+
}
|
668 |
+
}
|
669 |
+
);
|
670 |
+
|
671 |
+
this.$c.bind("mousewheel DOMMouseScroll", mw);
|
672 |
+
this.$.bind("mousewheel DOMMouseScroll", mw);
|
673 |
+
};
|
674 |
+
|
675 |
+
this.init = function () {
|
676 |
+
if (this.v < this.o.min
|
677 |
+
|| this.v > this.o.max) { this.v = this.o.min; }
|
678 |
+
|
679 |
+
this.$.val(this.v);
|
680 |
+
this.w2 = this.w / 2;
|
681 |
+
this.cursorExt = this.o.cursor / 100;
|
682 |
+
this.xy = this.w2 * this.scale;
|
683 |
+
this.lineWidth = this.xy * this.o.thickness;
|
684 |
+
this.lineCap = this.o.lineCap;
|
685 |
+
this.radius = this.xy - this.lineWidth / 2;
|
686 |
+
|
687 |
+
this.o.angleOffset
|
688 |
+
&& (this.o.angleOffset = isNaN(this.o.angleOffset) ? 0 : this.o.angleOffset);
|
689 |
+
|
690 |
+
this.o.angleArc
|
691 |
+
&& (this.o.angleArc = isNaN(this.o.angleArc) ? this.PI2 : this.o.angleArc);
|
692 |
+
|
693 |
+
// deg to rad
|
694 |
+
this.angleOffset = this.o.angleOffset * Math.PI / 180;
|
695 |
+
this.angleArc = this.o.angleArc * Math.PI / 180;
|
696 |
+
|
697 |
+
// compute start and end angles
|
698 |
+
this.startAngle = 1.5 * Math.PI + this.angleOffset;
|
699 |
+
this.endAngle = 1.5 * Math.PI + this.angleOffset + this.angleArc;
|
700 |
+
|
701 |
+
var s = max(
|
702 |
+
String(Math.abs(this.o.max)).length,
|
703 |
+
String(Math.abs(this.o.min)).length,
|
704 |
+
2
|
705 |
+
) + 2;
|
706 |
+
|
707 |
+
this.o.displayInput
|
708 |
+
&& this.i.css({
|
709 |
+
'width' : ((this.w / 2 + 4) >> 0) + 'px',
|
710 |
+
'height' : ((this.w / 3) >> 0) + 'px',
|
711 |
+
'position' : 'absolute',
|
712 |
+
'vertical-align' : 'middle',
|
713 |
+
'margin-top' : ((this.w / 3) >> 0) + 'px',
|
714 |
+
'margin-left' : '-' + ((this.w * 3 / 4 + 2) >> 0) + 'px',
|
715 |
+
'border' : 0,
|
716 |
+
'background' : 'none',
|
717 |
+
'font' : this.o.fontWeight + ' ' + ((this.w / s) >> 0) + 'px ' + this.o.font,
|
718 |
+
'text-align' : 'center',
|
719 |
+
'color' : this.o.inputColor || this.o.fgColor,
|
720 |
+
'padding' : '0px',
|
721 |
+
'-webkit-appearance': 'none'
|
722 |
+
}) || this.i.css({
|
723 |
+
'width': '0px',
|
724 |
+
'visibility': 'hidden'
|
725 |
+
});
|
726 |
+
};
|
727 |
+
|
728 |
+
this.change = function (v) {
|
729 |
+
this.cv = v;
|
730 |
+
this.$.val(this.o.format(v));
|
731 |
+
};
|
732 |
+
|
733 |
+
this.angle = function (v) {
|
734 |
+
return (v - this.o.min) * this.angleArc / (this.o.max - this.o.min);
|
735 |
+
};
|
736 |
+
|
737 |
+
this.arc = function (v) {
|
738 |
+
var sa, ea;
|
739 |
+
v = this.angle(v);
|
740 |
+
if (this.o.flip) {
|
741 |
+
sa = this.endAngle + 0.00001;
|
742 |
+
ea = sa - v - 0.00001;
|
743 |
+
} else {
|
744 |
+
sa = this.startAngle - 0.00001;
|
745 |
+
ea = sa + v + 0.00001;
|
746 |
+
}
|
747 |
+
this.o.cursor
|
748 |
+
&& (sa = ea - this.cursorExt)
|
749 |
+
&& (ea = ea + this.cursorExt);
|
750 |
+
|
751 |
+
return {
|
752 |
+
s: sa,
|
753 |
+
e: ea,
|
754 |
+
d: this.o.flip && !this.o.cursor
|
755 |
+
};
|
756 |
+
};
|
757 |
+
|
758 |
+
this.draw = function () {
|
759 |
+
var c = this.g, // context
|
760 |
+
a = this.arc(this.cv), // Arc
|
761 |
+
pa, // Previous arc
|
762 |
+
r = 1;
|
763 |
+
|
764 |
+
c.lineWidth = this.lineWidth;
|
765 |
+
c.lineCap = this.lineCap;
|
766 |
+
|
767 |
+
if (this.o.bgColor !== "none") {
|
768 |
+
c.beginPath();
|
769 |
+
c.strokeStyle = this.o.bgColor;
|
770 |
+
c.arc(this.xy, this.xy, this.radius, this.endAngle - 0.00001, this.startAngle + 0.00001, true);
|
771 |
+
c.stroke();
|
772 |
+
}
|
773 |
+
|
774 |
+
if (this.o.displayPrevious) {
|
775 |
+
pa = this.arc(this.v);
|
776 |
+
c.beginPath();
|
777 |
+
c.strokeStyle = this.pColor;
|
778 |
+
c.arc(this.xy, this.xy, this.radius, pa.s, pa.e, pa.d);
|
779 |
+
c.stroke();
|
780 |
+
r = this.cv == this.v;
|
781 |
+
}
|
782 |
+
|
783 |
+
c.beginPath();
|
784 |
+
c.strokeStyle = r ? this.o.fgColor : this.fgColor ;
|
785 |
+
c.arc(this.xy, this.xy, this.radius, a.s, a.e, a.d);
|
786 |
+
c.stroke();
|
787 |
+
};
|
788 |
+
|
789 |
+
this.cancel = function () {
|
790 |
+
this.val(this.v);
|
791 |
+
};
|
792 |
+
};
|
793 |
+
|
794 |
+
$.fn.dial = $.fn.knob = function (o) {
|
795 |
+
return this.each(
|
796 |
+
function () {
|
797 |
+
var d = new k.Dial();
|
798 |
+
d.o = o;
|
799 |
+
d.$ = $(this);
|
800 |
+
d.run();
|
801 |
+
}
|
802 |
+
).parent();
|
803 |
+
};
|
804 |
+
|
805 |
+
}));
|
res/js/jquery.tooltip.js
ADDED
@@ -0,0 +1,207 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
(function($){
|
2 |
+
|
3 |
+
$.fn.tooltip = function(instanceSettings){
|
4 |
+
|
5 |
+
$.fn.tooltip.defaultsSettings = {
|
6 |
+
attributeName:'title',
|
7 |
+
borderColor:'#ccc',
|
8 |
+
borderSize:'1',
|
9 |
+
cancelClick:0,
|
10 |
+
followMouse:1,
|
11 |
+
height:'auto',
|
12 |
+
hoverIntent:{sensitivity:7,interval:100,timeout:0},
|
13 |
+
loader:0,
|
14 |
+
loaderHeight:0,
|
15 |
+
loaderImagePath:'',
|
16 |
+
loaderWidth:0,
|
17 |
+
positionTop: 12,
|
18 |
+
positionLeft: 12,
|
19 |
+
width:'auto',
|
20 |
+
titleAttributeContent:'',
|
21 |
+
tooltipBGColor:'#fff',
|
22 |
+
tooltipBGImage:'none', // http path
|
23 |
+
tooltipHTTPType:'get',
|
24 |
+
tooltipPadding:10,
|
25 |
+
tooltipSource:'attribute', //inline, ajax, iframe, attribute
|
26 |
+
tooltipSourceID:'',
|
27 |
+
tooltipSourceURL:'',
|
28 |
+
tooltipID:'tooltip'
|
29 |
+
};
|
30 |
+
|
31 |
+
//s = settings
|
32 |
+
var s = $.extend({}, $.fn.tooltip.defaultsSettings , instanceSettings || {});
|
33 |
+
|
34 |
+
var positionTooltip = function(e){
|
35 |
+
|
36 |
+
var posx = 0;
|
37 |
+
var posy = 0;
|
38 |
+
if (!e) var e = window.event;
|
39 |
+
if (e.pageX || e.pageY) {
|
40 |
+
posx = e.pageX;
|
41 |
+
posy = e.pageY;
|
42 |
+
}
|
43 |
+
else if (e.clientX || e.clientY) {
|
44 |
+
posx = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
|
45 |
+
posy = e.clientY + document.body.scrollTop + document.documentElement.scrollTop;
|
46 |
+
}
|
47 |
+
|
48 |
+
var p = {
|
49 |
+
x: posx + s.positionLeft,
|
50 |
+
y: posy + s.positionTop,
|
51 |
+
w: $('#'+s.tooltipID).width(),
|
52 |
+
h: $('#'+s.tooltipID).height()
|
53 |
+
}
|
54 |
+
|
55 |
+
var v = {
|
56 |
+
x: $(window).scrollLeft(),
|
57 |
+
y: $(window).scrollTop(),
|
58 |
+
w: $(window).width() - 20,
|
59 |
+
h: $(window).height() - 20
|
60 |
+
};
|
61 |
+
|
62 |
+
//don't go off screen
|
63 |
+
if(p.y + p.h > v.y + v.h && p.x + p.w > v.x + v.w){
|
64 |
+
p.x = (p.x - p.w) - 45;
|
65 |
+
p.y = (p.y - p.h) - 45;
|
66 |
+
}else if(p.x + p.w > v.x + v.w){
|
67 |
+
p.x = p.x - (((p.x+p.w)-(v.x+v.w)) + 20);
|
68 |
+
}else if(p.y + p.h > v.y + v.h){
|
69 |
+
p.y = p.y - (((p.y+p.h)-(v.y+v.h)) + 20);
|
70 |
+
}
|
71 |
+
|
72 |
+
$('#'+s.tooltipID).css({'left':p.x + 'px','top':p.y + 'px'});
|
73 |
+
}
|
74 |
+
|
75 |
+
var showTooltip = function(){
|
76 |
+
$('#tooltipLoader').remove();
|
77 |
+
$('#'+s.tooltipID+' #tooltipContent').show();
|
78 |
+
|
79 |
+
if($.browser.version == '6.0'){//IE6 only
|
80 |
+
$('#'+s.tooltipID).append('<iframe id="tooltipIE6FixIframe" style="width:'+($('#'+s.tooltipID).width()+parseFloat(s.borderSize)+parseFloat(s.borderSize)+20)+'px;height:'+($('#'+s.tooltipID).height()+parseFloat(s.borderSize)+parseFloat(s.borderSize)+20)+'px;position:absolute;top:-'+s.borderSize+'px;left:-'+s.borderSize+'px;filter:alpha(opacity=0);"src="blank.html"></iframe>');
|
81 |
+
};
|
82 |
+
}
|
83 |
+
|
84 |
+
var hideTooltip = function(valueOfThis){
|
85 |
+
$('#'+s.tooltipID).fadeOut('fast').trigger("unload").remove();
|
86 |
+
if($(valueOfThis).filter('[title]')){
|
87 |
+
$(valueOfThis).attr('title',s.titleAttributeContent);
|
88 |
+
}
|
89 |
+
}
|
90 |
+
|
91 |
+
var urlQueryToObject = function(s){
|
92 |
+
var query = {};
|
93 |
+
s.replace(/b([^&=]*)=([^&=]*)b/g, function (m, a, d) {
|
94 |
+
if (typeof query[a] != 'undefined') {
|
95 |
+
query[a] += ',' + d;
|
96 |
+
} else {
|
97 |
+
query[a] = d;
|
98 |
+
}
|
99 |
+
});
|
100 |
+
return query;
|
101 |
+
};
|
102 |
+
|
103 |
+
return this.each(function(index){
|
104 |
+
|
105 |
+
if(s.cancelClick){
|
106 |
+
$(this).bind("click", function(){return false});
|
107 |
+
}
|
108 |
+
|
109 |
+
if($.fn.hoverIntent){
|
110 |
+
$(this).hoverIntent({
|
111 |
+
sensitivity:s.hoverIntent.sensitivity,
|
112 |
+
interval:s.hoverIntent.interval,
|
113 |
+
over:on,
|
114 |
+
timeout:s.hoverIntent.timeout,
|
115 |
+
out:off
|
116 |
+
});
|
117 |
+
}else{
|
118 |
+
$(this).hover(on,off);
|
119 |
+
}
|
120 |
+
|
121 |
+
function on(e){
|
122 |
+
|
123 |
+
$('body').append('<div id="'+s.tooltipID+'" style="background-repeat:no-repeat;background-image:url('+s.tooltipBGImage+');padding:'+s.tooltipPadding+'px;display:none;height:'+s.height+';width:'+s.width+';background-color:'+s.tooltipBGColor+';border:'+s.borderSize+'px solid '+s.borderColor+'; position:absolute;z-index:100000000000;"><div id="tooltipContent" style="display:none;"></div></div>');
|
124 |
+
|
125 |
+
var $tt = $('#'+s.tooltipID);
|
126 |
+
var $ttContent = $('#'+s.tooltipID+' #tooltipContent');
|
127 |
+
|
128 |
+
if(s.loader && s.loaderImagePath != ''){
|
129 |
+
$tt.append('<div id="tooltipLoader" style="width:'+s.loaderWidth+'px;height:'+s.loaderHeight+'px;"><img src="'+s.loaderImagePath+'" /></div>');
|
130 |
+
}
|
131 |
+
|
132 |
+
if($(this).attr('title')){
|
133 |
+
s.titleAttributeContent = $(this).attr('title');
|
134 |
+
$(this).attr('title','');
|
135 |
+
}
|
136 |
+
|
137 |
+
if($(this).is('input')){
|
138 |
+
$(this).focus(function(){ hideTooltip(this); });
|
139 |
+
}
|
140 |
+
|
141 |
+
e.preventDefault();//stop
|
142 |
+
positionTooltip(e);
|
143 |
+
|
144 |
+
$tt.show();
|
145 |
+
|
146 |
+
//get values from element clicked, or assume its passed as an option
|
147 |
+
s.tooltipSourceID = $(this).attr('href') || s.tooltipSourceID;
|
148 |
+
s.tooltipSourceURL = $(this).attr('href') || s.tooltipSourceURL;
|
149 |
+
|
150 |
+
switch(s.tooltipSource){
|
151 |
+
case 'attribute':/*/////////////////////////////// attribute //////////////////////////////////////////*/
|
152 |
+
$ttContent.text(s.titleAttributeContent);
|
153 |
+
showTooltip();
|
154 |
+
break;
|
155 |
+
case 'inline':/*/////////////////////////////// inline //////////////////////////////////////////*/
|
156 |
+
$ttContent.html($(s.tooltipSourceID).children());
|
157 |
+
$tt.unload(function(){// move elements back when you're finished
|
158 |
+
$(s.tooltipSourceID).html($ttContent.children());
|
159 |
+
});
|
160 |
+
showTooltip();
|
161 |
+
break;
|
162 |
+
case 'ajax':/*/////////////////////////////// ajax //////////////////////////////////////////*/
|
163 |
+
if(s.tooltipHTTPType == 'post'){
|
164 |
+
var urlOnly, urlQueryObject;
|
165 |
+
if(s.tooltipSourceURL.indexOf("?") !== -1){//has a query string
|
166 |
+
urlOnly = s.windowSourceURL.substr(0, s.windowSourceURL.indexOf("?"));
|
167 |
+
urlQueryObject = urlQueryToObject(s.tooltipSourceURL);
|
168 |
+
}else{
|
169 |
+
urlOnly = s.tooltipSourceURL;
|
170 |
+
urlQueryObject = {};
|
171 |
+
}
|
172 |
+
$ttContent.load(urlOnly,urlQueryObject,function(){
|
173 |
+
showTooltip();
|
174 |
+
});
|
175 |
+
}else{
|
176 |
+
if(s.tooltipSourceURL.indexOf("?") == -1){ //no query string, so add one
|
177 |
+
s.tooltipSourceURL += '?';
|
178 |
+
}
|
179 |
+
$ttContent.load(
|
180 |
+
s.tooltipSourceURL + '&random=' + (new Date().getTime()),function(){
|
181 |
+
showTooltip();
|
182 |
+
});
|
183 |
+
}
|
184 |
+
break;
|
185 |
+
};
|
186 |
+
|
187 |
+
return false;
|
188 |
+
|
189 |
+
};
|
190 |
+
|
191 |
+
|
192 |
+
function off(e){
|
193 |
+
hideTooltip(this);
|
194 |
+
return false;
|
195 |
+
};
|
196 |
+
|
197 |
+
if(s.followMouse){
|
198 |
+
$(this).bind("mousemove", function(e){
|
199 |
+
positionTooltip(e);
|
200 |
+
return false;
|
201 |
+
});
|
202 |
+
}
|
203 |
+
|
204 |
+
});
|
205 |
+
};
|
206 |
+
|
207 |
+
})(jQuery);
|
{js → res/js}/short-pixel.js
RENAMED
@@ -18,6 +18,7 @@ jQuery(document).ready(function($){
|
|
18 |
clearBulkProcessor();
|
19 |
}
|
20 |
});
|
|
|
21 |
//check if bulk processing
|
22 |
checkQuotaExceededAlert();
|
23 |
checkBulkProgress();
|
@@ -42,10 +43,10 @@ var ShortPixel = function() {
|
|
42 |
var section = jQuery("section#" +target);
|
43 |
if(section.length > 0){
|
44 |
jQuery("section").removeClass("sel-tab");
|
45 |
-
jQuery("section#" +target).addClass("sel-tab");
|
46 |
}
|
47 |
}
|
48 |
-
|
49 |
function adjustSettingsTabsHeight(){
|
50 |
var sectionHeight = jQuery('.wp-shortpixel-options').height() + 60;
|
51 |
sectionHeight = Math.max(sectionHeight, jQuery('section#tab-resources .area1').height() + 20);
|
@@ -55,7 +56,7 @@ var ShortPixel = function() {
|
|
55 |
|
56 |
function dismissMediaAlert() {
|
57 |
var data = { action : 'shortpixel_dismiss_media_alert'};
|
58 |
-
jQuery.get(
|
59 |
data = JSON.parse(response);
|
60 |
if(data["Status"] == 'success') {
|
61 |
jQuery("#short-pixel-media-alert").hide();
|
@@ -74,6 +75,39 @@ var ShortPixel = function() {
|
|
74 |
}
|
75 |
}
|
76 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
77 |
function retry(msg) {
|
78 |
ShortPixel.retries++;
|
79 |
if(isNaN(ShortPixel.retries)) ShortPixel.retries = 1;
|
@@ -81,10 +115,100 @@ var ShortPixel = function() {
|
|
81 |
console.log("Invalid response from server (Error: " + msg + "). Retrying pass " + (ShortPixel.retries + 1) + "...");
|
82 |
setTimeout(checkBulkProgress, 5000);
|
83 |
} else {
|
|
|
84 |
console.log("Invalid response from server 6 times. Giving up.");
|
85 |
}
|
86 |
}
|
87 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
88 |
return {
|
89 |
setOptions : setOptions,
|
90 |
checkThumbsUpdTotal : checkThumbsUpdTotal,
|
@@ -92,7 +216,17 @@ var ShortPixel = function() {
|
|
92 |
adjustSettingsTabs : adjustSettingsTabsHeight,
|
93 |
onBulkThumbsCheck : onBulkThumbsCheck,
|
94 |
dismissMediaAlert : dismissMediaAlert,
|
95 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
96 |
}
|
97 |
}();
|
98 |
|
@@ -102,6 +236,7 @@ function showToolBarAlert($status, $message) {
|
|
102 |
case ShortPixel.STATUS_QUOTA_EXCEEDED:
|
103 |
if( window.location.href.search("wp-short-pixel-bulk") > 0
|
104 |
&& jQuery(".sp-quota-exceeded-alert").length == 0) { //if we're in bulk and the alert is not displayed reload to see all options
|
|
|
105 |
location.reload();
|
106 |
return;
|
107 |
}
|
@@ -130,11 +265,12 @@ function showToolBarAlert($status, $message) {
|
|
130 |
break;
|
131 |
case ShortPixel.STATUS_SUCCESS:
|
132 |
case ShortPixel.STATUS_RETRY:
|
|
|
133 |
robo.removeClass("shortpixel-alert");
|
134 |
jQuery("a", robo).removeAttr("target");
|
135 |
jQuery("a", robo).attr("href", jQuery("a img", robo).attr("success-url"));
|
136 |
}
|
137 |
-
|
138 |
}
|
139 |
function hideToolBarAlert () {
|
140 |
jQuery("li.shortpixel-toolbar-processing.shortpixel-processing").addClass("shortpixel-hide");
|
@@ -162,7 +298,10 @@ function checkBulkProgress() {
|
|
162 |
&& window.location.href.search(ShortPixel.WP_ADMIN_URL + "edit.php") < 0
|
163 |
&& window.location.href.search(ShortPixel.WP_ADMIN_URL + "edit-tags.php") < 0
|
164 |
&& window.location.href.search(ShortPixel.WP_ADMIN_URL + "post-new.php") < 0
|
165 |
-
&& window.location.href.search(ShortPixel.WP_ADMIN_URL + "post.php") < 0
|
|
|
|
|
|
|
166 |
hideToolBarAlert();
|
167 |
return;
|
168 |
}
|
@@ -183,11 +322,15 @@ function checkBulkProgress() {
|
|
183 |
//if I'm not the bulk processor, check every 20 sec. if the bulk processor is running, otherwise take the role
|
184 |
if(ShortPixel.bulkProcessor == true || typeof localStorage.bulkTime == 'undefined' || Math.floor(Date.now() / 1000) - localStorage.bulkTime > 90) {
|
185 |
ShortPixel.bulkProcessor = true;
|
|
|
186 |
localStorage.bulkTime = Math.floor(Date.now() / 1000);
|
187 |
console.log(localStorage.bulkTime);
|
188 |
checkBulkProcessingCallApi();
|
189 |
} else {
|
190 |
-
console.log("not the bulk processor")
|
|
|
|
|
|
|
191 |
setTimeout(checkBulkProgress, 5000);
|
192 |
}
|
193 |
}
|
@@ -197,7 +340,7 @@ function checkBulkProcessingCallApi(){
|
|
197 |
// since WP 2.8 ajaxurl is always defined in the admin header and points to admin-ajax.php
|
198 |
jQuery.ajax({
|
199 |
type: "POST",
|
200 |
-
url: ajaxurl,
|
201 |
data: data,
|
202 |
success: function(response)
|
203 |
{
|
@@ -210,29 +353,33 @@ function checkBulkProcessingCallApi(){
|
|
210 |
return;
|
211 |
}
|
212 |
var id = data["ImageID"];
|
213 |
-
|
214 |
var isBulkPage = (jQuery("div.short-pixel-bulk-page").length > 0);
|
215 |
|
216 |
switch (data["Status"]) {
|
217 |
case ShortPixel.STATUS_NO_KEY:
|
218 |
-
setCellMessage(id,
|
|
|
219 |
showToolBarAlert(ShortPixel.STATUS_NO_KEY);
|
220 |
break;
|
221 |
case ShortPixel.STATUS_QUOTA_EXCEEDED:
|
222 |
-
setCellMessage(id, "<
|
223 |
+ ShortPixel.API_KEY + "\" target=\"_blank\">Extend Quota</a>"
|
224 |
-
+ "<a class='button button-smaller' href='admin.php?action=shortpixel_check_quota'>Check Quota</a
|
225 |
-
|
226 |
showToolBarAlert(ShortPixel.STATUS_QUOTA_EXCEEDED);
|
227 |
-
if(data['Stop'] == false) { //there are other items in
|
228 |
-
setTimeout(checkBulkProgress, 5000);
|
229 |
-
}
|
230 |
break;
|
231 |
case ShortPixel.STATUS_FAIL:
|
232 |
-
setCellMessage(id, data["Message"]);
|
233 |
if(isBulkPage) {
|
|
|
234 |
showToolBarAlert(ShortPixel.STATUS_FAIL, data["Message"]);
|
235 |
-
|
|
|
|
|
236 |
}
|
237 |
console.log(data["Message"]);
|
238 |
setTimeout(checkBulkProgress, 5000);
|
@@ -253,32 +400,30 @@ function checkBulkProcessingCallApi(){
|
|
253 |
}
|
254 |
break;
|
255 |
case ShortPixel.STATUS_SUCCESS:
|
|
|
|
|
|
|
256 |
var percent = data["PercentImprovement"];
|
257 |
-
|
258 |
-
|
259 |
-
var cellMsg = (percent > 0 ? "<div class='sp-column-info'>Reduced by <span class='percent'>" + percent + "%</span> " : "")
|
260 |
-
+ (percent > 0 && percent < 5 ? "<br>" : '')
|
261 |
-
+ (percent < 5 ? "Bonus processing" : '')
|
262 |
-
+ (data["Type"].length > 0 ? " ("+data["Type"]+")" : "")
|
263 |
-
+ (0 + data['ThumbsCount'] > 0 ? "<br>+" + data['ThumbsCount'] + " thumbnails optimized" :"")
|
264 |
-
+ "</div>";
|
265 |
-
|
266 |
-
if(data["BackupEnabled"] == 1) {
|
267 |
-
cellMsg = '<div class="sp-column-actions">'
|
268 |
-
+ (data["ThumbsTotal"] > data["ThumbsCount"] ? "<a class='button button-smaller button-primary' href=\"javascript:optimizeThumbs(" + id + ");\">Optimize " + (data["ThumbsTotal"] - data["ThumbsCount"]) + " thumbnails</a>" : "")
|
269 |
-
+ (otherType.length ? "<a class='button button-smaller' href=\"javascript:reoptimize(" + id + ", '" + otherType + "');\">Re-optimize " + otherType + "</a>" : "")
|
270 |
-
+ "<a class='button button-smaller' href=\"admin.php?action=shortpixel_restore_backup&attachment_ID=" + id + ")\">Restore backup</a>"
|
271 |
-
+ "</div>" + cellMsg;
|
272 |
-
}
|
273 |
-
|
274 |
showToolBarAlert(ShortPixel.STATUS_SUCCESS, "");
|
275 |
-
|
|
|
|
|
|
|
|
|
|
|
276 |
var animator = new PercentageAnimator("#sp-msg-" + id + " span.percent", percent);
|
277 |
animator.animate(percent);
|
278 |
if(isBulkPage && typeof data["Thumb"] !== 'undefined') { // && data["PercentImprovement"] > 0) {
|
279 |
-
|
|
|
|
|
280 |
if(data["Thumb"].length > 0){
|
281 |
-
sliderUpdate(id, data["Thumb"], data["BkThumb"], data["PercentImprovement"]);
|
|
|
|
|
|
|
|
|
282 |
}
|
283 |
}
|
284 |
console.log('Server response: ' + response);
|
@@ -287,21 +432,32 @@ function checkBulkProcessingCallApi(){
|
|
287 |
}
|
288 |
setTimeout(checkBulkProgress, 5000);
|
289 |
break;
|
290 |
-
|
291 |
-
case ShortPixel.STATUS_ERROR: //for error and skip also we retry
|
292 |
case ShortPixel.STATUS_SKIP:
|
|
|
|
|
|
|
|
|
|
|
293 |
if(typeof data["Message"] !== 'undefined') {
|
294 |
showToolBarAlert(ShortPixel.STATUS_SKIP, data["Message"] + ' Image ID: ' + id);
|
295 |
-
setCellMessage(id, data["Message"]);
|
296 |
}
|
|
|
297 |
case ShortPixel.STATUS_RETRY:
|
298 |
console.log('Server response: ' + response);
|
299 |
showToolBarAlert(ShortPixel.STATUS_RETRY, "");
|
300 |
if(isBulkPage && typeof data["BulkPercent"] !== 'undefined') {
|
301 |
progressUpdate(data["BulkPercent"], data["BulkMsg"]);
|
302 |
}
|
|
|
|
|
|
|
303 |
setTimeout(checkBulkProgress, 5000);
|
304 |
break;
|
|
|
|
|
|
|
305 |
}
|
306 |
}
|
307 |
},
|
@@ -319,61 +475,67 @@ function clearBulkProcessor(){
|
|
319 |
}
|
320 |
}
|
321 |
|
322 |
-
function setCellMessage(id, message){
|
323 |
var msg = jQuery("#sp-msg-" + id);
|
324 |
-
if(
|
325 |
-
msg.html(
|
|
|
|
|
|
|
|
|
|
|
|
|
326 |
}
|
327 |
}
|
328 |
|
329 |
function manualOptimization(id) {
|
330 |
-
setCellMessage(id, "<img src='" + ShortPixel.WP_PLUGIN_URL + "/img/loading.gif' class='sp-loading-small'>Image waiting to be processed");
|
331 |
jQuery("li.shortpixel-toolbar-processing").removeClass("shortpixel-hide");
|
332 |
jQuery("li.shortpixel-toolbar-processing").addClass("shortpixel-processing");
|
333 |
var data = { action : 'shortpixel_manual_optimization',
|
334 |
image_id: id};
|
335 |
-
jQuery.get(
|
336 |
-
|
337 |
-
|
338 |
-
|
339 |
-
|
340 |
-
|
341 |
-
|
342 |
//aici e aici
|
343 |
});
|
344 |
}
|
345 |
|
346 |
function reoptimize(id, type) {
|
347 |
-
setCellMessage(id, "<img src='" + ShortPixel.WP_PLUGIN_URL + "/img/loading.gif' class='sp-loading-small'>Image waiting to be reprocessed");
|
348 |
jQuery("li.shortpixel-toolbar-processing").removeClass("shortpixel-hide");
|
349 |
jQuery("li.shortpixel-toolbar-processing").addClass("shortpixel-processing");
|
350 |
var data = { action : 'shortpixel_redo',
|
351 |
attachment_ID: id,
|
352 |
type: type};
|
353 |
-
jQuery.get(
|
354 |
data = JSON.parse(response);
|
355 |
if(data["Status"] == ShortPixel.STATUS_SUCCESS) {
|
356 |
setTimeout(checkBulkProgress, 2000);
|
357 |
} else {
|
358 |
$msg = typeof data["Message"] !== "undefined" ? data["Message"] : "This content is not processable.";
|
359 |
-
setCellMessage(id, $msg);
|
360 |
showToolBarAlert(ShortPixel.STATUS_FAIL, $msg);
|
361 |
}
|
362 |
});
|
363 |
}
|
364 |
|
365 |
function optimizeThumbs(id) {
|
366 |
-
setCellMessage(id, "<img src='" + ShortPixel.WP_PLUGIN_URL + "/img/loading.gif' class='sp-loading-small'>Image waiting to optimize thumbnails");
|
367 |
jQuery("li.shortpixel-toolbar-processing").removeClass("shortpixel-hide");
|
368 |
jQuery("li.shortpixel-toolbar-processing").addClass("shortpixel-processing");
|
369 |
var data = { action : 'shortpixel_optimize_thumbs',
|
370 |
attachment_ID: id};
|
371 |
-
jQuery.get(
|
372 |
data = JSON.parse(response);
|
373 |
if(data["Status"] == ShortPixel.STATUS_SUCCESS) {
|
374 |
setTimeout(checkBulkProgress, 2000);
|
375 |
} else {
|
376 |
-
setCellMessage(id, typeof data["Message"] !== "undefined" ? data["Message"] : "This content is not processable.");
|
377 |
}
|
378 |
});
|
379 |
}
|
@@ -382,7 +544,7 @@ function dismissShortPixelNotice(id) {
|
|
382 |
jQuery("#short-pixel-notice-" + id).hide();
|
383 |
var data = { action : 'shortpixel_dismiss_notice',
|
384 |
notice_id: id};
|
385 |
-
jQuery.get(
|
386 |
data = JSON.parse(response);
|
387 |
if(data["Status"] == ShortPixel.STATUS_SUCCESS) {
|
388 |
console.log("dismissed");
|
@@ -435,14 +597,21 @@ function progressUpdate(percent, message) {
|
|
435 |
}
|
436 |
}
|
437 |
|
438 |
-
|
|
|
|
|
439 |
var oldSlide = jQuery(".bulk-slider div.bulk-slide:first-child");
|
440 |
-
var newSlide = oldSlide.clone();
|
441 |
-
newSlide.attr("id", "slide-" + id);
|
442 |
if(oldSlide.attr("id") != "empty-slide") {
|
443 |
-
|
444 |
}
|
445 |
oldSlide.css("z-index", 1000);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
446 |
jQuery(".bulk-img-opt", newSlide).attr("src", thumb);
|
447 |
if(bkThumb.length > 0) {
|
448 |
jQuery(".img-original", newSlide).css("display", "inline-block");
|
@@ -450,14 +619,18 @@ function sliderUpdate(id, thumb, bkThumb, percent){
|
|
450 |
} else {
|
451 |
jQuery(".img-original", newSlide).css("display", "none");
|
452 |
}
|
453 |
-
jQuery(".bulk-opt-percent", newSlide).text
|
454 |
|
|
|
455 |
jQuery(".bulk-slider").append(newSlide);
|
|
|
|
|
|
|
456 |
if(oldSlide.attr("id") == "empty-slide") {
|
457 |
oldSlide.remove();
|
458 |
jQuery(".bulk-slider-container").css("display", "block");
|
459 |
} else {
|
460 |
-
oldSlide.animate({ left: oldSlide.width() }, 'slow', 'swing', function(){
|
461 |
oldSlide.remove();
|
462 |
newSlide.fadeIn("slow");
|
463 |
});
|
18 |
clearBulkProcessor();
|
19 |
}
|
20 |
});
|
21 |
+
ShortPixel.setOptions(ShortPixelConstants);
|
22 |
//check if bulk processing
|
23 |
checkQuotaExceededAlert();
|
24 |
checkBulkProgress();
|
43 |
var section = jQuery("section#" +target);
|
44 |
if(section.length > 0){
|
45 |
jQuery("section").removeClass("sel-tab");
|
46 |
+
jQuery("section#" +target).addClass("sel-tab");
|
47 |
}
|
48 |
}
|
49 |
+
|
50 |
function adjustSettingsTabsHeight(){
|
51 |
var sectionHeight = jQuery('.wp-shortpixel-options').height() + 60;
|
52 |
sectionHeight = Math.max(sectionHeight, jQuery('section#tab-resources .area1').height() + 20);
|
56 |
|
57 |
function dismissMediaAlert() {
|
58 |
var data = { action : 'shortpixel_dismiss_media_alert'};
|
59 |
+
jQuery.get(ShortPixel.AJAX_URL, data, function(response) {
|
60 |
data = JSON.parse(response);
|
61 |
if(data["Status"] == 'success') {
|
62 |
jQuery("#short-pixel-media-alert").hide();
|
75 |
}
|
76 |
}
|
77 |
|
78 |
+
function successMsg(id, percent, type, thumbsCount) {
|
79 |
+
return (percent > 0 ? "<div class='sp-column-info'>Reduced by <span class='percent'>" + percent + "%</span> " : "")
|
80 |
+
+ (percent > 0 && percent < 5 ? "<br>" : '')
|
81 |
+
+ (percent < 5 ? "Bonus processing" : '')
|
82 |
+
+ (type.length > 0 ? " ("+type+")" : "")
|
83 |
+
+ (0 + thumbsCount > 0 ? "<br>+" + thumbsCount + " thumbnails optimized" :"")
|
84 |
+
+ "</div>";
|
85 |
+
}
|
86 |
+
|
87 |
+
function percentDial(query, size) {
|
88 |
+
jQuery(query).knob({
|
89 |
+
'readOnly': true,
|
90 |
+
'width': size,
|
91 |
+
'height': size,
|
92 |
+
'fgColor': '#1CAECB',
|
93 |
+
'format' : function (value) {
|
94 |
+
return value + '%';
|
95 |
+
}
|
96 |
+
});
|
97 |
+
}
|
98 |
+
|
99 |
+
function successActions(id, type, thumbsCount, thumbsTotal, backupEnabled) {
|
100 |
+
if(backupEnabled == 1) {
|
101 |
+
var otherType = type.length > 0 ? (type == "lossy" ? "lossless" : "lossy") : "";
|
102 |
+
return '<div class="sp-column-actions">'
|
103 |
+
+ (thumbsTotal > thumbsCount ? "<a class='button button-smaller button-primary' href=\"javascript:optimizeThumbs(" + id + ");\">Optimize " + (thumbsTotal - thumbsCount) + " thumbnails</a>" : "")
|
104 |
+
+ (otherType.length ? "<a class='button button-smaller' href=\"javascript:reoptimize(" + id + ", '" + otherType + "');\">Re-optimize " + otherType + "</a>" : "")
|
105 |
+
+ "<a class='button button-smaller' href=\"admin.php?action=shortpixel_restore_backup&attachment_ID=" + id + ")\">Restore backup</a>"
|
106 |
+
+ "</div>";
|
107 |
+
}
|
108 |
+
return "";
|
109 |
+
}
|
110 |
+
|
111 |
function retry(msg) {
|
112 |
ShortPixel.retries++;
|
113 |
if(isNaN(ShortPixel.retries)) ShortPixel.retries = 1;
|
115 |
console.log("Invalid response from server (Error: " + msg + "). Retrying pass " + (ShortPixel.retries + 1) + "...");
|
116 |
setTimeout(checkBulkProgress, 5000);
|
117 |
} else {
|
118 |
+
ShortPixel.bulkShowError(-1,"Invalid response from server received 6 times. Please retry later by reloading this page, or contact support. (Error: " + msg + ")", "");
|
119 |
console.log("Invalid response from server 6 times. Giving up.");
|
120 |
}
|
121 |
}
|
122 |
|
123 |
+
function browseContent(browseData) {
|
124 |
+
browseData.action = 'shortpixel_browse_content';
|
125 |
+
var browseResponse = "";
|
126 |
+
jQuery.ajax({
|
127 |
+
type: "POST",
|
128 |
+
url: ShortPixel.AJAX_URL,
|
129 |
+
data: browseData,
|
130 |
+
success: function(response) {
|
131 |
+
browseResponse = response;
|
132 |
+
},
|
133 |
+
async: false
|
134 |
+
});
|
135 |
+
return browseResponse;
|
136 |
+
}
|
137 |
+
|
138 |
+
function initFolderSelector() {
|
139 |
+
jQuery(".select-folder-button").click(function(){
|
140 |
+
jQuery(".sp-folder-picker-shade").css("display", "block");
|
141 |
+
jQuery(".sp-folder-picker").fileTree({
|
142 |
+
script: ShortPixel.browseContent,
|
143 |
+
//folderEvent: 'dblclick',
|
144 |
+
multiFolder: false
|
145 |
+
//onlyFolders: true
|
146 |
+
});
|
147 |
+
});
|
148 |
+
jQuery(".sp-folder-picker-popup input.select-folder-cancel").click(function(){
|
149 |
+
jQuery(".sp-folder-picker-shade").css("display", "none");
|
150 |
+
});
|
151 |
+
jQuery(".sp-folder-picker-popup input.select-folder").click(function(){
|
152 |
+
var subPath = jQuery("UL.jqueryFileTree LI.directory.selected A").attr("rel");
|
153 |
+
if(subPath) {
|
154 |
+
var fullPath = jQuery("#customFolderBase").val() + subPath;
|
155 |
+
if(fullPath.slice(-1) == '/') fullPath = fullPath.slice(0, -1);
|
156 |
+
jQuery("#addCustomFolder").val(fullPath);
|
157 |
+
jQuery("#addCustomFolderView").val(fullPath);
|
158 |
+
jQuery(".sp-folder-picker-shade").css("display", "none");
|
159 |
+
} else {
|
160 |
+
alert("Please select a folder from the list.");
|
161 |
+
}
|
162 |
+
});
|
163 |
+
}
|
164 |
+
|
165 |
+
function bulkShowLengthyMsg(id, fileName, customLink){
|
166 |
+
var notice = jQuery(".bulk-notice-msg.bulk-lengthy");
|
167 |
+
if(notice.length == 0) return;
|
168 |
+
var link = jQuery("a", notice);
|
169 |
+
link.text(fileName);
|
170 |
+
if(customLink) {
|
171 |
+
link.attr("href", customLink);
|
172 |
+
} else {
|
173 |
+
link.attr("href", link.data("href").replace("__ID__", id));
|
174 |
+
}
|
175 |
+
|
176 |
+
notice.css("display", "block");
|
177 |
+
|
178 |
+
}
|
179 |
+
|
180 |
+
function bulkHideLengthyMsg(){
|
181 |
+
jQuery(".bulk-notice-msg.bulk-lengthy").css("display", "none");
|
182 |
+
}
|
183 |
+
|
184 |
+
function bulkShowError(id, msg, fileName, customLink) {
|
185 |
+
var noticeTpl = jQuery("#bulk-error-template");
|
186 |
+
if(noticeTpl.length == 0) return;
|
187 |
+
var notice = noticeTpl.clone();
|
188 |
+
notice.attr("id", "bulk-error-" + id);
|
189 |
+
if(id == -1) {
|
190 |
+
jQuery("span.sp-err-title", notice).remove();
|
191 |
+
}
|
192 |
+
jQuery("span.sp-err-content", notice).text(msg);
|
193 |
+
var link = jQuery("a.sp-post-link", notice);
|
194 |
+
if(customLink) {
|
195 |
+
link.attr("href", customLink);
|
196 |
+
} else {
|
197 |
+
link.attr("href", link.attr("href").replace("__ID__", id));
|
198 |
+
}
|
199 |
+
link.text(fileName);
|
200 |
+
noticeTpl.after(notice);
|
201 |
+
notice.css("display", "block");
|
202 |
+
}
|
203 |
+
|
204 |
+
function removeBulkMsg(me) {
|
205 |
+
jQuery(me).parent().parent().remove();
|
206 |
+
}
|
207 |
+
|
208 |
+
function isCustomImageId(id) {
|
209 |
+
return id.substring(0,2) == "C-";
|
210 |
+
}
|
211 |
+
|
212 |
return {
|
213 |
setOptions : setOptions,
|
214 |
checkThumbsUpdTotal : checkThumbsUpdTotal,
|
216 |
adjustSettingsTabs : adjustSettingsTabsHeight,
|
217 |
onBulkThumbsCheck : onBulkThumbsCheck,
|
218 |
dismissMediaAlert : dismissMediaAlert,
|
219 |
+
percentDial : percentDial,
|
220 |
+
successMsg : successMsg,
|
221 |
+
successActions : successActions,
|
222 |
+
retry : retry,
|
223 |
+
initFolderSelector : initFolderSelector,
|
224 |
+
browseContent : browseContent,
|
225 |
+
bulkShowLengthyMsg : bulkShowLengthyMsg,
|
226 |
+
bulkHideLengthyMsg : bulkHideLengthyMsg,
|
227 |
+
bulkShowError : bulkShowError,
|
228 |
+
removeBulkMsg : removeBulkMsg,
|
229 |
+
isCustomImageId : isCustomImageId
|
230 |
}
|
231 |
}();
|
232 |
|
236 |
case ShortPixel.STATUS_QUOTA_EXCEEDED:
|
237 |
if( window.location.href.search("wp-short-pixel-bulk") > 0
|
238 |
&& jQuery(".sp-quota-exceeded-alert").length == 0) { //if we're in bulk and the alert is not displayed reload to see all options
|
239 |
+
debugger;
|
240 |
location.reload();
|
241 |
return;
|
242 |
}
|
265 |
break;
|
266 |
case ShortPixel.STATUS_SUCCESS:
|
267 |
case ShortPixel.STATUS_RETRY:
|
268 |
+
robo.addClass("shortpixel-processing");
|
269 |
robo.removeClass("shortpixel-alert");
|
270 |
jQuery("a", robo).removeAttr("target");
|
271 |
jQuery("a", robo).attr("href", jQuery("a img", robo).attr("success-url"));
|
272 |
}
|
273 |
+
robo.removeClass("shortpixel-hide");
|
274 |
}
|
275 |
function hideToolBarAlert () {
|
276 |
jQuery("li.shortpixel-toolbar-processing.shortpixel-processing").addClass("shortpixel-hide");
|
298 |
&& window.location.href.search(ShortPixel.WP_ADMIN_URL + "edit.php") < 0
|
299 |
&& window.location.href.search(ShortPixel.WP_ADMIN_URL + "edit-tags.php") < 0
|
300 |
&& window.location.href.search(ShortPixel.WP_ADMIN_URL + "post-new.php") < 0
|
301 |
+
&& window.location.href.search(ShortPixel.WP_ADMIN_URL + "post.php") < 0
|
302 |
+
&& window.location.href.search("page=nggallery-manage-gallery") < 0
|
303 |
+
&& (ShortPixel.FRONT_BOOTSTRAP == 0 || window.location.href.search(ShortPixel.WP_ADMIN_URL) == 0)
|
304 |
+
) {
|
305 |
hideToolBarAlert();
|
306 |
return;
|
307 |
}
|
322 |
//if I'm not the bulk processor, check every 20 sec. if the bulk processor is running, otherwise take the role
|
323 |
if(ShortPixel.bulkProcessor == true || typeof localStorage.bulkTime == 'undefined' || Math.floor(Date.now() / 1000) - localStorage.bulkTime > 90) {
|
324 |
ShortPixel.bulkProcessor = true;
|
325 |
+
localStorage.bulkPage = (window.location.href.search("wp-short-pixel-bulk") >= 0 ? 1 : 0);
|
326 |
localStorage.bulkTime = Math.floor(Date.now() / 1000);
|
327 |
console.log(localStorage.bulkTime);
|
328 |
checkBulkProcessingCallApi();
|
329 |
} else {
|
330 |
+
/*console.log("not the bulk processor (bulkProcessor: " + ShortPixel.bulkProcessor.toString()
|
331 |
+
+ ", bulkTime: " + (localStorage.bulkTime == 'undefined' ? 'undefined': localStorage.bulkTime.toString())
|
332 |
+
+ " bulkPage: " + localStorage.bulkPage.toString()
|
333 |
+
+ " passed: " + (Math.floor(Date.now() / 1000) - localStorage.bulkTime).toString());*/
|
334 |
setTimeout(checkBulkProgress, 5000);
|
335 |
}
|
336 |
}
|
340 |
// since WP 2.8 ajaxurl is always defined in the admin header and points to admin-ajax.php
|
341 |
jQuery.ajax({
|
342 |
type: "POST",
|
343 |
+
url: ShortPixel.AJAX_URL, //formerly ajaxurl , but changed it because it's not available in the front-end and now we have an option to run in the front-end
|
344 |
data: data,
|
345 |
success: function(response)
|
346 |
{
|
353 |
return;
|
354 |
}
|
355 |
var id = data["ImageID"];
|
356 |
+
|
357 |
var isBulkPage = (jQuery("div.short-pixel-bulk-page").length > 0);
|
358 |
|
359 |
switch (data["Status"]) {
|
360 |
case ShortPixel.STATUS_NO_KEY:
|
361 |
+
setCellMessage(id, "<a class='button button-smaller button-primary' href=\"https://shortpixel.com/wp-apikey\" target=\"_blank\">Get API Key</a>",
|
362 |
+
data["Message"]);
|
363 |
showToolBarAlert(ShortPixel.STATUS_NO_KEY);
|
364 |
break;
|
365 |
case ShortPixel.STATUS_QUOTA_EXCEEDED:
|
366 |
+
setCellMessage(id, "<a class='button button-smaller button-primary' href=\"https://shortpixel.com/login/"
|
367 |
+ ShortPixel.API_KEY + "\" target=\"_blank\">Extend Quota</a>"
|
368 |
+
+ "<a class='button button-smaller' href='admin.php?action=shortpixel_check_quota'>Check Quota</a>",
|
369 |
+
data["Message"]);
|
370 |
showToolBarAlert(ShortPixel.STATUS_QUOTA_EXCEEDED);
|
371 |
+
if(data['Stop'] == false) { //there are other items in the priority list, maybe processed, try those
|
372 |
+
setTimeout(checkBulkProgress, 5000);
|
373 |
+
}
|
374 |
break;
|
375 |
case ShortPixel.STATUS_FAIL:
|
376 |
+
setCellMessage(id, data["Message"], "<a class='button button-smaller button-primary' href=\"javascript:manualOptimization('<?php echo($id)?>')\">Retry</a>");
|
377 |
if(isBulkPage) {
|
378 |
+
ShortPixel.bulkShowError(id, data["Message"], data["Filename"], data["CustomImageLink"]);
|
379 |
showToolBarAlert(ShortPixel.STATUS_FAIL, data["Message"]);
|
380 |
+
if(data["BulkPercent"]) {
|
381 |
+
progressUpdate(data["BulkPercent"], data["BulkMsg"]);
|
382 |
+
}
|
383 |
}
|
384 |
console.log(data["Message"]);
|
385 |
setTimeout(checkBulkProgress, 5000);
|
400 |
}
|
401 |
break;
|
402 |
case ShortPixel.STATUS_SUCCESS:
|
403 |
+
if(isBulkPage) {
|
404 |
+
ShortPixel.bulkHideLengthyMsg();
|
405 |
+
}
|
406 |
var percent = data["PercentImprovement"];
|
407 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
408 |
showToolBarAlert(ShortPixel.STATUS_SUCCESS, "");
|
409 |
+
//for now, until 4.1
|
410 |
+
var successActions = ShortPixel.isCustomImageId(id)
|
411 |
+
? ""
|
412 |
+
: ShortPixel.successActions(id, data["Type"], data['ThumbsCount'], data['ThumbsTotal'], data["BackupEnabled"]);
|
413 |
+
|
414 |
+
setCellMessage(id, ShortPixel.successMsg(id, percent, data["Type"], data['ThumbsCount']), successActions);
|
415 |
var animator = new PercentageAnimator("#sp-msg-" + id + " span.percent", percent);
|
416 |
animator.animate(percent);
|
417 |
if(isBulkPage && typeof data["Thumb"] !== 'undefined') { // && data["PercentImprovement"] > 0) {
|
418 |
+
if(data["BulkPercent"]) {
|
419 |
+
progressUpdate(data["BulkPercent"], data["BulkMsg"]);
|
420 |
+
}
|
421 |
if(data["Thumb"].length > 0){
|
422 |
+
sliderUpdate(id, data["Thumb"], data["BkThumb"], data["PercentImprovement"], data["Filename"]);
|
423 |
+
if(typeof data["AverageCompression"] !== 'undefined' && 0 + data["AverageCompression"] > 0){
|
424 |
+
jQuery("#sp-avg-optimization").html('<input type="text" class="dial" value="' + Math.round(data["AverageCompression"]) + '"/>');
|
425 |
+
ShortPixel.percentDial("#sp-avg-optimization .dial", 60);
|
426 |
+
}
|
427 |
}
|
428 |
}
|
429 |
console.log('Server response: ' + response);
|
432 |
}
|
433 |
setTimeout(checkBulkProgress, 5000);
|
434 |
break;
|
435 |
+
|
|
|
436 |
case ShortPixel.STATUS_SKIP:
|
437 |
+
if(data["Silent"] !== 1) {
|
438 |
+
ShortPixel.bulkShowError(id, data["Message"], data["Filename"], data["CustomImageLink"]);
|
439 |
+
}
|
440 |
+
//fall through
|
441 |
+
case ShortPixel.STATUS_ERROR: //for error and skip also we retry
|
442 |
if(typeof data["Message"] !== 'undefined') {
|
443 |
showToolBarAlert(ShortPixel.STATUS_SKIP, data["Message"] + ' Image ID: ' + id);
|
444 |
+
setCellMessage(id, data["Message"], "");
|
445 |
}
|
446 |
+
//fall through
|
447 |
case ShortPixel.STATUS_RETRY:
|
448 |
console.log('Server response: ' + response);
|
449 |
showToolBarAlert(ShortPixel.STATUS_RETRY, "");
|
450 |
if(isBulkPage && typeof data["BulkPercent"] !== 'undefined') {
|
451 |
progressUpdate(data["BulkPercent"], data["BulkMsg"]);
|
452 |
}
|
453 |
+
if(isBulkPage && data["Count"] > 3) {
|
454 |
+
ShortPixel.bulkShowLengthyMsg(id, data["Filename"], data["CustomImageLink"]);
|
455 |
+
}
|
456 |
setTimeout(checkBulkProgress, 5000);
|
457 |
break;
|
458 |
+
default:
|
459 |
+
ShortPixel.retry(e.message);
|
460 |
+
break;
|
461 |
}
|
462 |
}
|
463 |
},
|
475 |
}
|
476 |
}
|
477 |
|
478 |
+
function setCellMessage(id, message, actions){
|
479 |
var msg = jQuery("#sp-msg-" + id);
|
480 |
+
if(msg.length > 0) {
|
481 |
+
msg.html("<div class='sp-column-actions' style='width:110px;'>" + actions + "</div>"
|
482 |
+
+ "<div class='sp-column-info'>" + message + "</div>");
|
483 |
+
msg.css("color", "");
|
484 |
+
}
|
485 |
+
msg = jQuery("#sp-cust-msg-" + id);
|
486 |
+
if(msg.length > 0) {
|
487 |
+
msg.html("<div class='sp-column-info'>" + message + "</div>");
|
488 |
}
|
489 |
}
|
490 |
|
491 |
function manualOptimization(id) {
|
492 |
+
setCellMessage(id, "<img src='" + ShortPixel.WP_PLUGIN_URL + "/res/img/loading.gif' class='sp-loading-small'>Image waiting to be processed", "");
|
493 |
jQuery("li.shortpixel-toolbar-processing").removeClass("shortpixel-hide");
|
494 |
jQuery("li.shortpixel-toolbar-processing").addClass("shortpixel-processing");
|
495 |
var data = { action : 'shortpixel_manual_optimization',
|
496 |
image_id: id};
|
497 |
+
jQuery.get(ShortPixel.AJAX_URL, data, function(response) {
|
498 |
+
data = JSON.parse(response);
|
499 |
+
if(data["Status"] == ShortPixel.STATUS_SUCCESS) {
|
500 |
+
setTimeout(checkBulkProgress, 2000);
|
501 |
+
} else {
|
502 |
+
setCellMessage(id, typeof data["Message"] !== "undefined" ? data["Message"] : "This content is not processable.", "");
|
503 |
+
}
|
504 |
//aici e aici
|
505 |
});
|
506 |
}
|
507 |
|
508 |
function reoptimize(id, type) {
|
509 |
+
setCellMessage(id, "<img src='" + ShortPixel.WP_PLUGIN_URL + "/res/img/loading.gif' class='sp-loading-small'>Image waiting to be reprocessed", "");
|
510 |
jQuery("li.shortpixel-toolbar-processing").removeClass("shortpixel-hide");
|
511 |
jQuery("li.shortpixel-toolbar-processing").addClass("shortpixel-processing");
|
512 |
var data = { action : 'shortpixel_redo',
|
513 |
attachment_ID: id,
|
514 |
type: type};
|
515 |
+
jQuery.get(ShortPixel.AJAX_URL, data, function(response) {
|
516 |
data = JSON.parse(response);
|
517 |
if(data["Status"] == ShortPixel.STATUS_SUCCESS) {
|
518 |
setTimeout(checkBulkProgress, 2000);
|
519 |
} else {
|
520 |
$msg = typeof data["Message"] !== "undefined" ? data["Message"] : "This content is not processable.";
|
521 |
+
setCellMessage(id, $msg, "");
|
522 |
showToolBarAlert(ShortPixel.STATUS_FAIL, $msg);
|
523 |
}
|
524 |
});
|
525 |
}
|
526 |
|
527 |
function optimizeThumbs(id) {
|
528 |
+
setCellMessage(id, "<img src='" + ShortPixel.WP_PLUGIN_URL + "/res/img/loading.gif' class='sp-loading-small'>Image waiting to optimize thumbnails", "");
|
529 |
jQuery("li.shortpixel-toolbar-processing").removeClass("shortpixel-hide");
|
530 |
jQuery("li.shortpixel-toolbar-processing").addClass("shortpixel-processing");
|
531 |
var data = { action : 'shortpixel_optimize_thumbs',
|
532 |
attachment_ID: id};
|
533 |
+
jQuery.get(ShortPixel.AJAX_URL, data, function(response) {
|
534 |
data = JSON.parse(response);
|
535 |
if(data["Status"] == ShortPixel.STATUS_SUCCESS) {
|
536 |
setTimeout(checkBulkProgress, 2000);
|
537 |
} else {
|
538 |
+
setCellMessage(id, typeof data["Message"] !== "undefined" ? data["Message"] : "This content is not processable.", "");
|
539 |
}
|
540 |
});
|
541 |
}
|
544 |
jQuery("#short-pixel-notice-" + id).hide();
|
545 |
var data = { action : 'shortpixel_dismiss_notice',
|
546 |
notice_id: id};
|
547 |
+
jQuery.get(ShortPixel.AJAX_URL, data, function(response) {
|
548 |
data = JSON.parse(response);
|
549 |
if(data["Status"] == ShortPixel.STATUS_SUCCESS) {
|
550 |
console.log("dismissed");
|
597 |
}
|
598 |
}
|
599 |
|
600 |
+
|
601 |
+
|
602 |
+
function sliderUpdate(id, thumb, bkThumb, percent, filename){
|
603 |
var oldSlide = jQuery(".bulk-slider div.bulk-slide:first-child");
|
|
|
|
|
604 |
if(oldSlide.attr("id") != "empty-slide") {
|
605 |
+
oldSlide.hide();
|
606 |
}
|
607 |
oldSlide.css("z-index", 1000);
|
608 |
+
jQuery(".bulk-img-opt", oldSlide).attr("src", "");
|
609 |
+
if(bkThumb.length > 0) {
|
610 |
+
jQuery(".bulk-img-orig", oldSlide).attr("src", "");
|
611 |
+
}
|
612 |
+
|
613 |
+
var newSlide = oldSlide.clone();
|
614 |
+
newSlide.attr("id", "slide-" + id);
|
615 |
jQuery(".bulk-img-opt", newSlide).attr("src", thumb);
|
616 |
if(bkThumb.length > 0) {
|
617 |
jQuery(".img-original", newSlide).css("display", "inline-block");
|
619 |
} else {
|
620 |
jQuery(".img-original", newSlide).css("display", "none");
|
621 |
}
|
622 |
+
jQuery(".bulk-opt-percent", newSlide).html('<input type="text" class="dial" value="' + percent + '"/>');
|
623 |
|
624 |
+
//debugger;
|
625 |
jQuery(".bulk-slider").append(newSlide);
|
626 |
+
ShortPixel.percentDial("#" + newSlide.attr("id") + " .dial", 100);
|
627 |
+
|
628 |
+
jQuery(".bulk-slider-container span.filename").html(" " + filename);
|
629 |
if(oldSlide.attr("id") == "empty-slide") {
|
630 |
oldSlide.remove();
|
631 |
jQuery(".bulk-slider-container").css("display", "block");
|
632 |
} else {
|
633 |
+
oldSlide.animate({ left: oldSlide.width() + oldSlide.position().left }, 'slow', 'swing', function(){
|
634 |
oldSlide.remove();
|
635 |
newSlide.fadeIn("slow");
|
636 |
});
|
res/js/sp-file-tree.js
ADDED
@@ -0,0 +1,213 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
/*
|
3 |
+
* jQueryFileTree Plugin
|
4 |
+
*
|
5 |
+
* @author - Cory S.N. LaViska - A Beautiful Site (http://abeautifulsite.net/) - 24 March 2008
|
6 |
+
* @author - Dave Rogers - (https://github.com/daverogers/)
|
7 |
+
*
|
8 |
+
* Usage: $('.fileTreeDemo').fileTree({ options }, callback )
|
9 |
+
*
|
10 |
+
* TERMS OF USE
|
11 |
+
*
|
12 |
+
* This plugin is dual-licensed under the GNU General Public License and the MIT License and
|
13 |
+
* is copyright 2008 A Beautiful Site, LLC.
|
14 |
+
*/
|
15 |
+
var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
|
16 |
+
|
17 |
+
(function($, window) {
|
18 |
+
var FileTree;
|
19 |
+
FileTree = (function() {
|
20 |
+
function FileTree(el, args, callback) {
|
21 |
+
this.onEvent = bind(this.onEvent, this);
|
22 |
+
var $el, _this, defaults;
|
23 |
+
$el = $(el);
|
24 |
+
_this = this;
|
25 |
+
defaults = {
|
26 |
+
root: '/',
|
27 |
+
script: '/files/filetree',
|
28 |
+
folderEvent: 'click',
|
29 |
+
expandSpeed: 500,
|
30 |
+
collapseSpeed: 500,
|
31 |
+
expandEasing: 'swing',
|
32 |
+
collapseEasing: 'swing',
|
33 |
+
multiFolder: true,
|
34 |
+
loadMessage: 'Loading...',
|
35 |
+
errorMessage: 'Unable to get file tree information',
|
36 |
+
multiSelect: false,
|
37 |
+
onlyFolders: false,
|
38 |
+
onlyFiles: false,
|
39 |
+
preventLinkAction: false
|
40 |
+
};
|
41 |
+
this.jqft = {
|
42 |
+
container: $el
|
43 |
+
};
|
44 |
+
this.options = $.extend(defaults, args);
|
45 |
+
this.callback = callback;
|
46 |
+
this.data = {};
|
47 |
+
$el.html('<ul class="jqueryFileTree start"><li class="wait">' + this.options.loadMessage + '<li></ul>');
|
48 |
+
_this.showTree($el, escape(this.options.root), function() {
|
49 |
+
return _this._trigger('filetreeinitiated', {});
|
50 |
+
});
|
51 |
+
$el.delegate("li a", this.options.folderEvent, _this.onEvent);
|
52 |
+
}
|
53 |
+
|
54 |
+
FileTree.prototype.onEvent = function(event) {
|
55 |
+
var $ev, _this, callback, jqft, options, ref;
|
56 |
+
$ev = $(event.target);
|
57 |
+
options = this.options;
|
58 |
+
jqft = this.jqft;
|
59 |
+
_this = this;
|
60 |
+
callback = this.callback;
|
61 |
+
_this.data = {};
|
62 |
+
_this.data.li = $ev.closest('li');
|
63 |
+
_this.data.type = (ref = _this.data.li.hasClass('directory')) != null ? ref : {
|
64 |
+
'directory': 'file'
|
65 |
+
};
|
66 |
+
_this.data.value = $ev.text();
|
67 |
+
_this.data.rel = $ev.prop('rel');
|
68 |
+
_this.data.container = jqft.container;
|
69 |
+
if (options.preventLinkAction) {
|
70 |
+
event.preventDefault();
|
71 |
+
}
|
72 |
+
if ($ev.parent().hasClass('directory')) {
|
73 |
+
_this.jqft.container.find('LI.directory').removeClass('selected');
|
74 |
+
$ev.parent().addClass('selected');
|
75 |
+
if ($ev.parent().hasClass('collapsed')) {
|
76 |
+
if (!options.multiFolder) {
|
77 |
+
$ev.parent().parent().find('UL').slideUp({
|
78 |
+
duration: options.collapseSpeed,
|
79 |
+
easing: options.collapseEasing
|
80 |
+
});
|
81 |
+
$ev.parent().parent().find('LI.directory').removeClass('expanded').addClass('collapsed');
|
82 |
+
}
|
83 |
+
$ev.parent().removeClass('collapsed').addClass('expanded');
|
84 |
+
$ev.parent().find('UL').remove();
|
85 |
+
return _this.showTree($ev.parent(), $ev.attr('rel'), function() {
|
86 |
+
_this._trigger('filetreeexpanded', _this.data);
|
87 |
+
return callback != null;
|
88 |
+
});
|
89 |
+
} else {
|
90 |
+
return $ev.parent().find('UL').slideUp({
|
91 |
+
duration: options.collapseSpeed,
|
92 |
+
easing: options.collapseEasing,
|
93 |
+
start: function() {
|
94 |
+
return _this._trigger('filetreecollapse', _this.data);
|
95 |
+
},
|
96 |
+
complete: function() {
|
97 |
+
$ev.parent().removeClass('expanded').addClass('collapsed');
|
98 |
+
_this._trigger('filetreecollapsed', _this.data);
|
99 |
+
return callback != null;
|
100 |
+
}
|
101 |
+
});
|
102 |
+
}
|
103 |
+
} else {
|
104 |
+
if (!options.multiSelect) {
|
105 |
+
jqft.container.find('li').removeClass('selected');
|
106 |
+
$ev.parent().addClass('selected');
|
107 |
+
} else {
|
108 |
+
if ($ev.parent().find('input').is(':checked')) {
|
109 |
+
$ev.parent().find('input').prop('checked', false);
|
110 |
+
$ev.parent().removeClass('selected');
|
111 |
+
} else {
|
112 |
+
$ev.parent().find('input').prop('checked', true);
|
113 |
+
$ev.parent().addClass('selected');
|
114 |
+
}
|
115 |
+
}
|
116 |
+
_this._trigger('filetreeclicked', _this.data);
|
117 |
+
return typeof callback === "function" ? callback($ev.attr('rel')) : void 0;
|
118 |
+
}
|
119 |
+
};
|
120 |
+
|
121 |
+
FileTree.prototype.showTree = function(el, dir, finishCallback) {
|
122 |
+
var $el, _this, data, handleFail, handleResult, options, result;
|
123 |
+
$el = $(el);
|
124 |
+
options = this.options;
|
125 |
+
_this = this;
|
126 |
+
$el.addClass('wait');
|
127 |
+
$(".jqueryFileTree.start").remove();
|
128 |
+
data = {
|
129 |
+
dir: dir,
|
130 |
+
onlyFolders: options.onlyFolders,
|
131 |
+
onlyFiles: options.onlyFiles,
|
132 |
+
multiSelect: options.multiSelect
|
133 |
+
};
|
134 |
+
handleResult = function(result) {
|
135 |
+
var li;
|
136 |
+
$el.find('.start').html('');
|
137 |
+
$el.removeClass('wait').append(result);
|
138 |
+
if (options.root === dir) {
|
139 |
+
$el.find('UL:hidden').show(typeof callback !== "undefined" && callback !== null);
|
140 |
+
} else {
|
141 |
+
if (jQuery.easing[options.expandEasing] === void 0) {
|
142 |
+
console.log('Easing library not loaded. Include jQueryUI or 3rd party lib.');
|
143 |
+
options.expandEasing = 'swing';
|
144 |
+
}
|
145 |
+
$el.find('UL:hidden').slideDown({
|
146 |
+
duration: options.expandSpeed,
|
147 |
+
easing: options.expandEasing,
|
148 |
+
start: function() {
|
149 |
+
return _this._trigger('filetreeexpand', _this.data);
|
150 |
+
},
|
151 |
+
complete: finishCallback
|
152 |
+
});
|
153 |
+
}
|
154 |
+
li = $('[rel="' + decodeURIComponent(dir) + '"]').parent();
|
155 |
+
if (options.multiSelect && li.children('input').is(':checked')) {
|
156 |
+
li.find('ul li input').each(function() {
|
157 |
+
$(this).prop('checked', true);
|
158 |
+
return $(this).parent().addClass('selected');
|
159 |
+
});
|
160 |
+
}
|
161 |
+
return false;
|
162 |
+
};
|
163 |
+
handleFail = function() {
|
164 |
+
$el.find('.start').html('');
|
165 |
+
$el.removeClass('wait').append("<p>" + options.errorMessage + "</p>");
|
166 |
+
return false;
|
167 |
+
};
|
168 |
+
if (typeof options.script === 'function') {
|
169 |
+
result = options.script(data);
|
170 |
+
if (typeof result === 'string' || result instanceof jQuery) {
|
171 |
+
return handleResult(result);
|
172 |
+
} else {
|
173 |
+
return handleFail();
|
174 |
+
}
|
175 |
+
} else {
|
176 |
+
return $.ajax({
|
177 |
+
url: options.script,
|
178 |
+
type: 'POST',
|
179 |
+
dataType: 'HTML',
|
180 |
+
data: data
|
181 |
+
}).done(function(result) {
|
182 |
+
return handleResult(result);
|
183 |
+
}).fail(function() {
|
184 |
+
return handleFail();
|
185 |
+
});
|
186 |
+
}
|
187 |
+
};
|
188 |
+
|
189 |
+
FileTree.prototype._trigger = function(eventType, data) {
|
190 |
+
var $el;
|
191 |
+
$el = this.jqft.container;
|
192 |
+
return $el.triggerHandler(eventType, data);
|
193 |
+
};
|
194 |
+
|
195 |
+
return FileTree;
|
196 |
+
|
197 |
+
})();
|
198 |
+
return $.fn.extend({
|
199 |
+
fileTree: function(args, callback) {
|
200 |
+
return this.each(function() {
|
201 |
+
var $this, data;
|
202 |
+
$this = $(this);
|
203 |
+
data = $this.data('fileTree');
|
204 |
+
if (!data) {
|
205 |
+
$this.data('fileTree', (data = new FileTree(this, args, callback)));
|
206 |
+
}
|
207 |
+
if (typeof args === 'string') {
|
208 |
+
return data[option].apply(data);
|
209 |
+
}
|
210 |
+
});
|
211 |
+
}
|
212 |
+
});
|
213 |
+
})(window.jQuery, window);
|
shortpixel-debug.php
ADDED
@@ -0,0 +1,47 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
function process_error_backtrace($errno, $errstr, $errfile, $errline, $errcontext) {
|
3 |
+
if(!(error_reporting() & $errno))
|
4 |
+
return;
|
5 |
+
switch($errno) {
|
6 |
+
case E_WARNING :
|
7 |
+
case E_USER_WARNING :
|
8 |
+
case E_STRICT :
|
9 |
+
case E_NOTICE :
|
10 |
+
case E_USER_NOTICE :
|
11 |
+
$type = 'warning';
|
12 |
+
$fatal = false;
|
13 |
+
break;
|
14 |
+
default :
|
15 |
+
$type = 'fatal error';
|
16 |
+
$fatal = true;
|
17 |
+
break;
|
18 |
+
}
|
19 |
+
$trace = array_reverse(debug_backtrace());
|
20 |
+
array_pop($trace);
|
21 |
+
if(php_sapi_name() == 'cli') {
|
22 |
+
echo 'Backtrace from ' . $type . ' \'' . $errstr . '\' at ' . $errfile . ' ' . $errline . ':' . "\n";
|
23 |
+
foreach($trace as $item)
|
24 |
+
echo ' ' . (isset($item['file']) ? $item['file'] : '<unknown file>') . ' ' . (isset($item['line']) ? $item['line'] : '<unknown line>') . ' calling ' . $item['function'] . '()' . "\n";
|
25 |
+
} else {
|
26 |
+
echo '<p class="error_backtrace">' . "\n";
|
27 |
+
echo ' Backtrace from ' . $type . ' \'' . $errstr . '\' at ' . $errfile . ' ' . $errline . ':' . "\n";
|
28 |
+
echo ' <ol>' . "\n";
|
29 |
+
foreach($trace as $item)
|
30 |
+
echo ' <li>' . (isset($item['file']) ? $item['file'] : '<unknown file>') . ' ' . (isset($item['line']) ? $item['line'] : '<unknown line>') . ' calling ' . $item['function'] . '()</li>' . "\n";
|
31 |
+
echo ' </ol>' . "\n";
|
32 |
+
echo '</p>' . "\n";
|
33 |
+
}
|
34 |
+
if(ini_get('log_errors')) {
|
35 |
+
$items = array();
|
36 |
+
foreach($trace as $item)
|
37 |
+
$items[] = (isset($item['file']) ? $item['file'] : '<unknown file>') . ' ' . (isset($item['line']) ? $item['line'] : '<unknown line>') . ' calling ' . $item['function'] . '()';
|
38 |
+
$message = 'Backtrace from ' . $type . ' \'' . $errstr . '\' at ' . $errfile . ' ' . $errline . ': ' . join(' | ', $items);
|
39 |
+
error_log($message);
|
40 |
+
}
|
41 |
+
if($fatal)
|
42 |
+
exit(1);
|
43 |
+
}
|
44 |
+
|
45 |
+
if(WP_DEBUG === true) {
|
46 |
+
set_error_handler('process_error_backtrace');
|
47 |
+
}
|
shortpixel_api.php
CHANGED
@@ -14,6 +14,11 @@ class ShortPixelAPI {
|
|
14 |
const STATUS_NOT_FOUND = -5;
|
15 |
const STATUS_NO_KEY = -6;
|
16 |
const STATUS_RETRY = -7;
|
|
|
|
|
|
|
|
|
|
|
17 |
|
18 |
private $_settings;
|
19 |
private $_maxAttempts = 10;
|
@@ -23,14 +28,23 @@ class ShortPixelAPI {
|
|
23 |
public function __construct($settings) {
|
24 |
$this->_settings = $settings;
|
25 |
$this->_apiEndPoint = $this->_settings->httpProto . '://api.shortpixel.com/v2/reducer.php';
|
26 |
-
add_action('processImageAction', array(&$this, 'processImageAction'), 10, 4);
|
27 |
}
|
28 |
|
29 |
-
|
30 |
-
|
31 |
-
|
|
|
32 |
|
33 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
34 |
|
35 |
$requestParameters = array(
|
36 |
'plugin_version' => PLUGIN_VERSION,
|
@@ -54,15 +68,20 @@ class ShortPixelAPI {
|
|
54 |
'body' => json_encode($requestParameters),
|
55 |
'cookies' => array()
|
56 |
);
|
57 |
-
//add this explicitely only for https, otherwise (for http) it slows the request
|
58 |
if($this->_settings->httpProto !== 'https') {
|
59 |
unset($arguments['sslverify']);
|
60 |
}
|
|
|
|
|
|
|
61 |
$response = wp_remote_post($this->_apiEndPoint, $arguments );
|
62 |
|
63 |
//only if $Blocking is true analyze the response
|
64 |
if ( $Blocking )
|
65 |
{
|
|
|
|
|
66 |
//die(var_dump(array('URL: ' => $this->_apiEndPoint, '<br><br>REQUEST:' => $arguments, '<br><br>RESPONSE: ' => $response )));
|
67 |
//there was an error, save this error inside file's SP optimization field
|
68 |
if ( is_object($response) && get_class($response) == 'WP_Error' )
|
@@ -78,79 +97,109 @@ class ShortPixelAPI {
|
|
78 |
|
79 |
if ( isset($errorMessage) )
|
80 |
{//set details inside file so user can know what happened
|
81 |
-
$
|
82 |
-
$
|
83 |
-
|
84 |
-
|
|
|
|
|
85 |
return array("response" => array("code" => $errorCode, "message" => $errorMessage ));
|
86 |
}
|
87 |
|
88 |
return $response;//this can be an error or a good response
|
89 |
}
|
90 |
-
|
91 |
return $response;
|
92 |
}
|
93 |
|
|
|
|
|
|
|
|
|
|
|
94 |
public function parseResponse($response) {
|
95 |
$data = $response['body'];
|
96 |
-
$data =
|
97 |
return (array)$data;
|
98 |
}
|
99 |
|
100 |
-
|
101 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
102 |
{
|
103 |
-
|
104 |
-
$meta = wp_get_attachment_metadata($ID);
|
105 |
|
106 |
$PATHs = self::CheckAndFixImagePaths($PATHs);//check for images to make sure they exist on disk
|
107 |
if ( $PATHs === false ) {
|
108 |
$msg = 'The file(s) do not exist on disk.';
|
109 |
-
|
110 |
-
wp_update_attachment_metadata($ID, $meta);
|
111 |
-
|
|
|
112 |
}
|
113 |
|
114 |
//tries multiple times (till timeout almost reached) to fetch images.
|
115 |
if($startTime == 0) {
|
116 |
$startTime = time();
|
117 |
}
|
118 |
-
$apiRetries =
|
119 |
|
120 |
if( time() - $startTime > MAX_EXECUTION_TIME)
|
121 |
{//keeps track of time
|
122 |
if ( $apiRetries > MAX_API_RETRIES )//we tried to process this time too many times, giving up...
|
123 |
{
|
124 |
-
|
125 |
-
unset($meta['ShortPixel']['WaitingProcessing']);
|
126 |
-
|
127 |
-
|
128 |
-
|
|
|
|
|
|
|
|
|
129 |
}
|
130 |
else
|
131 |
{//we'll try again next time user visits a page on admin panel
|
132 |
$apiRetries++;
|
133 |
-
|
134 |
-
return array("Status" => self::STATUS_RETRY, "Message" => 'Timed out while processing. (pass '.$apiRetries.')'
|
|
|
135 |
}
|
136 |
}
|
137 |
|
138 |
-
|
139 |
-
$
|
|
|
|
|
140 |
|
141 |
if($response['response']['code'] != 200)//response <> 200 -> there was an error apparently?
|
142 |
return array("Status" => self::STATUS_FAIL, "Message" => "There was an error and your request was not processed.");
|
143 |
|
144 |
$APIresponse = $this->parseResponse($response);//get the actual response from API, its an array
|
145 |
-
|
146 |
-
if ( isset($APIresponse[0]) )//API returned image details
|
147 |
{
|
148 |
-
foreach ( $APIresponse as $imageObject )//this part makes sure that all the sizes were processed and ready to be downloaded
|
149 |
-
|
150 |
-
if ( $imageObject->Status->Code == 0 || $imageObject->Status->Code == 1 )
|
151 |
-
{
|
152 |
sleep(1);
|
153 |
-
return $this->
|
154 |
}
|
155 |
}
|
156 |
|
@@ -159,43 +208,67 @@ class ShortPixelAPI {
|
|
159 |
{
|
160 |
case 2:
|
161 |
//handle image has been processed
|
162 |
-
if(!isset($firstImage->Status->
|
163 |
$this->_settings->quotaExceeded = 0;//reset the quota exceeded flag
|
164 |
}
|
165 |
-
return $this->handleSuccess($APIresponse, $
|
166 |
-
break;
|
167 |
default:
|
168 |
//handle error
|
169 |
-
if ( !file_exists($PATHs[0]) )
|
170 |
-
|
|
|
|
|
|
|
|
|
171 |
elseif ( isset($APIresponse[0]->Status->Message) ) {
|
172 |
//return array("Status" => self::STATUS_FAIL, "Message" => "There was an error and your request was not processed (" . $APIresponse[0]->Status->Message . "). REQ: " . json_encode($URLs));
|
173 |
-
|
|
|
|
|
|
|
174 |
}
|
175 |
|
176 |
-
|
177 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
178 |
}
|
179 |
}
|
180 |
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
|
188 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
189 |
}
|
190 |
-
|
191 |
-
//sometimes the response array can be different
|
192 |
-
if ( is_numeric($APIresponse['Status']->Code) )
|
193 |
-
return array("Status" => self::STATUS_FAIL, "Message" => $APIresponse['Status']->Message);
|
194 |
-
else
|
195 |
-
return array("Status" => self::STATUS_FAIL, "Message" => $APIresponse[0]->Status->Message);
|
196 |
-
|
197 |
}
|
198 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
199 |
public function setPreferredProtocol($url, $reset = false) {
|
200 |
//switch protocol based on the formerly detected working protocol
|
201 |
if($this->_settings->downloadProto == '' || $reset) {
|
@@ -211,7 +284,13 @@ class ShortPixelAPI {
|
|
211 |
|
212 |
}
|
213 |
|
214 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
215 |
//var_dump($fileData);
|
216 |
if($compressionType)
|
217 |
{
|
@@ -232,83 +311,103 @@ class ShortPixelAPI {
|
|
232 |
$fileURL = $this->setPreferredProtocol(urldecode($fileData->$fileType));
|
233 |
|
234 |
$downloadTimeout = max(ini_get('max_execution_time') - 10, 15);
|
235 |
-
$
|
236 |
//var_dump($tempFiles);
|
237 |
|
238 |
-
if(is_wp_error( $
|
239 |
{ //try to switch the default protocol
|
240 |
$fileURL = $this->setPreferredProtocol(urldecode($fileData->$fileType), true); //force recheck of the protocol
|
241 |
-
$
|
242 |
}
|
243 |
//on success we return this
|
244 |
-
$returnMessage = array("Status" => self::STATUS_SUCCESS, "Message" => $
|
245 |
|
246 |
-
if ( is_wp_error( $
|
247 |
-
@unlink($
|
248 |
$returnMessage = array(
|
249 |
"Status" => self::STATUS_ERROR,
|
250 |
-
"Message" => "Error downloading file ({$fileData->$fileType}) " . $
|
251 |
}
|
252 |
//check response so that download is OK
|
253 |
-
elseif( filesize($
|
254 |
-
$size = filesize($
|
255 |
-
@unlink($
|
256 |
$returnMessage = array(
|
257 |
"Status" => self::STATUS_ERROR,
|
258 |
"Message" => "Error downloading file - incorrect file size (downloaded: {$size}, correct: {$correctFileSize} )");
|
259 |
}
|
260 |
-
elseif (!file_exists($
|
261 |
-
$returnMessage = array("Status" => self::STATUS_ERROR, "Message" => "Unable to locate downloaded file " . $
|
262 |
}
|
263 |
return $returnMessage;
|
264 |
}
|
265 |
|
266 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
267 |
$counter = $savedSpace = $originalSpace = $optimizedSpace = $averageCompression = 0;
|
268 |
$NoBackup = true;
|
269 |
-
|
|
|
|
|
270 |
//download each file from array and process it
|
271 |
foreach ( $APIresponse as $fileData )
|
272 |
{
|
273 |
if ( $fileData->Status->Code == 2 ) //file was processed OK
|
274 |
{
|
275 |
-
if ( $counter == 0 )//save percent improvement for main file
|
276 |
$percentImprovement = $fileData->PercentImprovement;
|
277 |
-
else //count thumbnails only
|
278 |
-
|
279 |
-
|
280 |
-
|
281 |
if ( $downloadResult['Status'] == self::STATUS_SUCCESS ) {
|
282 |
$tempFiles[$counter] = $downloadResult['Message'];
|
283 |
}
|
284 |
-
|
|
|
285 |
return array("Status" => $downloadResult['Status'], "Message" => $downloadResult['Message']);
|
|
|
|
|
|
|
|
|
|
|
|
|
286 |
}
|
287 |
-
else //there was an error while trying to download a file
|
288 |
$tempFiles[$counter] = "";
|
289 |
-
|
290 |
$counter++;
|
291 |
}
|
292 |
|
293 |
//figure out in what SubDir files should land
|
294 |
-
|
|
|
|
|
|
|
295 |
|
296 |
//if backup is enabled - we try to save the images
|
297 |
if( $this->_settings->backupImages )
|
298 |
{
|
299 |
-
$uploadDir = wp_upload_dir();
|
300 |
$source = $PATHs; //array with final paths for these files
|
301 |
|
302 |
if( !file_exists(SP_BACKUP_FOLDER) && !@mkdir(SP_BACKUP_FOLDER, 0777, true) ) {//creates backup folder if it doesn't exist
|
303 |
return array("Status" => self::STATUS_FAIL, "Message" => "Backup folder does not exist and it cannot be created");
|
304 |
}
|
305 |
//create subdir in backup folder if needed
|
306 |
-
@mkdir( SP_BACKUP_FOLDER . DIRECTORY_SEPARATOR . $
|
307 |
|
308 |
foreach ( $source as $fileID => $filePATH )//create destination files array
|
309 |
{
|
310 |
-
$destination[$fileID] = SP_BACKUP_FOLDER . DIRECTORY_SEPARATOR . $
|
311 |
}
|
|
|
312 |
|
313 |
//now that we have original files and where we should back them up we attempt to do just that
|
314 |
if(is_writable(SP_BACKUP_FOLDER))
|
@@ -319,20 +418,29 @@ class ShortPixelAPI {
|
|
319 |
{
|
320 |
if ( !@copy($source[$fileID], $destination[$fileID]) )
|
321 |
{//file couldn't be saved in backup folder
|
322 |
-
|
323 |
-
|
|
|
|
|
|
|
324 |
}
|
325 |
}
|
326 |
}
|
327 |
$NoBackup = true;
|
328 |
} else {//cannot write to the backup dir, return with an error
|
329 |
-
ShortPixelAPI::SaveMessageinMetadata($ID, 'Cannot save file in backup directory');
|
330 |
-
|
|
|
|
|
|
|
331 |
}
|
332 |
|
333 |
}//end backup section
|
334 |
|
335 |
$writeFailed = 0;
|
|
|
|
|
|
|
336 |
|
337 |
if ( !empty($tempFiles) )
|
338 |
{
|
@@ -340,23 +448,29 @@ class ShortPixelAPI {
|
|
340 |
foreach ( $tempFiles as $tempFileID => $tempFilePATH )
|
341 |
{
|
342 |
if ( file_exists($tempFilePATH) && file_exists($PATHs[$tempFileID]) && is_writable($PATHs[$tempFileID]) ) {
|
343 |
-
/*
|
344 |
-
echo("COPY FROM " . $tempFilePATH . " TO " . $PATHs[$tempFileID] . " TIME " . date("Y-m-d H:i:s"));
|
345 |
-
if(file_exists($PATHs[$tempFileID])) {
|
346 |
-
echo " TARGET IS THERE, SIZE " . filesize($PATHs[$tempFileID]) . ", FILEMTIME: " . date("Y-m-d H:i:s", filemtime($PATHs[$tempFileID])) . ", UNLINKING ... "
|
347 |
-
}
|
348 |
-
unlink($PATHs[$tempFileID]);
|
349 |
-
if(file_exists($PATHs[$tempFileID])) {
|
350 |
-
echo " NOT UNLINKED ";
|
351 |
-
}
|
352 |
-
*/
|
353 |
copy($tempFilePATH, $PATHs[$tempFileID]);
|
354 |
-
|
355 |
-
|
356 |
-
|
|
|
|
|
|
|
|
|
357 |
}
|
358 |
-
|
359 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
360 |
$writeFailed++;
|
361 |
}
|
362 |
@unlink($tempFilePATH);
|
@@ -364,30 +478,19 @@ class ShortPixelAPI {
|
|
364 |
|
365 |
if ( $writeFailed > 0 )//there was an error
|
366 |
{
|
367 |
-
|
|
|
|
|
|
|
368 |
update_option('bulkProcessingStatus', "error");
|
369 |
-
return array("Status" => self::STATUS_FAIL, "Code" =>"write-fail", "Message" =>
|
370 |
-
}
|
371 |
-
else
|
372 |
-
{//all files were copied, optimization data regarding the savings locally in DB
|
373 |
-
$fileType = ( $this->_settings->compressionType ) ? "LossySize" : "LoselessSize";
|
374 |
-
$savedSpace += $APIresponse[$tempFileID]->OriginalSize - $APIresponse[$tempFileID]->$fileType;
|
375 |
-
$originalSpace += $APIresponse[$tempFileID]->OriginalSize;
|
376 |
-
$optimizedSpace += $APIresponse[$tempFileID]->$fileType;
|
377 |
-
$averageCompression += $fileData->PercentImprovement;
|
378 |
-
|
379 |
-
//add the number of files with < 5% optimization
|
380 |
-
if ( ( ( 1 - $APIresponse[$tempFileID]->$fileType/$APIresponse[$tempFileID]->OriginalSize ) * 100 ) < 5 ) {
|
381 |
-
$this->_settings->under5Percent++;
|
382 |
-
}
|
383 |
}
|
384 |
} elseif( 0 + $fileData->PercentImprovement < 5) {
|
385 |
$this->_settings->under5Percent++;
|
386 |
}
|
387 |
//old average counting
|
388 |
$this->_settings->savedSpace += $savedSpace;
|
389 |
-
$averageCompression = $this->_settings->averageCompression * $this->_settings->fileCount;
|
390 |
-
$averageCompression = $averageCompression / ($this->_settings->fileCount + count($APIresponse));
|
391 |
$this->_settings->averageCompression = $averageCompression;
|
392 |
$this->_settings->fileCount += count($APIresponse);
|
393 |
//new average counting
|
@@ -395,71 +498,45 @@ class ShortPixelAPI {
|
|
395 |
$this->_settings->totalOptimized += $optimizedSpace;
|
396 |
|
397 |
//update metadata for this file
|
398 |
-
$
|
399 |
-
|
400 |
-
|
401 |
-
$
|
402 |
-
|
403 |
-
|
404 |
-
|
405 |
-
|
406 |
-
|
407 |
-
|
408 |
-
|
409 |
-
|
410 |
-
|
411 |
-
|
412 |
-
|
413 |
-
|
414 |
-
|
415 |
-
|
416 |
-
}
|
417 |
-
wp_update_attachment_metadata($_ID, $meta);
|
418 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
419 |
//we reset the retry counter in case of success
|
420 |
-
|
421 |
|
422 |
-
return array("Status" => self::STATUS_SUCCESS, "Message" => 'Success: No pixels remained unsqueezed :-)', "PercentImprovement" => $
|
423 |
}//end handleSuccess
|
424 |
-
|
425 |
-
static public function getWPMLDuplicates( $id ) {
|
426 |
-
global $wpdb;
|
427 |
-
|
428 |
-
$parentId = get_post_meta ($id, '_icl_lang_duplicate_of', true );
|
429 |
-
if($parentId) $id = $parentId;
|
430 |
-
|
431 |
-
$duplicates = $wpdb->get_col( $wpdb->prepare( "
|
432 |
-
SELECT pm.post_id FROM {$wpdb->postmeta} pm
|
433 |
-
WHERE pm.meta_value = %s AND pm.meta_key = '_icl_lang_duplicate_of'
|
434 |
-
", $id ) );
|
435 |
|
436 |
-
|
437 |
-
|
438 |
-
|
439 |
-
|
440 |
-
|
441 |
-
if(count($transGroupId)) {
|
442 |
-
$transGroup = $wpdb->get_results("SELECT element_id FROM {$wpdb->prefix}icl_translations WHERE trid = " . $transGroupId[0]->trid);
|
443 |
-
foreach($transGroup as $trans) {
|
444 |
-
$duplicates[] = $trans->element_id;
|
445 |
-
}
|
446 |
-
}
|
447 |
-
}
|
448 |
-
|
449 |
-
return array_unique($duplicates);
|
450 |
-
}
|
451 |
-
|
452 |
-
|
453 |
-
static public function returnSubDir($file)//return subdir for that particular attached file
|
454 |
-
{
|
455 |
-
$Atoms = explode("/", $file);
|
456 |
-
$Counter = count($Atoms);
|
457 |
-
$SubDir = $Atoms[$Counter-3] . DIRECTORY_SEPARATOR . $Atoms[$Counter-2] . DIRECTORY_SEPARATOR;
|
458 |
-
|
459 |
-
return $SubDir;
|
460 |
-
}
|
461 |
-
|
462 |
-
//a basename alternative that deals OK with multibyte charsets (e.g. Arabic)
|
463 |
static public function MB_basename($Path){
|
464 |
$Separator = " qq ";
|
465 |
$Path = preg_replace("/[^ ]/u", $Separator."\$0".$Separator, $Path);
|
@@ -468,9 +545,13 @@ class ShortPixelAPI {
|
|
468 |
return $Base;
|
469 |
}
|
470 |
|
471 |
-
|
|
|
|
|
|
|
|
|
472 |
static public function CheckAndFixImagePaths($PATHs){
|
473 |
-
|
474 |
$ErrorCount = 0;
|
475 |
$uploadDir = wp_upload_dir();
|
476 |
$Tmp = explode("/", $uploadDir['basedir']);
|
@@ -483,18 +564,19 @@ class ShortPixelAPI {
|
|
483 |
if ( !file_exists($File) ){
|
484 |
//$NewFile = $uploadDir['basedir'] . "/" . substr($File,strpos($File, $StichString));//+strlen($StichString));
|
485 |
$NewFile = $uploadDir['basedir'] . substr($File,strpos($File, $StichString)+strlen($StichString));
|
486 |
-
if (
|
487 |
$PATHs[$Id] = $NewFile;
|
488 |
-
else
|
489 |
$ErrorCount++;
|
|
|
490 |
}
|
491 |
}
|
492 |
|
493 |
-
if ( $ErrorCount > 0 )
|
494 |
return false;
|
495 |
-
else
|
496 |
return $PATHs;
|
497 |
-
|
498 |
}
|
499 |
|
500 |
static public function getCompressionTypeName($compressionType) {
|
@@ -508,15 +590,4 @@ class ShortPixelAPI {
|
|
508 |
unset($meta['ShortPixel']['WaitingProcessing']);
|
509 |
wp_update_attachment_metadata($ID, $meta);
|
510 |
}
|
511 |
-
|
512 |
-
public function parseJSON($data) {
|
513 |
-
if ( function_exists('json_decode') ) {
|
514 |
-
$data = json_decode( $data );
|
515 |
-
} else {
|
516 |
-
require_once( 'JSON/JSON.php' );
|
517 |
-
$json = new Services_JSON( );
|
518 |
-
$data = $json->decode( $data );
|
519 |
-
}
|
520 |
-
return $data;
|
521 |
-
}
|
522 |
}
|
14 |
const STATUS_NOT_FOUND = -5;
|
15 |
const STATUS_NO_KEY = -6;
|
16 |
const STATUS_RETRY = -7;
|
17 |
+
|
18 |
+
const ERR_FILE_NOT_FOUND = -2;
|
19 |
+
const ERR_TIMEOUT = -3;
|
20 |
+
const ERR_SAVE = -4;
|
21 |
+
const ERR_SAVE_BKP = -5;
|
22 |
|
23 |
private $_settings;
|
24 |
private $_maxAttempts = 10;
|
28 |
public function __construct($settings) {
|
29 |
$this->_settings = $settings;
|
30 |
$this->_apiEndPoint = $this->_settings->httpProto . '://api.shortpixel.com/v2/reducer.php';
|
31 |
+
//# TODO verifica- pare la oha: add_action('processImageAction', array(&$this, 'processImageAction'), 10, 4);
|
32 |
}
|
33 |
|
34 |
+
//# TODO verifica- pare la oha
|
35 |
+
//#public function processImageAction($url, $filePaths, $itemHandler, $time) {
|
36 |
+
//# $this->processImage($URLs, $PATHs, $itemHandler, $time);
|
37 |
+
//#}
|
38 |
|
39 |
+
/**
|
40 |
+
* sends a compression request to the API
|
41 |
+
* @param array $URLs - list of urls to send to API
|
42 |
+
* @param Boolean $Blocking - true means it will wait for an answer
|
43 |
+
* @param ShortPixelMetaFacade $itemHandler - the Facade that manages different types of image metadatas: MediaLibrary (postmeta table), ShortPixel custom (shortpixel_meta table)
|
44 |
+
* @param int $compressionType 1 - lossy, 0 - lossless
|
45 |
+
* @return response from wp_remote_post or error
|
46 |
+
*/
|
47 |
+
public function doRequests($URLs, $Blocking, $itemHandler, $compressionType = false) {
|
48 |
|
49 |
$requestParameters = array(
|
50 |
'plugin_version' => PLUGIN_VERSION,
|
68 |
'body' => json_encode($requestParameters),
|
69 |
'cookies' => array()
|
70 |
);
|
71 |
+
//add this explicitely only for https, otherwise (for http) it slows down the request
|
72 |
if($this->_settings->httpProto !== 'https') {
|
73 |
unset($arguments['sslverify']);
|
74 |
}
|
75 |
+
|
76 |
+
WpShortPixel::log("Calling API with params : " . json_encode($arguments));
|
77 |
+
|
78 |
$response = wp_remote_post($this->_apiEndPoint, $arguments );
|
79 |
|
80 |
//only if $Blocking is true analyze the response
|
81 |
if ( $Blocking )
|
82 |
{
|
83 |
+
WpShortPixel::log("API response : " . json_encode($response));
|
84 |
+
|
85 |
//die(var_dump(array('URL: ' => $this->_apiEndPoint, '<br><br>REQUEST:' => $arguments, '<br><br>RESPONSE: ' => $response )));
|
86 |
//there was an error, save this error inside file's SP optimization field
|
87 |
if ( is_object($response) && get_class($response) == 'WP_Error' )
|
97 |
|
98 |
if ( isset($errorMessage) )
|
99 |
{//set details inside file so user can know what happened
|
100 |
+
$itemHandler->setError($errorCode, $errorMessage);
|
101 |
+
$itemHandler->incrementRetries();
|
102 |
+
//$meta = wp_get_attachment_metadata($ID);
|
103 |
+
//$meta['ShortPixelImprovement'] = 'Error: <i>' . $errorMessage . '</i>';
|
104 |
+
//unset($meta['ShortPixel']['WaitingProcessing']);
|
105 |
+
//wp_update_attachment_metadata($ID, $meta);
|
106 |
return array("response" => array("code" => $errorCode, "message" => $errorMessage ));
|
107 |
}
|
108 |
|
109 |
return $response;//this can be an error or a good response
|
110 |
}
|
111 |
+
|
112 |
return $response;
|
113 |
}
|
114 |
|
115 |
+
/**
|
116 |
+
* parse the JSON response
|
117 |
+
* @param $response
|
118 |
+
* @return parsed array
|
119 |
+
*/
|
120 |
public function parseResponse($response) {
|
121 |
$data = $response['body'];
|
122 |
+
$data = ShortPixelTools::parseJSON($data);
|
123 |
return (array)$data;
|
124 |
}
|
125 |
|
126 |
+
/**
|
127 |
+
* handles the processing of the image using the ShortPixel API
|
128 |
+
* @param array $URLs - list of urls to send to API
|
129 |
+
* @param array $PATHs - list of local paths for the images
|
130 |
+
* @param ShortPixelMetaFacade $itemHandler - the Facade that manages different types of image metadatas: MediaLibrary (postmeta table), ShortPixel custom (shortpixel_meta table)
|
131 |
+
* @return status/message array
|
132 |
+
*/
|
133 |
+
public function processImage($URLs, $PATHs, $itemHandler = null) {
|
134 |
+
return $this->processImageRecursive($URLs, $PATHs, $itemHandler, 0);
|
135 |
+
}
|
136 |
+
|
137 |
+
/**
|
138 |
+
* handles the processing of the image using the ShortPixel API - cals itself recursively until success
|
139 |
+
* @param array $URLs - list of urls to send to API
|
140 |
+
* @param array $PATHs - list of local paths for the images
|
141 |
+
* @param ShortPixelMetaFacade $itemHandler - the Facade that manages different types of image metadatas: MediaLibrary (postmeta table), ShortPixel custom (shortpixel_meta table)
|
142 |
+
* @param type $startTime - time of the first call
|
143 |
+
* @return status/message array
|
144 |
+
*/
|
145 |
+
private function processImageRecursive($URLs, $PATHs, $itemHandler = null, $startTime = 0)
|
146 |
{
|
147 |
+
//#$meta = wp_get_attachment_metadata($ID);
|
|
|
148 |
|
149 |
$PATHs = self::CheckAndFixImagePaths($PATHs);//check for images to make sure they exist on disk
|
150 |
if ( $PATHs === false ) {
|
151 |
$msg = 'The file(s) do not exist on disk.';
|
152 |
+
//#$meta['ShortPixelImprovement'] = $msg;
|
153 |
+
//#wp_update_attachment_metadata($ID, $meta);
|
154 |
+
$itemHandler->setError(self::ERR_FILE_NOT_FOUND, $msg );
|
155 |
+
return array("Status" => self::STATUS_SKIP, "Message" => $msg, "Silent" => $itemHandler->getType() == ShortPixelMetaFacade::CUSTOM_TYPE ? 1 : 0);
|
156 |
}
|
157 |
|
158 |
//tries multiple times (till timeout almost reached) to fetch images.
|
159 |
if($startTime == 0) {
|
160 |
$startTime = time();
|
161 |
}
|
162 |
+
$apiRetries = $this->_settings->apiRetries;
|
163 |
|
164 |
if( time() - $startTime > MAX_EXECUTION_TIME)
|
165 |
{//keeps track of time
|
166 |
if ( $apiRetries > MAX_API_RETRIES )//we tried to process this time too many times, giving up...
|
167 |
{
|
168 |
+
//#$meta['ShortPixelImprovement'] = 'Timed out while processing.';
|
169 |
+
//#unset($meta['ShortPixel']['WaitingProcessing']);
|
170 |
+
//#wp_update_attachment_metadata($ID, $meta);
|
171 |
+
$itemHandler->setError(self::ERR_TIMEOUT, 'Timed out while processing.');
|
172 |
+
$itemHandler->incrementRetries();
|
173 |
+
$this->_settings->apiRetries = 0; //fai added to solve a bug?
|
174 |
+
return array("Status" => self::STATUS_SKIP,
|
175 |
+
"Message" => ($itemHandler->getType() == ShortPixelMetaFacade::CUSTOM_TYPE ? "Image ID: " : "Media ID: ")
|
176 |
+
. $itemHandler->getId() .' Skip this image, try the next one.');
|
177 |
}
|
178 |
else
|
179 |
{//we'll try again next time user visits a page on admin panel
|
180 |
$apiRetries++;
|
181 |
+
$this->_settings->apiRetries = $apiRetries;
|
182 |
+
return array("Status" => self::STATUS_RETRY, "Message" => 'Timed out while processing. (pass '.$apiRetries.')',
|
183 |
+
"Count" => $apiRetries);
|
184 |
}
|
185 |
}
|
186 |
|
187 |
+
//#$compressionType = isset($meta['ShortPixel']['type']) ? ($meta['ShortPixel']['type'] == 'lossy' ? 1 : 0) : $this->_settings->compressionType;
|
188 |
+
$meta = $itemHandler->getMeta();
|
189 |
+
$compressionType = $meta->getCompressionType() !== null ? $meta->getCompressionType() : $this->_settings->compressionType;
|
190 |
+
$response = $this->doRequests($URLs, true, $itemHandler, $compressionType);//send requests to API
|
191 |
|
192 |
if($response['response']['code'] != 200)//response <> 200 -> there was an error apparently?
|
193 |
return array("Status" => self::STATUS_FAIL, "Message" => "There was an error and your request was not processed.");
|
194 |
|
195 |
$APIresponse = $this->parseResponse($response);//get the actual response from API, its an array
|
196 |
+
|
197 |
+
if ( isset($APIresponse[0]) ) //API returned image details
|
198 |
{
|
199 |
+
foreach ( $APIresponse as $imageObject ) {//this part makes sure that all the sizes were processed and ready to be downloaded
|
200 |
+
if ( $imageObject->Status->Code == 0 || $imageObject->Status->Code == 1 ) {
|
|
|
|
|
201 |
sleep(1);
|
202 |
+
return $this->processImageRecursive($URLs, $PATHs, $itemHandler, $startTime);
|
203 |
}
|
204 |
}
|
205 |
|
208 |
{
|
209 |
case 2:
|
210 |
//handle image has been processed
|
211 |
+
if(!isset($firstImage->Status->QuotaExceeded)) {
|
212 |
$this->_settings->quotaExceeded = 0;//reset the quota exceeded flag
|
213 |
}
|
214 |
+
return $this->handleSuccess($APIresponse, $PATHs, $itemHandler, $compressionType);
|
|
|
215 |
default:
|
216 |
//handle error
|
217 |
+
if ( !file_exists($PATHs[0]) ) {
|
218 |
+
$itemHandler->incrementRetries(2);
|
219 |
+
$err = array("Status" => self::STATUS_NOT_FOUND, "Message" => "File not found on disk. "
|
220 |
+
. ($itemHandler->getType() == ShortPixelMetaFacade::CUSTOM_TYPE ? "Image " : "Media ")
|
221 |
+
. " ID: " . $itemHandler->getId());
|
222 |
+
}
|
223 |
elseif ( isset($APIresponse[0]->Status->Message) ) {
|
224 |
//return array("Status" => self::STATUS_FAIL, "Message" => "There was an error and your request was not processed (" . $APIresponse[0]->Status->Message . "). REQ: " . json_encode($URLs));
|
225 |
+
$err = array("Status" => self::STATUS_FAIL, "Code" => (isset($APIresponse[0]->Status->Code) ? $APIresponse[0]->Status->Code : ""),
|
226 |
+
"Message" => "There was an error and your request was not processed (" . $APIresponse[0]->Status->Message . ")");
|
227 |
+
} else {
|
228 |
+
$err = array("Status" => self::STATUS_FAIL, "Message" => "There was an error and your request was not processed");
|
229 |
}
|
230 |
|
231 |
+
$itemHandler->incrementRetries();
|
232 |
+
$meta = $itemHandler->getMeta();
|
233 |
+
if($meta->getRetries() >= MAX_FAIL_RETRIES) {
|
234 |
+
$meta->setStatus($APIresponse[0]->Status->Code);
|
235 |
+
$meta->setMessage($APIresponse[0]->Status->Message);
|
236 |
+
$itemHandler->updateMeta();
|
237 |
+
}
|
238 |
+
return $err;
|
239 |
}
|
240 |
}
|
241 |
|
242 |
+
if(!isset($APIresponse['Status'])) {
|
243 |
+
WpShortPixel::log("API Response Status unfound : " . json_encode($APIresponse));
|
244 |
+
return array("Status" => self::STATUS_FAIL, "Message" => "Unecognized API response. Please contact support.");
|
245 |
+
} else {
|
246 |
+
switch($APIresponse['Status']->Code)
|
247 |
+
{
|
248 |
+
case -403:
|
249 |
+
@delete_option('bulkProcessingStatus');
|
250 |
+
$this->_settings->quotaExceeded = 1;
|
251 |
+
return array("Status" => self::STATUS_QUOTA_EXCEEDED, "Message" => "Quota exceeded.");
|
252 |
+
break;
|
253 |
+
}
|
254 |
+
|
255 |
+
//sometimes the response array can be different
|
256 |
+
if (is_numeric($APIresponse['Status']->Code)) {
|
257 |
+
return array("Status" => self::STATUS_FAIL, "Message" => $APIresponse['Status']->Message);
|
258 |
+
} else {
|
259 |
+
return array("Status" => self::STATUS_FAIL, "Message" => $APIresponse[0]->Status->Message);
|
260 |
+
}
|
261 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
262 |
}
|
263 |
|
264 |
+
/**
|
265 |
+
* sets the preferred protocol of URL using the globally set preferred protocol.
|
266 |
+
* If global protocol not set, sets it by testing the download of a http test image from ShortPixel site.
|
267 |
+
* If http works then it's http, otherwise sets https
|
268 |
+
* @param string $url
|
269 |
+
* @param bool $reset - forces recheck even if preferred protocol is already set
|
270 |
+
* @return url with the preferred protocol
|
271 |
+
*/
|
272 |
public function setPreferredProtocol($url, $reset = false) {
|
273 |
//switch protocol based on the formerly detected working protocol
|
274 |
if($this->_settings->downloadProto == '' || $reset) {
|
284 |
|
285 |
}
|
286 |
|
287 |
+
/**
|
288 |
+
* handles the download of an optimized image from ShortPixel API
|
289 |
+
* @param type $fileData - info about the file
|
290 |
+
* @param int $compressionType - 1 - lossy, 0 - lossless
|
291 |
+
* @return status/message array
|
292 |
+
*/
|
293 |
+
private function handleDownload($fileData, $compressionType){
|
294 |
//var_dump($fileData);
|
295 |
if($compressionType)
|
296 |
{
|
311 |
$fileURL = $this->setPreferredProtocol(urldecode($fileData->$fileType));
|
312 |
|
313 |
$downloadTimeout = max(ini_get('max_execution_time') - 10, 15);
|
314 |
+
$tempFile = download_url($fileURL, $downloadTimeout);
|
315 |
//var_dump($tempFiles);
|
316 |
|
317 |
+
if(is_wp_error( $tempFile ))
|
318 |
{ //try to switch the default protocol
|
319 |
$fileURL = $this->setPreferredProtocol(urldecode($fileData->$fileType), true); //force recheck of the protocol
|
320 |
+
$tempFile = download_url($fileURL, $downloadTimeout);
|
321 |
}
|
322 |
//on success we return this
|
323 |
+
$returnMessage = array("Status" => self::STATUS_SUCCESS, "Message" => $tempFile);
|
324 |
|
325 |
+
if ( is_wp_error( $tempFile ) ) {
|
326 |
+
@unlink($tempFile);
|
327 |
$returnMessage = array(
|
328 |
"Status" => self::STATUS_ERROR,
|
329 |
+
"Message" => "Error downloading file ({$fileData->$fileType}) " . $tempFile->get_error_message());
|
330 |
}
|
331 |
//check response so that download is OK
|
332 |
+
elseif( filesize($tempFile) != $correctFileSize) {
|
333 |
+
$size = filesize($tempFile);
|
334 |
+
@unlink($tempFile);
|
335 |
$returnMessage = array(
|
336 |
"Status" => self::STATUS_ERROR,
|
337 |
"Message" => "Error downloading file - incorrect file size (downloaded: {$size}, correct: {$correctFileSize} )");
|
338 |
}
|
339 |
+
elseif (!file_exists($tempFile)) {
|
340 |
+
$returnMessage = array("Status" => self::STATUS_ERROR, "Message" => "Unable to locate downloaded file " . $tempFile);
|
341 |
}
|
342 |
return $returnMessage;
|
343 |
}
|
344 |
|
345 |
+
/**
|
346 |
+
* handles a successful optimization, setting metadata and handling download for each file in the set
|
347 |
+
* @param type $APIresponse - the response from the API - contains the optimized images URLs to download
|
348 |
+
* @param type $PATHs - list of local paths for the files
|
349 |
+
* @param ShortPixelMetaFacade $itemHandler - the Facade that manages different types of image metadatas: MediaLibrary (postmeta table), ShortPixel custom (shortpixel_meta table)
|
350 |
+
* @param int $compressionType - 1 - lossy, 0 - lossless
|
351 |
+
* @return status/message array
|
352 |
+
*/
|
353 |
+
private function handleSuccess($APIresponse, $PATHs, $itemHandler, $compressionType) {
|
354 |
$counter = $savedSpace = $originalSpace = $optimizedSpace = $averageCompression = 0;
|
355 |
$NoBackup = true;
|
356 |
+
|
357 |
+
$fileType = ( $compressionType ) ? "LossySize" : "LoselessSize";
|
358 |
+
|
359 |
//download each file from array and process it
|
360 |
foreach ( $APIresponse as $fileData )
|
361 |
{
|
362 |
if ( $fileData->Status->Code == 2 ) //file was processed OK
|
363 |
{
|
364 |
+
if ( $counter == 0 ) { //save percent improvement for main file
|
365 |
$percentImprovement = $fileData->PercentImprovement;
|
366 |
+
} else { //count thumbnails only
|
367 |
+
$this->_settings->thumbsCount = $this->_settings->thumbsCount + 1;
|
368 |
+
}
|
369 |
+
$downloadResult = $this->handleDownload($fileData,$compressionType);
|
370 |
if ( $downloadResult['Status'] == self::STATUS_SUCCESS ) {
|
371 |
$tempFiles[$counter] = $downloadResult['Message'];
|
372 |
}
|
373 |
+
//when the status is STATUS_UNCHANGED we just skip the array line for that one
|
374 |
+
elseif ( $downloadResult['Status'] <> self::STATUS_UNCHANGED ) {
|
375 |
return array("Status" => $downloadResult['Status'], "Message" => $downloadResult['Message']);
|
376 |
+
}
|
377 |
+
else { //this image is unchanged so won't be copied below, only the optimization stats need to be computed
|
378 |
+
$originalSpace += $fileData->OriginalSize;
|
379 |
+
$optimizedSpace += $fileData->$fileType;
|
380 |
+
}
|
381 |
+
|
382 |
}
|
383 |
+
else { //there was an error while trying to download a file
|
384 |
$tempFiles[$counter] = "";
|
385 |
+
}
|
386 |
$counter++;
|
387 |
}
|
388 |
|
389 |
//figure out in what SubDir files should land
|
390 |
+
//#$SubDir = $this->returnSubDir(get_attached_file($ID));
|
391 |
+
$fullSubDir = str_replace(WP_CONTENT_DIR, "", dirname($itemHandler->getMeta()->getPath())) . DIRECTORY_SEPARATOR;
|
392 |
+
//die("Uploads base: " . SP_UPLOADS_BASE . " FullSubDir: ". $fullSubDir . " PATH: " . dirname($itemHandler->getMeta()->getPath()));
|
393 |
+
$SubDir = ShortPixelMetaFacade::returnSubDir($itemHandler->getMeta()->getPath(), $itemHandler->getType());
|
394 |
|
395 |
//if backup is enabled - we try to save the images
|
396 |
if( $this->_settings->backupImages )
|
397 |
{
|
|
|
398 |
$source = $PATHs; //array with final paths for these files
|
399 |
|
400 |
if( !file_exists(SP_BACKUP_FOLDER) && !@mkdir(SP_BACKUP_FOLDER, 0777, true) ) {//creates backup folder if it doesn't exist
|
401 |
return array("Status" => self::STATUS_FAIL, "Message" => "Backup folder does not exist and it cannot be created");
|
402 |
}
|
403 |
//create subdir in backup folder if needed
|
404 |
+
@mkdir( SP_BACKUP_FOLDER . DIRECTORY_SEPARATOR . $fullSubDir, 0777, true);
|
405 |
|
406 |
foreach ( $source as $fileID => $filePATH )//create destination files array
|
407 |
{
|
408 |
+
$destination[$fileID] = SP_BACKUP_FOLDER . DIRECTORY_SEPARATOR . $fullSubDir . self::MB_basename($source[$fileID]);
|
409 |
}
|
410 |
+
//die("IZ BACKUP: " . SP_BACKUP_FOLDER . DIRECTORY_SEPARATOR . $SubDir . var_dump($destination));
|
411 |
|
412 |
//now that we have original files and where we should back them up we attempt to do just that
|
413 |
if(is_writable(SP_BACKUP_FOLDER))
|
418 |
{
|
419 |
if ( !@copy($source[$fileID], $destination[$fileID]) )
|
420 |
{//file couldn't be saved in backup folder
|
421 |
+
$msg = 'Cannot save file <i>' . self::MB_basename($source[$fileID]) . '</i> in backup directory';
|
422 |
+
//#ShortPixelAPI::SaveMessageinMetadata($ID, $msg);
|
423 |
+
$itemHandler->setError(self::ERR_SAVE_BKP, $msg);
|
424 |
+
$itemHandler->incrementRetries();
|
425 |
+
return array("Status" => self::STATUS_FAIL, "Message" => $msg);
|
426 |
}
|
427 |
}
|
428 |
}
|
429 |
$NoBackup = true;
|
430 |
} else {//cannot write to the backup dir, return with an error
|
431 |
+
//#ShortPixelAPI::SaveMessageinMetadata($ID, 'Cannot save file in backup directory');
|
432 |
+
$msg = 'Cannot save file in backup directory';
|
433 |
+
$itemHandler->setError(self::ERR_SAVE_BKP, $msg);
|
434 |
+
$itemHandler->incrementRetries();
|
435 |
+
return array("Status" => self::STATUS_FAIL, "Message" => $msg);
|
436 |
}
|
437 |
|
438 |
}//end backup section
|
439 |
|
440 |
$writeFailed = 0;
|
441 |
+
$firstImage = true;
|
442 |
+
$width = $height = null;
|
443 |
+
$resize = $this->_settings->resizeImages;
|
444 |
|
445 |
if ( !empty($tempFiles) )
|
446 |
{
|
448 |
foreach ( $tempFiles as $tempFileID => $tempFilePATH )
|
449 |
{
|
450 |
if ( file_exists($tempFilePATH) && file_exists($PATHs[$tempFileID]) && is_writable($PATHs[$tempFileID]) ) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
451 |
copy($tempFilePATH, $PATHs[$tempFileID]);
|
452 |
+
if($firstImage) { //this is the main image
|
453 |
+
$firstImage = false;
|
454 |
+
if($resize) {
|
455 |
+
$size = getimagesize($PATHs[$tempFileID]);
|
456 |
+
$width = $size[0];
|
457 |
+
$height = $size[1];
|
458 |
+
}
|
459 |
}
|
460 |
+
//Calculate the saved space
|
461 |
+
$fileData = $APIresponse[$tempFileID];
|
462 |
+
$savedSpace += $fileData->OriginalSize - $fileData->$fileType;
|
463 |
+
$originalSpace += $fileData->OriginalSize;
|
464 |
+
$optimizedSpace += $fileData->$fileType;
|
465 |
+
$averageCompression += $fileData->PercentImprovement;
|
466 |
+
WPShortPixel::log("HANDLE SUCCESS: Image " . $PATHs[$tempFileID] . " original size: ".$fileData->OriginalSize . " optimized: " . $fileData->$fileType);
|
467 |
+
|
468 |
+
//add the number of files with < 5% optimization
|
469 |
+
if ( ( ( 1 - $APIresponse[$tempFileID]->$fileType/$APIresponse[$tempFileID]->OriginalSize ) * 100 ) < 5 ) {
|
470 |
+
$this->_settings->under5Percent++;
|
471 |
+
}
|
472 |
+
}
|
473 |
+
else {
|
474 |
$writeFailed++;
|
475 |
}
|
476 |
@unlink($tempFilePATH);
|
478 |
|
479 |
if ( $writeFailed > 0 )//there was an error
|
480 |
{
|
481 |
+
$msg = 'Optimized version of ' . $writeFailed . ' file(s) couldn\'t be updated.';
|
482 |
+
//#ShortPixelAPI::SaveMessageinMetadata($ID, 'Error: optimized version of ' . $writeFailed . ' file(s) couldn\'t be updated.');
|
483 |
+
$itemHandler->setError(self::ERR_SAVE, $msg);
|
484 |
+
$itemHandler->incrementRetries();
|
485 |
update_option('bulkProcessingStatus', "error");
|
486 |
+
return array("Status" => self::STATUS_FAIL, "Code" =>"write-fail", "Message" => $msg);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
487 |
}
|
488 |
} elseif( 0 + $fileData->PercentImprovement < 5) {
|
489 |
$this->_settings->under5Percent++;
|
490 |
}
|
491 |
//old average counting
|
492 |
$this->_settings->savedSpace += $savedSpace;
|
493 |
+
$averageCompression = $this->_settings->averageCompression * $this->_settings->fileCount / ($this->_settings->fileCount + count($APIresponse));
|
|
|
494 |
$this->_settings->averageCompression = $averageCompression;
|
495 |
$this->_settings->fileCount += count($APIresponse);
|
496 |
//new average counting
|
498 |
$this->_settings->totalOptimized += $optimizedSpace;
|
499 |
|
500 |
//update metadata for this file
|
501 |
+
$meta = $itemHandler->getMeta();
|
502 |
+
// die(var_dump($percentImprovement));
|
503 |
+
if($meta->getThumbsTodo()) {
|
504 |
+
$percentImprovement = $meta->getImprovementPercent();
|
505 |
+
}
|
506 |
+
$meta->setMessage($originalSpace
|
507 |
+
? number_format(100.0 - 100.0 * $optimizedSpace / $originalSpace, 2)
|
508 |
+
: "Couldn't compute thumbs optimization percent. Main image: " . $percentImprovement);
|
509 |
+
WPShortPixel::log("HANDLE SUCCESS: Image optimization: ".$meta->getMessage());
|
510 |
+
$meta->setCompressionType($compressionType);
|
511 |
+
$meta->setCompressedSize(filesize($meta->getPath()));
|
512 |
+
$meta->setKeepExif($this->_settings->keepExif);
|
513 |
+
$meta->setTsOptimized(date("Y-m-d H:i:s"));
|
514 |
+
$meta->setThumbsOpt(($meta->getThumbsTodo() || $this->_settings->processThumbnails) ? count($meta->getThumbs()) : 0);
|
515 |
+
$meta->setThumbsTodo(false);
|
516 |
+
if($width && $height) {
|
517 |
+
$meta->setActualWidth($width);
|
518 |
+
$meta->setActualHeight($height);
|
|
|
|
|
519 |
}
|
520 |
+
$meta->setRetries($meta->getRetries() + 1);
|
521 |
+
$meta->setBackup(!$NoBackup);
|
522 |
+
$meta->setStatus(2);
|
523 |
+
|
524 |
+
$itemHandler->updateMeta($meta);
|
525 |
+
if(!$originalSpace) { //das kann nicht sein, alles klar?!
|
526 |
+
throw new Exception("OriginalSpace = 0. APIResponse" . json_encode($APIresponse));
|
527 |
+
}
|
528 |
+
|
529 |
//we reset the retry counter in case of success
|
530 |
+
$this->_settings->apiRetries = 0;
|
531 |
|
532 |
+
return array("Status" => self::STATUS_SUCCESS, "Message" => 'Success: No pixels remained unsqueezed :-)', "PercentImprovement" => $meta->getMessage());
|
533 |
}//end handleSuccess
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
534 |
|
535 |
+
/**
|
536 |
+
* a basename alternative that deals OK with multibyte charsets (e.g. Arabic)
|
537 |
+
* @param string $Path
|
538 |
+
* @return string
|
539 |
+
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
540 |
static public function MB_basename($Path){
|
541 |
$Separator = " qq ";
|
542 |
$Path = preg_replace("/[^ ]/u", $Separator."\$0".$Separator, $Path);
|
545 |
return $Base;
|
546 |
}
|
547 |
|
548 |
+
/**
|
549 |
+
* sometimes, the paths to the files as defined in metadata are wrong, we try to automatically correct them
|
550 |
+
* @param type $PATHs
|
551 |
+
* @return boolean|string
|
552 |
+
*/
|
553 |
static public function CheckAndFixImagePaths($PATHs){
|
554 |
+
|
555 |
$ErrorCount = 0;
|
556 |
$uploadDir = wp_upload_dir();
|
557 |
$Tmp = explode("/", $uploadDir['basedir']);
|
564 |
if ( !file_exists($File) ){
|
565 |
//$NewFile = $uploadDir['basedir'] . "/" . substr($File,strpos($File, $StichString));//+strlen($StichString));
|
566 |
$NewFile = $uploadDir['basedir'] . substr($File,strpos($File, $StichString)+strlen($StichString));
|
567 |
+
if (file_exists($NewFile)) {
|
568 |
$PATHs[$Id] = $NewFile;
|
569 |
+
} else {
|
570 |
$ErrorCount++;
|
571 |
+
}
|
572 |
}
|
573 |
}
|
574 |
|
575 |
+
if ( $ErrorCount > 0 ) {
|
576 |
return false;
|
577 |
+
} else {
|
578 |
return $PATHs;
|
579 |
+
}
|
580 |
}
|
581 |
|
582 |
static public function getCompressionTypeName($compressionType) {
|
590 |
unset($meta['ShortPixel']['WaitingProcessing']);
|
591 |
wp_update_attachment_metadata($ID, $meta);
|
592 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
593 |
}
|
shortpixel_queue.php
CHANGED
@@ -4,15 +4,6 @@ class ShortPixelQueue {
|
|
4 |
|
5 |
private $ctrl;
|
6 |
private $settings;
|
7 |
-
private $startBulkId;
|
8 |
-
private $stopBulkId;
|
9 |
-
private $bulkCount;
|
10 |
-
private $bulkPreviousPercent;
|
11 |
-
private $bulkCurrentlyProcessed;
|
12 |
-
private $bulkAlreadyDoneCount;
|
13 |
-
private $lastBulkStartTime;
|
14 |
-
private $lastBulkSuccessTime;
|
15 |
-
private $bulkRunningTime;
|
16 |
|
17 |
const BULK_NEVER = 0; //bulk never ran
|
18 |
const BULK_RUNNING = 1; //bulk is running
|
@@ -23,31 +14,31 @@ class ShortPixelQueue {
|
|
23 |
$this->ctrl = $controller;
|
24 |
$this->settings = $settings;
|
25 |
//init the option if needed
|
26 |
-
if(!isset($_SESSION["wp-short-pixel-priorityQueue"])
|
|
|
27 |
//take the priority list from the options (we persist there the priority IDs from the previous session)
|
28 |
$prioQueueOpt = $this->settings->getOpt( 'wp-short-pixel-priorityQueue', array());//here we save the IDs for the files that need to be processed after an image upload for example
|
29 |
$_SESSION["wp-short-pixel-priorityQueue"] = array();
|
30 |
foreach($prioQueueOpt as $ID) {
|
31 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
32 |
WPShortPixel::log("INIT: Item $ID from options has metadata: " .json_encode($meta));
|
33 |
-
if(
|
34 |
$this->push($ID);
|
35 |
}
|
36 |
}
|
37 |
-
$this->settings->
|
38 |
-
|
|
|
|
|
39 |
.json_encode($_SESSION["wp-short-pixel-priorityQueue"]));
|
|
|
40 |
}
|
41 |
-
|
42 |
-
$this->startBulkId = $this->settings->getOpt( 'wp-short-pixel-query-id-start', 0);//current query ID used for postmeta queries
|
43 |
-
$this->stopBulkId = $this->settings->getOpt( 'wp-short-pixel-query-id-stop', 0);//min ID used for postmeta queries
|
44 |
-
$this->bulkCount = $this->settings->getOpt( "wp-short-pixel-bulk-count", 0);
|
45 |
-
$this->bulkPreviousPercent = $this->settings->getOpt( "wp-short-pixel-bulk-previous-percent", 0);
|
46 |
-
$this->bulkCurrentlyProcessed = $this->settings->getOpt( "wp-short-pixel-bulk-processed-items", 0);
|
47 |
-
$this->bulkAlreadyDoneCount = $this->settings->getOpt( "wp-short-pixel-bulk-done-count", 0);
|
48 |
-
$this->lastBulkStartTime = $this->settings->getOpt( 'wp-short-pixel-last-bulk-start-time', 0);//time of the last start of the bulk.
|
49 |
-
$this->lastBulkSuccessTime = $this->settings->getOpt( 'wp-short-pixel-last-bulk-success-time', 0);//time of the last start of the bulk.
|
50 |
-
$this->bulkRunningTime = $this->settings->getOpt( 'wp-short-pixel-bulk-running-time', 0);//how long the bulk ran that far.
|
51 |
}
|
52 |
|
53 |
//handling older
|
@@ -62,46 +53,46 @@ class ShortPixelQueue {
|
|
62 |
public function skip($id) {
|
63 |
if(is_array($this->settings->prioritySkip)) {
|
64 |
$this->settings->prioritySkip = array_merge($this->settings->prioritySkip, array($id));
|
65 |
-
} else {
|
66 |
$this->settings->prioritySkip = array($id);
|
67 |
}
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
{
|
98 |
$priorityQueue = $_SESSION["wp-short-pixel-priorityQueue"]; //get_option("wp-short-pixel-priorityQueue");
|
99 |
WPShortPixel::log("PUSH: Push ID $ID into queue ".json_encode($priorityQueue));
|
100 |
array_push($priorityQueue, $ID);
|
101 |
$prioQ = array_unique($priorityQueue);
|
102 |
$_SESSION["wp-short-pixel-priorityQueue"] = $prioQ;
|
103 |
-
//push also to the options queue, in case the session gets killed retrieve
|
104 |
-
$this->settings->
|
105 |
|
106 |
WPShortPixel::log("PUSH: Updated: ".json_encode($_SESSION["wp-short-pixel-priorityQueue"]));//get_option("wp-short-pixel-priorityQueue")));
|
107 |
}
|
@@ -112,6 +103,28 @@ class ShortPixelQueue {
|
|
112 |
$count = min(count($priorityQueue), $count);
|
113 |
return(array_slice($priorityQueue, count($priorityQueue) - $count, $count));
|
114 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
115 |
|
116 |
public function remove($ID)//remove an ID from priority queue
|
117 |
{
|
@@ -133,34 +146,40 @@ class ShortPixelQueue {
|
|
133 |
}
|
134 |
|
135 |
public function removeFromFailed($ID) {
|
136 |
-
$failed = explode(",", $this->settings->
|
137 |
$key = array_search($ID, $failed);
|
138 |
if($key !== false) {
|
139 |
unset($failed[$key]);
|
140 |
$failed = array_values($failed);
|
141 |
-
$this->settings->
|
142 |
}
|
143 |
}
|
144 |
|
145 |
public function addToFailed($ID) {
|
146 |
-
$failed = $this->settings->
|
147 |
if(!in_array($ID, explode(",", $failed))) {
|
148 |
-
$this->settings->
|
149 |
}
|
150 |
}
|
151 |
|
152 |
public function getFailed() {
|
153 |
-
$failed = $this->settings->
|
154 |
-
$failed = "83";
|
155 |
if(!strlen($failed)) return array();
|
156 |
$ret = explode(",", $failed);
|
157 |
$fails = array();
|
158 |
foreach($ret as $fail) {
|
159 |
-
|
160 |
-
|
161 |
-
|
|
|
|
|
162 |
} else {
|
163 |
-
$
|
|
|
|
|
|
|
|
|
|
|
164 |
}
|
165 |
}
|
166 |
return $fails;
|
@@ -168,16 +187,16 @@ class ShortPixelQueue {
|
|
168 |
|
169 |
public function bulkRunning() {
|
170 |
//$bulkProcessingStatus = get_option('bulkProcessingStatus');
|
171 |
-
return $this->startBulkId > $this->stopBulkId;
|
172 |
}
|
173 |
|
174 |
public function bulkPaused() {
|
175 |
-
WPShortPixel::log("Bulk Paused: " .
|
176 |
-
return $this->settings->
|
177 |
}
|
178 |
|
179 |
public function bulkRan() {
|
180 |
-
return $this->settings->
|
181 |
}
|
182 |
|
183 |
public function processing() {
|
@@ -186,60 +205,52 @@ class ShortPixelQueue {
|
|
186 |
}
|
187 |
|
188 |
public function getFlagBulkId() {
|
189 |
-
return $this->settings->
|
190 |
}
|
191 |
|
192 |
public function getStartBulkId() {
|
193 |
-
return $this->startBulkId;
|
194 |
}
|
195 |
|
196 |
public function resetStartBulkId() {
|
197 |
-
$this->setStartBulkId(
|
198 |
}
|
199 |
|
200 |
public function setStartBulkId($start){
|
201 |
-
$this->startBulkId = $start;
|
202 |
-
$this->settings->setOpt("wp-short-pixel-query-id-start", $this->startBulkId);
|
203 |
}
|
204 |
|
205 |
public function getStopBulkId() {
|
206 |
-
return $this->stopBulkId;
|
207 |
}
|
208 |
|
209 |
public function resetStopBulkId() {
|
210 |
-
$this->stopBulkId =
|
211 |
-
$this->settings->setOpt("wp-short-pixel-query-id-stop", $this->stopBulkId);
|
212 |
}
|
213 |
|
214 |
public function setBulkPreviousPercent() {
|
215 |
//processable and already processed
|
216 |
-
$res =
|
217 |
-
$this->bulkCount = $res["mainFiles"];
|
218 |
-
$this->settings->setOpt("wp-short-pixel-bulk-count", $this->bulkCount);
|
219 |
|
220 |
//if compression type changed, add also the images with the other compression type
|
221 |
-
$this->bulkAlreadyDoneCount = $res["mainProcessedFiles"] - $res["mainProc".((0 + $this->ctrl->getCompressionType() == 1) ? "Lossless" : "Lossy")."Files"];
|
222 |
// if the thumbnails are to be processed, add also the images that have thumbs not processed
|
223 |
if($this->settings->processThumbnails) {
|
224 |
-
$this->bulkAlreadyDoneCount -= $res["mainUnprocessedThumbs"];
|
225 |
}
|
226 |
|
227 |
-
//die(var_dump($res));
|
228 |
-
|
229 |
-
$this->settings->setOpt("wp-short-pixel-bulk-done-count", $this->bulkAlreadyDoneCount);
|
230 |
//percent already done
|
231 |
-
$this->bulkPreviousPercent = round($this->bulkAlreadyDoneCount / ($this->bulkCount ? $this->bulkCount : 1) * 100);
|
232 |
-
$this->settings->setOpt("wp-short-pixel-bulk-previous-percent", $this->bulkPreviousPercent);
|
233 |
}
|
234 |
|
235 |
public function getBulkToProcess() {
|
236 |
-
return $this->bulkCount - $this->bulkAlreadyDoneCount;
|
237 |
}
|
238 |
|
239 |
public function flagBulkStart() {
|
240 |
-
$this->settings->
|
241 |
-
|
242 |
-
add_option('bulkProcessingStatus', 'running');//set bulk flag
|
243 |
}
|
244 |
|
245 |
public function startBulk() {
|
@@ -248,14 +259,15 @@ class ShortPixelQueue {
|
|
248 |
$this->flagBulkStart(); //we use this to detect new added files while bulk is running
|
249 |
$this->setBulkPreviousPercent();
|
250 |
$this->resetBulkCurrentlyProcessed();
|
251 |
-
$this->settings->
|
252 |
}
|
253 |
|
254 |
public function pauseBulk() {
|
255 |
-
$cancelPointer = $this->startBulkId;
|
256 |
$bulkStartId = $this->getFlagBulkId();
|
257 |
-
$this->settings->
|
258 |
-
|
|
|
259 |
//remove the bulk items from prio queue
|
260 |
foreach($this->get() as $qItem) {
|
261 |
if($qItem < $bulkStartId) {
|
@@ -265,46 +277,46 @@ class ShortPixelQueue {
|
|
265 |
$this->stopBulk();
|
266 |
}
|
267 |
|
|
|
|
|
|
|
|
|
|
|
|
|
268 |
public function stopBulk() {
|
269 |
-
$this->startBulkId =
|
270 |
-
$this->stopBulkId = $this->startBulkId;
|
271 |
-
$this->settings->
|
272 |
-
$this->settings->
|
273 |
-
delete_option('bulkProcessingStatus');
|
274 |
-
return $this->settings->getOpt('wp-short-pixel-bulk-ever-ran', 0);
|
275 |
}
|
276 |
|
277 |
public function resumeBulk() {
|
278 |
-
$this->startBulkId =
|
279 |
-
$this->settings->
|
280 |
-
$this->stopBulkId = $this->ctrl->getMinMediaId();
|
281 |
-
$this->settings->setOpt("wp-short-pixel-query-id-stop", $this->stopBulkId);
|
282 |
//$this->settings->setOpt("wp-short-pixel-flag-id", $this->startBulkId);//we use to detect new added files while bulk is running
|
283 |
-
|
284 |
-
|
285 |
-
WPShortPixel::log("Resumed: (pause says: " . $this->bulkPaused() . ") Start from: " . $this->startBulkId . " to " . $this->stopBulkId);
|
286 |
}
|
287 |
|
288 |
public function resetBulkCurrentlyProcessed() {
|
289 |
-
$this->bulkCurrentlyProcessed = 0;
|
290 |
-
$this->settings->setOpt( "wp-short-pixel-bulk-processed-items", $this->bulkCurrentlyProcessed);
|
291 |
}
|
292 |
|
293 |
public function incrementBulkCurrentlyProcessed() {
|
294 |
-
$this->bulkCurrentlyProcessed
|
295 |
-
$this->settings->setOpt( "wp-short-pixel-bulk-processed-items", $this->bulkCurrentlyProcessed);
|
296 |
}
|
297 |
|
298 |
public function markBulkComplete() {
|
299 |
-
|
300 |
-
|
301 |
}
|
302 |
|
303 |
public static function resetBulk() {
|
304 |
delete_option('bulkProcessingStatus');
|
305 |
delete_option( 'wp-short-pixel-cancel-pointer');
|
306 |
delete_option( "wp-short-pixel-flag-id");
|
307 |
-
$startBulkId = $stopBulkId =
|
308 |
update_option( 'wp-short-pixel-query-id-stop', $startBulkId );
|
309 |
update_option( 'wp-short-pixel-query-id-start', $startBulkId );
|
310 |
delete_option( "wp-short-pixel-bulk-previous-percent");
|
@@ -327,26 +339,25 @@ class ShortPixelQueue {
|
|
327 |
public function logBulkProgress() {
|
328 |
$t = time();
|
329 |
$this->incrementBulkCurrentlyProcessed();
|
330 |
-
|
331 |
-
|
332 |
-
$this->settings->
|
333 |
-
$this->lastBulkStartTime = $
|
334 |
-
$this->settings->
|
335 |
-
$this->settings->setOpt('wp-short-pixel-last-bulk-success-time', $t);
|
336 |
} else {
|
337 |
-
$this->lastBulkSuccessTime = $t;
|
338 |
-
$this->settings->setOpt('wp-short-pixel-last-bulk-success-time', $t);
|
339 |
}
|
340 |
}
|
341 |
|
342 |
public function getBulkPercent() {
|
343 |
-
|
344 |
-
|
|
|
345 |
|
346 |
if($this->getBulkToProcess() <= 0) return ($this->processing () ? 99: 100);
|
347 |
// return maximum 99%
|
348 |
-
$percent = $
|
349 |
-
* (100 - $
|
350 |
|
351 |
WPShortPixel::log("QUEUE - Calculated Percent: " . $percent);
|
352 |
|
@@ -354,14 +365,14 @@ class ShortPixelQueue {
|
|
354 |
}
|
355 |
|
356 |
public function getDeltaBulkPercent() {
|
357 |
-
return $this->getBulkPercent() - $this->bulkPreviousPercent;
|
358 |
}
|
359 |
|
360 |
public function getTimeRemaining (){
|
361 |
$p = $this->getBulkPercent();
|
362 |
-
$pAlready = $this->bulkCount == 0 ? 0 : round($this->bulkAlreadyDoneCount / $this->bulkCount * 100);
|
363 |
// die("" . ($this->lastBulkSuccessTime - $this->lastBulkStartTime));
|
364 |
if(($p - $pAlready) == 0) return 0;
|
365 |
-
return round(((100 - $p) / ($p - $pAlready)) * ($this->bulkRunningTime + $this->lastBulkSuccessTime - $this->lastBulkStartTime)/60);
|
366 |
}
|
367 |
}
|
4 |
|
5 |
private $ctrl;
|
6 |
private $settings;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
7 |
|
8 |
const BULK_NEVER = 0; //bulk never ran
|
9 |
const BULK_RUNNING = 1; //bulk is running
|
14 |
$this->ctrl = $controller;
|
15 |
$this->settings = $settings;
|
16 |
//init the option if needed
|
17 |
+
if( !isset($_SESSION["wp-short-pixel-priorityQueue"]) //session is not defined
|
18 |
+
|| !(is_admin() && function_exists("is_user_logged_in") && is_user_logged_in())) { //or we're not in the admin - re-init each time
|
19 |
//take the priority list from the options (we persist there the priority IDs from the previous session)
|
20 |
$prioQueueOpt = $this->settings->getOpt( 'wp-short-pixel-priorityQueue', array());//here we save the IDs for the files that need to be processed after an image upload for example
|
21 |
$_SESSION["wp-short-pixel-priorityQueue"] = array();
|
22 |
foreach($prioQueueOpt as $ID) {
|
23 |
+
if(ShortPixelMetaFacade::isCustomQueuedId($ID)) {
|
24 |
+
$meta = $this->ctrl->getSpMetaDao()->getMeta(ShortPixelMetaFacade::stripQueuedIdType($ID));
|
25 |
+
$todo = isset($meta) && ($meta->getStatus() == 0 || $meta->getStatus() == 1);
|
26 |
+
} else {
|
27 |
+
$meta = wp_get_attachment_metadata($ID);
|
28 |
+
$todo = !isset($meta['ShortPixelImprovement']);
|
29 |
+
}
|
30 |
WPShortPixel::log("INIT: Item $ID from options has metadata: " .json_encode($meta));
|
31 |
+
if($todo) {
|
32 |
$this->push($ID);
|
33 |
}
|
34 |
}
|
35 |
+
$this->settings->priorityQueue = $_SESSION["wp-short-pixel-priorityQueue"];
|
36 |
+
|
37 |
+
if(is_admin() && function_exists("is_user_logged_in") && is_user_logged_in()) {
|
38 |
+
WPShortPixel::log("INIT: Session queue not found, updated from Options with "
|
39 |
.json_encode($_SESSION["wp-short-pixel-priorityQueue"]));
|
40 |
+
}
|
41 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
42 |
}
|
43 |
|
44 |
//handling older
|
53 |
public function skip($id) {
|
54 |
if(is_array($this->settings->prioritySkip)) {
|
55 |
$this->settings->prioritySkip = array_merge($this->settings->prioritySkip, array($id));
|
56 |
+
} else {
|
57 |
$this->settings->prioritySkip = array($id);
|
58 |
}
|
59 |
+
}
|
60 |
+
|
61 |
+
public function allSkipped() {
|
62 |
+
if( !is_array($this->settings->prioritySkip) ) return false;
|
63 |
+
count(array_diff($_SESSION["wp-short-pixel-priorityQueue"], $this->settings->prioritySkip));
|
64 |
+
}
|
65 |
+
|
66 |
+
public function skippedCount() {
|
67 |
+
return is_array($this->settings->prioritySkip) ? count($this->settings->prioritySkip) : 0;
|
68 |
+
}
|
69 |
+
|
70 |
+
public function isSkipped($id) {
|
71 |
+
return is_array($this->settings->prioritySkip) && in_array($id, $this->settings->prioritySkip);
|
72 |
+
}
|
73 |
+
|
74 |
+
public function isPrio($id) {
|
75 |
+
return is_array($_SESSION["wp-short-pixel-priorityQueue"]) && in_array($id, $_SESSION["wp-short-pixel-priorityQueue"]);
|
76 |
+
}
|
77 |
+
|
78 |
+
public function getSkipped() {
|
79 |
+
return $this->settings->prioritySkip;
|
80 |
+
}
|
81 |
+
|
82 |
+
public function reverse() {
|
83 |
+
$this->settings->priorityQueue = $_SESSION["wp-short-pixel-priorityQueue"] = array_reverse($_SESSION["wp-short-pixel-priorityQueue"]);
|
84 |
+
|
85 |
+
}
|
86 |
+
|
87 |
+
public function push($ID)//add an ID to priority queue
|
88 |
{
|
89 |
$priorityQueue = $_SESSION["wp-short-pixel-priorityQueue"]; //get_option("wp-short-pixel-priorityQueue");
|
90 |
WPShortPixel::log("PUSH: Push ID $ID into queue ".json_encode($priorityQueue));
|
91 |
array_push($priorityQueue, $ID);
|
92 |
$prioQ = array_unique($priorityQueue);
|
93 |
$_SESSION["wp-short-pixel-priorityQueue"] = $prioQ;
|
94 |
+
//push also to the options queue, in case the session gets killed retrieve from there
|
95 |
+
$this->settings->priorityQueue = $prioQ;
|
96 |
|
97 |
WPShortPixel::log("PUSH: Updated: ".json_encode($_SESSION["wp-short-pixel-priorityQueue"]));//get_option("wp-short-pixel-priorityQueue")));
|
98 |
}
|
103 |
$count = min(count($priorityQueue), $count);
|
104 |
return(array_slice($priorityQueue, count($priorityQueue) - $count, $count));
|
105 |
}
|
106 |
+
|
107 |
+
public function getFromPrioAndCheck() {
|
108 |
+
$ids = array();
|
109 |
+
$removeIds = array();
|
110 |
+
|
111 |
+
$idsPrio = $this->get();
|
112 |
+
for($i = count($idsPrio) - 1, $cnt = 0; $i>=0 && $cnt < 3; $i--) {
|
113 |
+
if(!isset($idsPrio[$i])) continue; //saw this situation but then couldn't reproduce it to see the cause, so at least treat the effects.
|
114 |
+
$id = $idsPrio[$i];
|
115 |
+
if(!$this->isSkipped($id) && $this->ctrl->isValidMetaId($id)) {
|
116 |
+
$ids[] = $id; //valid ID
|
117 |
+
$cnt++;
|
118 |
+
} elseif(!$this->isSkipped($id)) {
|
119 |
+
$removeIds[] = $id;//not skipped, url not found, means it's absent, to remove
|
120 |
+
}
|
121 |
+
}
|
122 |
+
foreach($removeIds as $rId){
|
123 |
+
WPShortPixel::log("HIP: Unfound ID $rId Remove from Priority Queue: ".json_encode($this->get()));
|
124 |
+
$this->remove($rId);
|
125 |
+
}
|
126 |
+
return $ids;
|
127 |
+
}
|
128 |
|
129 |
public function remove($ID)//remove an ID from priority queue
|
130 |
{
|
146 |
}
|
147 |
|
148 |
public function removeFromFailed($ID) {
|
149 |
+
$failed = explode(",", $this->settings->failedImages);
|
150 |
$key = array_search($ID, $failed);
|
151 |
if($key !== false) {
|
152 |
unset($failed[$key]);
|
153 |
$failed = array_values($failed);
|
154 |
+
$this->settings->failedImages = implode(",", $failed) ;
|
155 |
}
|
156 |
}
|
157 |
|
158 |
public function addToFailed($ID) {
|
159 |
+
$failed = $this->settings->failedImages;
|
160 |
if(!in_array($ID, explode(",", $failed))) {
|
161 |
+
$this->settings->failedImages = (strlen($failed) ? $failed . "," : "") . $ID;
|
162 |
}
|
163 |
}
|
164 |
|
165 |
public function getFailed() {
|
166 |
+
$failed = $this->settings->failedImages;
|
|
|
167 |
if(!strlen($failed)) return array();
|
168 |
$ret = explode(",", $failed);
|
169 |
$fails = array();
|
170 |
foreach($ret as $fail) {
|
171 |
+
if(ShortPixelMetaFacade::isCustomQueuedId($fail)) {
|
172 |
+
$meta = $this->ctrl->getSpMetaDao()->getMeta(ShortPixelMetaFacade::stripQueuedIdType($fail));
|
173 |
+
if($meta) {
|
174 |
+
$fails[] = (object)array("id" => ShortPixelMetaFacade::stripQueuedIdType($fail), "type" => ShortPixelMetaFacade::CUSTOM_TYPE, "meta" => $meta);
|
175 |
+
}
|
176 |
} else {
|
177 |
+
$meta = wp_get_attachment_metadata($fail);
|
178 |
+
if(!$meta || (isset($meta["ShortPixelImprovement"]) && is_numeric($meta["ShortPixelImprovement"]))){
|
179 |
+
$this->removeFromFailed($fail);
|
180 |
+
} else {
|
181 |
+
$fails[] = (object)array("id" => $fail, "type" => ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE, "meta" => $meta);
|
182 |
+
}
|
183 |
}
|
184 |
}
|
185 |
return $fails;
|
187 |
|
188 |
public function bulkRunning() {
|
189 |
//$bulkProcessingStatus = get_option('bulkProcessingStatus');
|
190 |
+
return $this->settings->startBulkId > $this->settings->stopBulkId;
|
191 |
}
|
192 |
|
193 |
public function bulkPaused() {
|
194 |
+
WPShortPixel::log("Bulk Paused: " . $this->settings->cancelPointer);
|
195 |
+
return $this->settings->cancelPointer;
|
196 |
}
|
197 |
|
198 |
public function bulkRan() {
|
199 |
+
return $this->settings->bulkEverRan != 0;
|
200 |
}
|
201 |
|
202 |
public function processing() {
|
205 |
}
|
206 |
|
207 |
public function getFlagBulkId() {
|
208 |
+
return $this->settings->flagId;
|
209 |
}
|
210 |
|
211 |
public function getStartBulkId() {
|
212 |
+
return $this->settings->startBulkId;
|
213 |
}
|
214 |
|
215 |
public function resetStartBulkId() {
|
216 |
+
$this->setStartBulkId(ShortPixelMetaFacade::getMaxMediaId());
|
217 |
}
|
218 |
|
219 |
public function setStartBulkId($start){
|
220 |
+
$this->settings->startBulkId = $start;
|
|
|
221 |
}
|
222 |
|
223 |
public function getStopBulkId() {
|
224 |
+
return $this->settings->stopBulkId;
|
225 |
}
|
226 |
|
227 |
public function resetStopBulkId() {
|
228 |
+
$this->settings->stopBulkId = ShortPixelMetaFacade::getMinMediaId();
|
|
|
229 |
}
|
230 |
|
231 |
public function setBulkPreviousPercent() {
|
232 |
//processable and already processed
|
233 |
+
$res = WpShortPixelMediaLbraryAdapter::countAllProcessableFiles($this->getFlagBulkId(), $this->settings->stopBulkId);
|
234 |
+
$this->settings->bulkCount = $res["mainFiles"];
|
|
|
235 |
|
236 |
//if compression type changed, add also the images with the other compression type
|
237 |
+
$this->settings->bulkAlreadyDoneCount = $res["mainProcessedFiles"] - $res["mainProc".((0 + $this->ctrl->getCompressionType() == 1) ? "Lossless" : "Lossy")."Files"];
|
238 |
// if the thumbnails are to be processed, add also the images that have thumbs not processed
|
239 |
if($this->settings->processThumbnails) {
|
240 |
+
$this->settings->bulkAlreadyDoneCount -= $res["mainUnprocessedThumbs"];
|
241 |
}
|
242 |
|
|
|
|
|
|
|
243 |
//percent already done
|
244 |
+
$this->settings->bulkPreviousPercent = round($this->settings->bulkAlreadyDoneCount / ($this->settings->bulkCount ? $this->settings->bulkCount : 1) * 100);
|
|
|
245 |
}
|
246 |
|
247 |
public function getBulkToProcess() {
|
248 |
+
return $this->settings->bulkCount - $this->settings->bulkAlreadyDoneCount;
|
249 |
}
|
250 |
|
251 |
public function flagBulkStart() {
|
252 |
+
$this->settings->flagId = $this->settings->startBulkId;
|
253 |
+
$this->settings->bulkProcessingStatus = 'running';//set bulk flag
|
|
|
254 |
}
|
255 |
|
256 |
public function startBulk() {
|
259 |
$this->flagBulkStart(); //we use this to detect new added files while bulk is running
|
260 |
$this->setBulkPreviousPercent();
|
261 |
$this->resetBulkCurrentlyProcessed();
|
262 |
+
$this->settings->bulkEverRan = 1;
|
263 |
}
|
264 |
|
265 |
public function pauseBulk() {
|
266 |
+
$cancelPointer = $this->settings->startBulkId;
|
267 |
$bulkStartId = $this->getFlagBulkId();
|
268 |
+
$this->settings->cancelPointer = $cancelPointer;//we save this so we can resume bulk processing
|
269 |
+
$this->settings->skipToCustom = NULL;
|
270 |
+
WPShortPixel::log("PAUSE: Pointer = ".$this->settings->cancelPointer);
|
271 |
//remove the bulk items from prio queue
|
272 |
foreach($this->get() as $qItem) {
|
273 |
if($qItem < $bulkStartId) {
|
277 |
$this->stopBulk();
|
278 |
}
|
279 |
|
280 |
+
public function cancelBulk() {
|
281 |
+
$this->pauseBulk();
|
282 |
+
WPShortPixel::log("STOP, delete pointer.");
|
283 |
+
$this->settings->cancelPointer = NULL;
|
284 |
+
}
|
285 |
+
|
286 |
public function stopBulk() {
|
287 |
+
$this->settings->startBulkId = ShortPixelMetaFacade::getMaxMediaId();
|
288 |
+
$this->settings->stopBulkId = $this->settings->startBulkId;
|
289 |
+
$this->settings->bulkProcessingStatus = null;
|
290 |
+
return $this->settings->bulkEverRan;
|
|
|
|
|
291 |
}
|
292 |
|
293 |
public function resumeBulk() {
|
294 |
+
$this->settings->startBulkId = $this->settings->cancelPointer;
|
295 |
+
$this->settings->stopBulkId = ShortPixelMetaFacade::getMinMediaId();
|
|
|
|
|
296 |
//$this->settings->setOpt("wp-short-pixel-flag-id", $this->startBulkId);//we use to detect new added files while bulk is running
|
297 |
+
$this->settings->bulkProcessingStatus = 'running';//set bulk flag
|
298 |
+
$this->settings->cancelPointer = null;
|
299 |
+
WPShortPixel::log("Resumed: (pause says: " . $this->bulkPaused() . ") Start from: " . $this->settings->startBulkId . " to " . $this->settings->stopBulkId);
|
300 |
}
|
301 |
|
302 |
public function resetBulkCurrentlyProcessed() {
|
303 |
+
$this->settings->bulkCurrentlyProcessed = 0;
|
|
|
304 |
}
|
305 |
|
306 |
public function incrementBulkCurrentlyProcessed() {
|
307 |
+
$this->settings->bulkCurrentlyProcessed = $this->settings->bulkCurrentlyProcessed + 1;
|
|
|
308 |
}
|
309 |
|
310 |
public function markBulkComplete() {
|
311 |
+
$this->settings->bulkProcessingStatus = null;
|
312 |
+
$this->settings->cancelPointer = null;
|
313 |
}
|
314 |
|
315 |
public static function resetBulk() {
|
316 |
delete_option('bulkProcessingStatus');
|
317 |
delete_option( 'wp-short-pixel-cancel-pointer');
|
318 |
delete_option( "wp-short-pixel-flag-id");
|
319 |
+
$startBulkId = $stopBulkId = ShortPixelMetaFacade::getMaxMediaId();
|
320 |
update_option( 'wp-short-pixel-query-id-stop', $startBulkId );
|
321 |
update_option( 'wp-short-pixel-query-id-start', $startBulkId );
|
322 |
delete_option( "wp-short-pixel-bulk-previous-percent");
|
339 |
public function logBulkProgress() {
|
340 |
$t = time();
|
341 |
$this->incrementBulkCurrentlyProcessed();
|
342 |
+
$successTime = $this->settings->lastBulkSuccessTime;
|
343 |
+
if($t - $successTime > 120) { //if break longer than two minutes we mark a pause in the bulk
|
344 |
+
$this->settings->bulkRunningTime += ($successTime - $this->settings->lastBulkStartTime);
|
345 |
+
$this->settings->lastBulkStartTime = $t;
|
346 |
+
$this->settings->lastBulkSuccessTime = $t;
|
|
|
347 |
} else {
|
348 |
+
$this->settings->lastBulkSuccessTime = $t;
|
|
|
349 |
}
|
350 |
}
|
351 |
|
352 |
public function getBulkPercent() {
|
353 |
+
$previousPercent = $this->settings->bulkPreviousPercent;
|
354 |
+
WPShortPixel::log("QUEUE - BulkPrevPercent: " . $previousPercent . " BulkCurrentlyProcessing: "
|
355 |
+
. $this->settings->bulkCurrentlyProcessed . " out of " . $this->getBulkToProcess());
|
356 |
|
357 |
if($this->getBulkToProcess() <= 0) return ($this->processing () ? 99: 100);
|
358 |
// return maximum 99%
|
359 |
+
$percent = $previousPercent + round($this->settings->bulkCurrentlyProcessed / $this->getBulkToProcess()
|
360 |
+
* (100 - $previousPercent));
|
361 |
|
362 |
WPShortPixel::log("QUEUE - Calculated Percent: " . $percent);
|
363 |
|
365 |
}
|
366 |
|
367 |
public function getDeltaBulkPercent() {
|
368 |
+
return $this->getBulkPercent() - $this->settings->bulkPreviousPercent;
|
369 |
}
|
370 |
|
371 |
public function getTimeRemaining (){
|
372 |
$p = $this->getBulkPercent();
|
373 |
+
$pAlready = $this->settings->bulkCount == 0 ? 0 : round($this->settings->bulkAlreadyDoneCount / $this->settings->bulkCount * 100);
|
374 |
// die("" . ($this->lastBulkSuccessTime - $this->lastBulkStartTime));
|
375 |
if(($p - $pAlready) == 0) return 0;
|
376 |
+
return round(((100 - $p) / ($p - $pAlready)) * ($this->settings->bulkRunningTime + $this->settings->lastBulkSuccessTime - $this->settings->lastBulkStartTime)/60);
|
377 |
}
|
378 |
}
|
shortpixel_view.php
CHANGED
@@ -470,7 +470,7 @@ class ShortPixelView {
|
|
470 |
<th scope="row"><label for="backupImages">Image backup</label></th>
|
471 |
<td>
|
472 |
<input name="backupImages" type="checkbox" id="backupImages" <?php echo( $checkedBackupImages );?>> Save and keep a backup of your original images in a separate folder.
|
473 |
-
<p class="settings-info">
|
474 |
</td>
|
475 |
</tr>
|
476 |
<tr>
|
470 |
<th scope="row"><label for="backupImages">Image backup</label></th>
|
471 |
<td>
|
472 |
<input name="backupImages" type="checkbox" id="backupImages" <?php echo( $checkedBackupImages );?>> Save and keep a backup of your original images in a separate folder.
|
473 |
+
<p class="settings-info">Usually recommended for safety.</p>
|
474 |
</td>
|
475 |
</tr>
|
476 |
<tr>
|
wp-shortpixel-req.php
ADDED
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
require_once('shortpixel-debug.php');
|
3 |
+
|
4 |
+
require_once('wp-shortpixel-settings.php');
|
5 |
+
require_once('shortpixel_api.php');
|
6 |
+
require_once('shortpixel_queue.php');
|
7 |
+
//entities
|
8 |
+
require_once('class/model/shortpixel-entity.php');
|
9 |
+
require_once('class/model/shortpixel-meta.php');
|
10 |
+
require_once('class/model/shortpixel-folder.php');
|
11 |
+
//exceptions
|
12 |
+
require_once('class/model/sp-file-rights-exception.php');
|
13 |
+
//database access
|
14 |
+
require_once('class/db/shortpixel-db.php');
|
15 |
+
require_once('class/db/wp-shortpixel-db.php');
|
16 |
+
require_once('class/db/shortpixel-custom-meta-dao.php');
|
17 |
+
require_once('class/db/shortpixel-nextgen-adapter.php');
|
18 |
+
require_once('class/db/wp-shortpixel-media-library-adapter.php');
|
19 |
+
require_once('class/db/shortpixel-meta-facade.php');
|
20 |
+
//view
|
21 |
+
require_once('class/view/shortpixel_view.php');
|
22 |
+
|
23 |
+
require_once('class/shortpixel-tools.php');
|
24 |
+
|
25 |
+
require_once( ABSPATH . 'wp-admin/includes/image.php' );
|
26 |
+
include_once( ABSPATH . 'wp-admin/includes/plugin.php' );
|
27 |
+
|
28 |
+
/*
|
29 |
+
if ( !is_plugin_active( 'wpmandrill/wpmandrill.php' ) //avoid conflicts with some plugins
|
30 |
+
&& !is_plugin_active( 'wp-ses/wp-ses.php' )
|
31 |
+
&& !is_plugin_active( 'wordfence/wordfence.php') ) {
|
32 |
+
require_once( ABSPATH . 'wp-includes/pluggable.php' );
|
33 |
+
}
|
34 |
+
*/
|
35 |
+
|
36 |
+
|
wp-shortpixel-settings.php
CHANGED
@@ -12,8 +12,12 @@ class WPShortPixelSettings {
|
|
12 |
private $_resizeImages = false;
|
13 |
private $_resizeWidth = 0;
|
14 |
private $_resizeHeight = 0;
|
15 |
-
|
16 |
private static $_optionsMap = array(
|
|
|
|
|
|
|
|
|
17 |
'apiKey' => 'wp-short-pixel-apiKey',
|
18 |
'verifiedKey' => 'wp-short-pixel-verifiedKey',
|
19 |
'compressionType' => 'wp-short-pixel-compression',
|
@@ -21,25 +25,58 @@ class WPShortPixelSettings {
|
|
21 |
'keepExif' => 'wp-short-pixel-keep-exif',
|
22 |
'CMYKtoRGBconversion' => 'wp-short-pixel_cmyk2rgb',
|
23 |
'backupImages' => 'wp-short-backup_images',
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
24 |
'fileCount' => 'wp-short-pixel-fileCount',
|
25 |
'thumbsCount' => 'wp-short-pixel-thumbnail-count',
|
26 |
'under5Percent' => 'wp-short-pixel-files-under-5-percent',
|
27 |
'savedSpace' => 'wp-short-pixel-savedSpace',
|
28 |
'averageCompression' => 'wp-short-pixel-averageCompression',
|
29 |
-
'apiRetries' => 'wp-short-pixel-api-retries',
|
30 |
-
'resizeImages' => 'wp-short-pixel-resize-images',
|
31 |
-
'resizeWidth' => 'wp-short-pixel-resize-width',
|
32 |
-
'resizeHeight' => 'wp-short-pixel-resize-height',
|
33 |
'totalOptimized' => 'wp-short-pixel-total-optimized',
|
34 |
'totalOriginal' => 'wp-short-pixel-total-original',
|
35 |
'quotaExceeded' => 'wp-short-pixel-quota-exceeded',
|
36 |
'httpProto' => 'wp-short-pixel-protocol',
|
37 |
'downloadProto' => 'wp-short-pixel-download-protocol',
|
38 |
'mediaAlert' => 'wp-short-pixel-media-alert',
|
39 |
-
'
|
40 |
-
'
|
41 |
-
'
|
|
|
42 |
'redirectedSettings' => 'wp-short-pixel-redirected-settings',
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
43 |
'' => '',
|
44 |
);
|
45 |
|
@@ -72,7 +109,7 @@ class WPShortPixelSettings {
|
|
72 |
}
|
73 |
|
74 |
public static function debugResetOptions() {
|
75 |
-
delete_option('wp-short-pixel-apiKey');
|
76 |
delete_option('wp-short-pixel-verifiedKey');
|
77 |
delete_option('wp-short-pixel-compression');
|
78 |
delete_option('wp-short-process_thumbnails');
|
@@ -96,7 +133,10 @@ class WPShortPixelSettings {
|
|
96 |
delete_option( 'wp-short-pixel-resize-width');
|
97 |
delete_option( 'wp-short-pixel-resize-height');
|
98 |
delete_option( 'wp-short-pixel-dismissed-notices');
|
99 |
-
|
|
|
|
|
|
|
100 |
if(isset($_SESSION["wp-short-pixel-priorityQueue"])) {
|
101 |
unset($_SESSION["wp-short-pixel-priorityQueue"]);
|
102 |
}
|
@@ -116,11 +156,6 @@ class WPShortPixelSettings {
|
|
116 |
}
|
117 |
|
118 |
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
public function __get($name)
|
125 |
{
|
126 |
if (array_key_exists($name, self::$_optionsMap)) {
|
@@ -137,7 +172,11 @@ class WPShortPixelSettings {
|
|
137 |
|
138 |
public function __set($name, $value) {
|
139 |
if (array_key_exists($name, self::$_optionsMap)) {
|
140 |
-
|
|
|
|
|
|
|
|
|
141 |
}
|
142 |
}
|
143 |
|
12 |
private $_resizeImages = false;
|
13 |
private $_resizeWidth = 0;
|
14 |
private $_resizeHeight = 0;
|
15 |
+
|
16 |
private static $_optionsMap = array(
|
17 |
+
//This one is accessed also directly via get_option
|
18 |
+
'frontBootstrap' => 'wp-short-pixel-front-bootstrap', //set to 1 when need the plugin active for logged in user in the front-end
|
19 |
+
'lastBackAction' => 'wp-short-pixel-last-back-action', //when less than 10 min. passed from this timestamp, the front-bootstrap is ineffective.
|
20 |
+
//optimization options
|
21 |
'apiKey' => 'wp-short-pixel-apiKey',
|
22 |
'verifiedKey' => 'wp-short-pixel-verifiedKey',
|
23 |
'compressionType' => 'wp-short-pixel-compression',
|
25 |
'keepExif' => 'wp-short-pixel-keep-exif',
|
26 |
'CMYKtoRGBconversion' => 'wp-short-pixel_cmyk2rgb',
|
27 |
'backupImages' => 'wp-short-backup_images',
|
28 |
+
'resizeImages' => 'wp-short-pixel-resize-images',
|
29 |
+
'resizeWidth' => 'wp-short-pixel-resize-width',
|
30 |
+
'resizeHeight' => 'wp-short-pixel-resize-height',
|
31 |
+
'siteAuthUser' => 'wp-short-pixel-site-auth-user',
|
32 |
+
'siteAuthPass' => 'wp-short-pixel-site-auth-pass',
|
33 |
+
|
34 |
+
//optimize other images than the ones in Media Library
|
35 |
+
'includeNextGen' => 'wp-short-pixel-include-next-gen',
|
36 |
+
'hasCustomFolders' => 'wp-short-pixel-has-custom-folders',
|
37 |
+
'customBulkPaused' => 'wp-short-pixel-custom-bulk-paused',
|
38 |
+
|
39 |
+
//stats, notices, etc.
|
40 |
+
'currentTotalFiles' => 'wp-short-pixel-current-total-files',
|
41 |
'fileCount' => 'wp-short-pixel-fileCount',
|
42 |
'thumbsCount' => 'wp-short-pixel-thumbnail-count',
|
43 |
'under5Percent' => 'wp-short-pixel-files-under-5-percent',
|
44 |
'savedSpace' => 'wp-short-pixel-savedSpace',
|
45 |
'averageCompression' => 'wp-short-pixel-averageCompression',
|
46 |
+
'apiRetries' => 'wp-short-pixel-api-retries',
|
|
|
|
|
|
|
47 |
'totalOptimized' => 'wp-short-pixel-total-optimized',
|
48 |
'totalOriginal' => 'wp-short-pixel-total-original',
|
49 |
'quotaExceeded' => 'wp-short-pixel-quota-exceeded',
|
50 |
'httpProto' => 'wp-short-pixel-protocol',
|
51 |
'downloadProto' => 'wp-short-pixel-download-protocol',
|
52 |
'mediaAlert' => 'wp-short-pixel-media-alert',
|
53 |
+
'dismissedNotices' => 'wp-short-pixel-dismissed-notices',
|
54 |
+
'activationDate' => 'wp-short-pixel-activation-date',
|
55 |
+
'activationNotice' => 'wp-short-pixel-activation-notice',
|
56 |
+
'mediaLibraryViewMode' => 'wp-short-pixel-view-mode',
|
57 |
'redirectedSettings' => 'wp-short-pixel-redirected-settings',
|
58 |
+
|
59 |
+
//bulk state machine
|
60 |
+
'bulkLastStatus' => 'wp-short-pixel-bulk-last-status',
|
61 |
+
'startBulkId' => 'wp-short-pixel-query-id-start',
|
62 |
+
'stopBulkId' => 'wp-short-pixel-query-id-stop',
|
63 |
+
'bulkCount' => 'wp-short-pixel-bulk-count',
|
64 |
+
'bulkPreviousPercent' => 'wp-short-pixel-bulk-previous-percent',
|
65 |
+
'bulkCurrentlyProcessed' => 'wp-short-pixel-bulk-processed-items',
|
66 |
+
'bulkAlreadyDoneCount' => 'wp-short-pixel-bulk-done-count',
|
67 |
+
'lastBulkStartTime' => 'wp-short-pixel-last-bulk-start-time',
|
68 |
+
'lastBulkSuccessTime' => 'wp-short-pixel-last-bulk-success-time',
|
69 |
+
'bulkRunningTime' => 'wp-short-pixel-bulk-running-time',
|
70 |
+
'cancelPointer' => 'wp-short-pixel-cancel-pointer',
|
71 |
+
'skipToCustom' => 'wp-short-pixel-skip-to-custom',
|
72 |
+
'bulkEverRan' => 'wp-short-pixel-bulk-ever-ran',
|
73 |
+
'flagId' => 'wp-short-pixel-flag-id',
|
74 |
+
'failedImages' => 'wp-short-pixel-failed-imgs',
|
75 |
+
'bulkProcessingStatus' => 'bulkProcessingStatus',
|
76 |
+
|
77 |
+
'priorityQueue' => 'wp-short-pixel-priorityQueue',
|
78 |
+
'prioritySkip' => 'wp-short-pixel-prioritySkip',
|
79 |
+
|
80 |
'' => '',
|
81 |
);
|
82 |
|
109 |
}
|
110 |
|
111 |
public static function debugResetOptions() {
|
112 |
+
/* delete_option('wp-short-pixel-apiKey');
|
113 |
delete_option('wp-short-pixel-verifiedKey');
|
114 |
delete_option('wp-short-pixel-compression');
|
115 |
delete_option('wp-short-process_thumbnails');
|
133 |
delete_option( 'wp-short-pixel-resize-width');
|
134 |
delete_option( 'wp-short-pixel-resize-height');
|
135 |
delete_option( 'wp-short-pixel-dismissed-notices');
|
136 |
+
*/
|
137 |
+
foreach(self::$_optionsMap as $key => $val) {
|
138 |
+
delete_option($val);
|
139 |
+
}
|
140 |
if(isset($_SESSION["wp-short-pixel-priorityQueue"])) {
|
141 |
unset($_SESSION["wp-short-pixel-priorityQueue"]);
|
142 |
}
|
156 |
}
|
157 |
|
158 |
|
|
|
|
|
|
|
|
|
|
|
159 |
public function __get($name)
|
160 |
{
|
161 |
if (array_key_exists($name, self::$_optionsMap)) {
|
172 |
|
173 |
public function __set($name, $value) {
|
174 |
if (array_key_exists($name, self::$_optionsMap)) {
|
175 |
+
if($value !== null) {
|
176 |
+
$this->setOpt(self::$_optionsMap[$name], $value);
|
177 |
+
} else {
|
178 |
+
delete_option(self::$_optionsMap[$name]);
|
179 |
+
}
|
180 |
}
|
181 |
}
|
182 |
|
wp-shortpixel.php
CHANGED
@@ -3,36 +3,33 @@
|
|
3 |
* Plugin Name: ShortPixel Image Optimizer
|
4 |
* Plugin URI: https://shortpixel.com/
|
5 |
* Description: ShortPixel optimizes images automatically, while guarding the quality of your images. Check your <a href="options-general.php?page=wp-shortpixel" target="_blank">Settings > ShortPixel</a> page on how to start optimizing your image library and make your website load faster.
|
6 |
-
* Version:
|
7 |
* Author: ShortPixel
|
8 |
* Author URI: https://shortpixel.com
|
9 |
*/
|
10 |
|
11 |
-
require_once('wp-shortpixel-settings.php');
|
12 |
-
require_once('shortpixel_api.php');
|
13 |
-
require_once('shortpixel_queue.php');
|
14 |
-
require_once('shortpixel_view.php');
|
15 |
-
require_once( ABSPATH . 'wp-admin/includes/image.php' );
|
16 |
-
include_once( ABSPATH . 'wp-admin/includes/plugin.php' );
|
17 |
-
|
18 |
-
/*if ( !is_plugin_active( 'wpmandrill/wpmandrill.php' ) && !is_plugin_active( 'wp-ses/wp-ses.php' ) ) {
|
19 |
-
require_once( ABSPATH . 'wp-includes/pluggable.php' );//to avoid conflict with wpmandrill plugin
|
20 |
-
}
|
21 |
-
*/
|
22 |
-
|
23 |
define('SP_RESET_ON_ACTIVATE', false); //if true TODO set false
|
24 |
|
25 |
define('SP_AFFILIATE_CODE', '');
|
26 |
|
27 |
-
define('PLUGIN_VERSION', "
|
28 |
define('SP_MAX_TIMEOUT', 10);
|
29 |
define('SP_VALIDATE_MAX_TIMEOUT', 15);
|
30 |
define('SP_BACKUP', 'ShortpixelBackups');
|
31 |
-
define('SP_BACKUP_FOLDER', WP_CONTENT_DIR . DIRECTORY_SEPARATOR . 'uploads' . DIRECTORY_SEPARATOR . SP_BACKUP);
|
32 |
define('MAX_API_RETRIES', 50);
|
33 |
define('MAX_ERR_RETRIES', 5);
|
|
|
34 |
$MAX_EXECUTION_TIME = ini_get('max_execution_time');
|
35 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
36 |
/*
|
37 |
if ( is_numeric($MAX_EXECUTION_TIME) && $MAX_EXECUTION_TIME > 10 )
|
38 |
define('MAX_EXECUTION_TIME', $MAX_EXECUTION_TIME - 5 ); //in seconds
|
@@ -53,17 +50,26 @@ class WPShortPixel {
|
|
53 |
private $_settings = null;
|
54 |
private $prioQ = null;
|
55 |
private $view = null;
|
|
|
|
|
|
|
|
|
|
|
56 |
|
57 |
public function __construct() {
|
58 |
if (!session_id()) {
|
59 |
session_start();
|
60 |
}
|
|
|
|
|
61 |
|
62 |
$isAdminUser = current_user_can( 'manage_options' );
|
63 |
|
64 |
$this->_affiliateSufix = (strlen(SP_AFFILIATE_CODE)) ? "/affiliate/" . SP_AFFILIATE_CODE : "";
|
65 |
$this->_settings = new WPShortPixelSettings();
|
66 |
$this->_apiInterface = new ShortPixelAPI($this->_settings);
|
|
|
|
|
67 |
$this->prioQ = new ShortPixelQueue($this, $this->_settings);
|
68 |
$this->view = new ShortPixelView($this);
|
69 |
|
@@ -72,7 +78,7 @@ class WPShortPixel {
|
|
72 |
$this->setDefaultViewModeList();//set default mode as list. only @ first run
|
73 |
|
74 |
//add hook for image upload processing
|
75 |
-
add_filter( 'wp_generate_attachment_metadata', array( &$this, '
|
76 |
add_filter( 'plugin_action_links_' . plugin_basename(__FILE__), array(&$this, 'generatePluginLinks'));//for plugin settings page
|
77 |
|
78 |
//add_action( 'admin_footer', array(&$this, 'handleImageProcessing'));
|
@@ -80,6 +86,16 @@ class WPShortPixel {
|
|
80 |
//Media custom column
|
81 |
add_filter( 'manage_media_columns', array( &$this, 'columns' ) );//add media library column header
|
82 |
add_action( 'manage_media_custom_column', array( &$this, 'generateCustomColumn' ), 10, 2 );//generate the media library column
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
83 |
//custom hook
|
84 |
add_action( 'shortpixel-optimize-now', array( &$this, 'optimizeNowHook' ), 10, 1);
|
85 |
|
@@ -87,6 +103,8 @@ class WPShortPixel {
|
|
87 |
//add settings page
|
88 |
add_action( 'admin_menu', array( &$this, 'registerSettingsPage' ) );//display SP in Settings menu
|
89 |
add_action( 'admin_menu', array( &$this, 'registerAdminPage' ) );
|
|
|
|
|
90 |
|
91 |
add_action( 'delete_attachment', array( &$this, 'handleDeleteAttachmentInBackup' ) );
|
92 |
add_action( 'load-upload.php', array( &$this, 'handleCustomBulk'));
|
@@ -111,12 +129,18 @@ class WPShortPixel {
|
|
111 |
add_action( 'wp_ajax_shortpixel_dismiss_media_alert', array(&$this, 'dismissMediaAlert'));
|
112 |
//check quota
|
113 |
add_action('admin_action_shortpixel_check_quota', array(&$this, 'handleCheckQuota'));
|
114 |
-
|
115 |
//This adds the constants used in PHP to be available also in JS
|
116 |
add_action( 'admin_footer', array( &$this, 'shortPixelJS') );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
117 |
//register a method to display admin notices if necessary
|
118 |
add_action('admin_notices', array( &$this, 'displayAdminNotices'));
|
119 |
-
|
120 |
$this->migrateBackupFolder();
|
121 |
|
122 |
if(!$this->_settings->redirectedSettings && !$this->_settings->verifiedKey && (!function_exists("is_multisite") || !is_multisite())) {
|
@@ -136,6 +160,9 @@ class WPShortPixel {
|
|
136 |
}
|
137 |
|
138 |
function registerAdminPage( ) {
|
|
|
|
|
|
|
139 |
add_media_page( 'ShortPixel Bulk Process', 'Bulk ShortPixel', 'edit_others_posts', 'wp-short-pixel-bulk', array( &$this, 'bulkProcess' ) );
|
140 |
}
|
141 |
|
@@ -150,7 +177,7 @@ class WPShortPixel {
|
|
150 |
|
151 |
public static function shortPixelDeactivatePlugin()//reset some params to avoid trouble for plugins that were activated/deactivated/activated
|
152 |
{
|
153 |
-
include_once dirname( __FILE__ ) . '/
|
154 |
ShortPixelQueue::resetBulk();
|
155 |
ShortPixelQueue::resetPrio();
|
156 |
WPShortPixelSettings::onDeactivate();
|
@@ -158,12 +185,12 @@ class WPShortPixel {
|
|
158 |
|
159 |
public function displayAdminNotices() {
|
160 |
if(!$this->_settings->verifiedKey) {
|
161 |
-
$dismissed = $this->_settings->
|
162 |
$now = time();
|
163 |
-
$act = $this->_settings->
|
164 |
-
if($this->_settings->
|
165 |
ShortPixelView::displayActivationNotice();
|
166 |
-
|
167 |
}
|
168 |
if( ($now > $act + 7200) && !isset($dismissed['2h'])) {
|
169 |
ShortPixelView::displayActivationNotice('2h');
|
@@ -175,9 +202,9 @@ class WPShortPixel {
|
|
175 |
|
176 |
public function dismissAdminNotice() {
|
177 |
$noticeId = preg_replace('|[^a-z0-9]|i', '', $_GET['notice_id']);
|
178 |
-
$dismissed = $this->_settings->
|
179 |
$dismissed[$noticeId] = true;
|
180 |
-
|
181 |
die(json_encode(array("Status" => 'success', "Message" => 'Notice ID: ' . $noticeId . ' dismissed')));
|
182 |
}
|
183 |
|
@@ -189,9 +216,9 @@ class WPShortPixel {
|
|
189 |
//set default move as "list". only set once, it won't try to set the default mode again.
|
190 |
public function setDefaultViewModeList()
|
191 |
{
|
192 |
-
if($this->_settings->
|
193 |
{
|
194 |
-
$this->_settings->
|
195 |
if ( function_exists('get_currentuserinfo') )
|
196 |
{
|
197 |
global $current_user;
|
@@ -215,27 +242,27 @@ class WPShortPixel {
|
|
215 |
|
216 |
function shortPixelJS() { ?>
|
217 |
<script type="text/javascript" >
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
}
|
235 |
-
});
|
236 |
</script> <?php
|
237 |
-
wp_enqueue_style('short-pixel.css', plugins_url('/css/short-pixel.css',__FILE__) );
|
238 |
-
wp_enqueue_script('short-pixel.js', plugins_url('/js/short-pixel.js',__FILE__) );
|
|
|
|
|
239 |
}
|
240 |
|
241 |
function toolbar_shortpixel_processing( $wp_admin_bar ) {
|
@@ -257,18 +284,16 @@ class WPShortPixel {
|
|
257 |
//$blank = '_blank';
|
258 |
//$icon = "shortpixel-alert.png";
|
259 |
}
|
260 |
-
$lastStatus = $this->_settings->
|
261 |
-
if($lastStatus['Status'] != ShortPixelAPI::STATUS_SUCCESS) {
|
262 |
$extraClasses = " shortpixel-alert shortpixel-processing";
|
263 |
$tooltip = $lastStatus['Message'];
|
264 |
}
|
265 |
-
self::log("TB: Start: " . $this->prioQ->getStartBulkId() . ", stop: " . $this->prioQ->getStopBulkId() . " PrioQ: "
|
266 |
-
.json_encode($this->prioQ->get()));
|
267 |
|
268 |
$args = array(
|
269 |
'id' => 'shortpixel_processing',
|
270 |
'title' => '<div title="' . $tooltip . '" ><img src="'
|
271 |
-
. plugins_url( 'img/'.$icon, __FILE__ ) . '" success-url="' . $successLink . '"><span class="shp-alert">!</span></div>',
|
272 |
'href' => $link,
|
273 |
'meta' => array('target'=> $blank, 'class' => 'shortpixel-toolbar-processing' . $extraClasses)
|
274 |
);
|
@@ -303,7 +328,13 @@ class WPShortPixel {
|
|
303 |
}
|
304 |
}
|
305 |
|
306 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
307 |
{
|
308 |
if( !$this->_settings->verifiedKey) {// no API Key set/verified -> do nothing here, just return
|
309 |
return $meta;
|
@@ -319,7 +350,9 @@ class WPShortPixel {
|
|
319 |
else
|
320 |
{//the kind of file we can process. goody.
|
321 |
$this->prioQ->push($ID);
|
322 |
-
$
|
|
|
|
|
323 |
//send a processing request right after a file was uploaded, do NOT wait for response
|
324 |
$this->_apiInterface->doRequests($URLsAndPATHs['URLs'], false, $ID);
|
325 |
self::log("IMG: sent: " . json_encode($URLsAndPATHs));
|
@@ -327,25 +360,82 @@ class WPShortPixel {
|
|
327 |
return $meta;
|
328 |
}
|
329 |
|
330 |
-
}//end
|
331 |
|
332 |
-
|
333 |
-
|
334 |
-
|
335 |
-
|
336 |
-
|
337 |
-
|
338 |
-
|
339 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
340 |
}
|
341 |
-
$queryPostMeta = "SELECT COUNT(DISTINCT post_id) items FROM " . $wpdb->prefix . "postmeta
|
342 |
-
WHERE ( post_id <= $startQueryID AND post_id > $endQueryID ) AND (
|
343 |
-
meta_key = '_wp_attached_file'
|
344 |
-
OR meta_key = '_wp_attachment_metadata' )";
|
345 |
-
$res = $wpdb->get_results($queryPostMeta);
|
346 |
-
return $res[0]->items;
|
347 |
}
|
348 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
349 |
public function getBulkItemsFromDb(){
|
350 |
global $wpdb;
|
351 |
|
@@ -357,8 +447,9 @@ class WPShortPixel {
|
|
357 |
return false;
|
358 |
}
|
359 |
$idList = array();
|
|
|
360 |
for ($sanityCheck = 0, $crtStartQueryID = $startQueryID;
|
361 |
-
$crtStartQueryID >= $endQueryID && count($
|
362 |
|
363 |
self::log("GETDB: current StartID: " . $crtStartQueryID);
|
364 |
|
@@ -377,24 +468,27 @@ class WPShortPixel {
|
|
377 |
foreach ( $resultsPostMeta as $itemMetaData ) {
|
378 |
$crtStartQueryID = $itemMetaData->post_id;
|
379 |
if(!in_array($crtStartQueryID, $idList) && self::isProcessable($crtStartQueryID)) {
|
380 |
-
$
|
381 |
-
$
|
382 |
|
383 |
-
if(
|
|
|
384 |
$idList[] = $crtStartQueryID;
|
385 |
}
|
386 |
-
elseif(
|
387 |
-
if($this->doRestore($crtStartQueryID
|
|
|
388 |
$idList[] = $crtStartQueryID;
|
389 |
} else {
|
390 |
$skippedAlreadyProcessed++;
|
391 |
}
|
392 |
}
|
393 |
-
elseif( $this->_settings->processThumbnails &&
|
394 |
-
&&
|
395 |
//if($crtStartQueryID == 44 || $crtStartQueryID == 49) {echo("No THuMBS?");die(var_dump($meta));}
|
396 |
-
$meta
|
397 |
-
wp_update_attachment_metadata($crtStartQueryID, $meta);
|
|
|
398 |
$idList[] = $crtStartQueryID;
|
399 |
}
|
400 |
elseif($itemMetaData->meta_key == '_wp_attachment_metadata') { //count skipped
|
@@ -406,54 +500,52 @@ class WPShortPixel {
|
|
406 |
//daca n-am adaugat niciuna pana acum, n-are sens sa mai selectez zona asta de id-uri in bulk-ul asta.
|
407 |
$leapStart = $this->prioQ->getStartBulkId();
|
408 |
$crtStartQueryID = $startQueryID = $itemMetaData->post_id - 1; //decrement it so we don't select it again
|
409 |
-
$res =
|
410 |
$skippedAlreadyProcessed += $res["mainProcessedFiles"] - $res["mainProc".($this->getCompressionType() == 1 ? "Lossy" : "Lossless")."Files"];
|
411 |
$this->prioQ->setStartBulkId($startQueryID);
|
412 |
} else {
|
413 |
$crtStartQueryID--;
|
414 |
}
|
415 |
}
|
416 |
-
return array("
|
417 |
}
|
418 |
|
419 |
/**
|
420 |
* Get last added items from priority
|
421 |
* @return type
|
422 |
*/
|
|
|
423 |
public function getFromPrioAndCheck() {
|
424 |
-
$
|
425 |
-
$
|
426 |
-
|
427 |
-
$idsPrio = $this->prioQ->get();
|
428 |
-
for($i = count($idsPrio) - 1, $cnt = 0; $i>=0 && $cnt < 3; $i--) {
|
429 |
-
$id = $idsPrio[$i];
|
430 |
-
if(!$this->prioQ->isSkipped($id) && wp_get_attachment_url($id)) {
|
431 |
-
$ids[] = $id; //valid ID
|
432 |
-
} elseif(!$this->prioQ->isSkipped($id)) {
|
433 |
-
$removeIds[] = $id;//not skipped, url not found, means it's absent, to remove
|
434 |
-
}
|
435 |
-
}
|
436 |
-
foreach($removeIds as $rId){
|
437 |
-
self::log("HIP: Unfound ID $rID Remove from Priority Queue: ".json_encode(get_option($this->prioQ->get())));
|
438 |
-
$this->prioQ->remove($rId);
|
439 |
}
|
440 |
-
return $
|
441 |
}
|
442 |
|
443 |
public function handleImageProcessing($ID = null) {
|
444 |
-
//
|
|
|
|
|
|
|
445 |
//0: check key
|
446 |
if( $this->_settings->verifiedKey == false) {
|
447 |
if($ID == null){
|
448 |
$ids = $this->getFromPrioAndCheck();
|
449 |
-
$
|
450 |
}
|
451 |
-
$response = array("Status" => ShortPixelAPI::STATUS_NO_KEY, "ImageID" => $
|
452 |
-
|
453 |
die(json_encode($response));
|
454 |
}
|
455 |
|
|
|
|
|
|
|
|
|
|
|
456 |
self::log("HIP: 0 Priority Queue: ".json_encode($this->prioQ->get()));
|
|
|
457 |
|
458 |
//1: get 3 ids to process. Take them with priority from the queue
|
459 |
$ids = $this->getFromPrioAndCheck();
|
@@ -461,16 +553,33 @@ class WPShortPixel {
|
|
461 |
$bulkStatus = $this->prioQ->bulkRunning();
|
462 |
if($bulkStatus =='running') {
|
463 |
$res = $this->getBulkItemsFromDb();
|
464 |
-
$bulkItems = $res['
|
465 |
if($bulkItems){
|
466 |
$ids = array_merge ($ids, $bulkItems);
|
467 |
}
|
468 |
}
|
469 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
470 |
if ($ids === false || count( $ids ) == 0 ){
|
471 |
$bulkEverRan = $this->prioQ->stopBulk();
|
472 |
-
$avg =
|
473 |
-
$fileCount =
|
474 |
$response = array("Status" => self::BULK_EMPTY_QUEUE,
|
475 |
"Message" => 'Empty queue ' . $this->prioQ->getStartBulkId() . '->' . $this->prioQ->getStopBulkId(),
|
476 |
"BulkStatus" => ($this->prioQ->bulkRunning()
|
@@ -482,13 +591,16 @@ class WPShortPixel {
|
|
482 |
}
|
483 |
|
484 |
self::log("HIP: 1 Prio Queue: ".json_encode($this->prioQ->get()));
|
|
|
485 |
|
486 |
//2: Send up to 3 files to the server for processing
|
487 |
for($i = 0; $i < min(3, count($ids)); $i++) {
|
488 |
-
$
|
489 |
-
$tmpMeta =
|
490 |
-
|
491 |
-
$
|
|
|
|
|
492 |
if($i == 0) { //save for later use
|
493 |
$firstUrlAndPaths = $URLsAndPATHs;
|
494 |
}
|
@@ -496,135 +608,229 @@ class WPShortPixel {
|
|
496 |
|
497 |
self::log("HIP: 2 Prio Queue: ".json_encode($this->prioQ->get()));
|
498 |
//3: Retrieve the file for the first element of the list
|
499 |
-
$
|
500 |
-
$
|
501 |
-
$result[
|
|
|
|
|
|
|
502 |
|
503 |
self::log("HIP: 3 Prio Queue: ".json_encode($this->prioQ->get()));
|
504 |
|
505 |
//4: update counters and priority list
|
506 |
if( $result["Status"] == ShortPixelAPI::STATUS_SUCCESS) {
|
507 |
-
self::log("HIP: Image ID $
|
508 |
-
$prio = $this->prioQ->remove($
|
509 |
//remove also from the failed list if it failed in the past
|
510 |
-
$prio = $this->prioQ->removeFromFailed($
|
511 |
-
$
|
512 |
-
$result["Type"] = isset($meta['ShortPixel']['type']) ? $meta['ShortPixel']['type'] : '';
|
513 |
$result["ThumbsTotal"] = isset($meta['sizes']) && is_array($meta['sizes']) ? count($meta['sizes']): 0;
|
514 |
$result["ThumbsCount"] = isset($meta['ShortPixel']['thumbsOpt'])
|
515 |
? $meta['ShortPixel']['thumbsOpt'] //below is the fallback for old optimized images that don't have thumbsOpt
|
516 |
: ($this->_settings->processThumbnails ? $result["ThumbsTotal"] : 0);
|
|
|
|
|
|
|
|
|
|
|
|
|
517 |
|
518 |
-
|
|
|
519 |
|
520 |
-
if(!$prio && $
|
521 |
-
|
522 |
-
$this->
|
|
|
|
|
|
|
|
|
|
|
523 |
|
524 |
$thumb = $bkThumb = "";
|
525 |
-
|
526 |
-
|
527 |
-
|
528 |
-
|
529 |
-
|
|
|
|
|
|
|
530 |
|
531 |
//Get a suitable thumb
|
532 |
-
if(isset($meta["sizes"]) && count($meta["sizes"])) {
|
533 |
-
|
534 |
-
|
535 |
-
|
536 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
537 |
}
|
538 |
-
} else { //fallback to the image itself
|
539 |
-
$thumb = is_array($filePath) ? $filePath[count($filePath) - 1] : $filePath;
|
540 |
-
}
|
541 |
-
|
542 |
-
if(strlen($thumb) && $this->_settings->backupImages && $this->_settings->processThumbnails) {
|
543 |
-
$backupUrl = content_url() . "/uploads/" . SP_BACKUP . "/";
|
544 |
-
$urlBkPath = $this->_apiInterface->returnSubDir(get_attached_file($ID));
|
545 |
-
$bkThumb = $backupUrl . $urlBkPath . "/" . $thumb;
|
546 |
-
}
|
547 |
-
if(strlen($thumb)) {
|
548 |
-
$uploadDir = wp_upload_dir();
|
549 |
-
$uploadsUrl = $uploadDir["baseurl"] . "/";
|
550 |
-
$urlPath = implode("/", array_slice($filePath, 0, count($filePath) - 1));
|
551 |
-
$thumb = $uploadsUrl . $urlPath . "/" . $thumb;
|
552 |
}
|
|
|
553 |
$result["Thumb"] = $thumb;
|
554 |
$result["BkThumb"] = $bkThumb;
|
555 |
}
|
556 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
557 |
}
|
558 |
elseif ($result["Status"] == ShortPixelAPI::STATUS_ERROR) {
|
559 |
-
|
560 |
-
if(isset($meta['ShortPixel']['Retries']) && $meta['ShortPixel']['Retries'] > MAX_ERR_RETRIES) {
|
561 |
-
|
562 |
-
|
|
|
|
|
|
|
563 |
}
|
564 |
-
unset($meta['ShortPixel']);
|
565 |
-
wp_update_attachment_metadata($ID, $meta);
|
|
|
566 |
$result["Status"] = ShortPixelAPI::STATUS_SKIP;
|
567 |
-
$result["Message"] .= " Retry limit reached. Skipping file ID " . $
|
568 |
}
|
569 |
else {
|
570 |
-
if(!isset($meta['ShortPixel'])) { $meta['ShortPixel'] = array(); }
|
571 |
-
|
572 |
-
wp_update_attachment_metadata($ID, $meta);
|
|
|
573 |
}
|
574 |
}
|
575 |
elseif ($result["Status"] == ShortPixelAPI::STATUS_SKIP
|
576 |
|| $result["Status"] == ShortPixelAPI::STATUS_FAIL) {
|
577 |
-
$
|
578 |
-
|
|
|
|
|
|
|
|
|
|
|
579 |
//put this one in the failed images list - to show the user at the end
|
580 |
-
$prio = $this->prioQ->addToFailed($
|
581 |
-
}
|
582 |
-
$this->advanceBulk($
|
583 |
-
|
584 |
-
|
585 |
-
|
586 |
-
|
587 |
-
|
588 |
-
|
589 |
-
|
590 |
-
|
591 |
-
|
592 |
-
|
593 |
-
|
594 |
-
|
595 |
-
|
596 |
-
|
597 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
598 |
}
|
599 |
die(json_encode($result));
|
600 |
}
|
601 |
|
|
|
602 |
private function advanceBulk($processedID, &$result) {
|
|
|
603 |
if($processedID <= $this->prioQ->getStartBulkId()) {
|
604 |
$this->prioQ->setStartBulkId($processedID - 1);
|
605 |
$this->prioQ->logBulkProgress();
|
606 |
-
$deltaBulkPercent = $this->prioQ->getDeltaBulkPercent();
|
607 |
-
$msg = $this->bulkProgressMessage($deltaBulkPercent, $this->prioQ->getTimeRemaining());
|
608 |
-
$result["BulkPercent"] = $this->prioQ->getBulkPercent();
|
609 |
-
$result["BulkMsg"] = $msg;
|
610 |
}
|
611 |
}
|
612 |
|
613 |
-
private function
|
614 |
-
$
|
615 |
-
$
|
616 |
-
$
|
617 |
-
|
618 |
-
|
619 |
-
|
620 |
-
|
621 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
622 |
return $URLsAndPATHs;
|
623 |
}
|
624 |
|
625 |
public function handleManualOptimization() {
|
626 |
-
$imageId =
|
627 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
628 |
//do_action('shortpixel-optimize-now', $imageId);
|
629 |
|
630 |
}
|
@@ -633,7 +839,7 @@ class WPShortPixel {
|
|
633 |
public function optimizeNowHook($imageId) {
|
634 |
if(self::isProcessable($imageId)) {
|
635 |
$this->prioQ->push($imageId);
|
636 |
-
$this->sendToProcessing($imageId);
|
637 |
$ret = array("Status" => ShortPixelAPI::STATUS_SUCCESS, "message" => "");
|
638 |
} else {
|
639 |
$ret = array("Status" => ShortPixelAPI::STATUS_SKIP, "message" => $imageId);
|
@@ -651,7 +857,7 @@ class WPShortPixel {
|
|
651 |
|
652 |
public function getBackupFolder($file) {
|
653 |
$fileExtension = strtolower(substr($file,strrpos($file,".")+1));
|
654 |
-
$SubDir =
|
655 |
|
656 |
//sometimes the month of original file and backup can differ
|
657 |
if ( !file_exists(SP_BACKUP_FOLDER . DIRECTORY_SEPARATOR . $SubDir . ShortPixelAPI::MB_basename($file)) ) {
|
@@ -682,19 +888,23 @@ class WPShortPixel {
|
|
682 |
$pathInfo = pathinfo($file);
|
683 |
|
684 |
$bkFolder = $this->getBackupFolder($file);
|
|
|
685 |
$bkFile = $bkFolder . ShortPixelAPI::MB_basename($file);
|
686 |
|
|
|
|
|
|
|
|
|
687 |
//first check if the file is readable by the current user - otherwise it will be unaccessible for the web browser
|
688 |
// - collect the thumbs paths in the process
|
689 |
if(! $this->setFilePerms($bkFile) ) return false;
|
690 |
$thumbsPaths = array();
|
691 |
if( !empty($meta['file']) && is_array($meta["sizes"]) ) {
|
692 |
foreach($meta["sizes"] as $size => $imageData) {
|
693 |
-
|
694 |
-
|
695 |
-
|
696 |
-
|
697 |
-
}
|
698 |
}
|
699 |
}
|
700 |
|
@@ -708,7 +918,7 @@ class WPShortPixel {
|
|
708 |
@rename($source, $destination);
|
709 |
}
|
710 |
|
711 |
-
$duplicates =
|
712 |
foreach($duplicates as $ID) {
|
713 |
$crtMeta = $attachmentID == $ID ? $meta : wp_get_attachment_metadata($ID);
|
714 |
if(is_numeric($crtMeta["ShortPixelImprovement"]) && 0 + $crtMeta["ShortPixelImprovement"] < 5 && $this->_settings->under5Percent > 0) {
|
@@ -745,16 +955,23 @@ class WPShortPixel {
|
|
745 |
}
|
746 |
|
747 |
public function handleRedo() {
|
748 |
-
$ID =
|
749 |
-
$
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
750 |
|
751 |
$meta = $this->doRestore($ID);
|
752 |
//die(var_dump($meta));
|
753 |
if($meta) { //restore succeeded
|
754 |
-
$meta['ShortPixel'] = array("type" => $
|
755 |
wp_update_attachment_metadata($ID, $meta);
|
756 |
$this->prioQ->push($ID);
|
757 |
-
$this->sendToProcessing($ID, $
|
758 |
$ret = array("Status" => ShortPixelAPI::STATUS_SUCCESS, "Message" => "");
|
759 |
} else {
|
760 |
$ret = array("Status" => ShortPixelAPI::STATUS_SKIP, "Message" => "Could not restore from backup: " . $ID);
|
@@ -772,7 +989,7 @@ class WPShortPixel {
|
|
772 |
$meta['ShortPixel']['thumbsTodo'] = true;
|
773 |
wp_update_attachment_metadata($ID, $meta);
|
774 |
$this->prioQ->push($ID);
|
775 |
-
$this->sendToProcessing($ID);
|
776 |
$ret = array("Status" => ShortPixelAPI::STATUS_SUCCESS, "message" => "");
|
777 |
} else {
|
778 |
$ret = array("Status" => ShortPixelAPI::STATUS_SKIP, "message" => (isset($meta['ShortPixelImprovement']) ? "No thumbnails to optimize for ID: " : "Please optimize image for ID:") . $ID);
|
@@ -797,9 +1014,8 @@ class WPShortPixel {
|
|
797 |
|
798 |
if(self::isProcessable($ID) != false)
|
799 |
{
|
800 |
-
$SubDir = $this->_apiInterface->returnSubDir($file);
|
801 |
try {
|
802 |
-
$SubDir =
|
803 |
|
804 |
@unlink(SP_BACKUP_FOLDER . DIRECTORY_SEPARATOR . $SubDir . ShortPixelAPI::MB_basename($file));
|
805 |
|
@@ -809,9 +1025,7 @@ class WPShortPixel {
|
|
809 |
//remove thumbs thumbnails
|
810 |
if(isset($meta["sizes"])) {
|
811 |
foreach($meta["sizes"] as $size => $imageData) {
|
812 |
-
|
813 |
-
@unlink($filesPath . ShortPixelAPI::MB_basename($imageData['file']));//remove thumbs
|
814 |
-
}
|
815 |
}
|
816 |
}
|
817 |
}
|
@@ -830,19 +1044,29 @@ class WPShortPixel {
|
|
830 |
return $quotaData;
|
831 |
}
|
832 |
//$tempus = microtime(true);
|
833 |
-
$imageCount =
|
|
|
|
|
|
|
834 |
//echo("Count took (seconds): " . (microtime(true) - $tempus));
|
835 |
foreach($imageCount as $key => $val) {
|
836 |
$quotaData[$key] = $val;
|
837 |
}
|
838 |
-
|
839 |
-
|
840 |
-
|
841 |
-
|
|
|
|
|
|
|
|
|
|
|
842 |
|
843 |
if($quotaData['APICallsQuotaNumeric'] + $quotaData['APICallsQuotaOneTimeNumeric'] > $quotaData['APICallsMadeNumeric'] + $quotaData['APICallsMadeOneTimeNumeric']) {
|
844 |
$this->_settings->quotaExceeded = '0';
|
845 |
$this->_settings->prioritySkip = NULL;
|
|
|
|
|
846 |
?><script>var shortPixelQuotaExceeded = 0;</script><?php
|
847 |
}
|
848 |
else {
|
@@ -851,7 +1075,59 @@ class WPShortPixel {
|
|
851 |
}
|
852 |
return $quotaData;
|
853 |
}
|
854 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
855 |
public function bulkProcess() {
|
856 |
global $wpdb;
|
857 |
|
@@ -866,24 +1142,42 @@ class WPShortPixel {
|
|
866 |
if(isset($_POST['bulkProcessPause']))
|
867 |
{//pause an ongoing bulk processing, it might be needed sometimes
|
868 |
$this->prioQ->pauseBulk();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
869 |
}
|
870 |
|
871 |
if(isset($_POST["bulkProcess"]))
|
872 |
{
|
873 |
//set the thumbnails option
|
874 |
if ( isset($_POST['thumbnails']) ) {
|
875 |
-
|
876 |
} else {
|
877 |
-
|
878 |
}
|
879 |
$this->prioQ->startBulk();
|
|
|
880 |
self::log("BULK: Start: " . $this->prioQ->getStartBulkId() . ", stop: " . $this->prioQ->getStopBulkId() . " PrioQ: "
|
881 |
.json_encode($this->prioQ->get()));
|
882 |
}//end bulk process was clicked
|
883 |
|
884 |
-
if(isset($_POST["bulkProcessResume"]))
|
885 |
{
|
886 |
$this->prioQ->resumeBulk();
|
|
|
|
|
|
|
|
|
|
|
|
|
887 |
}//resume was clicked
|
888 |
|
889 |
//figure out all the files that could be processed
|
@@ -892,13 +1186,26 @@ class WPShortPixel {
|
|
892 |
$allFiles = $wpdb->get_results($qry);
|
893 |
//figure out the files that are left to be processed
|
894 |
$qry_left = "SELECT count(*) FilesLeftToBeProcessed FROM " . $wpdb->prefix . "postmeta
|
895 |
-
WHERE meta_key = '_wp_attached_file' AND post_id <= " . $this->prioQ->getStartBulkId();
|
896 |
$filesLeft = $wpdb->get_results($qry_left);
|
897 |
-
|
898 |
-
|
|
|
|
|
|
|
|
|
|
|
899 |
{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
900 |
$msg = $this->bulkProgressMessage($this->prioQ->getDeltaBulkPercent(), $this->prioQ->getTimeRemaining());
|
901 |
-
$this->view->displayBulkProcessingRunning($this->
|
|
|
902 |
|
903 |
// $imagesLeft = $filesLeft[0]->FilesLeftToBeProcessed;
|
904 |
// $totalImages = $allFiles[0]->FilesToBeProcessed;
|
@@ -909,7 +1216,7 @@ class WPShortPixel {
|
|
909 |
if($this->prioQ->bulkRan() && !$this->prioQ->bulkPaused()) {
|
910 |
$this->prioQ->markBulkComplete();
|
911 |
}
|
912 |
-
|
913 |
//image count
|
914 |
//$imageCount = $this->countAllProcessableFiles();
|
915 |
$imageOnlyThumbs = $quotaData['totalFiles'] - $quotaData['mainFiles'];
|
@@ -918,9 +1225,10 @@ class WPShortPixel {
|
|
918 |
|
919 |
//average compression
|
920 |
$averageCompression = self::getAverageCompression();
|
921 |
-
$this->
|
922 |
-
|
923 |
-
|
|
|
924 |
}
|
925 |
}
|
926 |
//end bulk processing
|
@@ -935,7 +1243,7 @@ class WPShortPixel {
|
|
935 |
} elseif ($minutes > 240) {
|
936 |
$timeEst = "~ " . round($minutes / 60) . " hours left";
|
937 |
} elseif ($minutes > 60) {
|
938 |
-
$timeEst = "~ " . round($minutes / 60) . " hours " . round($minutes%60/10) * 10 . " min. left";
|
939 |
} elseif ($minutes > 20) {
|
940 |
$timeEst = "~ " . round($minutes / 10) * 10 . " minutes left";
|
941 |
} else {
|
@@ -975,17 +1283,107 @@ class WPShortPixel {
|
|
975 |
return count(scandir(SP_BACKUP_FOLDER)) > 2 ? false : true;
|
976 |
}
|
977 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
978 |
public function renderSettingsMenu() {
|
979 |
if ( !current_user_can( 'manage_options' ) ) {
|
980 |
wp_die('You do not have sufficient permissions to access this page.');
|
981 |
}
|
982 |
|
|
|
|
|
|
|
983 |
//die(var_dump($_POST));
|
984 |
$noticeHTML = "";
|
985 |
$notice = null;
|
986 |
-
|
|
|
|
|
987 |
$this->_settings->redirectedSettings = 2;
|
988 |
-
|
989 |
//by default we try to fetch the API Key from wp-config.php (if defined)
|
990 |
if ( defined("SHORTPIXEL_API_KEY") && strlen(SHORTPIXEL_API_KEY) == 20)
|
991 |
{
|
@@ -995,9 +1393,15 @@ class WPShortPixel {
|
|
995 |
$_POST['key'] = SHORTPIXEL_API_KEY;
|
996 |
}
|
997 |
|
998 |
-
|
999 |
-
|
1000 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
1001 |
|
1002 |
if ( strlen($_POST['key']) <> 20 )
|
1003 |
{
|
@@ -1014,9 +1418,9 @@ class WPShortPixel {
|
|
1014 |
if($validityData['APIKeyValid']) {
|
1015 |
if(isset($_POST['validate']) && $_POST['validate'] == "validate") {
|
1016 |
// delete last status if it was no valid key
|
1017 |
-
$lastStatus =
|
1018 |
-
if(isset($lastStatus) && $lastStatus['Status'] == ShortPixelAPI::STATUS_NO_KEY) {
|
1019 |
-
|
1020 |
}
|
1021 |
//display notification
|
1022 |
$urlParts = explode("/", get_site_url());
|
@@ -1034,7 +1438,7 @@ class WPShortPixel {
|
|
1034 |
//test that the "uploads" have the right rights and also we can create the backup dir for ShortPixel
|
1035 |
if ( !file_exists(SP_BACKUP_FOLDER) && !@mkdir(SP_BACKUP_FOLDER, 0777, true) )
|
1036 |
$notice = array("status" => "error", "msg" => "There is something preventing us to create a new folder for backing up your original files.<BR>
|
1037 |
-
Please make sure that folder <b>" . WP_CONTENT_DIR . DIRECTORY_SEPARATOR . "
|
1038 |
} else {
|
1039 |
if(isset($_POST['validate'])) {
|
1040 |
//display notification
|
@@ -1044,9 +1448,8 @@ class WPShortPixel {
|
|
1044 |
}
|
1045 |
}
|
1046 |
|
1047 |
-
|
1048 |
//if save button - we process the rest of the form elements
|
1049 |
-
if(isset($_POST['save'])) {
|
1050 |
$this->_settings->compressionType = $_POST['compressionType'];
|
1051 |
if(isset($_POST['thumbnails'])) { $this->_settings->processThumbnails = 1; } else { $this->_settings->processThumbnails = 0; }
|
1052 |
if(isset($_POST['backupImages'])) { $this->_settings->backupImages = 1; } else { $this->_settings->backupImages = 0; }
|
@@ -1059,12 +1462,42 @@ class WPShortPixel {
|
|
1059 |
$this->_settings->siteAuthUser = (isset($_POST['siteAuthUser']) ? $_POST['siteAuthUser']: $this->_settings->siteAuthUser);
|
1060 |
$this->_settings->siteAuthPass = (isset($_POST['siteAuthPass']) ? $_POST['siteAuthPass']: $this->_settings->siteAuthPass);
|
1061 |
|
1062 |
-
|
|
|
|
|
|
|
|
|
1063 |
wp_redirect("upload.php?page=wp-short-pixel-bulk");
|
1064 |
exit();
|
1065 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1066 |
}
|
1067 |
}
|
|
|
1068 |
//now output headers. They were prevented with noheaders=true in the form url in order to be able to redirect if bulk was pressed
|
1069 |
if(isset($_REQUEST['noheader'])) {
|
1070 |
require_once(ABSPATH . 'wp-admin/admin-header.php');
|
@@ -1076,17 +1509,35 @@ class WPShortPixel {
|
|
1076 |
}
|
1077 |
|
1078 |
$quotaData = $this->checkQuotaAndAlert(isset($validityData) ? $validityData : null);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1079 |
|
|
|
|
|
|
|
|
|
|
|
|
|
1080 |
if($this->_settings->verifiedKey) {
|
1081 |
$fileCount = number_format($this->_settings->fileCount);
|
1082 |
$savedSpace = self::formatBytes($this->_settings->savedSpace,2);
|
1083 |
-
$averageCompression =
|
1084 |
$savedBandwidth = self::formatBytes($this->_settings->savedSpace * 10000,2);
|
1085 |
if (is_numeric($quotaData['APICallsQuota'])) {
|
1086 |
$quotaData['APICallsQuota'] .= "/month";
|
1087 |
}
|
1088 |
$backupFolderSize = self::formatBytes(self::folderSize(SP_BACKUP_FOLDER));
|
1089 |
-
$remainingImages = $quotaData['
|
1090 |
$remainingImages = ( $remainingImages < 0 ) ? 0 : number_format($remainingImages);
|
1091 |
$totalCallsMade = number_format($quotaData['APICallsMadeNumeric'] + $quotaData['APICallsMadeOneTimeNumeric']);
|
1092 |
|
@@ -1094,16 +1545,31 @@ class WPShortPixel {
|
|
1094 |
if(is_wp_error( $resources )) {
|
1095 |
$resources = array();
|
1096 |
}
|
1097 |
-
$this->view->displaySettings(
|
1098 |
-
$quotaData, $notice, $resources, $averageCompression, $savedSpace, $savedBandwidth,
|
1099 |
-
$
|
|
|
1100 |
} else {
|
1101 |
-
$this->view->displaySettings(
|
1102 |
-
$quotaData, $notice);
|
1103 |
}
|
1104 |
|
1105 |
}
|
1106 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1107 |
public function getAverageCompression(){
|
1108 |
return $this->_settings->totalOptimized > 0
|
1109 |
? round(( 1 - ( $this->_settings->totalOptimized / $this->_settings->totalOriginal ) ) * 100, 2)
|
@@ -1138,7 +1604,7 @@ class WPShortPixel {
|
|
1138 |
}
|
1139 |
if($validate) {
|
1140 |
$args['body']['DomainCheck'] = get_site_url();
|
1141 |
-
$imageCount =
|
1142 |
$args['body']['ImagesCount'] = $imageCount['mainFiles'];
|
1143 |
$args['body']['ThumbsCount'] = $imageCount['totalFiles'] - $imageCount['mainFiles'];
|
1144 |
$argsStr .= "&DomainCheck={$args['body']['DomainCheck']}&ImagesCount={$imageCount['mainFiles']}&ThumbsCount={$args['body']['ThumbsCount']}";
|
@@ -1188,7 +1654,7 @@ class WPShortPixel {
|
|
1188 |
$response = wp_remote_get($requestURL, $args);
|
1189 |
$comm[] = array("sent" => "POST: " . $requestURL, "args" => $args, "received" => $response);
|
1190 |
}
|
1191 |
-
|
1192 |
$defaultData = array(
|
1193 |
"APIKeyValid" => false,
|
1194 |
"Message" => 'API Key could not be validated due to a connectivity error.<BR>Your firewall may be blocking us. Please contact your hosting provider and ask them to allow connections from your site to IP 176.9.106.46.<BR> If you still cannot validate your API Key after this, please <a href="https://shortpixel.com/contact" target="_blank">contact us</a> and we will try to help. ',
|
@@ -1212,7 +1678,7 @@ class WPShortPixel {
|
|
1212 |
}
|
1213 |
|
1214 |
$data = $response['body'];
|
1215 |
-
$data =
|
1216 |
|
1217 |
if(empty($data)) { return $defaultData; }
|
1218 |
|
@@ -1226,10 +1692,10 @@ class WPShortPixel {
|
|
1226 |
else
|
1227 |
$this->_settings->quotaExceeded = 1;//activate quota limiting
|
1228 |
|
1229 |
-
//if a
|
1230 |
-
$lastStatus = $this->_settings->
|
1231 |
-
if($lastStatus['Status'] == ShortPixelAPI::STATUS_NO_KEY) {
|
1232 |
-
|
1233 |
}
|
1234 |
|
1235 |
return array(
|
@@ -1242,6 +1708,7 @@ class WPShortPixel {
|
|
1242 |
"APICallsQuotaNumeric" => $data->APICallsQuota,
|
1243 |
"APICallsMadeOneTimeNumeric" => $data->APICallsMadeOneTime,
|
1244 |
"APICallsQuotaOneTimeNumeric" => $data->APICallsQuotaOneTime,
|
|
|
1245 |
"APILastRenewalDate" => $data->DateSubscription,
|
1246 |
"DomainCheck" => (isset($data->DomainCheck) ? $data->DomainCheck : null)
|
1247 |
);
|
@@ -1257,9 +1724,6 @@ class WPShortPixel {
|
|
1257 |
$quotaExceeded = $this->_settings->quotaExceeded;
|
1258 |
$renderData = array("id" => $id, "showActions" => current_user_can( 'manage_options' ));
|
1259 |
|
1260 |
-
$data2 = $data;
|
1261 |
-
|
1262 |
-
|
1263 |
if($invalidKey) { //invalid key - let the user first register and only then
|
1264 |
$renderData['status'] = 'invalidKey';
|
1265 |
$this->view->renderCustomColumn($id, $renderData);
|
@@ -1315,16 +1779,16 @@ class WPShortPixel {
|
|
1315 |
}
|
1316 |
elseif(isset($data['ShortPixel']['WaitingProcessing'])) {
|
1317 |
$renderData['status'] = $quotaExceeded ? 'quotaExceeded' : 'retry';
|
1318 |
-
$renderData['message'] = "<img src=\"" . plugins_url( 'img/loading.gif', __FILE__ ) . "\" class='sp-loading-small'> Image waiting to be processed.";
|
1319 |
-
if($id > $this->prioQ->getFlagBulkId()) $this->prioQ->push($id); //should be there but just to make sure
|
1320 |
}
|
1321 |
else { //finally
|
1322 |
$renderData['status'] = $quotaExceeded ? 'quotaExceeded' : 'optimizeNow';
|
1323 |
$sizes = isset($data['sizes']) ? count($data['sizes']) : 0;
|
1324 |
$renderData['thumbsTotal'] = $sizes;
|
1325 |
$renderData['message'] = ($fileExtension == "pdf" ? 'PDF' : 'Image') . ' not processed.';
|
1326 |
-
}
|
1327 |
-
|
1328 |
$this->view->renderCustomColumn($id, $renderData);
|
1329 |
}
|
1330 |
}
|
@@ -1337,23 +1801,58 @@ class WPShortPixel {
|
|
1337 |
return $defaults;
|
1338 |
}
|
1339 |
|
1340 |
-
public function
|
1341 |
-
$
|
1342 |
-
|
1343 |
-
|
|
|
|
|
1344 |
}
|
1345 |
|
1346 |
-
public function
|
1347 |
-
|
1348 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1349 |
} else {
|
1350 |
-
|
1351 |
-
|
1352 |
-
|
|
|
|
|
|
|
|
|
1353 |
}
|
1354 |
-
return $
|
1355 |
}
|
1356 |
|
|
|
|
|
|
|
|
|
|
|
1357 |
|
1358 |
static public function formatBytes($bytes, $precision = 2) {
|
1359 |
$units = array('B', 'KB', 'MB', 'GB', 'TB');
|
@@ -1374,7 +1873,7 @@ class WPShortPixel {
|
|
1374 |
|
1375 |
static public function isProcessablePath($path) {
|
1376 |
$pathParts = pathinfo($path);
|
1377 |
-
if( isset($pathParts['extension']) && in_array(strtolower($pathParts['extension']),
|
1378 |
return true;
|
1379 |
} else {
|
1380 |
return false;
|
@@ -1383,50 +1882,14 @@ class WPShortPixel {
|
|
1383 |
|
1384 |
|
1385 |
//return an array with URL(s) and PATH(s) for this file
|
1386 |
-
public function getURLsAndPATHs($
|
1387 |
-
|
1388 |
-
if ( !parse_url(WP_CONTENT_URL, PHP_URL_SCHEME) ) {//no absolute URLs used -> we implement a hack
|
1389 |
-
$url = get_site_url() . wp_get_attachment_url($ID);//get the file URL
|
1390 |
-
}
|
1391 |
-
else {
|
1392 |
-
$url = wp_get_attachment_url($ID);//get the file URL
|
1393 |
-
}
|
1394 |
-
$urlList[] = $url;
|
1395 |
-
$path = get_attached_file($ID);//get the full file PATH
|
1396 |
-
$filePath[] = $path;
|
1397 |
-
|
1398 |
-
if ( $meta == NULL ) {
|
1399 |
-
$meta = wp_get_attachment_metadata($ID);
|
1400 |
-
}
|
1401 |
-
|
1402 |
-
//it is NOT a PDF file and thumbs are processable
|
1403 |
-
if ( strtolower(substr($filePath[0],strrpos($filePath[0], ".")+1)) != "pdf"
|
1404 |
-
&& ($this->_settings->processThumbnails || $onlyThumbs)
|
1405 |
-
&& isset($meta['sizes']) && is_array($meta['sizes']))
|
1406 |
-
{
|
1407 |
-
foreach( $meta['sizes'] as $thumbnailInfo ) {
|
1408 |
-
if(isset($thumbnailInfo['file'])) {
|
1409 |
-
$urlList[] = str_replace(ShortPixelAPI::MB_basename($urlList[0]), $thumbnailInfo['file'], $url);
|
1410 |
-
$filePath[] = str_replace(ShortPixelAPI::MB_basename($filePath[0]), $thumbnailInfo['file'], $path);
|
1411 |
-
}
|
1412 |
-
}
|
1413 |
-
}
|
1414 |
-
if(!isset($meta['sizes']) || !is_array($meta['sizes'])) {
|
1415 |
-
self::log("getURLsAndPATHs: no meta sizes for ID $ID : " . json_encode($meta));
|
1416 |
-
}
|
1417 |
-
|
1418 |
-
if($onlyThumbs) { //remove the main image
|
1419 |
-
array_shift($urlList);
|
1420 |
-
array_shift($filePath);
|
1421 |
-
}
|
1422 |
-
return array("URLs" => $urlList, "PATHs" => $filePath);
|
1423 |
}
|
1424 |
|
1425 |
|
1426 |
public static function deleteDir($dirPath) {
|
1427 |
-
if (substr($dirPath, strlen($dirPath) - 1, 1) !=
|
1428 |
-
|
1429 |
-
$dirPath .= '/';
|
1430 |
}
|
1431 |
$files = glob($dirPath . '*', GLOB_MARK);
|
1432 |
foreach ($files as $file) {
|
@@ -1446,7 +1909,7 @@ class WPShortPixel {
|
|
1446 |
} else {
|
1447 |
return $total_size;
|
1448 |
}
|
1449 |
-
$cleanPath = rtrim($path,
|
1450 |
foreach($files as $t) {
|
1451 |
if ($t<>"." && $t<>"..")
|
1452 |
{
|
@@ -1464,200 +1927,34 @@ class WPShortPixel {
|
|
1464 |
return $total_size;
|
1465 |
}
|
1466 |
|
1467 |
-
public static function getMaxMediaId() {
|
1468 |
-
global $wpdb;
|
1469 |
-
$queryMax = "SELECT max(post_id) as QueryID FROM " . $wpdb->prefix . "postmeta";
|
1470 |
-
$resultQuery = $wpdb->get_results($queryMax);
|
1471 |
-
return $resultQuery[0]->QueryID;
|
1472 |
-
}
|
1473 |
-
|
1474 |
-
public function getMinMediaId() {
|
1475 |
-
global $wpdb;
|
1476 |
-
$queryMax = "SELECT min(post_id) as QueryID FROM " . $wpdb->prefix . "postmeta";
|
1477 |
-
$resultQuery = $wpdb->get_results($queryMax);
|
1478 |
-
return $resultQuery[0]->QueryID;
|
1479 |
-
}
|
1480 |
-
|
1481 |
-
protected function getOptimalChunkSize() {
|
1482 |
-
global $wpdb;
|
1483 |
-
$cnt = $wpdb->get_results("SELECT count(*) posts FROM " . $wpdb->prefix . "posts");
|
1484 |
-
$posts = isset($cnt) && count($cnt) > 0 ? $cnt[0]->posts : 0;
|
1485 |
-
if($posts > 100000) {
|
1486 |
-
return 20000;
|
1487 |
-
} elseif ($posts > 50000) {
|
1488 |
-
return 5000;
|
1489 |
-
} elseif($posts > 10000) {
|
1490 |
-
return 2000;
|
1491 |
-
} else {
|
1492 |
-
return 500;
|
1493 |
-
}
|
1494 |
-
}
|
1495 |
-
|
1496 |
-
protected function getPostIdsChunk($minId, $maxId, $pointer, $limit) {
|
1497 |
-
global $wpdb;
|
1498 |
-
|
1499 |
-
$ids = array();
|
1500 |
-
$idList = $wpdb->get_results("SELECT ID, post_mime_type FROM " . $wpdb->prefix . "posts
|
1501 |
-
WHERE ( ID <= $maxId AND ID > $minId )
|
1502 |
-
LIMIT $pointer,$limit");
|
1503 |
-
if ( empty($idList) ) {
|
1504 |
-
return null;
|
1505 |
-
}
|
1506 |
-
foreach($idList as $item) {
|
1507 |
-
if($item->post_mime_type != '') {
|
1508 |
-
$ids[] = $item->ID;
|
1509 |
-
}
|
1510 |
-
}
|
1511 |
-
return $ids;
|
1512 |
-
}
|
1513 |
-
|
1514 |
-
//count all the processable files in media library (while limiting the results to max 10000)
|
1515 |
-
public function countAllProcessableFiles($maxId = PHP_INT_MAX, $minId = 0){
|
1516 |
-
global $wpdb;
|
1517 |
-
|
1518 |
-
$totalFiles = $mainFiles = $processedMainFiles = $processedTotalFiles =
|
1519 |
-
$procLossyMainFiles = $procLossyTotalFiles = $procLosslessMainFiles = $procLosslessTotalFiles = $mainUnprocessedThumbs = 0;
|
1520 |
-
$filesMap = $processedFilesMap = array();
|
1521 |
-
$limit = $this->getOptimalChunkSize();
|
1522 |
-
$pointer = 0;
|
1523 |
-
$filesWithErrors = array();
|
1524 |
-
|
1525 |
-
//count all the files, main and thumbs
|
1526 |
-
while ( 1 ) {
|
1527 |
-
/* ALTERNATE CODE WITH JOIN - seems less efficient than select ids / select in
|
1528 |
-
$filesList= $wpdb->get_results("SELECT pm.* FROM " . $wpdb->prefix . "postmeta pm
|
1529 |
-
INNER JOIN " . $wpdb->prefix . "posts p on p.ID = pm.post_id
|
1530 |
-
WHERE ( p.ID <= $maxId AND p.ID > $minId ) and p.post_mime_type <> ''
|
1531 |
-
AND ( pm.meta_key = '_wp_attached_file' OR pm.meta_key = '_wp_attachment_metadata' )
|
1532 |
-
LIMIT $pointer,$limit");
|
1533 |
-
if ( empty($filesList) ) //we parsed all the results
|
1534 |
-
break;
|
1535 |
-
*/
|
1536 |
-
$ids = $this->getPostIdsChunk($minId, $maxId, $pointer, $limit);
|
1537 |
-
if($ids === null) {
|
1538 |
-
break; //we parsed all the results
|
1539 |
-
}
|
1540 |
-
elseif(count($ids) == 0) {
|
1541 |
-
$pointer += $limit;
|
1542 |
-
continue;
|
1543 |
-
}
|
1544 |
-
|
1545 |
-
$filesList= $wpdb->get_results("SELECT * FROM " . $wpdb->prefix . "postmeta
|
1546 |
-
WHERE post_id IN (" . implode(',', $ids) . ")
|
1547 |
-
AND ( meta_key = '_wp_attached_file' OR meta_key = '_wp_attachment_metadata' )");
|
1548 |
-
|
1549 |
-
foreach ( $filesList as $file )
|
1550 |
-
{
|
1551 |
-
if ( $file->meta_key == "_wp_attached_file" )
|
1552 |
-
{//count pdf files only
|
1553 |
-
$extension = substr($file->meta_value, strrpos($file->meta_value,".") + 1 );
|
1554 |
-
if ( $extension == "pdf" && !isset($filesMap[$file->meta_value]))
|
1555 |
-
{
|
1556 |
-
$totalFiles++;
|
1557 |
-
$mainFiles++;
|
1558 |
-
$filesMap[$file->meta_value] = 1;
|
1559 |
-
}
|
1560 |
-
}
|
1561 |
-
else //_wp_attachment_metadata
|
1562 |
-
{
|
1563 |
-
$attachment = unserialize($file->meta_value);
|
1564 |
-
//processable
|
1565 |
-
$isProcessable = false;
|
1566 |
-
if(isset($attachment['file']) && !isset($filesMap[$attachment['file']]) && self::isProcessablePath($attachment['file'])){
|
1567 |
-
$isProcessable = true;
|
1568 |
-
if ( isset($attachment['sizes']) ) {
|
1569 |
-
$totalFiles += count($attachment['sizes']);
|
1570 |
-
}
|
1571 |
-
if ( isset($attachment['file']) )
|
1572 |
-
{
|
1573 |
-
$totalFiles++;
|
1574 |
-
$mainFiles++;
|
1575 |
-
$filesMap[$attachment['file']] = 1;
|
1576 |
-
}
|
1577 |
-
}
|
1578 |
-
//processed
|
1579 |
-
if (isset($attachment['ShortPixelImprovement'])
|
1580 |
-
&& ($attachment['ShortPixelImprovement'] > 0 || $attachment['ShortPixelImprovement'] === 0.0 || $attachment['ShortPixelImprovement'] === "0")
|
1581 |
-
//for PDFs there is no file field so just let it pass.
|
1582 |
-
&& (!isset($attachment['file']) || !isset($processedFilesMap[$attachment['file']])) ) {
|
1583 |
-
|
1584 |
-
//add main file to counts
|
1585 |
-
$processedMainFiles++;
|
1586 |
-
$processedTotalFiles++;
|
1587 |
-
$type = isset($attachment['ShortPixel']['type']) ? $attachment['ShortPixel']['type'] : null;
|
1588 |
-
if($type == 'lossy') {
|
1589 |
-
$procLossyMainFiles++;
|
1590 |
-
$procLossyTotalFiles++;
|
1591 |
-
} else {
|
1592 |
-
$procLosslessMainFiles++;
|
1593 |
-
$procLosslessTotalFiles++;
|
1594 |
-
}
|
1595 |
-
|
1596 |
-
//get the thumbs processed for that attachment
|
1597 |
-
$thumbs = $allThumbs = 0;
|
1598 |
-
if ( isset($attachment['ShortPixel']['thumbsOpt']) ) {
|
1599 |
-
$thumbs = $attachment['ShortPixel']['thumbsOpt'];
|
1600 |
-
}
|
1601 |
-
elseif ( isset($attachment['sizes']) ) {
|
1602 |
-
$thumbs = count($attachment['sizes']);
|
1603 |
-
}
|
1604 |
-
if ( isset($attachment['sizes']) && count($attachment['sizes']) > $thumbs) {
|
1605 |
-
$mainUnprocessedThumbs++;
|
1606 |
-
}
|
1607 |
-
|
1608 |
-
//increment with thumbs processed
|
1609 |
-
$processedTotalFiles += $thumbs;
|
1610 |
-
if($type == 'lossy') {
|
1611 |
-
$procLossyTotalFiles += $thumbs;
|
1612 |
-
} else {
|
1613 |
-
$procLosslessTotalFiles += $thumbs;
|
1614 |
-
}
|
1615 |
-
|
1616 |
-
if ( isset($attachment['file']) ) {
|
1617 |
-
$processedFilesMap[$attachment['file']] = 1;
|
1618 |
-
}
|
1619 |
-
}
|
1620 |
-
elseif($isProcessable && isset($attachment['ShortPixelImprovement']) && count($filesWithErrors) < 50) {
|
1621 |
-
$filePath = explode("/", $attachment["file"]);
|
1622 |
-
$name = is_array($filePath)? $filePath[count($filePath) - 1] : $file->post_id;
|
1623 |
-
$filesWithErrors[$file->post_id] = array('Name' => $name, 'Message' => $attachment['ShortPixelImprovement']);
|
1624 |
-
}
|
1625 |
-
|
1626 |
-
}
|
1627 |
-
}
|
1628 |
-
unset($filesList);
|
1629 |
-
$pointer += $limit;
|
1630 |
-
|
1631 |
-
}//end while
|
1632 |
-
|
1633 |
-
return array("totalFiles" => $totalFiles, "mainFiles" => $mainFiles,
|
1634 |
-
"totalProcessedFiles" => $processedTotalFiles, "mainProcessedFiles" => $processedMainFiles,
|
1635 |
-
"totalProcLossyFiles" => $procLossyTotalFiles, "mainProcLossyFiles" => $procLossyMainFiles,
|
1636 |
-
"totalProcLosslessFiles" => $procLosslessTotalFiles, "mainProcLosslessFiles" => $procLosslessMainFiles,
|
1637 |
-
"mainUnprocessedThumbs" => $mainUnprocessedThumbs,
|
1638 |
-
"filesWithErrors" => $filesWithErrors
|
1639 |
-
);
|
1640 |
-
}
|
1641 |
-
|
1642 |
public function migrateBackupFolder() {
|
1643 |
-
$oldBackupFolder = WP_CONTENT_DIR . DIRECTORY_SEPARATOR .
|
1644 |
|
1645 |
-
if(
|
1646 |
|
1647 |
if(!file_exists(SP_BACKUP_FOLDER)) {
|
1648 |
-
|
1649 |
-
|
1650 |
-
|
1651 |
|
1652 |
-
|
1653 |
-
|
1654 |
-
|
|
|
|
|
|
|
|
|
|
|
1655 |
}
|
1656 |
-
|
1657 |
-
if(
|
1658 |
-
@
|
|
|
|
|
|
|
|
|
|
|
1659 |
}
|
1660 |
-
|
1661 |
return;
|
1662 |
}
|
1663 |
|
@@ -1691,7 +1988,7 @@ class WPShortPixel {
|
|
1691 |
*/
|
1692 |
public static function encrypt($pure_string, $encryption_key)
|
1693 |
{
|
1694 |
-
if(!function_exists("mcrypt_get_iv_size")
|
1695 |
return "";
|
1696 |
}
|
1697 |
$iv_size = \mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB);
|
@@ -1725,7 +2022,6 @@ class WPShortPixel {
|
|
1725 |
return $this->_settings;
|
1726 |
}
|
1727 |
|
1728 |
-
|
1729 |
public function getResizeImages() {
|
1730 |
return $this->_settings->resizeImages;
|
1731 |
}
|
@@ -1746,20 +2042,57 @@ class WPShortPixel {
|
|
1746 |
public function getCompressionType() {
|
1747 |
return $this->_settings->compressionType;
|
1748 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1749 |
|
1750 |
}
|
1751 |
|
1752 |
-
|
1753 |
-
|
1754 |
-
return;
|
1755 |
-
}
|
1756 |
-
$pluginInstance = new WPShortPixel;
|
1757 |
global $pluginInstance;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1758 |
}
|
1759 |
|
1760 |
-
|
1761 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1762 |
|
|
|
|
|
|
|
|
|
|
|
1763 |
register_activation_hook( __FILE__, array( 'WPShortPixel', 'shortPixelActivatePlugin' ) );
|
1764 |
register_deactivation_hook( __FILE__, array( 'WPShortPixel', 'shortPixelDeactivatePlugin' ) );
|
1765 |
|
3 |
* Plugin Name: ShortPixel Image Optimizer
|
4 |
* Plugin URI: https://shortpixel.com/
|
5 |
* Description: ShortPixel optimizes images automatically, while guarding the quality of your images. Check your <a href="options-general.php?page=wp-shortpixel" target="_blank">Settings > ShortPixel</a> page on how to start optimizing your image library and make your website load faster.
|
6 |
+
* Version: 4.0.0
|
7 |
* Author: ShortPixel
|
8 |
* Author URI: https://shortpixel.com
|
9 |
*/
|
10 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
11 |
define('SP_RESET_ON_ACTIVATE', false); //if true TODO set false
|
12 |
|
13 |
define('SP_AFFILIATE_CODE', '');
|
14 |
|
15 |
+
define('PLUGIN_VERSION', "4.0.0");
|
16 |
define('SP_MAX_TIMEOUT', 10);
|
17 |
define('SP_VALIDATE_MAX_TIMEOUT', 15);
|
18 |
define('SP_BACKUP', 'ShortpixelBackups');
|
|
|
19 |
define('MAX_API_RETRIES', 50);
|
20 |
define('MAX_ERR_RETRIES', 5);
|
21 |
+
define('MAX_FAIL_RETRIES', 3);
|
22 |
$MAX_EXECUTION_TIME = ini_get('max_execution_time');
|
23 |
|
24 |
+
require_once(ABSPATH . 'wp-admin/includes/file.php');
|
25 |
+
|
26 |
+
$sp__uploads = wp_upload_dir();
|
27 |
+
define('SP_UPLOADS_BASE', $sp__uploads['basedir']);
|
28 |
+
define('SP_UPLOADS_NAME', basename(is_main_site() ? SP_UPLOADS_BASE : dirname(dirname(SP_UPLOADS_BASE))));
|
29 |
+
define('SP_UPLOADS_BASE_REL', str_replace(get_home_path(),"", $sp__uploads['basedir']));
|
30 |
+
$sp__backupBase = is_main_site() ? SP_UPLOADS_BASE : dirname(dirname(SP_UPLOADS_BASE));
|
31 |
+
define('SP_BACKUP_FOLDER', $sp__backupBase . DIRECTORY_SEPARATOR . SP_BACKUP);
|
32 |
+
|
33 |
/*
|
34 |
if ( is_numeric($MAX_EXECUTION_TIME) && $MAX_EXECUTION_TIME > 10 )
|
35 |
define('MAX_EXECUTION_TIME', $MAX_EXECUTION_TIME - 5 ); //in seconds
|
50 |
private $_settings = null;
|
51 |
private $prioQ = null;
|
52 |
private $view = null;
|
53 |
+
|
54 |
+
private $hasNextGen = false;
|
55 |
+
private $spMetaDao = null;
|
56 |
+
|
57 |
+
public static $PROCESSABLE_EXTENSIONS = array('jpg', 'jpeg', 'gif', 'png', 'pdf');
|
58 |
|
59 |
public function __construct() {
|
60 |
if (!session_id()) {
|
61 |
session_start();
|
62 |
}
|
63 |
+
|
64 |
+
require_once('wp-shortpixel-req.php');
|
65 |
|
66 |
$isAdminUser = current_user_can( 'manage_options' );
|
67 |
|
68 |
$this->_affiliateSufix = (strlen(SP_AFFILIATE_CODE)) ? "/affiliate/" . SP_AFFILIATE_CODE : "";
|
69 |
$this->_settings = new WPShortPixelSettings();
|
70 |
$this->_apiInterface = new ShortPixelAPI($this->_settings);
|
71 |
+
$this->hasNextGen = ShortPixelNextGenAdapter::hasNextGen();
|
72 |
+
$this->spMetaDao = new ShortPixelCustomMetaDao(new WpShortPixelDb(), $this->_settings->hasCustomFolders);
|
73 |
$this->prioQ = new ShortPixelQueue($this, $this->_settings);
|
74 |
$this->view = new ShortPixelView($this);
|
75 |
|
78 |
$this->setDefaultViewModeList();//set default mode as list. only @ first run
|
79 |
|
80 |
//add hook for image upload processing
|
81 |
+
//add_filter( 'wp_generate_attachment_metadata', array( &$this, 'handleMediaLibraryImageUpload' ), 10, 2 ); // now external
|
82 |
add_filter( 'plugin_action_links_' . plugin_basename(__FILE__), array(&$this, 'generatePluginLinks'));//for plugin settings page
|
83 |
|
84 |
//add_action( 'admin_footer', array(&$this, 'handleImageProcessing'));
|
86 |
//Media custom column
|
87 |
add_filter( 'manage_media_columns', array( &$this, 'columns' ) );//add media library column header
|
88 |
add_action( 'manage_media_custom_column', array( &$this, 'generateCustomColumn' ), 10, 2 );//generate the media library column
|
89 |
+
//for NextGen
|
90 |
+
if($this->_settings->hasCustomFolders) {
|
91 |
+
add_filter( 'ngg_manage_images_columns', array( &$this, 'nggColumns' ) );
|
92 |
+
add_filter( 'ngg_manage_images_number_of_columns', array( &$this, 'nggCountColumns' ) );
|
93 |
+
add_filter( 'ngg_manage_images_column_7_header', array( &$this, 'nggColumnHeader' ) );
|
94 |
+
add_filter( 'ngg_manage_images_column_7_content', array( &$this, 'nggColumnContent' ) );
|
95 |
+
// hook on the NextGen gallery list update
|
96 |
+
add_action('ngg_update_addgallery_page', array( &$this, 'addNextGenGalleriesToCustom'));
|
97 |
+
}
|
98 |
+
|
99 |
//custom hook
|
100 |
add_action( 'shortpixel-optimize-now', array( &$this, 'optimizeNowHook' ), 10, 1);
|
101 |
|
103 |
//add settings page
|
104 |
add_action( 'admin_menu', array( &$this, 'registerSettingsPage' ) );//display SP in Settings menu
|
105 |
add_action( 'admin_menu', array( &$this, 'registerAdminPage' ) );
|
106 |
+
|
107 |
+
add_action('wp_ajax_shortpixel_browse_content', array(&$this, 'browseContent'));
|
108 |
|
109 |
add_action( 'delete_attachment', array( &$this, 'handleDeleteAttachmentInBackup' ) );
|
110 |
add_action( 'load-upload.php', array( &$this, 'handleCustomBulk'));
|
129 |
add_action( 'wp_ajax_shortpixel_dismiss_media_alert', array(&$this, 'dismissMediaAlert'));
|
130 |
//check quota
|
131 |
add_action('admin_action_shortpixel_check_quota', array(&$this, 'handleCheckQuota'));
|
|
|
132 |
//This adds the constants used in PHP to be available also in JS
|
133 |
add_action( 'admin_footer', array( &$this, 'shortPixelJS') );
|
134 |
+
|
135 |
+
if($this->_settings->frontBootstrap) {
|
136 |
+
//also need to have it in the front footer then
|
137 |
+
add_action( 'wp_footer', array( &$this, 'shortPixelJS') );
|
138 |
+
//need to add the nopriv action for when items exist in the queue and no user is logged in
|
139 |
+
add_action( 'wp_ajax_nopriv_shortpixel_image_processing', array( &$this, 'handleImageProcessing') );
|
140 |
+
}
|
141 |
//register a method to display admin notices if necessary
|
142 |
add_action('admin_notices', array( &$this, 'displayAdminNotices'));
|
143 |
+
|
144 |
$this->migrateBackupFolder();
|
145 |
|
146 |
if(!$this->_settings->redirectedSettings && !$this->_settings->verifiedKey && (!function_exists("is_multisite") || !is_multisite())) {
|
160 |
}
|
161 |
|
162 |
function registerAdminPage( ) {
|
163 |
+
if(count($this->spMetaDao->hasFoldersTable() && $this->spMetaDao->getFolders())) {
|
164 |
+
add_media_page( 'Other Media Optimized by ShortPixel', 'Other Media', 'edit_others_posts', 'wp-short-pixel-custom', array( &$this, 'listCustomMedia' ) );
|
165 |
+
}
|
166 |
add_media_page( 'ShortPixel Bulk Process', 'Bulk ShortPixel', 'edit_others_posts', 'wp-short-pixel-bulk', array( &$this, 'bulkProcess' ) );
|
167 |
}
|
168 |
|
177 |
|
178 |
public static function shortPixelDeactivatePlugin()//reset some params to avoid trouble for plugins that were activated/deactivated/activated
|
179 |
{
|
180 |
+
include_once dirname( __FILE__ ) . '/wp-shortpixel-req.php';
|
181 |
ShortPixelQueue::resetBulk();
|
182 |
ShortPixelQueue::resetPrio();
|
183 |
WPShortPixelSettings::onDeactivate();
|
185 |
|
186 |
public function displayAdminNotices() {
|
187 |
if(!$this->_settings->verifiedKey) {
|
188 |
+
$dismissed = $this->_settings->dismissedNotices ? $this->_settings->dismissedNotices : array();
|
189 |
$now = time();
|
190 |
+
$act = $this->_settings->activationDate ? $this->_settings->activationDate : $now;
|
191 |
+
if($this->_settings->activationNotice && $this->_settings->redirectedSettings >= 2) {
|
192 |
ShortPixelView::displayActivationNotice();
|
193 |
+
$this->_settings->activationNotice = null;
|
194 |
}
|
195 |
if( ($now > $act + 7200) && !isset($dismissed['2h'])) {
|
196 |
ShortPixelView::displayActivationNotice('2h');
|
202 |
|
203 |
public function dismissAdminNotice() {
|
204 |
$noticeId = preg_replace('|[^a-z0-9]|i', '', $_GET['notice_id']);
|
205 |
+
$dismissed = $this->_settings->dismissedNotices ? $this->_settings->dismissedNotices : array();
|
206 |
$dismissed[$noticeId] = true;
|
207 |
+
$this->_settings->dismissedNotices = $dismissed;
|
208 |
die(json_encode(array("Status" => 'success', "Message" => 'Notice ID: ' . $noticeId . ' dismissed')));
|
209 |
}
|
210 |
|
216 |
//set default move as "list". only set once, it won't try to set the default mode again.
|
217 |
public function setDefaultViewModeList()
|
218 |
{
|
219 |
+
if($this->_settings->mediaLibraryViewMode === false)
|
220 |
{
|
221 |
+
$this->_settings->mediaLibraryViewMode = 1;
|
222 |
if ( function_exists('get_currentuserinfo') )
|
223 |
{
|
224 |
global $current_user;
|
242 |
|
243 |
function shortPixelJS() { ?>
|
244 |
<script type="text/javascript" >
|
245 |
+
var ShortPixelConstants = {
|
246 |
+
STATUS_SUCCESS: <?php echo ShortPixelAPI::STATUS_SUCCESS; ?>,
|
247 |
+
STATUS_EMPTY_QUEUE: <?php echo self::BULK_EMPTY_QUEUE; ?>,
|
248 |
+
STATUS_ERROR: <?php echo ShortPixelAPI::STATUS_ERROR; ?>,
|
249 |
+
STATUS_FAIL: <?php echo ShortPixelAPI::STATUS_FAIL; ?>,
|
250 |
+
STATUS_QUOTA_EXCEEDED: <?php echo ShortPixelAPI::STATUS_QUOTA_EXCEEDED; ?>,
|
251 |
+
STATUS_SKIP: <?php echo ShortPixelAPI::STATUS_SKIP; ?>,
|
252 |
+
STATUS_NO_KEY: <?php echo ShortPixelAPI::STATUS_NO_KEY; ?>,
|
253 |
+
STATUS_RETRY: <?php echo ShortPixelAPI::STATUS_RETRY; ?>,
|
254 |
+
WP_PLUGIN_URL: '<?php echo plugins_url( '', __FILE__ ); ?>',
|
255 |
+
WP_ADMIN_URL: '<?php echo admin_url(); ?>',
|
256 |
+
API_KEY: "<?php echo $this->_settings->apiKey; ?>",
|
257 |
+
MEDIA_ALERT: '<?php echo $this->_settings->mediaAlert ? "done" : "todo"; ?>',
|
258 |
+
FRONT_BOOTSTRAP: <?php echo $this->_settings->frontBootstrap && (time() - $this->_settings->lastBackAction > 60) ? 1 : 0; ?>,
|
259 |
+
AJAX_URL: '<?php echo admin_url('admin-ajax.php'); ?>'
|
260 |
+
};
|
|
|
|
|
261 |
</script> <?php
|
262 |
+
wp_enqueue_style('short-pixel.css', plugins_url('/res/css/short-pixel.css',__FILE__) );
|
263 |
+
wp_enqueue_script('short-pixel.js', plugins_url('/res/js/short-pixel.js',__FILE__) );
|
264 |
+
wp_enqueue_script('jquery.knob.js', plugins_url('/res/js/jquery.knob.js',__FILE__) );
|
265 |
+
wp_enqueue_script('jquery.tooltip.js', plugins_url('/res/js/jquery.tooltip.js',__FILE__) );
|
266 |
}
|
267 |
|
268 |
function toolbar_shortpixel_processing( $wp_admin_bar ) {
|
284 |
//$blank = '_blank';
|
285 |
//$icon = "shortpixel-alert.png";
|
286 |
}
|
287 |
+
$lastStatus = $this->_settings->bulkLastStatus;
|
288 |
+
if($lastStatus && $lastStatus['Status'] != ShortPixelAPI::STATUS_SUCCESS) {
|
289 |
$extraClasses = " shortpixel-alert shortpixel-processing";
|
290 |
$tooltip = $lastStatus['Message'];
|
291 |
}
|
|
|
|
|
292 |
|
293 |
$args = array(
|
294 |
'id' => 'shortpixel_processing',
|
295 |
'title' => '<div title="' . $tooltip . '" ><img src="'
|
296 |
+
. plugins_url( 'res/img/'.$icon, __FILE__ ) . '" success-url="' . $successLink . '"><span class="shp-alert">!</span></div>',
|
297 |
'href' => $link,
|
298 |
'meta' => array('target'=> $blank, 'class' => 'shortpixel-toolbar-processing' . $extraClasses)
|
299 |
);
|
328 |
}
|
329 |
}
|
330 |
|
331 |
+
/**
|
332 |
+
* this is hooked onto the MediaLibrary image upload
|
333 |
+
* @param array $meta - the wordpress postmeta structure
|
334 |
+
* @param type $ID - the Media Library ID
|
335 |
+
* @return the meta structure updated with ShortPixel info if case
|
336 |
+
*/
|
337 |
+
public function handleMediaLibraryImageUpload($meta, $ID = null)
|
338 |
{
|
339 |
if( !$this->_settings->verifiedKey) {// no API Key set/verified -> do nothing here, just return
|
340 |
return $meta;
|
350 |
else
|
351 |
{//the kind of file we can process. goody.
|
352 |
$this->prioQ->push($ID);
|
353 |
+
$itemHandler = new ShortPixelMetaFacade($ID);
|
354 |
+
$itemHandler->setRawMeta($meta);
|
355 |
+
$URLsAndPATHs = $this->getURLsAndPATHs($itemHandler);
|
356 |
//send a processing request right after a file was uploaded, do NOT wait for response
|
357 |
$this->_apiInterface->doRequests($URLsAndPATHs['URLs'], false, $ID);
|
358 |
self::log("IMG: sent: " . json_encode($URLsAndPATHs));
|
360 |
return $meta;
|
361 |
}
|
362 |
|
363 |
+
}//end handleMediaLibraryImageUpload
|
364 |
|
365 |
+
/**
|
366 |
+
* this is hooked onto the NextGen upload
|
367 |
+
* @param type $image
|
368 |
+
*/
|
369 |
+
public function handleNextGenImageUpload($image) {
|
370 |
+
if($this->_settings->includeNextGen == 1) {
|
371 |
+
$imageFsPath = ShortPixelNextGenAdapter::getImageAbspath($image);
|
372 |
+
|
373 |
+
$customFolders = $this->spMetaDao->getFolders();
|
374 |
+
|
375 |
+
$folderId = -1;
|
376 |
+
foreach($customFolders as $folder) {
|
377 |
+
if(strpos($imageFsPath, $folder->getPath()) === 0) {
|
378 |
+
$folderId = $folder->getId();
|
379 |
+
break;
|
380 |
+
}
|
381 |
+
}
|
382 |
+
if($folderId == -1) { //if not found, create
|
383 |
+
$galleryPath = dirname($imageFsPath);
|
384 |
+
$folder = new ShortPixelFolder(array("path" => $galleryPath));
|
385 |
+
$folderMsg = $this->spMetaDao->saveFolder($folder);
|
386 |
+
$folderId = $folder->getId();
|
387 |
+
self::log("NG Image Upload: created folder from path $galleryPath : Folder info: " . json_encode($folder));
|
388 |
+
}
|
389 |
+
$pathParts = explode(DIRECTORY_SEPARATOR, trim($imageFsPath));
|
390 |
+
//Add the main image
|
391 |
+
$meta = new ShortPixelMeta();
|
392 |
+
$meta->setPath($imageFsPath);
|
393 |
+
$meta->setName($pathParts[count($pathParts) - 1]);
|
394 |
+
$meta->setFolderId($folderId);
|
395 |
+
$meta->setExtMetaId($image->pid); // do this only for main image, not for thumbnais.
|
396 |
+
$meta->setCompressionType($this->_settings->compressionType);
|
397 |
+
$meta->setKeepExif($this->_settings->keepExif);
|
398 |
+
$meta->setCmyk2rgb($this->_settings->CMYKtoRGBconversion);
|
399 |
+
$meta->setResize($this->_settings->resizeImages);
|
400 |
+
$meta->setResizeWidth($this->_settings->resizeWidth);
|
401 |
+
$meta->setResizeHeight($this->_settings->resizeHeight);
|
402 |
+
$ID = $this->spMetaDao->addImage($meta);
|
403 |
+
$meta->setId($ID);
|
404 |
+
$this->prioQ->push('C-' . $ID);
|
405 |
+
//add the thumb image if exists
|
406 |
+
$pathParts[] = "thumbs_" . $pathParts[count($pathParts) - 1];
|
407 |
+
$pathParts[count($pathParts) - 2] = "thumbs";
|
408 |
+
$thumbPath = implode(DIRECTORY_SEPARATOR, $pathParts);
|
409 |
+
if(file_exists($thumbPath)) {
|
410 |
+
$metaThumb = new ShortPixelMeta();
|
411 |
+
$metaThumb->setPath($thumbPath);
|
412 |
+
$metaThumb->setName($pathParts[count($pathParts) - 1]);
|
413 |
+
$metaThumb->setFolderId($folderId);
|
414 |
+
$metaThumb->setCompressionType($this->_settings->compressionType);
|
415 |
+
$metaThumb->setKeepExif($this->_settings->keepExif);
|
416 |
+
$metaThumb->setCmyk2rgb($this->_settings->CMYKtoRGBconversion);
|
417 |
+
$metaThumb->setResize($this->_settings->resizeImages);
|
418 |
+
$metaThumb->setResizeWidth($this->_settings->resizeWidth);
|
419 |
+
$metaThumb->setResizeHeight($this->_settings->resizeHeight);
|
420 |
+
$ID = $this->spMetaDao->addImage($metaThumb);
|
421 |
+
$metaThumb->setId($ID);
|
422 |
+
$this->prioQ->push('C-' . $ID);
|
423 |
+
}
|
424 |
+
return $meta;
|
425 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
426 |
}
|
427 |
|
428 |
+
public function optimizeCustomImage($id) {
|
429 |
+
$meta = $this->spMetaDao->getMeta($id);
|
430 |
+
if($meta->getStatus() != 2) {
|
431 |
+
$meta->setStatus(1);
|
432 |
+
$meta->setRetries(0);
|
433 |
+
$this->spMetaDao->update($meta);
|
434 |
+
$this->prioQ->push('C-' . $id);
|
435 |
+
}
|
436 |
+
}
|
437 |
+
|
438 |
+
//TODO muta in bulkProvider
|
439 |
public function getBulkItemsFromDb(){
|
440 |
global $wpdb;
|
441 |
|
447 |
return false;
|
448 |
}
|
449 |
$idList = array();
|
450 |
+
$itemList = array();
|
451 |
for ($sanityCheck = 0, $crtStartQueryID = $startQueryID;
|
452 |
+
$crtStartQueryID >= $endQueryID && count($itemList) < 3; $sanityCheck++) {
|
453 |
|
454 |
self::log("GETDB: current StartID: " . $crtStartQueryID);
|
455 |
|
468 |
foreach ( $resultsPostMeta as $itemMetaData ) {
|
469 |
$crtStartQueryID = $itemMetaData->post_id;
|
470 |
if(!in_array($crtStartQueryID, $idList) && self::isProcessable($crtStartQueryID)) {
|
471 |
+
$item = new ShortPixelMetaFacade($crtStartQueryID);
|
472 |
+
$meta = $item->getMeta();//wp_get_attachment_metadata($crtStartQueryID);
|
473 |
|
474 |
+
if($meta->getStatus() != 2) {
|
475 |
+
$itemList[] = $item;
|
476 |
$idList[] = $crtStartQueryID;
|
477 |
}
|
478 |
+
elseif($meta->getCompressionType() !== null && $meta->getCompressionType() != $this->_settings->compressionType) {//a different type of compression was chosen in settings
|
479 |
+
if($this->doRestore($crtStartQueryID)) {
|
480 |
+
$itemList[] = $item = new ShortPixelMetaFacade($crtStartQueryID); //force reload after restore
|
481 |
$idList[] = $crtStartQueryID;
|
482 |
} else {
|
483 |
$skippedAlreadyProcessed++;
|
484 |
}
|
485 |
}
|
486 |
+
elseif( $this->_settings->processThumbnails && $meta->getThumbsOpt() !== null
|
487 |
+
&& $meta->getThumbsOpt() == 0 && count($meta->getThumbs()) > 0) { //thumbs were chosen in settings
|
488 |
//if($crtStartQueryID == 44 || $crtStartQueryID == 49) {echo("No THuMBS?");die(var_dump($meta));}
|
489 |
+
$meta->setThumbsTodo(true);
|
490 |
+
$item->updateMeta($meta);//wp_update_attachment_metadata($crtStartQueryID, $meta);
|
491 |
+
$itemList[] = $item;
|
492 |
$idList[] = $crtStartQueryID;
|
493 |
}
|
494 |
elseif($itemMetaData->meta_key == '_wp_attachment_metadata') { //count skipped
|
500 |
//daca n-am adaugat niciuna pana acum, n-are sens sa mai selectez zona asta de id-uri in bulk-ul asta.
|
501 |
$leapStart = $this->prioQ->getStartBulkId();
|
502 |
$crtStartQueryID = $startQueryID = $itemMetaData->post_id - 1; //decrement it so we don't select it again
|
503 |
+
$res = WpShortPixelMediaLbraryAdapter::countAllProcessableFiles($leapStart, $crtStartQueryID);
|
504 |
$skippedAlreadyProcessed += $res["mainProcessedFiles"] - $res["mainProc".($this->getCompressionType() == 1 ? "Lossy" : "Lossless")."Files"];
|
505 |
$this->prioQ->setStartBulkId($startQueryID);
|
506 |
} else {
|
507 |
$crtStartQueryID--;
|
508 |
}
|
509 |
}
|
510 |
+
return array("items" => $itemList, "skipped" => $skippedAlreadyProcessed);
|
511 |
}
|
512 |
|
513 |
/**
|
514 |
* Get last added items from priority
|
515 |
* @return type
|
516 |
*/
|
517 |
+
//TODO muta in bulkProvider - prio
|
518 |
public function getFromPrioAndCheck() {
|
519 |
+
$items = array();
|
520 |
+
foreach ($this->prioQ->getFromPrioAndCheck() as $id) {
|
521 |
+
$items[] = new ShortPixelMetaFacade($id);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
522 |
}
|
523 |
+
return $items;
|
524 |
}
|
525 |
|
526 |
public function handleImageProcessing($ID = null) {
|
527 |
+
//if(rand(1,2) == 2) {
|
528 |
+
// header($_SERVER['SERVER_PROTOCOL'] . ' 500 Internal Server Error', true, 500);
|
529 |
+
// die("za stop");
|
530 |
+
//}
|
531 |
//0: check key
|
532 |
if( $this->_settings->verifiedKey == false) {
|
533 |
if($ID == null){
|
534 |
$ids = $this->getFromPrioAndCheck();
|
535 |
+
$itemHandler = (count($ids) > 0 ? $ids[0] : null);
|
536 |
}
|
537 |
+
$response = array("Status" => ShortPixelAPI::STATUS_NO_KEY, "ImageID" => $itemHandler ? $itemHandler->getId() : "-1", "Message" => "Missing API Key");
|
538 |
+
$this->_settings->bulkLastStatus = $response;
|
539 |
die(json_encode($response));
|
540 |
}
|
541 |
|
542 |
+
if($this->_settings->frontBootstrap && is_admin() && !ShortPixelTools::requestIsFrontendAjax()) {
|
543 |
+
//if in backend, and front-end is activated, mark processing from backend to shut off the front-end for 10 min.
|
544 |
+
$this->_settings->lastBackAction = time();
|
545 |
+
}
|
546 |
+
|
547 |
self::log("HIP: 0 Priority Queue: ".json_encode($this->prioQ->get()));
|
548 |
+
self::log("HIP: 0 Skipped: ".json_encode($this->prioQ->getSkipped()));
|
549 |
|
550 |
//1: get 3 ids to process. Take them with priority from the queue
|
551 |
$ids = $this->getFromPrioAndCheck();
|
553 |
$bulkStatus = $this->prioQ->bulkRunning();
|
554 |
if($bulkStatus =='running') {
|
555 |
$res = $this->getBulkItemsFromDb();
|
556 |
+
$bulkItems = $res['items'];
|
557 |
if($bulkItems){
|
558 |
$ids = array_merge ($ids, $bulkItems);
|
559 |
}
|
560 |
}
|
561 |
}
|
562 |
+
|
563 |
+
self::log("HIP: 0 Bulk ran: " . $this->prioQ->bulkRan());
|
564 |
+
$customIds = false;
|
565 |
+
if(count($ids) < 3 && $this->prioQ->bulkRan() && $this->_settings->hasCustomFolders
|
566 |
+
&& (!$this->_settings->cancelPointer || $this->_settings->skipToCustom)
|
567 |
+
&& !$this->_settings->customBulkPaused)
|
568 |
+
{ //take from custom images if any left to optimize - only if bulk was ever started
|
569 |
+
$customIds = $this->spMetaDao->getPendingMetas( 3 - count($ids));
|
570 |
+
if(is_array($customIds)) {
|
571 |
+
$ids = array_merge($ids, array_map(function($item) {
|
572 |
+
return new ShortPixelMetaFacade("C-" . $item->id);
|
573 |
+
}, $customIds));
|
574 |
+
}
|
575 |
+
}
|
576 |
+
// var_dump($ids);
|
577 |
+
// die("za stop 2");
|
578 |
+
|
579 |
if ($ids === false || count( $ids ) == 0 ){
|
580 |
$bulkEverRan = $this->prioQ->stopBulk();
|
581 |
+
$avg = $this->getAverageCompression();
|
582 |
+
$fileCount = $this->_settings->fileCount;
|
583 |
$response = array("Status" => self::BULK_EMPTY_QUEUE,
|
584 |
"Message" => 'Empty queue ' . $this->prioQ->getStartBulkId() . '->' . $this->prioQ->getStopBulkId(),
|
585 |
"BulkStatus" => ($this->prioQ->bulkRunning()
|
591 |
}
|
592 |
|
593 |
self::log("HIP: 1 Prio Queue: ".json_encode($this->prioQ->get()));
|
594 |
+
self::log("HIP: 1 Selected IDs count: ".count($ids));
|
595 |
|
596 |
//2: Send up to 3 files to the server for processing
|
597 |
for($i = 0; $i < min(3, count($ids)); $i++) {
|
598 |
+
$itemHandler = $ids[$i];
|
599 |
+
$tmpMeta = $itemHandler->getMeta();
|
600 |
+
//$compType = (isset($tmpMeta['ShortPixel']['type']) ? ($tmpMeta['ShortPixel']['type'] == 'lossy' ? 1 : 0) : $this->_settings->compressionType);
|
601 |
+
$compType = ($tmpMeta->getCompressionType() !== null ? $tmpMeta->getCompressionType() : $this->_settings->compressionType);
|
602 |
+
//$URLsAndPATHs = $this->sendToProcessing($ID, $compType, isset($tmpMeta['ShortPixel']['thumbsTodo']));
|
603 |
+
$URLsAndPATHs = $this->sendToProcessing($itemHandler, $compType, $tmpMeta->getThumbsTodo());
|
604 |
if($i == 0) { //save for later use
|
605 |
$firstUrlAndPaths = $URLsAndPATHs;
|
606 |
}
|
608 |
|
609 |
self::log("HIP: 2 Prio Queue: ".json_encode($this->prioQ->get()));
|
610 |
//3: Retrieve the file for the first element of the list
|
611 |
+
$itemHandler = $ids[0];
|
612 |
+
$itemId = $itemHandler->getQueuedId();
|
613 |
+
$result = $this->_apiInterface->processImage($firstUrlAndPaths['URLs'], $firstUrlAndPaths['PATHs'], $itemHandler);
|
614 |
+
$result["ImageID"] = $itemId;
|
615 |
+
$meta = $itemHandler->getMeta();
|
616 |
+
$result["Filename"] = basename($meta->getPath());
|
617 |
|
618 |
self::log("HIP: 3 Prio Queue: ".json_encode($this->prioQ->get()));
|
619 |
|
620 |
//4: update counters and priority list
|
621 |
if( $result["Status"] == ShortPixelAPI::STATUS_SUCCESS) {
|
622 |
+
self::log("HIP: Image ID " . $itemId . " optimized successfully: ".json_encode($result));
|
623 |
+
$prio = $this->prioQ->remove($itemId);
|
624 |
//remove also from the failed list if it failed in the past
|
625 |
+
$prio = $this->prioQ->removeFromFailed($itemId);
|
626 |
+
/* $result["Type"] = isset($meta['ShortPixel']['type']) ? $meta['ShortPixel']['type'] : '';
|
|
|
627 |
$result["ThumbsTotal"] = isset($meta['sizes']) && is_array($meta['sizes']) ? count($meta['sizes']): 0;
|
628 |
$result["ThumbsCount"] = isset($meta['ShortPixel']['thumbsOpt'])
|
629 |
? $meta['ShortPixel']['thumbsOpt'] //below is the fallback for old optimized images that don't have thumbsOpt
|
630 |
: ($this->_settings->processThumbnails ? $result["ThumbsTotal"] : 0);
|
631 |
+
*/
|
632 |
+
$result["Type"] = $meta->getCompressionType() !== null ? ShortPixelAPI::getCompressionTypeName($meta->getCompressionType()) : '';
|
633 |
+
$result["ThumbsTotal"] = $meta->getThumbs() && is_array($meta->getThumbs()) ? count($meta->getThumbs()): 0;
|
634 |
+
$result["ThumbsCount"] = $meta->getThumbsOpt()
|
635 |
+
? $meta->getThumbsOpt() //below is the fallback for old optimized images that don't have thumbsOpt
|
636 |
+
: ($this->_settings->processThumbnails ? $result["ThumbsTotal"] : 0);
|
637 |
|
638 |
+
//$result["BackupEnabled"] = ($this->getBackupFolder(get_attached_file($ID)) ? true : false);//$this->_settings->backupImages;
|
639 |
+
$result["BackupEnabled"] = ($this->getBackupFolder($meta->getPath()) ? true : false);//$this->_settings->backupImages;
|
640 |
|
641 |
+
if(!$prio && $itemId <= $this->prioQ->getStartBulkId()) {
|
642 |
+
$this->advanceBulk($itemId, $result);
|
643 |
+
$this->setBulkInfo($itemId, $result);
|
644 |
+
}
|
645 |
+
|
646 |
+
$result["AverageCompression"] = $this->getAverageCompression();
|
647 |
+
|
648 |
+
if($itemHandler->getType() == ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE) {
|
649 |
|
650 |
$thumb = $bkThumb = "";
|
651 |
+
//$percent = 0;
|
652 |
+
$percent = $meta->getImprovementPercent();
|
653 |
+
//if(isset($meta["ShortPixelImprovement"]) && isset($meta["file"])){
|
654 |
+
if($percent){
|
655 |
+
//$percent = $meta["ShortPixelImprovement"];
|
656 |
+
|
657 |
+
//$filePath = explode("/", $meta["file"]);
|
658 |
+
$filePath = explode("/", $meta->getPath());
|
659 |
|
660 |
//Get a suitable thumb
|
661 |
+
//if(isset($meta["sizes"]) && count($meta["sizes"])) {
|
662 |
+
//$sizes = $meta["sizes"];
|
663 |
+
$sizes = $meta->getThumbs();
|
664 |
+
if('pdf' == strtolower(pathinfo($result["Filename"], PATHINFO_EXTENSION))) {
|
665 |
+
// echo($result["Filename"] . " ESTE --> "); die(var_dump(strtolower(pathinfo($result["Filename"], PATHINFO_EXTENSION))));
|
666 |
+
$thumb = plugins_url( 'shortpixel-image-optimiser/res/img/logo-pdf.png' );
|
667 |
+
$bkThumb = '';
|
668 |
+
} else {
|
669 |
+
if(count($sizes)) {
|
670 |
+
$thumb = (isset($sizes["medium"]) ? $sizes["medium"]["file"] : (isset($sizes["thumbnail"]) ? $sizes["thumbnail"]["file"]: ""));
|
671 |
+
if(!strlen($thumb)) { //fallback to the first in the list
|
672 |
+
$sizeVals = array_values($sizes);
|
673 |
+
$thumb = count($sizeVals) ? $sizeVals[0]['file'] : '';
|
674 |
+
}
|
675 |
+
} else { //fallback to the image itself
|
676 |
+
$thumb = is_array($filePath) ? $filePath[count($filePath) - 1] : $filePath;
|
677 |
+
}
|
678 |
+
|
679 |
+
if(strlen($thumb) && $this->_settings->backupImages && $this->_settings->processThumbnails) {
|
680 |
+
$backupUrl = content_url() . "/" . SP_UPLOADS_NAME . "/" . SP_BACKUP . "/";
|
681 |
+
//$urlBkPath = $this->_apiInterface->returnSubDir(get_attached_file($ID));
|
682 |
+
$urlBkPath = ShortPixelMetaFacade::returnSubDir($meta->getPath(), ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE);
|
683 |
+
$bkThumb = $backupUrl . $urlBkPath . $thumb;
|
684 |
+
}
|
685 |
+
if(strlen($thumb)) {
|
686 |
+
$uploadsUrl = content_url() . "/";
|
687 |
+
$urlPath = ShortPixelMetaFacade::returnSubDir($meta->getPath(), ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE);
|
688 |
+
//$urlPath = implode("/", array_slice($filePath, 0, count($filePath) - 1));
|
689 |
+
$thumb = $uploadsUrl . $urlPath . $thumb;
|
690 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
691 |
}
|
692 |
+
|
693 |
$result["Thumb"] = $thumb;
|
694 |
$result["BkThumb"] = $bkThumb;
|
695 |
}
|
696 |
}
|
697 |
+
elseif( is_array($customIds)) { // this item is from custom bulk
|
698 |
+
foreach($customIds as $customId) {
|
699 |
+
$contentUrl = network_site_url("/") . "/wp-content";
|
700 |
+
if($customId->id == $itemHandler->getId()) {
|
701 |
+
if('pdf' == strtolower(pathinfo($meta->getName(), PATHINFO_EXTENSION))) {
|
702 |
+
$result["Thumb"] = plugins_url( 'shortpixel-image-optimiser/res/img/logo-pdf.png' );
|
703 |
+
$result["BkThumb"] = "";
|
704 |
+
} else {
|
705 |
+
$result["Thumb"] = $thumb = $contentUrl . "/" . $meta->getWebPath();
|
706 |
+
if($this->_settings->backupImages) {
|
707 |
+
$result["BkThumb"] = str_replace($contentUrl, $contentUrl. "/" . SP_UPLOADS_NAME . "/" . SP_BACKUP, $thumb);
|
708 |
+
}
|
709 |
+
}
|
710 |
+
$this->setBulkInfo($itemId, $result);
|
711 |
+
break;
|
712 |
+
}
|
713 |
+
}
|
714 |
+
}
|
715 |
}
|
716 |
elseif ($result["Status"] == ShortPixelAPI::STATUS_ERROR) {
|
717 |
+
//$meta = wp_get_attachment_metadata($ID);
|
718 |
+
//if(isset($meta['ShortPixel']['Retries']) && $meta['ShortPixel']['Retries'] > MAX_ERR_RETRIES) {
|
719 |
+
if($meta->getRetries() > MAX_ERR_RETRIES) {
|
720 |
+
//if(! $this->prioQ->remove($ID) ){
|
721 |
+
if(! $this->prioQ->remove($itemId) ){
|
722 |
+
//$this->advanceBulk($ID, $result);
|
723 |
+
$this->advanceBulk($meta->getId(), $result);
|
724 |
}
|
725 |
+
//unset($meta['ShortPixel']);
|
726 |
+
//wp_update_attachment_metadata($ID, $meta);
|
727 |
+
$itemHandler->deleteMeta(); //this deletes only the ShortPixel fields from meta, in case of WP Media library
|
728 |
$result["Status"] = ShortPixelAPI::STATUS_SKIP;
|
729 |
+
$result["Message"] .= " Retry limit reached. Skipping file ID " . $itemId . ".";
|
730 |
}
|
731 |
else {
|
732 |
+
//if(!isset($meta['ShortPixel'])) { $meta['ShortPixel'] = array(); }
|
733 |
+
//$meta['ShortPixel']['Retries'] = isset($meta['ShortPixel']['Retries']) ? $meta['ShortPixel']['Retries'] + 1 : 1;
|
734 |
+
//wp_update_attachment_metadata($ID, $meta);
|
735 |
+
$itemHandler->incrementRetries();
|
736 |
}
|
737 |
}
|
738 |
elseif ($result["Status"] == ShortPixelAPI::STATUS_SKIP
|
739 |
|| $result["Status"] == ShortPixelAPI::STATUS_FAIL) {
|
740 |
+
$meta = $itemHandler->getMeta();
|
741 |
+
//$prio = $this->prioQ->remove($ID);
|
742 |
+
$prio = $this->prioQ->remove($itemId);
|
743 |
+
if(isset($result["Code"])
|
744 |
+
&& ( $result["Code"] == "write-fail" //could not write
|
745 |
+
//|| $result["Code"] == -201)) {
|
746 |
+
|| (in_array(0+$result["Code"], array(-201)) && $meta->getRetries() >= 3))) { //for -201 (invalid image format) we retry only 3 times.
|
747 |
//put this one in the failed images list - to show the user at the end
|
748 |
+
$prio = $this->prioQ->addToFailed($itemHandler->getQueuedId());
|
749 |
+
}
|
750 |
+
$this->advanceBulk($meta->getId(), $result);
|
751 |
+
if($itemHandler->getType() == ShortPixelMetaFacade::CUSTOM_TYPE) {
|
752 |
+
$result["CustomImageLink"] = trailingslashit(network_site_url("/")) . "wp-content/" . $meta->getWebPath();
|
753 |
+
}
|
754 |
+
}
|
755 |
+
elseif ($this->prioQ->isPrio($itemId) && $result["Status"] == ShortPixelAPI::STATUS_QUOTA_EXCEEDED) {
|
756 |
+
if(!$this->prioQ->skippedCount()) {
|
757 |
+
$this->prioQ->reverse(); //for the first prio item with quota exceeded, revert the prio queue as probably the bottom ones were processed
|
758 |
+
}
|
759 |
+
if($this->prioQ->allSkipped()) {
|
760 |
+
$result["Stop"] = true;
|
761 |
+
} else {
|
762 |
+
$result["Stop"] = false;
|
763 |
+
$this->prioQ->skip($itemId);
|
764 |
+
}
|
765 |
+
self::log("HIP: 5 Prio Skipped: ".json_encode($this->prioQ->getSkipped()));
|
766 |
+
}
|
767 |
+
elseif($result["Status"] == ShortPixelAPI::STATUS_RETRY && is_array($customIds)) {
|
768 |
+
$result["CustomImageLink"] = $thumb = trailingslashit(network_site_url("/")) . "wp-content/" . $meta->getWebPath();
|
769 |
+
}
|
770 |
+
|
771 |
+
if($result["Status"] !== ShortPixelAPI::STATUS_RETRY) {
|
772 |
+
$this->_settings->bulkLastStatus = $result;
|
773 |
}
|
774 |
die(json_encode($result));
|
775 |
}
|
776 |
|
777 |
+
|
778 |
private function advanceBulk($processedID, &$result) {
|
779 |
+
//echo("ADVANCE BULK: ");die(var_dump($result));
|
780 |
if($processedID <= $this->prioQ->getStartBulkId()) {
|
781 |
$this->prioQ->setStartBulkId($processedID - 1);
|
782 |
$this->prioQ->logBulkProgress();
|
|
|
|
|
|
|
|
|
783 |
}
|
784 |
}
|
785 |
|
786 |
+
private function setBulkInfo($processedID, &$result) {
|
787 |
+
$deltaBulkPercent = $this->prioQ->getDeltaBulkPercent();
|
788 |
+
$minutesRemaining = $this->prioQ->getTimeRemaining();
|
789 |
+
$pendingMeta = $this->_settings->hasCustomFolders ? $this->spMetaDao->getPendingMetaCount() : 0;
|
790 |
+
$percent = $this->prioQ->getBulkPercent();
|
791 |
+
if(0 + $pendingMeta > 0) {
|
792 |
+
$customMeta = $this->spMetaDao->getCustomMetaCount();
|
793 |
+
$totalPercent = round(($percent * $this->_settings->currentTotalFiles + ($customMeta - $pendingMeta) * 100) / ($this->_settings->currentTotalFiles + $customMeta));
|
794 |
+
$minutesRemaining = round($minutesRemaining * (100 - $totalPercent) / max(1, 100 - $percent));
|
795 |
+
$percent = $totalPercent;
|
796 |
+
}
|
797 |
+
$result["BulkPercent"] = $percent;
|
798 |
+
$result["BulkMsg"] = $this->bulkProgressMessage($deltaBulkPercent, $minutesRemaining);
|
799 |
+
}
|
800 |
+
|
801 |
+
private function sendToProcessing($itemHandler, $compressionType = false, $onlyThumbs = false) {
|
802 |
+
$URLsAndPATHs = $this->getURLsAndPATHs($itemHandler, NULL, $onlyThumbs);
|
803 |
+
//echo("URLS: "); die(var_dump($URLsAndPATHs));
|
804 |
+
$this->_apiInterface->doRequests($URLsAndPATHs['URLs'], false, $itemHandler,
|
805 |
+
$compressionType === false ? $this->_settings->compressionType : $compressionType);//send a request, do NOT wait for response
|
806 |
+
$itemHandler->setWaitingProcessing();
|
807 |
+
//$meta = wp_get_attachment_metadata($ID);
|
808 |
+
//$meta['ShortPixel']['WaitingProcessing'] = true;
|
809 |
+
//wp_update_attachment_metadata($ID, $meta);
|
810 |
return $URLsAndPATHs;
|
811 |
}
|
812 |
|
813 |
public function handleManualOptimization() {
|
814 |
+
$imageId = $_GET['image_id'];
|
815 |
+
switch(substr($imageId, 0, 2)) {
|
816 |
+
case "N-":
|
817 |
+
return "Add the gallery to the custom folders list in ShortPixel settings.";
|
818 |
+
// Later
|
819 |
+
if(class_exists("C_Image_Mapper")) { //this is a NextGen image but not added to our tables, so add it now.
|
820 |
+
$image_mapper = C_Image_Mapper::get_instance();
|
821 |
+
$image = $image_mapper->find(intval(substr($imageId, 2)));
|
822 |
+
if($image) {
|
823 |
+
$this->handleNextGenImageUpload($image, true);
|
824 |
+
return array("Status" => ShortPixelAPI::STATUS_SUCCESS, "message" => "");
|
825 |
+
}
|
826 |
+
}
|
827 |
+
return array("Status" => ShortPixelAPI::STATUS_FAIL, "message" => "NextGen image not found");
|
828 |
+
break;
|
829 |
+
case "C-":
|
830 |
+
throw new Exception("HandleManualOptimization for custom images not implemented");
|
831 |
+
default:
|
832 |
+
$this->optimizeNowHook(intval($imageId));
|
833 |
+
}
|
834 |
//do_action('shortpixel-optimize-now', $imageId);
|
835 |
|
836 |
}
|
839 |
public function optimizeNowHook($imageId) {
|
840 |
if(self::isProcessable($imageId)) {
|
841 |
$this->prioQ->push($imageId);
|
842 |
+
$this->sendToProcessing(new ShortPixelMetaFacade($imageId));
|
843 |
$ret = array("Status" => ShortPixelAPI::STATUS_SUCCESS, "message" => "");
|
844 |
} else {
|
845 |
$ret = array("Status" => ShortPixelAPI::STATUS_SKIP, "message" => $imageId);
|
857 |
|
858 |
public function getBackupFolder($file) {
|
859 |
$fileExtension = strtolower(substr($file,strrpos($file,".")+1));
|
860 |
+
$SubDir = ShortPixelMetaFacade::returnSubDir($file, ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE);
|
861 |
|
862 |
//sometimes the month of original file and backup can differ
|
863 |
if ( !file_exists(SP_BACKUP_FOLDER . DIRECTORY_SEPARATOR . $SubDir . ShortPixelAPI::MB_basename($file)) ) {
|
888 |
$pathInfo = pathinfo($file);
|
889 |
|
890 |
$bkFolder = $this->getBackupFolder($file);
|
891 |
+
$bkNewFile = str_replace(dirname(SP_BACKUP_FOLDER), SP_BACKUP_FOLDER, $file);
|
892 |
$bkFile = $bkFolder . ShortPixelAPI::MB_basename($file);
|
893 |
|
894 |
+
if(file_exists($bkNewFile)) {
|
895 |
+
$bkFile = $bkNewFile;
|
896 |
+
}
|
897 |
+
|
898 |
//first check if the file is readable by the current user - otherwise it will be unaccessible for the web browser
|
899 |
// - collect the thumbs paths in the process
|
900 |
if(! $this->setFilePerms($bkFile) ) return false;
|
901 |
$thumbsPaths = array();
|
902 |
if( !empty($meta['file']) && is_array($meta["sizes"]) ) {
|
903 |
foreach($meta["sizes"] as $size => $imageData) {
|
904 |
+
$source = $bkFolder . $imageData['file'];
|
905 |
+
if(!file_exists($source)) continue; // if thumbs were not optimized, then the backups will not be there.
|
906 |
+
$thumbsPaths[$source] = $pathInfo['dirname'] . DIRECTORY_SEPARATOR . $imageData['file'];
|
907 |
+
if(! $this->setFilePerms($source)) return false;
|
|
|
908 |
}
|
909 |
}
|
910 |
|
918 |
@rename($source, $destination);
|
919 |
}
|
920 |
|
921 |
+
$duplicates = ShortPixelMetaFacade::getWPMLDuplicates($attachmentID);
|
922 |
foreach($duplicates as $ID) {
|
923 |
$crtMeta = $attachmentID == $ID ? $meta : wp_get_attachment_metadata($ID);
|
924 |
if(is_numeric($crtMeta["ShortPixelImprovement"]) && 0 + $crtMeta["ShortPixelImprovement"] < 5 && $this->_settings->under5Percent > 0) {
|
955 |
}
|
956 |
|
957 |
public function handleRedo() {
|
958 |
+
$ID = $_GET['attachment_ID'];
|
959 |
+
$mediaType = ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE;
|
960 |
+
if(strpos($ID, 'C-') === 0) {
|
961 |
+
die("handleRedo not implemented for Custom media");
|
962 |
+
$ID = substr($ID, 2);
|
963 |
+
$mediaType = ShortPixelMetaFacade::CUSTOM_TYPE;
|
964 |
+
}
|
965 |
+
$ID = intval($ID);
|
966 |
+
$compressionType = ($_GET['type'] == 'lossless' ? 'lossless' : 'lossy'); //sanity check
|
967 |
|
968 |
$meta = $this->doRestore($ID);
|
969 |
//die(var_dump($meta));
|
970 |
if($meta) { //restore succeeded
|
971 |
+
$meta['ShortPixel'] = array("type" => $compressionType);
|
972 |
wp_update_attachment_metadata($ID, $meta);
|
973 |
$this->prioQ->push($ID);
|
974 |
+
$this->sendToProcessing(new ShortPixelMetaFacade($ID), $compressionType == 'lossy' ? 1 : 0);
|
975 |
$ret = array("Status" => ShortPixelAPI::STATUS_SUCCESS, "Message" => "");
|
976 |
} else {
|
977 |
$ret = array("Status" => ShortPixelAPI::STATUS_SKIP, "Message" => "Could not restore from backup: " . $ID);
|
989 |
$meta['ShortPixel']['thumbsTodo'] = true;
|
990 |
wp_update_attachment_metadata($ID, $meta);
|
991 |
$this->prioQ->push($ID);
|
992 |
+
$this->sendToProcessing(new ShortPixelMetaFacade($ID));
|
993 |
$ret = array("Status" => ShortPixelAPI::STATUS_SUCCESS, "message" => "");
|
994 |
} else {
|
995 |
$ret = array("Status" => ShortPixelAPI::STATUS_SKIP, "message" => (isset($meta['ShortPixelImprovement']) ? "No thumbnails to optimize for ID: " : "Please optimize image for ID:") . $ID);
|
1014 |
|
1015 |
if(self::isProcessable($ID) != false)
|
1016 |
{
|
|
|
1017 |
try {
|
1018 |
+
$SubDir = ShortPixelMetaFacade::returnSubDir($file, ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE);
|
1019 |
|
1020 |
@unlink(SP_BACKUP_FOLDER . DIRECTORY_SEPARATOR . $SubDir . ShortPixelAPI::MB_basename($file));
|
1021 |
|
1025 |
//remove thumbs thumbnails
|
1026 |
if(isset($meta["sizes"])) {
|
1027 |
foreach($meta["sizes"] as $size => $imageData) {
|
1028 |
+
@unlink($filesPath . ShortPixelAPI::MB_basename($imageData['file']));//remove thumbs
|
|
|
|
|
1029 |
}
|
1030 |
}
|
1031 |
}
|
1044 |
return $quotaData;
|
1045 |
}
|
1046 |
//$tempus = microtime(true);
|
1047 |
+
$imageCount = WpShortPixelMediaLbraryAdapter::countAllProcessableFiles();
|
1048 |
+
|
1049 |
+
$this->_settings->currentTotalFiles = $imageCount['totalFiles'];
|
1050 |
+
|
1051 |
//echo("Count took (seconds): " . (microtime(true) - $tempus));
|
1052 |
foreach($imageCount as $key => $val) {
|
1053 |
$quotaData[$key] = $val;
|
1054 |
}
|
1055 |
+
|
1056 |
+
if($this->_settings->hasCustomFolders) {
|
1057 |
+
$customImageCount = $this->spMetaDao->countAllProcessableFiles();
|
1058 |
+
foreach($customImageCount as $key => $val) {
|
1059 |
+
$quotaData[$key] = isset($quotaData[$key])
|
1060 |
+
? (is_array($quotaData[$key]) ? array_merge($quotaData[$key], $val) : $quotaData[$key] + $val)
|
1061 |
+
: $val;
|
1062 |
+
}
|
1063 |
+
}
|
1064 |
|
1065 |
if($quotaData['APICallsQuotaNumeric'] + $quotaData['APICallsQuotaOneTimeNumeric'] > $quotaData['APICallsMadeNumeric'] + $quotaData['APICallsMadeOneTimeNumeric']) {
|
1066 |
$this->_settings->quotaExceeded = '0';
|
1067 |
$this->_settings->prioritySkip = NULL;
|
1068 |
+
self::log("CHECK QUOTA: Skipped: ".json_encode($this->prioQ->getSkipped()));
|
1069 |
+
|
1070 |
?><script>var shortPixelQuotaExceeded = 0;</script><?php
|
1071 |
}
|
1072 |
else {
|
1075 |
}
|
1076 |
return $quotaData;
|
1077 |
}
|
1078 |
+
|
1079 |
+
public function isValidMetaId($id) {
|
1080 |
+
return substr($id, 0, 2 ) == "C-" ? $this->spMetaDao->getMeta(substr($id, 2)) : wp_get_attachment_url($id);
|
1081 |
+
}
|
1082 |
+
|
1083 |
+
public function listCustomMedia() {
|
1084 |
+
if( ! class_exists( 'ShortPixelListTable' ) ) {
|
1085 |
+
require_once('class/view/shortpixel-list-table.php');
|
1086 |
+
}
|
1087 |
+
if(isset($_REQUEST['refresh']) && esc_attr($_REQUEST['refresh']) == 1) {
|
1088 |
+
$notice = null;
|
1089 |
+
$this->refreshCustomFolders($notice);
|
1090 |
+
}
|
1091 |
+
if(isset($_REQUEST['action']) && esc_attr($_REQUEST['action']) == 'optimize' && isset($_REQUEST['image'])) {
|
1092 |
+
//die(ShortPixelMetaFacade::queuedId(ShortPixelMetaFacade::CUSTOM_TYPE, $_REQUEST['image']));
|
1093 |
+
$this->prioQ->push(ShortPixelMetaFacade::queuedId(ShortPixelMetaFacade::CUSTOM_TYPE, $_REQUEST['image']));
|
1094 |
+
}
|
1095 |
+
$customMediaListTable = new ShortPixelListTable($this, $this->spMetaDao, $this->hasNextGen);
|
1096 |
+
?>
|
1097 |
+
<div class="wrap">
|
1098 |
+
<h2>
|
1099 |
+
<div style="float:right;">
|
1100 |
+
<a href="upload.php?page=wp-short-pixel-custom&refresh=1" id="refresh" class="button button-primary" title="Refresh custom folders content">
|
1101 |
+
Refresh folders
|
1102 |
+
</a>
|
1103 |
+
</div>
|
1104 |
+
Other Media optimized by ShortPixel
|
1105 |
+
</h2>
|
1106 |
+
|
1107 |
+
<div id="poststuff">
|
1108 |
+
<div id="post-body" class="metabox-holder columns-2">
|
1109 |
+
<div id="post-body-content">
|
1110 |
+
<div class="meta-box-sortables ui-sortable">
|
1111 |
+
<form method="post" class="shortpixel-table">
|
1112 |
+
<?php
|
1113 |
+
$items = $customMediaListTable->prepare_items();
|
1114 |
+
$customMediaListTable->display();
|
1115 |
+
//push to the processing list the pending ones, just in case
|
1116 |
+
$count = $this->spMetaDao->getCustomMetaCount();
|
1117 |
+
foreach ($items as $item) {
|
1118 |
+
if($item->status == 1){
|
1119 |
+
$this->prioQ->push(ShortPixelMetaFacade::queuedId(ShortPixelMetaFacade::CUSTOM_TYPE, $item->id));
|
1120 |
+
}
|
1121 |
+
}
|
1122 |
+
?>
|
1123 |
+
</form>
|
1124 |
+
</div>
|
1125 |
+
</div>
|
1126 |
+
</div>
|
1127 |
+
<br class="clear">
|
1128 |
+
</div>
|
1129 |
+
</div> <?php
|
1130 |
+
}
|
1131 |
public function bulkProcess() {
|
1132 |
global $wpdb;
|
1133 |
|
1142 |
if(isset($_POST['bulkProcessPause']))
|
1143 |
{//pause an ongoing bulk processing, it might be needed sometimes
|
1144 |
$this->prioQ->pauseBulk();
|
1145 |
+
if($this->_settings->hasCustomFolders && $this->spMetaDao->getPendingMetaCount()) {
|
1146 |
+
$this->_settings->customBulkPaused = 1;
|
1147 |
+
}
|
1148 |
+
}
|
1149 |
+
|
1150 |
+
if(isset($_POST['bulkProcessStop']))
|
1151 |
+
{//stop an ongoing bulk processing
|
1152 |
+
$this->prioQ->cancelBulk();
|
1153 |
+
if($this->_settings->hasCustomFolders && $this->spMetaDao->getPendingMetaCount()) {
|
1154 |
+
$this->_settings->customBulkPaused = 1;
|
1155 |
+
}
|
1156 |
}
|
1157 |
|
1158 |
if(isset($_POST["bulkProcess"]))
|
1159 |
{
|
1160 |
//set the thumbnails option
|
1161 |
if ( isset($_POST['thumbnails']) ) {
|
1162 |
+
$this->_settings->processThumbnails = 1;
|
1163 |
} else {
|
1164 |
+
$this->_settings->processThumbnails = 0;
|
1165 |
}
|
1166 |
$this->prioQ->startBulk();
|
1167 |
+
$this->_settings->customBulkPaused = 0;
|
1168 |
self::log("BULK: Start: " . $this->prioQ->getStartBulkId() . ", stop: " . $this->prioQ->getStopBulkId() . " PrioQ: "
|
1169 |
.json_encode($this->prioQ->get()));
|
1170 |
}//end bulk process was clicked
|
1171 |
|
1172 |
+
if(isset($_POST["bulkProcessResume"]))
|
1173 |
{
|
1174 |
$this->prioQ->resumeBulk();
|
1175 |
+
$this->_settings->customBulkPaused = 0;
|
1176 |
+
}//resume was clicked
|
1177 |
+
|
1178 |
+
if(isset($_POST["skipToCustom"]))
|
1179 |
+
{
|
1180 |
+
$this->_settings->skipToCustom = true;
|
1181 |
}//resume was clicked
|
1182 |
|
1183 |
//figure out all the files that could be processed
|
1186 |
$allFiles = $wpdb->get_results($qry);
|
1187 |
//figure out the files that are left to be processed
|
1188 |
$qry_left = "SELECT count(*) FilesLeftToBeProcessed FROM " . $wpdb->prefix . "postmeta
|
1189 |
+
WHERE meta_key = '_wp_attached_file' AND post_id <= " . (0 + $this->prioQ->getStartBulkId());
|
1190 |
$filesLeft = $wpdb->get_results($qry_left);
|
1191 |
+
|
1192 |
+
//check the custom bulk
|
1193 |
+
$pendingMeta = $this->_settings->hasCustomFolders ? $this->spMetaDao->getPendingMetaCount() : 0;
|
1194 |
+
|
1195 |
+
if ( ($filesLeft[0]->FilesLeftToBeProcessed > 0 && $this->prioQ->bulkRunning())
|
1196 |
+
|| (0 + $pendingMeta > 0 && !$this->_settings->customBulkPaused && $this->prioQ->bulkRan())//bulk processing was started
|
1197 |
+
&& (!$this->prioQ->bulkPaused() || $this->_settings->skipToCustom)) //bulk not paused or if paused, user pressed Process Custom button
|
1198 |
{
|
1199 |
+
/*$percent = $this->prioQ->getBulkPercent();
|
1200 |
+
if(0 + $pendingMeta > 0) {
|
1201 |
+
$customMeta = $this->spMetaDao->getCustomMetaCount();
|
1202 |
+
$percent = round(($percent * $quotaData["totalFiles"] + ($customMeta - $pendingMeta) * 100) / ($quotaData["totalFiles"] + $customMeta));
|
1203 |
+
$percent = round($quotaData["totalProcessedFiles"] / $quotaData["totalFiles"]);
|
1204 |
+
}*/
|
1205 |
+
$percent = min(99, round($quotaData["totalProcessedFiles"] *100.0 / $quotaData["totalFiles"]));
|
1206 |
$msg = $this->bulkProgressMessage($this->prioQ->getDeltaBulkPercent(), $this->prioQ->getTimeRemaining());
|
1207 |
+
$this->view->displayBulkProcessingRunning($percent, $msg, $quotaData['APICallsRemaining'], $this->getAverageCompression(),
|
1208 |
+
($pendingMeta !== null ? ($this->prioQ->bulkRunning() ? 3 : 2) : 1));
|
1209 |
|
1210 |
// $imagesLeft = $filesLeft[0]->FilesLeftToBeProcessed;
|
1211 |
// $totalImages = $allFiles[0]->FilesToBeProcessed;
|
1216 |
if($this->prioQ->bulkRan() && !$this->prioQ->bulkPaused()) {
|
1217 |
$this->prioQ->markBulkComplete();
|
1218 |
}
|
1219 |
+
|
1220 |
//image count
|
1221 |
//$imageCount = $this->countAllProcessableFiles();
|
1222 |
$imageOnlyThumbs = $quotaData['totalFiles'] - $quotaData['mainFiles'];
|
1225 |
|
1226 |
//average compression
|
1227 |
$averageCompression = self::getAverageCompression();
|
1228 |
+
$percent = $this->prioQ->bulkPaused() ? round($quotaData["totalProcessedFiles"] *100.0 / $quotaData["totalFiles"]) : false;
|
1229 |
+
$this->view->displayBulkProcessingForm($quotaData, $thumbsProcessedCount, $under5PercentCount,
|
1230 |
+
$this->prioQ->bulkRan(), $averageCompression, $this->_settings->fileCount,
|
1231 |
+
self::formatBytes($this->_settings->savedSpace), $percent, $pendingMeta);
|
1232 |
}
|
1233 |
}
|
1234 |
//end bulk processing
|
1243 |
} elseif ($minutes > 240) {
|
1244 |
$timeEst = "~ " . round($minutes / 60) . " hours left";
|
1245 |
} elseif ($minutes > 60) {
|
1246 |
+
$timeEst = "~ " . round($minutes / 60) . " hours " . round($minutes % 60 / 10) * 10 . " min. left";
|
1247 |
} elseif ($minutes > 20) {
|
1248 |
$timeEst = "~ " . round($minutes / 10) * 10 . " minutes left";
|
1249 |
} else {
|
1283 |
return count(scandir(SP_BACKUP_FOLDER)) > 2 ? false : true;
|
1284 |
}
|
1285 |
|
1286 |
+
public function browseContent() {
|
1287 |
+
if ( !current_user_can( 'manage_options' ) ) {
|
1288 |
+
wp_die('You do not have sufficient permissions to access this page.');
|
1289 |
+
}
|
1290 |
+
|
1291 |
+
$root = $this->getCustomFolderBase();
|
1292 |
+
|
1293 |
+
$postDir = rawurldecode($root.(isset($_POST['dir']) ? $_POST['dir'] : null ));
|
1294 |
+
|
1295 |
+
// set checkbox if multiSelect set to true
|
1296 |
+
$checkbox = ( isset($_POST['multiSelect']) && $_POST['multiSelect'] == 'true' ) ? "<input type='checkbox' />" : null;
|
1297 |
+
$onlyFolders = ( isset($_POST['onlyFolders']) && $_POST['onlyFolders'] == 'true' ) ? true : false;
|
1298 |
+
$onlyFiles = ( isset($_POST['onlyFiles']) && $_POST['onlyFiles'] == 'true' ) ? true : false;
|
1299 |
+
|
1300 |
+
if( file_exists($postDir) ) {
|
1301 |
+
|
1302 |
+
$files = scandir($postDir);
|
1303 |
+
$returnDir = substr($postDir, strlen($root));
|
1304 |
+
|
1305 |
+
natcasesort($files);
|
1306 |
+
|
1307 |
+
if( count($files) > 2 ) { // The 2 accounts for . and ..
|
1308 |
+
echo "<ul class='jqueryFileTree'>";
|
1309 |
+
foreach( $files as $file ) {
|
1310 |
+
|
1311 |
+
if($file == 'ShortpixelBackups') continue;
|
1312 |
+
|
1313 |
+
$htmlRel = htmlentities($returnDir . $file);
|
1314 |
+
$htmlName = htmlentities($file);
|
1315 |
+
$ext = preg_replace('/^.*\./', '', $file);
|
1316 |
+
|
1317 |
+
if( file_exists($postDir . $file) && $file != '.' && $file != '..' ) {
|
1318 |
+
if( is_dir($postDir . $file) && (!$onlyFiles || $onlyFolders) )
|
1319 |
+
echo "<li class='directory collapsed'>{$checkbox}<a rel='" .$htmlRel. "/'>" . $htmlName . "</a></li>";
|
1320 |
+
else if (!$onlyFolders || $onlyFiles)
|
1321 |
+
echo "<li class='file ext_{$ext}'>{$checkbox}<a rel='" . $htmlRel . "'>" . $htmlName . "</a></li>";
|
1322 |
+
}
|
1323 |
+
}
|
1324 |
+
|
1325 |
+
echo "</ul>";
|
1326 |
+
}
|
1327 |
+
}
|
1328 |
+
die();
|
1329 |
+
}
|
1330 |
+
|
1331 |
+
public function getCustomFolderBase() {
|
1332 |
+
if(is_main_site()) {
|
1333 |
+
return WP_CONTENT_DIR;
|
1334 |
+
} else {
|
1335 |
+
$up = wp_upload_dir();
|
1336 |
+
return $up['basedir'];
|
1337 |
+
}
|
1338 |
+
}
|
1339 |
+
|
1340 |
+
protected function refreshCustomFolders(&$notice, $ignore = false) {
|
1341 |
+
$customFolders = array();
|
1342 |
+
if($this->_settings->hasCustomFolders) {
|
1343 |
+
$customFolders = $this->spMetaDao->getFolders();
|
1344 |
+
foreach($customFolders as $folder) {
|
1345 |
+
if($folder->getPath() === $ignore) continue;
|
1346 |
+
try {
|
1347 |
+
$mt = $folder->getFolderContentsChangeDate();
|
1348 |
+
if($mt > strtotime($folder->getTsUpdated())) {
|
1349 |
+
$fileList = $folder->getFileList(strtotime($folder->getTsUpdated()));
|
1350 |
+
$this->spMetaDao->batchInsertImages($fileList, $folder->getId());
|
1351 |
+
$folder->setTsUpdated(date("Y-m-d H:i:s", $mt));
|
1352 |
+
$folder->setFileCount($folder->countFiles());
|
1353 |
+
$this->spMetaDao->update($folder);
|
1354 |
+
}
|
1355 |
+
//echo ("mt: " . $mt);
|
1356 |
+
//die(var_dump($folder));
|
1357 |
+
} catch(SpFileRightsException $ex) {
|
1358 |
+
if(is_array($notice)) {
|
1359 |
+
if($notice['status'] == 'error') {
|
1360 |
+
$notice['msg'] .= " " . $ex->getMessage();
|
1361 |
+
}
|
1362 |
+
} else {
|
1363 |
+
$notice = array("status" => "error", "msg" => $ex->getMessage());
|
1364 |
+
}
|
1365 |
+
}
|
1366 |
+
}
|
1367 |
+
}
|
1368 |
+
return $customFolders;
|
1369 |
+
}
|
1370 |
+
|
1371 |
public function renderSettingsMenu() {
|
1372 |
if ( !current_user_can( 'manage_options' ) ) {
|
1373 |
wp_die('You do not have sufficient permissions to access this page.');
|
1374 |
}
|
1375 |
|
1376 |
+
wp_enqueue_style('sp-file-tree.css', plugins_url('/res/css/sp-file-tree.css',__FILE__) );
|
1377 |
+
wp_enqueue_script('sp-file-tree.js', plugins_url('/res/js/sp-file-tree.js',__FILE__) );
|
1378 |
+
|
1379 |
//die(var_dump($_POST));
|
1380 |
$noticeHTML = "";
|
1381 |
$notice = null;
|
1382 |
+
$folderMsg = false;
|
1383 |
+
$addedFolder = false;
|
1384 |
+
|
1385 |
$this->_settings->redirectedSettings = 2;
|
1386 |
+
|
1387 |
//by default we try to fetch the API Key from wp-config.php (if defined)
|
1388 |
if ( defined("SHORTPIXEL_API_KEY") && strlen(SHORTPIXEL_API_KEY) == 20)
|
1389 |
{
|
1393 |
$_POST['key'] = SHORTPIXEL_API_KEY;
|
1394 |
}
|
1395 |
|
1396 |
+
//check all custom folders and update meta table if files appeared
|
1397 |
+
$customFolders = $this->refreshCustomFolders($notice, isset($_POST['removeFolder']) ? $_POST['removeFolder'] : null);
|
1398 |
+
|
1399 |
+
if( isset($_POST['save']) || isset($_POST['saveAdv'])
|
1400 |
+
|| (isset($_POST['validate']) && $_POST['validate'] == "validate")
|
1401 |
+
|| isset($_POST['removeFolder'])) {
|
1402 |
+
|
1403 |
+
//handle API Key - common for save and validate.
|
1404 |
+
$_POST['key'] = trim(str_replace("*", "", isset($_POST['key']) ? $_POST['key'] : $this->_settings->apiKey)); //the API key might not be set if the editing is disabled.
|
1405 |
|
1406 |
if ( strlen($_POST['key']) <> 20 )
|
1407 |
{
|
1418 |
if($validityData['APIKeyValid']) {
|
1419 |
if(isset($_POST['validate']) && $_POST['validate'] == "validate") {
|
1420 |
// delete last status if it was no valid key
|
1421 |
+
$lastStatus = $this->_settings->bulkLastStatus;
|
1422 |
+
if(isset($lastStatus['Status']) && $lastStatus['Status'] == ShortPixelAPI::STATUS_NO_KEY) {
|
1423 |
+
$this->_settings->bulkLastStatus = null;
|
1424 |
}
|
1425 |
//display notification
|
1426 |
$urlParts = explode("/", get_site_url());
|
1438 |
//test that the "uploads" have the right rights and also we can create the backup dir for ShortPixel
|
1439 |
if ( !file_exists(SP_BACKUP_FOLDER) && !@mkdir(SP_BACKUP_FOLDER, 0777, true) )
|
1440 |
$notice = array("status" => "error", "msg" => "There is something preventing us to create a new folder for backing up your original files.<BR>
|
1441 |
+
Please make sure that folder <b>" . WP_CONTENT_DIR . DIRECTORY_SEPARATOR . SP_UPLOADS_NAME . "</b> has the necessary write and read rights.");
|
1442 |
} else {
|
1443 |
if(isset($_POST['validate'])) {
|
1444 |
//display notification
|
1448 |
}
|
1449 |
}
|
1450 |
|
|
|
1451 |
//if save button - we process the rest of the form elements
|
1452 |
+
if(isset($_POST['save']) || isset($_POST['saveAdv'])) {
|
1453 |
$this->_settings->compressionType = $_POST['compressionType'];
|
1454 |
if(isset($_POST['thumbnails'])) { $this->_settings->processThumbnails = 1; } else { $this->_settings->processThumbnails = 0; }
|
1455 |
if(isset($_POST['backupImages'])) { $this->_settings->backupImages = 1; } else { $this->_settings->backupImages = 0; }
|
1462 |
$this->_settings->siteAuthUser = (isset($_POST['siteAuthUser']) ? $_POST['siteAuthUser']: $this->_settings->siteAuthUser);
|
1463 |
$this->_settings->siteAuthPass = (isset($_POST['siteAuthPass']) ? $_POST['siteAuthPass']: $this->_settings->siteAuthPass);
|
1464 |
|
1465 |
+
$uploadDir = wp_upload_dir();
|
1466 |
+
$uploadPath = $uploadDir["basedir"];
|
1467 |
+
|
1468 |
+
if( isset($_POST['save']) && $_POST['save'] == "Save and Go to Bulk Process"
|
1469 |
+
|| isset($_POST['saveAdv']) && $_POST['saveAdv'] == "Save and Go to Bulk Process") {
|
1470 |
wp_redirect("upload.php?page=wp-short-pixel-bulk");
|
1471 |
exit();
|
1472 |
}
|
1473 |
+
|
1474 |
+
if(isset($_POST['nextGen'])) {
|
1475 |
+
WpShortPixelDb::checkCustomTables(); // check if custom tables are created, if not, create them
|
1476 |
+
$prevNextGen = $this->_settings->includeNextGen;
|
1477 |
+
$this->_settings->includeNextGen = 1;
|
1478 |
+
$ret = $this->addNextGenGalleriesToCustom($prevNextGen);
|
1479 |
+
$folderMsg = $ret["message"];
|
1480 |
+
$customFolders = $ret["customFolders"];
|
1481 |
+
} else {
|
1482 |
+
$this->_settings->includeNextGen = 0;
|
1483 |
+
}
|
1484 |
+
if(isset($_POST['addCustomFolder']) && strlen($_POST['addCustomFolder']) > 0) {
|
1485 |
+
$folderMsg = $this->spMetaDao->newFolderFromPath($_POST['addCustomFolder'], $uploadPath, $this->getCustomFolderBase());
|
1486 |
+
if(!$folderMsg) {
|
1487 |
+
$notice = array("status" => "success", "msg" => 'Folder added successfully.');
|
1488 |
+
}
|
1489 |
+
$customFolders = $this->spMetaDao->getFolders();
|
1490 |
+
$this->_settings->hasCustomFolders = true;
|
1491 |
+
}
|
1492 |
+
if(isset($_POST['frontBootstrap'])) { $this->_settings->frontBootstrap = 1; } else { $this->_settings->frontBootstrap = 0; }
|
1493 |
+
}
|
1494 |
+
if(isset($_POST['removeFolder']) && strlen(($_POST['removeFolder']))) {
|
1495 |
+
$this->spMetaDao->removeFolder($_POST['removeFolder']);
|
1496 |
+
$customFolders = $this->spMetaDao->getFolders();
|
1497 |
+
$_POST["saveAdv"] = true;
|
1498 |
}
|
1499 |
}
|
1500 |
+
|
1501 |
//now output headers. They were prevented with noheaders=true in the form url in order to be able to redirect if bulk was pressed
|
1502 |
if(isset($_REQUEST['noheader'])) {
|
1503 |
require_once(ABSPATH . 'wp-admin/admin-header.php');
|
1509 |
}
|
1510 |
|
1511 |
$quotaData = $this->checkQuotaAndAlert(isset($validityData) ? $validityData : null);
|
1512 |
+
|
1513 |
+
if($this->hasNextGen) {
|
1514 |
+
$ngg = array_map(function($item){
|
1515 |
+
return str_replace(DIRECTORY_SEPARATOR.DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR, get_home_path() . $item);
|
1516 |
+
}, ShortPixelNextGenAdapter::getGalleries());
|
1517 |
+
//die(var_dump($ngg));
|
1518 |
+
for($i = 0; $i < count($customFolders); $i++) {
|
1519 |
+
if(in_array($customFolders[$i]->getPath(), $ngg )) {
|
1520 |
+
$customFolders[$i]->setType("NextGen");
|
1521 |
+
}
|
1522 |
+
}
|
1523 |
+
}
|
1524 |
|
1525 |
+
$showApiKey = is_main_site() || (function_exists("is_multisite") && is_multisite() && !defined("SHORTPIXEL_API_KEY"));
|
1526 |
+
$editApiKey = ( is_main_site() && function_exists("is_multisite") && is_multisite()
|
1527 |
+
|| !function_exists("is_multisite")
|
1528 |
+
|| !is_multisite() )
|
1529 |
+
&& !defined("SHORTPIXEL_API_KEY");
|
1530 |
+
|
1531 |
if($this->_settings->verifiedKey) {
|
1532 |
$fileCount = number_format($this->_settings->fileCount);
|
1533 |
$savedSpace = self::formatBytes($this->_settings->savedSpace,2);
|
1534 |
+
$averageCompression = $this->getAverageCompression();
|
1535 |
$savedBandwidth = self::formatBytes($this->_settings->savedSpace * 10000,2);
|
1536 |
if (is_numeric($quotaData['APICallsQuota'])) {
|
1537 |
$quotaData['APICallsQuota'] .= "/month";
|
1538 |
}
|
1539 |
$backupFolderSize = self::formatBytes(self::folderSize(SP_BACKUP_FOLDER));
|
1540 |
+
$remainingImages = $quotaData['APICallsRemaining'];
|
1541 |
$remainingImages = ( $remainingImages < 0 ) ? 0 : number_format($remainingImages);
|
1542 |
$totalCallsMade = number_format($quotaData['APICallsMadeNumeric'] + $quotaData['APICallsMadeOneTimeNumeric']);
|
1543 |
|
1545 |
if(is_wp_error( $resources )) {
|
1546 |
$resources = array();
|
1547 |
}
|
1548 |
+
$this->view->displaySettings($showApiKey, $editApiKey,
|
1549 |
+
$quotaData, $notice, $resources, $averageCompression, $savedSpace, $savedBandwidth, $remainingImages,
|
1550 |
+
$totalCallsMade, $fileCount, $backupFolderSize, $customFolders,
|
1551 |
+
$folderMsg, $folderMsg ? $addedFolder : false, isset($_POST['saveAdv']));
|
1552 |
} else {
|
1553 |
+
$this->view->displaySettings($showApiKey, $editApiKey, $quotaData, $notice);
|
|
|
1554 |
}
|
1555 |
|
1556 |
}
|
1557 |
|
1558 |
+
public function addNextGenGalleriesToCustom($silent) {
|
1559 |
+
$customFolders = array();
|
1560 |
+
$folderMsg = "";
|
1561 |
+
if($this->_settings->includeNextGen) {
|
1562 |
+
//add the NextGen galleries to custom folders
|
1563 |
+
$ngGalleries = ShortPixelNextGenAdapter::getGalleries();
|
1564 |
+
foreach($ngGalleries as $gallery) {
|
1565 |
+
$folderMsg = $this->spMetaDao->newFolderFromPath($gallery, get_home_path(), $this->getCustomFolderBase());
|
1566 |
+
$this->_settings->hasCustomFolders = true;
|
1567 |
+
}
|
1568 |
+
$customFolders = $this->spMetaDao->getFolders();
|
1569 |
+
}
|
1570 |
+
return array("message" => $silent? "" : $folderMsg, "customFolders" => $customFolders);
|
1571 |
+
}
|
1572 |
+
|
1573 |
public function getAverageCompression(){
|
1574 |
return $this->_settings->totalOptimized > 0
|
1575 |
? round(( 1 - ( $this->_settings->totalOptimized / $this->_settings->totalOriginal ) ) * 100, 2)
|
1604 |
}
|
1605 |
if($validate) {
|
1606 |
$args['body']['DomainCheck'] = get_site_url();
|
1607 |
+
$imageCount = WpShortPixelMediaLbraryAdapter::countAllProcessableFiles();
|
1608 |
$args['body']['ImagesCount'] = $imageCount['mainFiles'];
|
1609 |
$args['body']['ThumbsCount'] = $imageCount['totalFiles'] - $imageCount['mainFiles'];
|
1610 |
$argsStr .= "&DomainCheck={$args['body']['DomainCheck']}&ImagesCount={$imageCount['mainFiles']}&ThumbsCount={$args['body']['ThumbsCount']}";
|
1654 |
$response = wp_remote_get($requestURL, $args);
|
1655 |
$comm[] = array("sent" => "POST: " . $requestURL, "args" => $args, "received" => $response);
|
1656 |
}
|
1657 |
+
|
1658 |
$defaultData = array(
|
1659 |
"APIKeyValid" => false,
|
1660 |
"Message" => 'API Key could not be validated due to a connectivity error.<BR>Your firewall may be blocking us. Please contact your hosting provider and ask them to allow connections from your site to IP 176.9.106.46.<BR> If you still cannot validate your API Key after this, please <a href="https://shortpixel.com/contact" target="_blank">contact us</a> and we will try to help. ',
|
1678 |
}
|
1679 |
|
1680 |
$data = $response['body'];
|
1681 |
+
$data = ShortPixelTools::parseJSON($data);
|
1682 |
|
1683 |
if(empty($data)) { return $defaultData; }
|
1684 |
|
1692 |
else
|
1693 |
$this->_settings->quotaExceeded = 1;//activate quota limiting
|
1694 |
|
1695 |
+
//if a non-valid status exists, delete it
|
1696 |
+
$lastStatus = $this->_settings->bulkLastStatus = null;
|
1697 |
+
if($lastStatus && $lastStatus['Status'] == ShortPixelAPI::STATUS_NO_KEY) {
|
1698 |
+
$this->_settings->bulkLastStatus = null;
|
1699 |
}
|
1700 |
|
1701 |
return array(
|
1708 |
"APICallsQuotaNumeric" => $data->APICallsQuota,
|
1709 |
"APICallsMadeOneTimeNumeric" => $data->APICallsMadeOneTime,
|
1710 |
"APICallsQuotaOneTimeNumeric" => $data->APICallsQuotaOneTime,
|
1711 |
+
"APICallsRemaining" => $data->APICallsQuota + $data->APICallsQuotaOneTime - $data->APICallsMade - $data->APICallsMadeOneTime,
|
1712 |
"APILastRenewalDate" => $data->DateSubscription,
|
1713 |
"DomainCheck" => (isset($data->DomainCheck) ? $data->DomainCheck : null)
|
1714 |
);
|
1724 |
$quotaExceeded = $this->_settings->quotaExceeded;
|
1725 |
$renderData = array("id" => $id, "showActions" => current_user_can( 'manage_options' ));
|
1726 |
|
|
|
|
|
|
|
1727 |
if($invalidKey) { //invalid key - let the user first register and only then
|
1728 |
$renderData['status'] = 'invalidKey';
|
1729 |
$this->view->renderCustomColumn($id, $renderData);
|
1779 |
}
|
1780 |
elseif(isset($data['ShortPixel']['WaitingProcessing'])) {
|
1781 |
$renderData['status'] = $quotaExceeded ? 'quotaExceeded' : 'retry';
|
1782 |
+
$renderData['message'] = "<img src=\"" . plugins_url( 'res/img/loading.gif', __FILE__ ) . "\" class='sp-loading-small'> Image waiting to be processed.";
|
1783 |
+
if($id > $this->prioQ->getFlagBulkId() || !$this->prioQ->bulkRunning()) $this->prioQ->push($id); //should be there but just to make sure
|
1784 |
}
|
1785 |
else { //finally
|
1786 |
$renderData['status'] = $quotaExceeded ? 'quotaExceeded' : 'optimizeNow';
|
1787 |
$sizes = isset($data['sizes']) ? count($data['sizes']) : 0;
|
1788 |
$renderData['thumbsTotal'] = $sizes;
|
1789 |
$renderData['message'] = ($fileExtension == "pdf" ? 'PDF' : 'Image') . ' not processed.';
|
1790 |
+
}
|
1791 |
+
|
1792 |
$this->view->renderCustomColumn($id, $renderData);
|
1793 |
}
|
1794 |
}
|
1801 |
return $defaults;
|
1802 |
}
|
1803 |
|
1804 |
+
public function nggColumns( $defaults ) {
|
1805 |
+
$this->nggColumnIndex = count($defaults) + 1;
|
1806 |
+
add_filter( 'ngg_manage_images_column_' . $this->nggColumnIndex . '_header', array( &$this, 'nggColumnHeader' ) );
|
1807 |
+
add_filter( 'ngg_manage_images_column_' . $this->nggColumnIndex . '_content', array( &$this, 'nggColumnContent' ), 10, 2 );
|
1808 |
+
$defaults['wp-shortPixelNgg'] = 'ShortPixel Compression';
|
1809 |
+
return $defaults;
|
1810 |
}
|
1811 |
|
1812 |
+
public function nggCountColumns( $count ) {
|
1813 |
+
return $count + 1;
|
1814 |
+
}
|
1815 |
+
|
1816 |
+
public function nggColumnHeader( $default ) {
|
1817 |
+
return 'ShortPixel Compression';
|
1818 |
+
}
|
1819 |
+
|
1820 |
+
public function nggColumnContent( $unknown, $picture ) {
|
1821 |
+
|
1822 |
+
$meta = $this->spMetaDao->getMetaForPath($picture->imagePath);
|
1823 |
+
if($meta) {
|
1824 |
+
switch($meta->getStatus()) {
|
1825 |
+
case "0": echo("<div id='sp-msg-C-{$meta->getId()}' class='column-wp-shortPixel' style='color: #928B1E'>Waiting</div>"); break;
|
1826 |
+
case "1": echo("<div id='sp-msg-C-{$meta->getId()}' class='column-wp-shortPixel' style='color: #1919E2'>Pending</div>"); break;
|
1827 |
+
case "2": $this->view->renderCustomColumn("C-" . $meta->getId(), array(
|
1828 |
+
'showActions' => false && current_user_can( 'manage_options' ),
|
1829 |
+
'status' => 'imgOptimized',
|
1830 |
+
'type' => ShortPixelAPI::getCompressionTypeName($meta->getCompressionType()),
|
1831 |
+
'percent' => $meta->getImprovementPercent(),
|
1832 |
+
'bonus' => $meta->getImprovementPercent() < 5,
|
1833 |
+
'thumbsOpt' => 0,
|
1834 |
+
'thumbsTotal' => 0,
|
1835 |
+
'backup' => true
|
1836 |
+
));
|
1837 |
+
break;
|
1838 |
+
}
|
1839 |
} else {
|
1840 |
+
$this->view->renderCustomColumn($meta ? "C-" . $meta->getId() : "N-" . $picture->pid, array(
|
1841 |
+
'showActions' => false && current_user_can( 'manage_options' ),
|
1842 |
+
'status' => 'optimizeNow',
|
1843 |
+
'thumbsOpt' => 0,
|
1844 |
+
'thumbsTotal' => 0,
|
1845 |
+
'message' => "Not optimized"
|
1846 |
+
));
|
1847 |
}
|
1848 |
+
// return var_dump($meta);
|
1849 |
}
|
1850 |
|
1851 |
+
public function generatePluginLinks($links) {
|
1852 |
+
$in = '<a href="options-general.php?page=wp-shortpixel">Settings</a>';
|
1853 |
+
array_unshift($links, $in);
|
1854 |
+
return $links;
|
1855 |
+
}
|
1856 |
|
1857 |
static public function formatBytes($bytes, $precision = 2) {
|
1858 |
$units = array('B', 'KB', 'MB', 'GB', 'TB');
|
1873 |
|
1874 |
static public function isProcessablePath($path) {
|
1875 |
$pathParts = pathinfo($path);
|
1876 |
+
if( isset($pathParts['extension']) && in_array(strtolower($pathParts['extension']), self::$PROCESSABLE_EXTENSIONS)) {
|
1877 |
return true;
|
1878 |
} else {
|
1879 |
return false;
|
1882 |
|
1883 |
|
1884 |
//return an array with URL(s) and PATH(s) for this file
|
1885 |
+
public function getURLsAndPATHs($itemHandler, $meta = NULL, $onlyThumbs = false) {
|
1886 |
+
return $itemHandler->getURLsAndPATHs($this->_settings->processThumbnails, $onlyThumbs);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1887 |
}
|
1888 |
|
1889 |
|
1890 |
public static function deleteDir($dirPath) {
|
1891 |
+
if (substr($dirPath, strlen($dirPath) - 1, 1) != DIRECTORY_SEPARATOR) {
|
1892 |
+
$dirPath .= DIRECTORY_SEPARATOR;
|
|
|
1893 |
}
|
1894 |
$files = glob($dirPath . '*', GLOB_MARK);
|
1895 |
foreach ($files as $file) {
|
1909 |
} else {
|
1910 |
return $total_size;
|
1911 |
}
|
1912 |
+
$cleanPath = rtrim($path, DIRECTORY_SEPARATOR). DIRECTORY_SEPARATOR;
|
1913 |
foreach($files as $t) {
|
1914 |
if ($t<>"." && $t<>"..")
|
1915 |
{
|
1927 |
return $total_size;
|
1928 |
}
|
1929 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1930 |
public function migrateBackupFolder() {
|
1931 |
+
$oldBackupFolder = WP_CONTENT_DIR . DIRECTORY_SEPARATOR . SP_BACKUP;
|
1932 |
|
1933 |
+
if(file_exists($oldBackupFolder)) { //if old backup folder does not exist then there is nothing to do
|
1934 |
|
1935 |
if(!file_exists(SP_BACKUP_FOLDER)) {
|
1936 |
+
//we check that the backup folder exists, if not we create it so we can copy into it
|
1937 |
+
if(!mkdir(SP_BACKUP_FOLDER, 0777, true)) return;
|
1938 |
+
}
|
1939 |
|
1940 |
+
$scannedDirectory = array_diff(scandir($oldBackupFolder), array('..', '.'));
|
1941 |
+
foreach($scannedDirectory as $file) {
|
1942 |
+
@rename($oldBackupFolder.DIRECTORY_SEPARATOR.$file, SP_BACKUP_FOLDER.DIRECTORY_SEPARATOR.$file);
|
1943 |
+
}
|
1944 |
+
$scannedDirectory = array_diff(scandir($oldBackupFolder), array('..', '.'));
|
1945 |
+
if(empty($scannedDirectory)) {
|
1946 |
+
@rmdir($oldBackupFolder);
|
1947 |
+
}
|
1948 |
}
|
1949 |
+
//now if the backup folder does not contain the uploads level, create it
|
1950 |
+
if(!is_dir(SP_BACKUP_FOLDER.DIRECTORY_SEPARATOR.SP_UPLOADS_NAME)) {
|
1951 |
+
@rename(SP_BACKUP_FOLDER, SP_BACKUP_FOLDER."_tmp");
|
1952 |
+
@mkdir(SP_BACKUP_FOLDER);
|
1953 |
+
@rename(SP_BACKUP_FOLDER."_tmp", SP_BACKUP_FOLDER.DIRECTORY_SEPARATOR.SP_UPLOADS_NAME);
|
1954 |
+
if(!file_exists(SP_BACKUP_FOLDER)) {//just in case..
|
1955 |
+
@rename(SP_BACKUP_FOLDER."_tmp", SP_BACKUP_FOLDER);
|
1956 |
+
}
|
1957 |
}
|
|
|
1958 |
return;
|
1959 |
}
|
1960 |
|
1988 |
*/
|
1989 |
public static function encrypt($pure_string, $encryption_key)
|
1990 |
{
|
1991 |
+
if(!function_exists("mcrypt_get_iv_size") || !function_exists('utf8_encode')) {
|
1992 |
return "";
|
1993 |
}
|
1994 |
$iv_size = \mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB);
|
2022 |
return $this->_settings;
|
2023 |
}
|
2024 |
|
|
|
2025 |
public function getResizeImages() {
|
2026 |
return $this->_settings->resizeImages;
|
2027 |
}
|
2042 |
public function getCompressionType() {
|
2043 |
return $this->_settings->compressionType;
|
2044 |
}
|
2045 |
+
public function hasNextGen() {
|
2046 |
+
return $this->hasNextGen;
|
2047 |
+
}
|
2048 |
+
|
2049 |
+
public function getSpMetaDao() {
|
2050 |
+
return $this->spMetaDao;
|
2051 |
+
}
|
2052 |
|
2053 |
}
|
2054 |
|
2055 |
+
|
2056 |
+
function shortpixelInit() {
|
|
|
|
|
|
|
2057 |
global $pluginInstance;
|
2058 |
+
//is admin, is logged in - :) seems funny but it's not, ajax scripts are admin even if no admin is logged in.
|
2059 |
+
$prio = get_option('wp-short-pixel-priorityQueue');
|
2060 |
+
if (!isset($pluginInstance)
|
2061 |
+
&& (($prio && is_array($prio) && count($prio) && get_option('wp-short-pixel-front-bootstrap'))
|
2062 |
+
|| is_admin()
|
2063 |
+
&& (function_exists("is_user_logged_in") && is_user_logged_in())
|
2064 |
+
&& ( current_user_can( 'manage_options' )
|
2065 |
+
|| current_user_can( 'upload_files' )
|
2066 |
+
|| current_user_can( 'edit_posts' )
|
2067 |
+
)
|
2068 |
+
)
|
2069 |
+
)
|
2070 |
+
{
|
2071 |
+
$pluginInstance = new WPShortPixel;
|
2072 |
+
}
|
2073 |
}
|
2074 |
|
2075 |
+
function handleImageUploadHook($meta, $ID = null) {
|
2076 |
+
global $pluginInstance;
|
2077 |
+
if(!isset($pluginInstance)) {
|
2078 |
+
$pluginInstance = new WPShortPixel;
|
2079 |
+
}
|
2080 |
+
return $pluginInstance->handleMediaLibraryImageUpload($meta, $ID);
|
2081 |
+
}
|
2082 |
+
|
2083 |
+
function shortpixelNggAdd($image) {
|
2084 |
+
global $pluginInstance;
|
2085 |
+
if(!isset($pluginInstance)) {
|
2086 |
+
$pluginInstance = new WPShortPixel;
|
2087 |
+
}
|
2088 |
+
$pluginInstance->handleNextGenImageUpload($image);
|
2089 |
+
}
|
2090 |
|
2091 |
+
if ( !function_exists( 'vc_action' ) || vc_action() !== 'vc_inline' ) { //handle incompatibility with Visual Composer
|
2092 |
+
add_action( 'init', 'shortpixelInit');
|
2093 |
+
add_action('ngg_added_new_image', 'shortpixelNggAdd');
|
2094 |
+
add_filter( 'wp_generate_attachment_metadata', 'handleImageUploadHook', 10, 2 );
|
2095 |
+
|
2096 |
register_activation_hook( __FILE__, array( 'WPShortPixel', 'shortPixelActivatePlugin' ) );
|
2097 |
register_deactivation_hook( __FILE__, array( 'WPShortPixel', 'shortPixelDeactivatePlugin' ) );
|
2098 |
|