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