ShortPixel Image Optimizer - Version 4.2.8

Version Description

  • fix bug when searching for thumbanils of files with same prefix
  • fix bug when several successive images have all files missing
Download this release

Release Info

Developer ShortPixel
Plugin Icon 128x128 ShortPixel Image Optimizer
Version 4.2.8
Comparing to
See all releases

Code changes from version 4.2.7 to 4.2.8

class/db/shortpixel-meta-facade.php CHANGED
@@ -49,7 +49,7 @@ class ShortPixelMetaFacade {
49
  $path = get_attached_file($ID);
50
  return new ShortPixelMeta(array(
51
  "id" => $ID,
52
- "name" => basename($path),
53
  "path" => $path,
54
  "webPath" => (isset($rawMeta["file"]) ? $rawMeta["file"] : null),
55
  "thumbs" => (isset($rawMeta["sizes"]) ? $rawMeta["sizes"] : array()),
49
  $path = get_attached_file($ID);
50
  return new ShortPixelMeta(array(
51
  "id" => $ID,
52
+ "name" => ShortPixelAPI::MB_basename($path),
53
  "path" => $path,
54
  "webPath" => (isset($rawMeta["file"]) ? $rawMeta["file"] : null),
55
  "thumbs" => (isset($rawMeta["sizes"]) ? $rawMeta["sizes"] : array()),
class/db/wp-shortpixel-media-library-adapter.php CHANGED
@@ -141,9 +141,30 @@ class WpShortPixelMediaLbraryAdapter {
141
  return $count;
142
  }
143
 
144
- public static function thumbsSearchPattern($mainFile) {
 
 
 
 
 
 
 
 
 
 
 
 
145
  $ext = pathinfo($mainFile, PATHINFO_EXTENSION);
146
- return substr($mainFile, 0, strlen($mainFile) - strlen($ext) - 1) . "*[0-9]x*[0-9]." . $ext;
 
 
 
 
 
 
 
 
 
147
  }
148
 
149
  protected static function getOptimalChunkSize() {
141
  return $count;
142
  }
143
 
144
+ public static function cleanupFoundThumbs($itemHandler) {
145
+ $meta = $itemHandler->getMeta();
146
+ $sizesAll = $meta->getThumbs();
147
+ $sizes = array();
148
+ foreach($sizesAll as $key => $size) {
149
+ if (strpos($key, ShortPixelMeta::FOUND_THUMB_PREFIX) === 0) continue;
150
+ $sizes[$key] = $size;
151
+ }
152
+ $meta->setThumbs($sizes);
153
+ $itemHandler->updateMeta($meta);
154
+ }
155
+
156
+ public static function findThumbs($mainFile) {
157
  $ext = pathinfo($mainFile, PATHINFO_EXTENSION);
158
+ $base = substr($mainFile, 0, strlen($mainFile) - strlen($ext) - 1);
159
+ $pattern = '/' . preg_quote($base, '/') . '-\d+x\d+\.'. $ext .'/';
160
+ $thumbsCandidates = @glob($base . "-*." . $ext);
161
+ $thumbs = array();
162
+ foreach($thumbsCandidates as $th) {
163
+ if(preg_match($pattern, $th)) {
164
+ $thumbs[]= $th;
165
+ }
166
+ }
167
+ return $thumbs;
168
  }
169
 
170
  protected static function getOptimalChunkSize() {
class/view/shortpixel_view.php CHANGED
@@ -907,7 +907,7 @@ class ShortPixelView {
907
  <tr>
908
  <th scope="row"><label for="optimizePdfs"><?php _e('Optimize PDFs','shortpixel-image-optimiser');?></label></th>
909
  <td>
910
- <input name="optimizePdfs" type="checkbox" id="optimizePdfs" <?php echo( $optimizePdfs );?>> <?php _e('Optimize PDF documents.','shortpixel-image-optimiser');?>
911
  </td>
912
  </tr>
913
  <tr>
907
  <tr>
908
  <th scope="row"><label for="optimizePdfs"><?php _e('Optimize PDFs','shortpixel-image-optimiser');?></label></th>
909
  <td>
910
+ <input name="optimizePdfs" type="checkbox" id="optimizePdfs" <?php echo( $optimizePdfs );?>> <?php _e('Automatically optimize PDF documents.','shortpixel-image-optimiser');?>
911
  </td>
912
  </tr>
913
  <tr>
class/wp-short-pixel.php ADDED
@@ -0,0 +1,2457 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class WPShortPixel {
4
+
5
+ const BULK_EMPTY_QUEUE = 0;
6
+
7
+ private $_affiliateSufix;
8
+
9
+ private $_apiInterface = null;
10
+ private $_settings = null;
11
+ private $prioQ = null;
12
+ private $view = null;
13
+
14
+ private $hasNextGen = false;
15
+ private $spMetaDao = null;
16
+
17
+ public static $PROCESSABLE_EXTENSIONS = array('jpg', 'jpeg', 'gif', 'png', 'pdf');
18
+
19
+ public function __construct() {
20
+ if (!session_id()) {
21
+ session_start();
22
+ }
23
+
24
+ load_plugin_textdomain('shortpixel-image-optimiser', false, plugin_basename(dirname( SHORTPIXEL_PLUGIN_FILE )).'/lang');
25
+
26
+ $isAdminUser = current_user_can( 'manage_options' );
27
+
28
+ $this->_affiliateSufix = (strlen(SP_AFFILIATE_CODE)) ? "/affiliate/" . SP_AFFILIATE_CODE : "";
29
+ $this->_settings = new WPShortPixelSettings();
30
+ $this->_apiInterface = new ShortPixelAPI($this->_settings);
31
+ $this->hasNextGen = ShortPixelNextGenAdapter::hasNextGen();
32
+ $this->spMetaDao = new ShortPixelCustomMetaDao(new WpShortPixelDb(), $this->_settings->hasCustomFolders);
33
+ $this->prioQ = new ShortPixelQueue($this, $this->_settings);
34
+ $this->view = new ShortPixelView($this);
35
+
36
+ define('QUOTA_EXCEEDED', $this->view->getQuotaExceededHTML());
37
+
38
+ $this->setDefaultViewModeList();//set default mode as list. only @ first run
39
+
40
+ //add hook for image upload processing
41
+ //add_filter( 'wp_generate_attachment_metadata', array( &$this, 'handleMediaLibraryImageUpload' ), 10, 2 ); // now external
42
+ add_filter( 'plugin_action_links_' . plugin_basename(SHORTPIXEL_PLUGIN_FILE), array(&$this, 'generatePluginLinks'));//for plugin settings page
43
+
44
+ //add_action( 'admin_footer', array(&$this, 'handleImageProcessing'));
45
+
46
+ //Media custom column
47
+ add_filter( 'manage_media_columns', array( &$this, 'columns' ) );//add media library column header
48
+ add_action( 'manage_media_custom_column', array( &$this, 'generateCustomColumn' ), 10, 2 );//generate the media library column
49
+ //Edit media meta box
50
+ add_action( 'add_meta_boxes', array( &$this, 'shortpixelInfoBox') );
51
+ //for cleaning up the WebP images when an attachment is deleted
52
+ add_action( 'delete_attachment', array( &$this, 'onDeleteImage') );
53
+
54
+ //for NextGen
55
+ if($this->_settings->hasCustomFolders) {
56
+ add_filter( 'ngg_manage_images_columns', array( &$this, 'nggColumns' ) );
57
+ add_filter( 'ngg_manage_images_number_of_columns', array( &$this, 'nggCountColumns' ) );
58
+ add_filter( 'ngg_manage_images_column_7_header', array( &$this, 'nggColumnHeader' ) );
59
+ add_filter( 'ngg_manage_images_column_7_content', array( &$this, 'nggColumnContent' ) );
60
+ // hook on the NextGen gallery list update
61
+ add_action('ngg_update_addgallery_page', array( &$this, 'addNextGenGalleriesToCustom'));
62
+ }
63
+
64
+ // integration with WP/LR Sync plugin
65
+ add_action( 'wplr_update_media', array( &$this, 'onWpLrUpdateMedia' ), 10, 2);
66
+
67
+ //custom hook
68
+ add_action( 'shortpixel-optimize-now', array( &$this, 'optimizeNowHook' ), 10, 1);
69
+
70
+ if($isAdminUser) {
71
+ //add settings page
72
+ add_action( 'admin_menu', array( &$this, 'registerSettingsPage' ) );//display SP in Settings menu
73
+ add_action( 'admin_menu', array( &$this, 'registerAdminPage' ) );
74
+
75
+ add_action('wp_ajax_shortpixel_browse_content', array(&$this, 'browseContent'));
76
+ add_action('wp_ajax_shortpixel_get_backup_size', array(&$this, 'getBackupSize'));
77
+
78
+ add_action( 'delete_attachment', array( &$this, 'handleDeleteAttachmentInBackup' ) );
79
+ add_action( 'load-upload.php', array( &$this, 'handleCustomBulk'));
80
+
81
+ //backup restore
82
+ add_action('admin_action_shortpixel_restore_backup', array(&$this, 'handleRestoreBackup'));
83
+ //reoptimize with a different algorithm (losless/lossy)
84
+ add_action('wp_ajax_shortpixel_redo', array(&$this, 'handleRedo'));
85
+ //optimize thumbnails
86
+ add_action('wp_ajax_shortpixel_optimize_thumbs', array(&$this, 'handleOptimizeThumbs'));
87
+
88
+ //toolbar notifications
89
+ add_action( 'admin_bar_menu', array( &$this, 'toolbar_shortpixel_processing'), 999 );
90
+ //deactivate plugin
91
+ add_action( 'admin_post_shortpixel_deactivate_plugin', array(&$this, 'deactivatePlugin'));
92
+ }
93
+
94
+ //automatic optimization
95
+ add_action( 'wp_ajax_shortpixel_image_processing', array( &$this, 'handleImageProcessing') );
96
+ //manual optimization
97
+ add_action( 'wp_ajax_shortpixel_manual_optimization', array(&$this, 'handleManualOptimization'));
98
+ //dismiss notices
99
+ add_action( 'wp_ajax_shortpixel_dismiss_notice', array(&$this, 'dismissAdminNotice'));
100
+ add_action( 'wp_ajax_shortpixel_dismiss_media_alert', array(&$this, 'dismissMediaAlert'));
101
+ //check quota
102
+ add_action('admin_action_shortpixel_check_quota', array(&$this, 'handleCheckQuota'));
103
+ //This adds the constants used in PHP to be available also in JS
104
+ add_action( 'admin_footer', array( &$this, 'shortPixelJS') );
105
+
106
+ if($this->_settings->frontBootstrap) {
107
+ //also need to have it in the front footer then
108
+ add_action( 'wp_footer', array( &$this, 'shortPixelJS') );
109
+ //need to add the nopriv action for when items exist in the queue and no user is logged in
110
+ add_action( 'wp_ajax_nopriv_shortpixel_image_processing', array( &$this, 'handleImageProcessing') );
111
+ }
112
+ //register a method to display admin notices if necessary
113
+ add_action('admin_notices', array( &$this, 'displayAdminNotices'));
114
+
115
+ $this->migrateBackupFolder();
116
+
117
+ if(!$this->_settings->redirectedSettings && !$this->_settings->verifiedKey && (!function_exists("is_multisite") || !is_multisite())) {
118
+ $this->_settings->redirectedSettings = 1;
119
+ wp_redirect(admin_url("options-general.php?page=wp-shortpixel"));
120
+ exit();
121
+ }
122
+ }
123
+
124
+ //handling older
125
+ public function WPShortPixel() {
126
+ $this->__construct();
127
+ }
128
+
129
+ public function registerSettingsPage() {
130
+ add_options_page( __('ShortPixel Settings','shortpixel-image-optimiser'), 'ShortPixel', 'manage_options', 'wp-shortpixel', array($this, 'renderSettingsMenu'));
131
+ }
132
+
133
+ function registerAdminPage( ) {
134
+ if($this->spMetaDao->hasFoldersTable() && count($this->spMetaDao->getFolders())) {
135
+ /*translators: title and menu name for the Other media page*/
136
+ add_media_page( __('Other Media Optimized by ShortPixel','shortpixel-image-optimiser'), __('Other Media','shortpixel-image-optimiser'), 'edit_others_posts', 'wp-short-pixel-custom', array( &$this, 'listCustomMedia' ) );
137
+ }
138
+ /*translators: title and menu name for the Bulk Processing page*/
139
+ add_media_page( __('ShortPixel Bulk Process','shortpixel-image-optimiser'), __('Bulk ShortPixel','shortpixel-image-optimiser'), 'edit_others_posts', 'wp-short-pixel-bulk', array( &$this, 'bulkProcess' ) );
140
+ }
141
+
142
+ public static function shortPixelActivatePlugin()//reset some params to avoid trouble for plugins that were activated/deactivated/activated
143
+ {
144
+ self::shortPixelDeactivatePlugin();
145
+ if(SP_RESET_ON_ACTIVATE === true && WP_DEBUG === true) { //force reset plugin counters, only on specific occasions and on test environments
146
+ WPShortPixelSettings::debugResetOptions();
147
+
148
+ $settings = new WPShortPixelSettings();
149
+ $spMetaDao = new ShortPixelCustomMetaDao(new WpShortPixelDb(), $settings->hasCustomFolders);
150
+ $spMetaDao->dropTables();
151
+ }
152
+ WPShortPixelSettings::onActivate();
153
+ }
154
+
155
+ public static function shortPixelDeactivatePlugin()//reset some params to avoid trouble for plugins that were activated/deactivated/activated
156
+ {
157
+ include_once dirname( SHORTPIXEL_PLUGIN_FILE ) . '/wp-shortpixel-req.php';
158
+ ShortPixelQueue::resetBulk();
159
+ ShortPixelQueue::resetPrio();
160
+ WPShortPixelSettings::onDeactivate();
161
+ }
162
+
163
+ public static function getConflictingPlugins() {
164
+ $conflictPlugins = array(
165
+ 'WP Smush - Image Optimization' => 'wp-smushit/wp-smush.php',
166
+ 'Imagify Image Optimizer' => 'imagify/imagify.php',
167
+ 'Compress JPEG & PNG images (TinyPNG)' => 'tiny-compress-images/tiny-compress-images.php',
168
+ 'Kraken.io Image Optimizer' => 'kraken-image-optimizer/kraken.php',
169
+ 'Optimus - WordPress Image Optimizer' => 'optimus/optimus.php',
170
+ 'EWWW Image Optimizer' => 'ewww-image-optimizer/ewww-image-optimizer.php',
171
+ 'ImageRecycle pdf & image compression' => 'imagerecycle-pdf-image-compression/wp-image-recycle.php',
172
+ 'CheetahO Image Optimizer' => 'cheetaho-image-optimizer/cheetaho.php',
173
+ 'Zara 4 Image Compression' => 'zara-4/zara-4.php',
174
+ 'Prizm Image' => 'prizm-image/wp-prizmimage.php',
175
+ 'CW Image Optimizer' => 'cw-image-optimizer/cw-image-optimizer.php'
176
+ );
177
+ $found = array();
178
+ foreach($conflictPlugins as $name => $path) {
179
+ if(is_plugin_active($path)) {
180
+ $found[] = array('name' => $name, 'path' => $path);
181
+ }
182
+ }
183
+ return $found;
184
+ }
185
+
186
+ public function displayAdminNotices() {
187
+ $dismissed = $this->_settings->dismissedNotices ? $this->_settings->dismissedNotices : array();
188
+ if(!$this->_settings->verifiedKey) {
189
+ $now = time();
190
+ $act = $this->_settings->activationDate ? $this->_settings->activationDate : $now;
191
+ if($this->_settings->activationNotice && $this->_settings->redirectedSettings >= 2) {
192
+ ShortPixelView::displayActivationNotice();
193
+ $this->_settings->activationNotice = null;
194
+ }
195
+ if( ($now > $act + 7200) && !isset($dismissed['2h'])) {
196
+ ShortPixelView::displayActivationNotice('2h');
197
+ } else if( ($now > $act + 72 * 3600) && !isset($dismissed['3d'])) {
198
+ ShortPixelView::displayActivationNotice('3d');
199
+ }
200
+ }
201
+ if(!isset($dismissed['compat'])) {
202
+ $conflictPlugins = self::getConflictingPlugins();
203
+ if(count($conflictPlugins)) {
204
+ ShortPixelView::displayActivationNotice('compat', $conflictPlugins);
205
+ }
206
+ }
207
+ }
208
+
209
+ public function dismissAdminNotice() {
210
+ $noticeId = preg_replace('|[^a-z0-9]|i', '', $_GET['notice_id']);
211
+ $dismissed = $this->_settings->dismissedNotices ? $this->_settings->dismissedNotices : array();
212
+ $dismissed[$noticeId] = true;
213
+ $this->_settings->dismissedNotices = $dismissed;
214
+ die(json_encode(array("Status" => 'success', "Message" => 'Notice ID: ' . $noticeId . ' dismissed')));
215
+ }
216
+
217
+ public function dismissMediaAlert() {
218
+ $this->_settings->mediaAlert = 1;
219
+ die(json_encode(array("Status" => 'success', "Message" => __('Media alert dismissed','shortpixel-image-optimiser'))));
220
+ }
221
+
222
+ //set default move as "list". only set once, it won't try to set the default mode again.
223
+ public function setDefaultViewModeList()
224
+ {
225
+ if($this->_settings->mediaLibraryViewMode === false)
226
+ {
227
+ $this->_settings->mediaLibraryViewMode = 1;
228
+ $currentUserID = false;
229
+ if ( function_exists('wp_get_current_user') ) {
230
+ $current_user = wp_get_current_user();
231
+ $currentUserID = $current_user->ID;
232
+ update_user_meta($currentUserID, "wp_media_library_mode", "list");
233
+ }
234
+ }
235
+
236
+ }
237
+
238
+ static function log($message) {
239
+ if (SHORTPIXEL_DEBUG === true) {
240
+ if (is_array($message) || is_object($message)) {
241
+ error_log(print_r($message, true));
242
+ } else {
243
+ error_log($message);
244
+ }
245
+ }
246
+ }
247
+
248
+ function shortPixelJS() { ?>
249
+ <script type="text/javascript" >
250
+ var ShortPixelConstants = {
251
+ STATUS_SUCCESS: <?php echo ShortPixelAPI::STATUS_SUCCESS; ?>,
252
+ STATUS_EMPTY_QUEUE: <?php echo self::BULK_EMPTY_QUEUE; ?>,
253
+ STATUS_ERROR: <?php echo ShortPixelAPI::STATUS_ERROR; ?>,
254
+ STATUS_FAIL: <?php echo ShortPixelAPI::STATUS_FAIL; ?>,
255
+ STATUS_QUOTA_EXCEEDED: <?php echo ShortPixelAPI::STATUS_QUOTA_EXCEEDED; ?>,
256
+ STATUS_SKIP: <?php echo ShortPixelAPI::STATUS_SKIP; ?>,
257
+ STATUS_NO_KEY: <?php echo ShortPixelAPI::STATUS_NO_KEY; ?>,
258
+ STATUS_RETRY: <?php echo ShortPixelAPI::STATUS_RETRY; ?>,
259
+ STATUS_QUEUE_FULL: <?php echo ShortPixelAPI::STATUS_QUEUE_FULL; ?>,
260
+ STATUS_MAINTENANCE: <?php echo ShortPixelAPI::STATUS_MAINTENANCE; ?>,
261
+ WP_PLUGIN_URL: '<?php echo plugins_url( '', SHORTPIXEL_PLUGIN_FILE ); ?>',
262
+ WP_ADMIN_URL: '<?php echo admin_url(); ?>',
263
+ API_KEY: "<?php echo $this->_settings->apiKey; ?>",
264
+ MEDIA_ALERT: '<?php echo $this->_settings->mediaAlert ? "done" : "todo"; ?>',
265
+ FRONT_BOOTSTRAP: <?php echo $this->_settings->frontBootstrap && (!isset($this->_settings->lastBackAction) || (time() - $this->_settings->lastBackAction > 600)) ? 1 : 0; ?>,
266
+ AJAX_URL: '<?php echo admin_url('admin-ajax.php'); ?>'
267
+ };
268
+ </script> <?php
269
+ wp_enqueue_style('short-pixel.css', plugins_url('/res/css/short-pixel.css',SHORTPIXEL_PLUGIN_FILE) );
270
+
271
+ wp_register_script('short-pixel.js', plugins_url('/res/js/short-pixel.js',SHORTPIXEL_PLUGIN_FILE) );
272
+ $jsTranslation = array(
273
+ 'optimizeWithSP' => __( 'Optimize with ShortPixel', 'shortpixel-image-optimiser' ),
274
+ 'changeMLToListMode' => __( 'In order to access the ShortPixel Optimization actions and info, please change to {0}List View{1}List View{2}Dismiss{3}', 'shortpixel-image-optimiser' ),
275
+ 'alertOnlyAppliesToNewImages' => __( 'This type of optimization will apply to new uploaded images. Images that were already processed will not be re-optimized unless you restart the bulk process.', 'shortpixel-image-optimiser' ),
276
+ 'areYouSureStopOptimizing' => __( 'Are you sure you want to stop optimizing the folder {0}?', 'shortpixel-image-optimiser' ),
277
+ 'reducedBy' => __( 'Reduced by', 'shortpixel-image-optimiser' ),
278
+ 'bonusProcessing' => __( 'Bonus processing', 'shortpixel-image-optimiser' ),
279
+ 'plusXthumbsOpt' => __( '+{0} thumbnails optimized', 'shortpixel-image-optimiser' ),
280
+ 'plusXretinasOpt' => __( '+{0} Retina images optimized', 'shortpixel-image-optimiser' ),
281
+ 'optXThumbs' => __( 'Optimize {0} thumbnails', 'shortpixel-image-optimiser' ),
282
+ 'reOptimizeAs' => __( 'Reoptimize {0}', 'shortpixel-image-optimiser' ),
283
+ 'restoreBackup' => __( 'Restore backup', 'shortpixel-image-optimiser' ),
284
+ 'getApiKey' => __( 'Get API Key', 'shortpixel-image-optimiser' ),
285
+ 'extendQuota' => __( 'Extend Quota', 'shortpixel-image-optimiser' ),
286
+ 'check__Quota' => __( 'Check&nbsp;&nbsp;Quota', 'shortpixel-image-optimiser' ),
287
+ 'retry' => __( 'Retry', 'shortpixel-image-optimiser' ),
288
+ 'thisContentNotProcessable' => __( 'This content is not processable.', 'shortpixel-image-optimiser' ),
289
+ 'imageWaitOptThumbs' => __( 'Image waiting to optimize thumbnails', 'shortpixel-image-optimiser' ),
290
+ 'pleaseDoNotSetLesserSize' => __( "Please do not set a {0} less than the {1} of the largest thumbnail which is {2}, to be able to still regenerate all your thumbnails in case you'll ever need this.", 'shortpixel-image-optimiser' ),
291
+ 'pleaseDoNotSetLesser1024' => __( "Please do not set a {0} less than 1024, to be able to still regenerate all your thumbnails in case you'll ever need this.", 'shortpixel-image-optimiser' )
292
+ );
293
+ wp_localize_script( 'short-pixel.js', '_spTr', $jsTranslation );
294
+ wp_enqueue_script('short-pixel.js');
295
+
296
+ wp_enqueue_script('jquery.knob.js', plugins_url('/res/js/jquery.knob.js',SHORTPIXEL_PLUGIN_FILE) );
297
+ wp_enqueue_script('jquery.tooltip.js', plugins_url('/res/js/jquery.tooltip.js',SHORTPIXEL_PLUGIN_FILE) );
298
+ wp_enqueue_script('punycode.js', plugins_url('/res/js/punycode.js',SHORTPIXEL_PLUGIN_FILE) );
299
+ }
300
+
301
+ function toolbar_shortpixel_processing( $wp_admin_bar ) {
302
+
303
+ $extraClasses = " shortpixel-hide";
304
+ /*translators: toolbar icon tooltip*/
305
+ $id = 'short-pixel-notice-toolbar';
306
+ $tooltip = __('ShortPixel optimizing...','shortpixel-image-optimiser');
307
+ $icon = "shortpixel.png";
308
+ $successLink = $link = current_user_can( 'edit_others_posts')? 'upload.php?page=wp-short-pixel-bulk' : 'upload.php';
309
+ $blank = "";
310
+ if($this->prioQ->processing()) {
311
+ $extraClasses = " shortpixel-processing";
312
+ }
313
+ if($this->_settings->quotaExceeded && !isset($this->_settings->dismissedNotices['exceed'])) {
314
+ $extraClasses = " shortpixel-alert shortpixel-quota-exceeded";
315
+ /*translators: toolbar icon tooltip*/
316
+ $id = 'short-pixel-notice-exceed';
317
+ $tooltip = '';
318
+ $exceedTooltip = __('ShortPixel quota exceeded. Click for details.','shortpixel-image-optimiser');
319
+ //$link = "http://shortpixel.com/login/" . $this->_settings->apiKey;
320
+ $link = "options-general.php?page=wp-shortpixel";
321
+ //$blank = '_blank';
322
+ //$icon = "shortpixel-alert.png";
323
+ }
324
+ $lastStatus = $this->_settings->bulkLastStatus;
325
+ if($lastStatus && $lastStatus['Status'] != ShortPixelAPI::STATUS_SUCCESS) {
326
+ $extraClasses = " shortpixel-alert shortpixel-processing";
327
+ $tooltip = $lastStatus['Message'];
328
+ }
329
+
330
+ $args = array(
331
+ 'id' => 'shortpixel_processing',
332
+ 'title' => '<div id="' . $id . '" title="' . $tooltip . '" ><img src="'
333
+ . plugins_url( 'res/img/'.$icon, SHORTPIXEL_PLUGIN_FILE ) . '" success-url="' . $successLink . '"><span class="shp-alert">!</span></div>',
334
+ 'href' => $link,
335
+ 'meta' => array('target'=> $blank, 'class' => 'shortpixel-toolbar-processing' . $extraClasses)
336
+ );
337
+ $wp_admin_bar->add_node( $args );
338
+ if($this->_settings->quotaExceeded && !isset($this->_settings->dismissedNotices['exceed'])) {
339
+ $wp_admin_bar->add_node( array(
340
+ 'id' => 'shortpixel_processing-title',
341
+ 'parent' => 'shortpixel_processing',
342
+ 'title' => $exceedTooltip,
343
+ 'href' => $link
344
+ ));
345
+ $wp_admin_bar->add_node( array(
346
+ 'id' => 'shortpixel_processing-dismiss',
347
+ 'parent' => 'shortpixel_processing',
348
+ 'title' => '<div style="text-align: right;">Dismiss</div>',
349
+ 'href' => "#",
350
+ 'meta' => array('onclick'=> 'dismissShortPixelNoticeExceed(event)')
351
+ ));
352
+ }
353
+ }
354
+
355
+ public function handleCustomBulk() {
356
+ // 1. get the action
357
+ $wp_list_table = _get_list_table('WP_Media_List_Table');
358
+ $action = $wp_list_table->current_action();
359
+
360
+ switch($action) {
361
+ // 2. Perform the action
362
+ case 'short-pixel-bulk':
363
+ // security check
364
+ check_admin_referer('bulk-media');
365
+ if(!is_array($_GET['media'])) {
366
+ break;
367
+ }
368
+ $mediaIds = array_reverse($_GET['media']);
369
+ foreach( $mediaIds as $ID ) {
370
+ $meta = wp_get_attachment_metadata($ID);
371
+ if( ( !isset($meta['ShortPixel']) //never touched by ShortPixel
372
+ || (isset($meta['ShortPixel']['WaitingProcessing']) && $meta['ShortPixel']['WaitingProcessing'] == true))
373
+ && (!isset($meta['ShortPixelImprovement']) || $meta['ShortPixelImprovement'] == __('Optimization N/A','shortpixel-image-optimiser'))) {
374
+ $this->prioQ->push($ID);
375
+ $meta['ShortPixel']['WaitingProcessing'] = true;
376
+ wp_update_attachment_metadata($ID, $meta);
377
+ }
378
+ }
379
+ break;
380
+ }
381
+ }
382
+
383
+ /**
384
+ * this is hooked onto the MediaLibrary image upload
385
+ * @param array $meta - the wordpress postmeta structure
386
+ * @param type $ID - the Media Library ID
387
+ * @return the meta structure updated with ShortPixel info if case
388
+ */
389
+ public function handleMediaLibraryImageUpload($meta, $ID = null)
390
+ {
391
+ if( !$this->_settings->verifiedKey) {// no API Key set/verified -> do nothing here, just return
392
+ return $meta;
393
+ }
394
+ //else
395
+ //self::log("IMG: Auto-analyzing file ID #{$ID}");
396
+
397
+ if( self::isProcessable($ID) == false )
398
+ {//not a file that we can process
399
+ $meta['ShortPixelImprovement'] = __('Optimization N/A','shortpixel-image-optimiser');
400
+ return $meta;
401
+ }
402
+ else
403
+ {//the kind of file we can process. goody.
404
+ $this->prioQ->push($ID);
405
+ //that's a hack for watermarking plugins, don't send the image right away to processing, only add it in the queue
406
+ include_once( ABSPATH . 'wp-admin/includes/plugin.php' );
407
+ if( !is_plugin_active('image-watermark/image-watermark.php')
408
+ && !is_plugin_active('easy-watermark/index.php')) {
409
+ $itemHandler = new ShortPixelMetaFacade($ID);
410
+ $itemHandler->setRawMeta($meta);
411
+ try {
412
+ $URLsAndPATHs = $this->getURLsAndPATHs($itemHandler);
413
+ //send a processing request right after a file was uploaded, do NOT wait for response
414
+ $this->_apiInterface->doRequests($URLsAndPATHs['URLs'], false, $ID);
415
+ } catch(Exception $e) {
416
+ $meta['ShortPixelImprovement'] = $e->getMessage();
417
+ return $meta;
418
+ }
419
+ //self::log("IMG: sent: " . json_encode($URLsAndPATHs));
420
+ }
421
+ $meta['ShortPixel']['WaitingProcessing'] = true;
422
+ return $meta;
423
+ }
424
+ }//end handleMediaLibraryImageUpload
425
+
426
+ /**
427
+ * this is hooked onto the NextGen upload
428
+ * @param type $image
429
+ */
430
+ public function handleNextGenImageUpload($image) {
431
+ if($this->_settings->includeNextGen == 1) {
432
+ $imageFsPath = ShortPixelNextGenAdapter::getImageAbspath($image);
433
+
434
+ $customFolders = $this->spMetaDao->getFolders();
435
+
436
+ $folderId = -1;
437
+ foreach($customFolders as $folder) {
438
+ if(strpos($imageFsPath, $folder->getPath()) === 0) {
439
+ $folderId = $folder->getId();
440
+ break;
441
+ }
442
+ }
443
+ if($folderId == -1) { //if not found, create
444
+ $galleryPath = dirname($imageFsPath);
445
+ $folder = new ShortPixelFolder(array("path" => $galleryPath));
446
+ $folderMsg = $this->spMetaDao->saveFolder($folder);
447
+ $folderId = $folder->getId();
448
+ //self::log("NG Image Upload: created folder from path $galleryPath : Folder info: " . json_encode($folder));
449
+ }
450
+ $pathParts = explode('/', trim($imageFsPath));
451
+ //Add the main image
452
+ $meta = new ShortPixelMeta();
453
+ $meta->setPath($imageFsPath);
454
+ $meta->setName($pathParts[count($pathParts) - 1]);
455
+ $meta->setFolderId($folderId);
456
+ $meta->setExtMetaId($image->pid); // do this only for main image, not for thumbnais.
457
+ $meta->setCompressionType($this->_settings->compressionType);
458
+ $meta->setKeepExif($this->_settings->keepExif);
459
+ $meta->setCmyk2rgb($this->_settings->CMYKtoRGBconversion);
460
+ $meta->setResize($this->_settings->resizeImages);
461
+ $meta->setResizeWidth($this->_settings->resizeWidth);
462
+ $meta->setResizeHeight($this->_settings->resizeHeight);
463
+ $ID = $this->spMetaDao->addImage($meta);
464
+ $meta->setId($ID);
465
+ $this->prioQ->push('C-' . $ID);
466
+ //add the thumb image if exists
467
+ $pathParts[] = "thumbs_" . $pathParts[count($pathParts) - 1];
468
+ $pathParts[count($pathParts) - 2] = "thumbs";
469
+ $thumbPath = implode('/', $pathParts);
470
+ if(file_exists($thumbPath)) {
471
+ $metaThumb = new ShortPixelMeta();
472
+ $metaThumb->setPath($thumbPath);
473
+ $metaThumb->setName($pathParts[count($pathParts) - 1]);
474
+ $metaThumb->setFolderId($folderId);
475
+ $metaThumb->setCompressionType($this->_settings->compressionType);
476
+ $metaThumb->setKeepExif($this->_settings->keepExif);
477
+ $metaThumb->setCmyk2rgb($this->_settings->CMYKtoRGBconversion);
478
+ $metaThumb->setResize($this->_settings->resizeImages);
479
+ $metaThumb->setResizeWidth($this->_settings->resizeWidth);
480
+ $metaThumb->setResizeHeight($this->_settings->resizeHeight);
481
+ $ID = $this->spMetaDao->addImage($metaThumb);
482
+ $metaThumb->setId($ID);
483
+ $this->prioQ->push('C-' . $ID);
484
+ }
485
+ return $meta;
486
+ }
487
+ }
488
+
489
+ public function optimizeCustomImage($id) {
490
+ $meta = $this->spMetaDao->getMeta($id);
491
+ if($meta->getStatus() != 2) {
492
+ $meta->setStatus(1);
493
+ $meta->setRetries(0);
494
+ $this->spMetaDao->update($meta);
495
+ $this->prioQ->push('C-' . $id);
496
+ }
497
+ }
498
+
499
+ //TODO muta in bulkProvider
500
+ public function getBulkItemsFromDb(){
501
+ global $wpdb;
502
+
503
+ $startQueryID = $this->prioQ->getStartBulkId();
504
+ $endQueryID = $this->prioQ->getStopBulkId();
505
+ $skippedAlreadyProcessed = 0;
506
+
507
+ if ( $startQueryID <= $endQueryID ) {
508
+ return false;
509
+ }
510
+ $idList = array();
511
+ $itemList = array();
512
+ for ($sanityCheck = 0, $crtStartQueryID = $startQueryID;
513
+ ($crtStartQueryID >= $endQueryID) && (count($itemList) < 3) && ($sanityCheck < 150); $sanityCheck++) {
514
+
515
+ self::log("GETDB: current StartID: " . $crtStartQueryID);
516
+
517
+ $queryPostMeta = "SELECT * FROM " . $wpdb->prefix . "postmeta
518
+ WHERE ( post_id <= $crtStartQueryID AND post_id >= $endQueryID )
519
+ AND ( meta_key = '_wp_attached_file' OR meta_key = '_wp_attachment_metadata' )
520
+ ORDER BY post_id DESC
521
+ LIMIT " . SP_MAX_RESULTS_QUERY;
522
+ $resultsPostMeta = $wpdb->get_results($queryPostMeta);
523
+
524
+ if ( empty($resultsPostMeta) ) {
525
+ $crtStartQueryID -= SP_MAX_RESULTS_QUERY;
526
+ $startQueryID = $crtStartQueryID;
527
+ $this->prioQ->setStartBulkId($startQueryID);
528
+ continue;
529
+ }
530
+
531
+ foreach ( $resultsPostMeta as $itemMetaData ) {
532
+ $crtStartQueryID = $itemMetaData->post_id;
533
+ if(!in_array($crtStartQueryID, $idList) && self::isProcessable($crtStartQueryID, ($this->_settings->optimizePdfs ? array() : array('pdf')))) {
534
+ $item = new ShortPixelMetaFacade($crtStartQueryID);
535
+ $meta = $item->getMeta();//wp_get_attachment_metadata($crtStartQueryID);
536
+
537
+ if($meta->getStatus() != 2) {
538
+ $itemList[] = $item;
539
+ $idList[] = $crtStartQueryID;
540
+ }
541
+ elseif($meta->getCompressionType() !== null && $meta->getCompressionType() != $this->_settings->compressionType) {//a different type of compression was chosen in settings
542
+ if($this->doRestore($crtStartQueryID)) {
543
+ $itemList[] = $item = new ShortPixelMetaFacade($crtStartQueryID); //force reload after restore
544
+ $idList[] = $crtStartQueryID;
545
+ } else {
546
+ $skippedAlreadyProcessed++;
547
+ }
548
+ }
549
+ elseif( $this->_settings->processThumbnails && $meta->getThumbsOpt() !== null
550
+ && $meta->getThumbsOpt() == 0 && count($meta->getThumbs()) > 0) { //thumbs were chosen in settings
551
+ //if($crtStartQueryID == 44 || $crtStartQueryID == 49) {echo("No THuMBS?");die(var_dump($meta));}
552
+ $meta->setThumbsTodo(true);
553
+ $item->updateMeta($meta);//wp_update_attachment_metadata($crtStartQueryID, $meta);
554
+ $itemList[] = $item;
555
+ $idList[] = $crtStartQueryID;
556
+ }
557
+ elseif($itemMetaData->meta_key == '_wp_attachment_metadata') { //count skipped
558
+ $skippedAlreadyProcessed++;
559
+ }
560
+ }
561
+ }
562
+ if(!count($idList) && $crtStartQueryID <= $startQueryID) {
563
+ //daca n-am adaugat niciuna pana acum, n-are sens sa mai selectez zona asta de id-uri in bulk-ul asta.
564
+ $leapStart = $this->prioQ->getStartBulkId();
565
+ $crtStartQueryID = $startQueryID = $itemMetaData->post_id - 1; //decrement it so we don't select it again
566
+ $res = WpShortPixelMediaLbraryAdapter::countAllProcessableFiles($this->_settings->optimizePdfs, $leapStart, $crtStartQueryID);
567
+ $skippedAlreadyProcessed += $res["mainProcessedFiles"] - $res["mainProc".($this->getCompressionType() == 1 ? "Lossy" : "Lossless")."Files"];
568
+ $this->prioQ->setStartBulkId($startQueryID);
569
+ } else {
570
+ $crtStartQueryID--;
571
+ }
572
+ }
573
+ return array("items" => $itemList, "skipped" => $skippedAlreadyProcessed, "searching" => ($sanityCheck >= 150));
574
+ }
575
+
576
+ /**
577
+ * Get last added items from priority
578
+ * @return type
579
+ */
580
+ //TODO muta in bulkProvider - prio
581
+ public function getFromPrioAndCheck() {
582
+ $items = array();
583
+ foreach ($this->prioQ->getFromPrioAndCheck() as $id) {
584
+ $items[] = new ShortPixelMetaFacade($id);
585
+ }
586
+ return $items;
587
+ }
588
+
589
+ public function handleImageProcessing($ID = null) {
590
+ //if(rand(1,2) == 2) {
591
+ // header($_SERVER['SERVER_PROTOCOL'] . ' 500 Internal Server Error', true, 500);
592
+ // die("za stop");
593
+ //}
594
+ //0: check key
595
+ if( $this->_settings->verifiedKey == false) {
596
+ if($ID == null){
597
+ $ids = $this->getFromPrioAndCheck();
598
+ $itemHandler = (count($ids) > 0 ? $ids[0] : null);
599
+ }
600
+ $response = array("Status" => ShortPixelAPI::STATUS_NO_KEY, "ImageID" => $itemHandler ? $itemHandler->getId() : "-1", "Message" => __('Missing API Key','shortpixel-image-optimiser'));
601
+ $this->_settings->bulkLastStatus = $response;
602
+ die(json_encode($response));
603
+ }
604
+
605
+ if($this->_settings->frontBootstrap && is_admin() && !ShortPixelTools::requestIsFrontendAjax()) {
606
+ //if in backend, and front-end is activated, mark processing from backend to shut off the front-end for 10 min.
607
+ $this->_settings->lastBackAction = time();
608
+ }
609
+
610
+ self::log("HIP: 0 Priority Queue: ".json_encode($this->prioQ->get()));
611
+ //self::log("HIP: 0 Bulk running? " . $this->prioQ->bulkRunning() . " START " . $this->_settings->startBulkId . " STOP " . $this->_settings->stopBulkId);
612
+
613
+ //1: get 3 ids to process. Take them with priority from the queue
614
+ $ids = $this->getFromPrioAndCheck();
615
+ if(count($ids) < 3 ) { //take from bulk if bulk processing active
616
+ if($this->prioQ->bulkRunning()) {
617
+ $res = $this->getBulkItemsFromDb();
618
+ $bulkItems = $res['items'];
619
+ //merge them into the $ids array based on the ID (the same ID could be in prio also)
620
+ if($bulkItems){
621
+ foreach($bulkItems as $bi) {
622
+ $add = true;
623
+ foreach($ids as $pi) {
624
+ if($pi->getType() == ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE && $bi->getId() == $pi->getId()) {
625
+ $add = false;
626
+ }
627
+ }
628
+ $ids[] = $bi;
629
+ }
630
+ }
631
+ }
632
+ }
633
+
634
+ self::log("HIP: 0 Bulk ran: " . $this->prioQ->bulkRan());
635
+ $customIds = false;
636
+ if(count($ids) < 3 && $this->prioQ->bulkRan() && $this->_settings->hasCustomFolders
637
+ && (!$this->_settings->cancelPointer || $this->_settings->skipToCustom)
638
+ && !$this->_settings->customBulkPaused)
639
+ { //take from custom images if any left to optimize - only if bulk was ever started
640
+ $customIds = $this->spMetaDao->getPendingMetas( 3 - count($ids));
641
+ if(is_array($customIds)) {
642
+ $ids = array_merge($ids, array_map(array('ShortPixelMetaFacade', 'getNewFromRow'), $customIds));
643
+ }
644
+ }
645
+ //var_dump($ids);
646
+ //die("za stop 2");
647
+
648
+ self::log("HIP: 1 Prio Queue: ".json_encode($this->prioQ->get()));
649
+ self::log("HIP: 1 Selected IDs count: ".count($ids));
650
+
651
+ //2: Send up to 3 files to the server for processing
652
+ for($i = 0, $itemHandler = false; $ids !== false && $i < min(3, count($ids)); $i++) {
653
+ $crtItemHandler = $ids[$i];
654
+ $tmpMeta = $crtItemHandler->getMeta();
655
+ $compType = ($tmpMeta->getCompressionType() !== null ? $tmpMeta->getCompressionType() : $this->_settings->compressionType);
656
+ try {
657
+ self::log("HIP: 1 sendToProcessing: ".$crtItemHandler->getId());
658
+ $URLsAndPATHs = $this->sendToProcessing($crtItemHandler, $compType, $tmpMeta->getThumbsTodo());
659
+ if(!$itemHandler) { //save for later use
660
+ $itemHandler = $ids[$i];
661
+ $firstUrlAndPaths = $URLsAndPATHs;
662
+ }
663
+ } catch(Exception $e) { // Exception("Post metadata is corrupt (No attachment URL)") or Exception("Image files are missing.")
664
+ $meta = $crtItemHandler->setError(ShortPixelAPI::ERR_FILE_NOT_FOUND, $e->getMessage());
665
+ $crtItemHandler->incrementRetries();
666
+ if(! $this->prioQ->remove($crtItemHandler->getQueuedId()) ){
667
+ $this->advanceBulk($crtItemHandler->getId());
668
+ $res['searching'] = true;
669
+ }
670
+ }
671
+ }
672
+
673
+ if (!$itemHandler){
674
+ //if searching, than the script is searching for not processed items and found none yet, should be relaunced
675
+ if(isset($res['searching']) && $res['searching']) {
676
+ die(json_encode(array("Status" => ShortPixelAPI::STATUS_RETRY,
677
+ "Message" => __('Searching images to optimize... ','shortpixel-image-optimiser') . $this->prioQ->getStartBulkId() . '->' . $this->prioQ->getStopBulkId() )));
678
+ }
679
+ //in this case the queue is really empty
680
+ self::log("HIP: 1 STOP BULK");
681
+ $bulkEverRan = $this->prioQ->stopBulk();
682
+ $avg = $this->getAverageCompression();
683
+ $fileCount = $this->_settings->fileCount;
684
+ $response = array("Status" => self::BULK_EMPTY_QUEUE,
685
+ /* translators: console message Empty queue 1234 -> 1234 */
686
+ "Message" => __('Empty queue ','shortpixel-image-optimiser') . $this->prioQ->getStartBulkId() . '->' . $this->prioQ->getStopBulkId(),
687
+ "BulkStatus" => ($this->prioQ->bulkRunning()
688
+ ? "1" : ($this->prioQ->bulkPaused() ? "2" : "0")),
689
+ "AverageCompression" => $avg,
690
+ "FileCount" => $fileCount,
691
+ "BulkPercent" => $this->prioQ->getBulkPercent());
692
+ die(json_encode($response));
693
+ }
694
+
695
+ self::log("HIP: 2 Prio Queue: ".json_encode($this->prioQ->get()));
696
+ //3: $itemHandler contains the first element of the list
697
+ $itemId = $itemHandler->getQueuedId();
698
+ $result = $this->_apiInterface->processImage($firstUrlAndPaths['URLs'], $firstUrlAndPaths['PATHs'], $itemHandler);
699
+
700
+ $result["ImageID"] = $itemId;
701
+ $meta = $itemHandler->getMeta();
702
+ $result["Filename"] = ShortPixelAPI::MB_basename($meta->getPath());
703
+
704
+ self::log("HIP: 3 Prio Queue: ".json_encode($this->prioQ->get()));
705
+
706
+ //4: update counters and priority list
707
+ if( $result["Status"] == ShortPixelAPI::STATUS_SUCCESS) {
708
+ self::log("HIP: Image ID " . $itemId . " optimized successfully: ".json_encode($result));
709
+ $prio = $this->prioQ->remove($itemId);
710
+ //remove also from the failed list if it failed in the past
711
+ $prio = $this->prioQ->removeFromFailed($itemId);
712
+ $result["Type"] = $meta->getCompressionType() !== null ? ShortPixelAPI::getCompressionTypeName($meta->getCompressionType()) : '';
713
+ $result["ThumbsTotal"] = $meta->getThumbs() && is_array($meta->getThumbs()) ? WpShortPixelMediaLbraryAdapter::countNonWebpSizes($meta->getThumbs()): 0;
714
+ $result["ThumbsTotal"] -= count($meta->getThumbsMissing());
715
+ $result["ThumbsCount"] = $meta->getThumbsOpt()
716
+ ? $meta->getThumbsOpt() //below is the fallback for old optimized images that don't have thumbsOpt
717
+ : ($this->_settings->processThumbnails ? $result["ThumbsTotal"] : 0);
718
+
719
+ $result["RetinasCount"] = $meta->getRetinasOpt();
720
+ $result["BackupEnabled"] = ($this->getBackupFolderAny($meta->getPath(), $meta->getThumbs()) ? true : false);//$this->_settings->backupImages;
721
+
722
+ if(!$prio && $itemId <= $this->prioQ->getStartBulkId()) {
723
+ $this->advanceBulk($itemId);
724
+ $this->setBulkInfo($itemId, $result);
725
+ }
726
+
727
+ $result["AverageCompression"] = $this->getAverageCompression();
728
+
729
+ if($itemHandler->getType() == ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE) {
730
+
731
+ $thumb = $bkThumb = "";
732
+ //$percent = 0;
733
+ $percent = $meta->getImprovementPercent();
734
+ if($percent){
735
+ $filePath = explode("/", $meta->getPath());
736
+
737
+ //Get a suitable thumb
738
+ $sizes = $meta->getThumbs();
739
+ if('pdf' == strtolower(pathinfo($result["Filename"], PATHINFO_EXTENSION))) {
740
+ // echo($result["Filename"] . " ESTE --> "); die(var_dump(strtolower(pathinfo($result["Filename"], PATHINFO_EXTENSION))));
741
+ $thumb = plugins_url( 'shortpixel-image-optimiser/res/img/logo-pdf.png' );
742
+ $bkThumb = '';
743
+ } else {
744
+ if(count($sizes)) {
745
+ $thumb = (isset($sizes["medium"]) ? $sizes["medium"]["file"] : (isset($sizes["thumbnail"]) ? $sizes["thumbnail"]["file"]: ""));
746
+ if(!strlen($thumb)) { //fallback to the first in the list
747
+ $sizeVals = array_values($sizes);
748
+ $thumb = count($sizeVals) ? $sizeVals[0]['file'] : '';
749
+ }
750
+ } else { //fallback to the image itself
751
+ $thumb = is_array($filePath) ? $filePath[count($filePath) - 1] : $filePath;
752
+ }
753
+
754
+ if(strlen($thumb) && $this->_settings->backupImages && $this->_settings->processThumbnails) {
755
+ $backupUrl = content_url() . "/" . SP_UPLOADS_NAME . "/" . SP_BACKUP . "/";
756
+ //$urlBkPath = $this->_apiInterface->returnSubDir(get_attached_file($ID));
757
+ $urlBkPath = ShortPixelMetaFacade::returnSubDir($meta->getPath(), ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE);
758
+ $bkThumb = $backupUrl . $urlBkPath . $thumb;
759
+ }
760
+ if(strlen($thumb)) {
761
+ $uploadsUrl = ShortPixelMetaFacade::getHomeUrl();
762
+ $urlPath = ShortPixelMetaFacade::returnSubDir($meta->getPath(), ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE);
763
+ //$urlPath = implode("/", array_slice($filePath, 0, count($filePath) - 1));
764
+ $thumb = $uploadsUrl . $urlPath . $thumb;
765
+ }
766
+ }
767
+
768
+ $result["Thumb"] = $thumb;
769
+ $result["BkThumb"] = $bkThumb;
770
+ }
771
+ }
772
+ elseif( is_array($customIds)) { // this item is from custom bulk
773
+ foreach($customIds as $customId) {
774
+ $rootUrl = ShortPixelMetaFacade::getHomeUrl();
775
+ if($customId->id == $itemHandler->getId()) {
776
+ if('pdf' == strtolower(pathinfo($meta->getName(), PATHINFO_EXTENSION))) {
777
+ $result["Thumb"] = plugins_url( 'shortpixel-image-optimiser/res/img/logo-pdf.png' );
778
+ $result["BkThumb"] = "";
779
+ } else {
780
+ $result["Thumb"] = $thumb = $rootUrl . $meta->getWebPath();
781
+ if($this->_settings->backupImages) {
782
+ $result["BkThumb"] = str_replace($rootUrl, $rootUrl. "/" . basename(dirname(dirname(SP_BACKUP_FOLDER))) . "/" . SP_UPLOADS_NAME . "/" . SP_BACKUP . "/", $thumb);
783
+ }
784
+ }
785
+ $this->setBulkInfo($itemId, $result);
786
+ break;
787
+ }
788
+ }
789
+ }
790
+ }
791
+ elseif ($result["Status"] == ShortPixelAPI::STATUS_ERROR) {
792
+ if($meta->getRetries() > MAX_ERR_RETRIES) {
793
+ if(! $this->prioQ->remove($itemId) ){
794
+ $this->advanceBulk($meta->getId());
795
+ }
796
+ if($itemHandler->getType() == ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE) {
797
+ $itemHandler->deleteMeta(); //this deletes only the ShortPixel fields from meta, in case of WP Media library
798
+ }
799
+ $result["Status"] = ShortPixelAPI::STATUS_SKIP;
800
+ $result["Message"] .= __(' Retry limit reached. Skipping file ID ','shortpixel-image-optimiser') . $itemId . ".";
801
+ $itemHandler->setError(isset($result['Code']) ? $result['Code'] : ShortPixelAPI::ERR_INCORRECT_FILE_SIZE, $result["Message"] );
802
+ }
803
+ else {
804
+ if(isset($result['Code'])) {
805
+ $itemHandler->setError($result['Code'], $result["Message"] );
806
+ }
807
+ $itemHandler->incrementRetries();
808
+ }
809
+ }
810
+ elseif ($result["Status"] == ShortPixelAPI::STATUS_SKIP
811
+ || $result["Status"] == ShortPixelAPI::STATUS_FAIL) {
812
+ $meta = $itemHandler->getMeta();
813
+ //$prio = $this->prioQ->remove($ID);
814
+ $prio = $this->prioQ->remove($itemId);
815
+ if(isset($result["Code"])
816
+ && ( $result["Code"] == "write-fail" //could not write
817
+ || (in_array(0+$result["Code"], array(-201)) && $meta->getRetries() >= 3))) { //for -201 (invalid image format) we retry only 3 times.
818
+ //put this one in the failed images list - to show the user at the end
819
+ $prio = $this->prioQ->addToFailed($itemHandler->getQueuedId());
820
+ }
821
+ $this->advanceBulk($meta->getId());
822
+ if($itemHandler->getType() == ShortPixelMetaFacade::CUSTOM_TYPE) {
823
+ $result["CustomImageLink"] = ShortPixelMetaFacade::getHomeUrl() . $meta->getWebPath();
824
+ }
825
+ }
826
+ elseif($result["Status"] == ShortPixelAPI::STATUS_QUEUE_FULL) {
827
+ //nimic?
828
+ }
829
+ elseif($result["Status"] == ShortPixelAPI::STATUS_MAINTENANCE) {
830
+ //nimic?
831
+ }
832
+ elseif ($this->prioQ->isPrio($itemId) && $result["Status"] == ShortPixelAPI::STATUS_QUOTA_EXCEEDED) {
833
+ if(!$this->prioQ->skippedCount()) {
834
+ $this->prioQ->reverse(); //for the first prio item with quota exceeded, revert the prio queue as probably the bottom ones were processed
835
+ }
836
+ if($this->prioQ->allSkipped()) {
837
+ $result["Stop"] = true;
838
+ } else {
839
+ $result["Stop"] = false;
840
+ $this->prioQ->skip($itemId);
841
+ }
842
+ self::log("HIP: 5 Prio Skipped: ".json_encode($this->prioQ->getSkipped()));
843
+ }
844
+ elseif($result["Status"] == ShortPixelAPI::STATUS_RETRY && is_array($customIds)) {
845
+ $result["CustomImageLink"] = $thumb = ShortPixelMetaFacade::getHomeUrl() . $meta->getWebPath();
846
+ }
847
+
848
+ if($result["Status"] !== ShortPixelAPI::STATUS_RETRY) {
849
+ $this->_settings->bulkLastStatus = $result;
850
+ }
851
+ die(json_encode($result));
852
+ }
853
+
854
+
855
+ private function advanceBulk($processedID) {
856
+ if($processedID <= $this->prioQ->getStartBulkId()) {
857
+ $this->prioQ->setStartBulkId($processedID - 1);
858
+ $this->prioQ->logBulkProgress();
859
+ }
860
+ }
861
+
862
+ private function setBulkInfo($processedID, &$result) {
863
+ $deltaBulkPercent = $this->prioQ->getDeltaBulkPercent();
864
+ $minutesRemaining = $this->prioQ->getTimeRemaining();
865
+ $pendingMeta = $this->_settings->hasCustomFolders ? $this->spMetaDao->getPendingMetaCount() : 0;
866
+ $percent = $this->prioQ->getBulkPercent();
867
+ if(0 + $pendingMeta > 0) {
868
+ $customMeta = $this->spMetaDao->getCustomMetaCount();
869
+ $totalPercent = round(($percent * $this->_settings->currentTotalFiles + ($customMeta - $pendingMeta) * 100) / ($this->_settings->currentTotalFiles + $customMeta));
870
+ $minutesRemaining = round($minutesRemaining * (100 - $totalPercent) / max(1, 100 - $percent));
871
+ $percent = $totalPercent;
872
+ }
873
+ $result["BulkPercent"] = $percent;
874
+ $result["BulkMsg"] = $this->bulkProgressMessage($deltaBulkPercent, $minutesRemaining);
875
+ }
876
+
877
+ private function sendToProcessing($itemHandler, $compressionType = false, $onlyThumbs = false) {
878
+ $URLsAndPATHs = $this->getURLsAndPATHs($itemHandler, NULL, $onlyThumbs);
879
+
880
+ $meta = $itemHandler->getMeta();
881
+ //find thumbs that are not listed in the metadata and add them in the sizes array
882
+ if($itemHandler->getType() == ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE) {
883
+ $mainFile = $meta->getPath();
884
+
885
+ $foundThumbs = WpShortPixelMediaLbraryAdapter::findThumbs($mainFile);
886
+ //first identify which thumbs are not in the sizes
887
+ $sizes = $meta->getThumbs();
888
+ foreach($foundThumbs as $id => $found) {
889
+ //get the mime-type from one of the thumbs metas
890
+ foreach($sizes as $size) {
891
+ if(pathinfo($mainFile, PATHINFO_EXTENSION) !== pathinfo($size['file'], PATHINFO_EXTENSION)){
892
+ continue;
893
+ }
894
+ $mimeType = $size['mime-type'];
895
+ if($size['file'] === ShortPixelAPI::MB_basename($found)) {
896
+ $foundThumbs[$id] = false;
897
+ }
898
+ }
899
+ }
900
+ // add the unfound ones to the sizes array
901
+ $ind = 1;
902
+ while (isset($sizes[ShortPixelMeta::FOUND_THUMB_PREFIX . str_pad("".$ind, 2, '0', STR_PAD_LEFT)])) $ind++;
903
+ $start = $ind;
904
+ foreach($foundThumbs as $found) {
905
+ if($found !== false) {
906
+ $size = getimagesize($found);
907
+ $sizes[ShortPixelMeta::FOUND_THUMB_PREFIX . str_pad("".$ind, 2, '0', STR_PAD_LEFT)]= array( // it's a file that has no corresponding thumb so it's the WEBP for the main file
908
+ 'file' => ShortPixelAPI::MB_basename($found),
909
+ 'width' => $size[0],
910
+ 'height' => $size[1],
911
+ 'mime-type' => $mimeType
912
+ );
913
+ $ind++;
914
+ }
915
+ }
916
+ if($ind > $start) { // at least one thumbnail added, update
917
+ $meta->setThumbs($sizes);
918
+ $itemHandler->updateMeta($meta);
919
+ $URLsAndPATHs = $this->getURLsAndPATHs($itemHandler, NULL, $onlyThumbs);
920
+ }
921
+ }
922
+
923
+ //find any missing thumbs files and mark them as such
924
+ if( isset($URLsAndPATHs['sizesMissing']) && count($URLsAndPATHs['sizesMissing'])
925
+ && (null === $meta->getThumbsMissing() || count(array_diff_key($meta->getThumbsMissing(), array_merge($URLsAndPATHs['sizesMissing'], $meta->getThumbsMissing()))))) {
926
+ //fix missing thumbs in the metadata before sending to processing
927
+ $meta->setThumbsMissing($URLsAndPATHs['sizesMissing']);
928
+ $itemHandler->updateMeta();
929
+ }
930
+ //die(var_dump($itemHandler));
931
+ $refresh = $meta->getStatus() === ShortPixelAPI::ERR_INCORRECT_FILE_SIZE;
932
+ //echo("URLS: "); die(var_dump($URLsAndPATHs));
933
+ $this->_apiInterface->doRequests($URLsAndPATHs['URLs'], false, $itemHandler,
934
+ $compressionType === false ? $this->_settings->compressionType : $compressionType, $refresh);//send a request, do NOT wait for response
935
+ $itemHandler->setWaitingProcessing();
936
+ //$meta = wp_get_attachment_metadata($ID);
937
+ //$meta['ShortPixel']['WaitingProcessing'] = true;
938
+ //wp_update_attachment_metadata($ID, $meta);
939
+ return $URLsAndPATHs;
940
+ }
941
+
942
+ public function handleManualOptimization() {
943
+ $imageId = $_GET['image_id'];
944
+ $cleanup = $_GET['cleanup'];
945
+ switch(substr($imageId, 0, 2)) {
946
+ case "N-":
947
+ return "Add the gallery to the custom folders list in ShortPixel settings.";
948
+ // Later
949
+ if(class_exists("C_Image_Mapper")) { //this is a NextGen image but not added to our tables, so add it now.
950
+ $image_mapper = C_Image_Mapper::get_instance();
951
+ $image = $image_mapper->find(intval(substr($imageId, 2)));
952
+ if($image) {
953
+ $this->handleNextGenImageUpload($image, true);
954
+ return array("Status" => ShortPixelAPI::STATUS_SUCCESS, "message" => "");
955
+ }
956
+ }
957
+ return array("Status" => ShortPixelAPI::STATUS_FAIL, "message" => __('NextGen image not found','shortpixel-image-optimiser'));
958
+ break;
959
+ case "C-":
960
+ throw new Exception("HandleManualOptimization for custom images not implemented");
961
+ default:
962
+ $this->optimizeNowHook(intval($imageId), true);
963
+ break;
964
+ }
965
+ //do_action('shortpixel-optimize-now', $imageId);
966
+
967
+ }
968
+
969
+ //custom hook
970
+ public function optimizeNowHook($imageId, $manual = false) {
971
+ if(self::isProcessable($imageId)) {
972
+ $this->prioQ->push($imageId);
973
+ $itemHandler = new ShortPixelMetaFacade($imageId);
974
+ $path = get_attached_file($ID);//get the full file PATH
975
+ if(!$manual && 'pdf' === pathinfo($path, PATHINFO_EXTENSION) && !$this->_settings->optimizePdfs) {
976
+ $ret = array("Status" => ShortPixelAPI::STATUS_SKIP, "Message" => $imageId);
977
+ } else {
978
+ try {
979
+ $this->sendToProcessing($itemHandler);
980
+ $ret = array("Status" => ShortPixelAPI::STATUS_SUCCESS, "Message" => "");
981
+ } catch(Exception $e) { // Exception("Post metadata is corrupt (No attachment URL)")
982
+ $itemHandler->getMeta();
983
+ $itemHandler->setError(ShortPixelAPI::ERR_FILE_NOT_FOUND, $e->getMessage());
984
+ $ret = array("Status" => ShortPixelAPI::STATUS_FAIL, "Message" => $e->getMessage());
985
+ }
986
+ }
987
+ } else {
988
+ $ret = array("Status" => ShortPixelAPI::STATUS_SKIP, "Message" => $imageId);
989
+ }
990
+ die(json_encode($ret));
991
+ }
992
+
993
+ //WP/LR Sync plugin integration
994
+ public function onWpLrUpdateMedia($imageId, $galleryIdsUnused) {
995
+ $meta = wp_get_attachment_metadata($imageId);
996
+ if(is_array($meta)) {
997
+ unset($meta['ShortPixel']);
998
+ $meta['ShortPixel'] = array();
999
+ $meta['ShortPixel']['WaitingProcessing'] = true;
1000
+ $this->prioQ->push($imageId);
1001
+ wp_update_attachment_metadata($imageId, $meta);
1002
+ }
1003
+ }
1004
+
1005
+
1006
+ //save error in file's meta data
1007
+ public function handleError($ID, $result)
1008
+ {
1009
+ $meta = wp_get_attachment_metadata($ID);
1010
+ $meta['ShortPixelImprovement'] = $result;
1011
+ wp_update_attachment_metadata($ID, $meta);
1012
+ }
1013
+
1014
+ public function getBackupFolder($file) {
1015
+ if(realpath($file)) {
1016
+ $file = realpath($file); //found cases when $file contains for example /wp/../wp-content - clean it up
1017
+ }
1018
+ $fileExtension = strtolower(substr($file,strrpos($file,".")+1));
1019
+ $SubDir = ShortPixelMetaFacade::returnSubDir($file, ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE);
1020
+ $SubDirOld = ShortPixelMetaFacade::returnSubDirOld($file, ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE);
1021
+
1022
+ if ( !file_exists(SP_BACKUP_FOLDER . '/' . $SubDir . ShortPixelAPI::MB_basename($file))
1023
+ && !file_exists(SP_BACKUP_FOLDER . '/' . date("Y") . "/" . date("m") . "/" . ShortPixelAPI::MB_basename($file)) ) {
1024
+ $SubDir = $SubDirOld; //maybe the folder was saved with the old method that returned the full path if the wp-content was not inside the root of the site.
1025
+ }
1026
+ if ( !file_exists(SP_BACKUP_FOLDER . '/' . $SubDir . ShortPixelAPI::MB_basename($file))
1027
+ && !file_exists(SP_BACKUP_FOLDER . '/' . date("Y") . "/" . date("m") . "/" . ShortPixelAPI::MB_basename($file)) ) {
1028
+ $SubDir = trailingslashit(substr(dirname($file), 1)); //try this too
1029
+ }
1030
+ //sometimes the month of original file and backup can differ
1031
+ if ( !file_exists(SP_BACKUP_FOLDER . '/' . $SubDir . ShortPixelAPI::MB_basename($file)) ) {
1032
+ $SubDir = date("Y") . "/" . date("m") . "/";
1033
+ if( !file_exists(SP_BACKUP_FOLDER . '/' . $SubDir . ShortPixelAPI::MB_basename($file)) ) {
1034
+ return false;
1035
+ }
1036
+ }
1037
+ return SP_BACKUP_FOLDER . '/' . $SubDir;
1038
+ }
1039
+
1040
+ public function getBackupFolderAny($file, $thumbs) {
1041
+ if(!file_exists($file)) {
1042
+ //try with the thumbnails
1043
+ if(isset($thumbs)) foreach($thumbs as $size) {
1044
+ $backup = $this->getBackupFolder(trailingslashit(dirname($file)) . $size['file']);
1045
+ if($backup) return $backup;
1046
+ }
1047
+ } else {
1048
+ return $this->getBackupFolder($file);
1049
+ }
1050
+ }
1051
+
1052
+ protected function setFilePerms($file) {
1053
+ //die(getenv('USERNAME') ? getenv('USERNAME') : getenv('USER'));
1054
+ if(strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') {
1055
+ //on *nix platforms check also the owner
1056
+ $owner = fileowner($file);
1057
+ if($owner !== false && $owner != posix_getuid()) { //files with changed owner
1058
+ return false;
1059
+ }
1060
+ }
1061
+ $perms = @fileperms($file);
1062
+ if(!($perms & 0x0100) || !($perms & 0x0080)) {
1063
+ if(!@chmod($file, $perms | 0x0100 | 0x0080)) {
1064
+ return false;
1065
+ }
1066
+ }
1067
+ return true;
1068
+ }
1069
+
1070
+ protected function doRestore($attachmentID, $meta = null) {
1071
+ $file = $origFile = get_attached_file($attachmentID);
1072
+ if(!$meta) {
1073
+ $meta = wp_get_attachment_metadata($attachmentID);
1074
+ }
1075
+ $pathInfo = pathinfo($file);
1076
+
1077
+ $bkFolder = $this->getBackupFolderAny($file, $meta["sizes"]);
1078
+ $bkFile = trailingslashit($bkFolder) . ShortPixelAPI::MB_basename($file);
1079
+
1080
+ //first check if the file is readable by the current user - otherwise it will be unaccessible for the web browser
1081
+ // - collect the thumbs paths in the process
1082
+ $bkCount = 0; $main = false;
1083
+ if(file_exists($bkFile)) {
1084
+ if(!$this->setFilePerms($bkFile) || (file_exists($file) && !$this->setFilePerms($file)) ) {
1085
+ return false;
1086
+ }
1087
+ $bkCount++;
1088
+ $main = true;
1089
+ }
1090
+ $thumbsPaths = array();
1091
+ if( !empty($meta['file']) && is_array($meta["sizes"]) ) {
1092
+ foreach($meta["sizes"] as $size => $imageData) {
1093
+ $dest = $pathInfo['dirname'] . '/' . $imageData['file'];
1094
+ $source = trailingslashit($bkFolder) . $imageData['file'];
1095
+ if(!file_exists($source)) continue; // if thumbs were not optimized, then the backups will not be there.
1096
+ if(!$this->setFilePerms($source) || (file_exists($dest) && !$this->setFilePerms($dest))) {
1097
+ return false;
1098
+ }
1099
+ $bkCount++;
1100
+ $thumbsPaths[$source] = $dest;
1101
+ }
1102
+ }
1103
+ if(!$bkCount) {
1104
+ return false;
1105
+ }
1106
+
1107
+ if($bkFolder) {
1108
+ try {
1109
+ //main file
1110
+ if($main) {
1111
+ $this->renameWithRetina($bkFile, $file);
1112
+ }
1113
+ //getSize to update meta if image was resized by ShortPixel
1114
+ $width = false;
1115
+ if(file_exists($file)) {
1116
+ $size = getimagesize($file);
1117
+ $width = $size[0];
1118
+ $height = $size[1];
1119
+ }
1120
+
1121
+ //overwriting thumbnails
1122
+ foreach($thumbsPaths as $source => $destination) {
1123
+ $this->renameWithRetina($source, $destination);
1124
+ }
1125
+ $duplicates = ShortPixelMetaFacade::getWPMLDuplicates($attachmentID);
1126
+ foreach($duplicates as $ID) {
1127
+ $crtMeta = $attachmentID == $ID ? $meta : wp_get_attachment_metadata($ID);
1128
+ if(is_numeric($crtMeta["ShortPixelImprovement"]) && 0 + $crtMeta["ShortPixelImprovement"] < 5 && $this->_settings->under5Percent > 0) {
1129
+ $this->_settings->under5Percent = $this->_settings->under5Percent - 1; // - (isset($crtMeta["ShortPixel"]["thumbsOpt"]) ? $crtMeta["ShortPixel"]["thumbsOpt"] : 0);
1130
+ }
1131
+ unset($crtMeta["ShortPixelImprovement"]);
1132
+ unset($crtMeta['ShortPixel']);
1133
+ if($width && $height) {
1134
+ $crtMeta['width'] = $width;
1135
+ $crtMeta['height'] = $height;
1136
+ }
1137
+ wp_update_attachment_metadata($ID, $crtMeta);
1138
+ }
1139
+ unset($meta["ShortPixelImprovement"]);
1140
+ unset($meta['ShortPixel']);
1141
+
1142
+ } catch(Exception $e) {
1143
+ //what to do, what to do?
1144
+ return false;
1145
+ }
1146
+ } else {
1147
+ return false;
1148
+ }
1149
+
1150
+ return $meta;
1151
+ }
1152
+
1153
+ protected function renameWithRetina($bkFile, $file) {
1154
+ @rename($bkFile, $file);
1155
+ $ext = pathinfo($file, PATHINFO_EXTENSION);
1156
+ @rename(substr($bkFile, 0, strlen($bkFile) - 1 - strlen($ext)) . "@2x." . $ext, substr($file, 0, strlen($file) - 1 - strlen($ext)) . "@2x." . $ext);
1157
+
1158
+ }
1159
+
1160
+ public function doCustomRestore($ID) {
1161
+ $meta = $this->spMetaDao->getMeta($ID);
1162
+ if(!$meta || $meta->getStatus() != 2) return false;
1163
+
1164
+ $file = $meta->getPath();
1165
+ $fullSubDir = str_replace(get_home_path(), "", dirname($file)) . '/';
1166
+ $bkFile = SP_BACKUP_FOLDER . '/' . $fullSubDir . ShortPixelAPI::MB_basename($file);
1167
+
1168
+ if(file_exists($bkFile)) {
1169
+ @rename($bkFile, $file);
1170
+ $meta->setStatus(3);
1171
+ $this->spMetaDao->update($meta);
1172
+ }
1173
+
1174
+ return $meta;
1175
+ }
1176
+
1177
+ public function handleRestoreBackup() {
1178
+ $attachmentID = intval($_GET['attachment_ID']);
1179
+
1180
+ $this->doRestore($attachmentID);
1181
+
1182
+ // get the referring webpage location
1183
+ $sendback = wp_get_referer();
1184
+ // sanitize the referring webpage location
1185
+ $sendback = preg_replace('|[^a-z0-9-~+_.?#=&;,/:]|i', '', $sendback);
1186
+ // send the user back where they came from
1187
+ wp_redirect($sendback);
1188
+ // we are done
1189
+ }
1190
+
1191
+ public function handleRedo() {
1192
+ die(json_encode($this->redo($_GET['attachment_ID'], $_GET['type'])));
1193
+ }
1194
+
1195
+ public function redo($qID, $type = false) {
1196
+ if(ShortPixelMetaFacade::isCustomQueuedId($qID)) {
1197
+ $ID = ShortPixelMetaFacade::stripQueuedIdType($qID);
1198
+ $meta = $this->doCustomRestore($ID);
1199
+ if($meta) {
1200
+ $meta->setCompressionType(1 - $meta->getCompressionType());
1201
+ $meta->setStatus(1);
1202
+ $this->spMetaDao->update($meta);
1203
+ $this->prioQ->push($qID);
1204
+ $ret = array("Status" => ShortPixelAPI::STATUS_SUCCESS, "Message" => "");
1205
+ } else {
1206
+ $ret = array("Status" => ShortPixelAPI::STATUS_SKIP, "Message" => __('Could not restore from backup: ','shortpixel-image-optimiser') . $qID);
1207
+ }
1208
+ } else {
1209
+ $ID = intval($qID);
1210
+ $compressionType = ($type == 'lossless' ? 'lossless' : 'lossy'); //sanity check
1211
+
1212
+ $meta = $this->doRestore($ID);
1213
+ if($meta) { //restore succeeded
1214
+ $meta['ShortPixel'] = array("type" => $compressionType);
1215
+ wp_update_attachment_metadata($ID, $meta);
1216
+ try {
1217
+ $this->sendToProcessing(new ShortPixelMetaFacade($ID), $compressionType == 'lossy' ? 1 : 0);
1218
+ $this->prioQ->push($ID);
1219
+ $ret = array("Status" => ShortPixelAPI::STATUS_SUCCESS, "Message" => "");
1220
+ } catch(Exception $e) { // Exception("Post metadata is corrupt (No attachment URL)") or Exception("Image files are missing.")
1221
+ $meta['ShortPixelImprovement'] = $e->getMessage();
1222
+ $meta['ShortPixel']['ErrCode'] = ShortPixelAPI::STATUS_FAIL;
1223
+ unset($meta['ShortPixel']['WaitingProcessing']);
1224
+ wp_update_attachment_metadata($ID, $meta);
1225
+ $ret = array("Status" => ShortPixelAPI::STATUS_FAIL, "Message" => $e->getMessage());
1226
+ }
1227
+ } else {
1228
+ $ret = array("Status" => ShortPixelAPI::STATUS_SKIP, "Message" => __('Could not restore from backup: ','shortpixel-image-optimiser') . $ID);
1229
+ }
1230
+ }
1231
+ return $ret;
1232
+ }
1233
+
1234
+ public function handleOptimizeThumbs() {
1235
+ $ID = intval($_GET['attachment_ID']);
1236
+ $meta = wp_get_attachment_metadata($ID);
1237
+ //die(var_dump($meta));
1238
+ if( isset($meta['ShortPixelImprovement'])
1239
+ && isset($meta['sizes']) && WpShortPixelMediaLbraryAdapter::countNonWebpSizes($meta['sizes'])
1240
+ && ( !isset($meta['ShortPixel']['thumbsOpt']) || $meta['ShortPixel']['thumbsOpt'] == 0)) { //optimized without thumbs, thumbs exist
1241
+ $meta['ShortPixel']['thumbsTodo'] = true;
1242
+ wp_update_attachment_metadata($ID, $meta);
1243
+ $this->prioQ->push($ID);
1244
+ try {
1245
+ $this->sendToProcessing(new ShortPixelMetaFacade($ID));
1246
+ $ret = array("Status" => ShortPixelAPI::STATUS_SUCCESS, "message" => "");
1247
+ } catch(Exception $e) { // Exception("Post metadata is corrupt (No attachment URL)") or Exception("Image files are missing.")
1248
+ $meta['ShortPixelImprovement'] = $e->getMessage();
1249
+ $meta['ShortPixel']['ErrCode'] = ShortPixelAPI::STATUS_FAIL;
1250
+ unset($meta['ShortPixel']['WaitingProcessing']);
1251
+ wp_update_attachment_metadata($ID, $meta);
1252
+ $ret = array("Status" => ShortPixelAPI::STATUS_FAIL, "Message" => $e->getMessage());
1253
+ }
1254
+ } else {
1255
+ $ret = array("Status" => ShortPixelAPI::STATUS_SKIP, "message" => (isset($meta['ShortPixelImprovement']) ? __('No thumbnails to optimize for ID: ','shortpixel-image-optimiser') : __('Please optimize image for ID: ','shortpixel-image-optimiser')) . $ID);
1256
+ }
1257
+ die(json_encode($ret));
1258
+ }
1259
+
1260
+ public function handleCheckQuota() {
1261
+ $this->getQuotaInformation();
1262
+ // store the referring webpage location
1263
+ $sendback = wp_get_referer();
1264
+ // sanitize the referring webpage location
1265
+ $sendback = preg_replace('|[^a-z0-9-~+_.?#=&;,/:]|i', '', $sendback);
1266
+ // send the user back where they came from
1267
+ wp_redirect($sendback);
1268
+ // we are done
1269
+ }
1270
+
1271
+ public function handleDeleteAttachmentInBackup($ID) {
1272
+ $file = get_attached_file($ID);
1273
+ $meta = wp_get_attachment_metadata($ID);
1274
+
1275
+ if(self::isProcessable($ID) != false)
1276
+ {
1277
+ try {
1278
+ $SubDir = ShortPixelMetaFacade::returnSubDir($file, ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE);
1279
+
1280
+ @unlink(SP_BACKUP_FOLDER . '/' . $SubDir . ShortPixelAPI::MB_basename($file));
1281
+
1282
+ if ( !empty($meta['file']) )
1283
+ {
1284
+ $filesPath = SP_BACKUP_FOLDER . '/' . $SubDir;//base BACKUP path
1285
+ //remove thumbs thumbnails
1286
+ if(isset($meta["sizes"])) {
1287
+ foreach($meta["sizes"] as $size => $imageData) {
1288
+ @unlink($filesPath . ShortPixelAPI::MB_basename($imageData['file']));//remove thumbs
1289
+ }
1290
+ }
1291
+ }
1292
+
1293
+ } catch(Exception $e) {
1294
+ //what to do, what to do?
1295
+ }
1296
+ }
1297
+ }
1298
+
1299
+ public function deactivatePlugin() {
1300
+ if ( ! wp_verify_nonce( $_GET['_wpnonce'], 'sp_deactivate_plugin_nonce' ) ) {
1301
+ wp_nonce_ays( '' );
1302
+ }
1303
+ deactivate_plugins( $_GET['plugin'] );
1304
+ wp_safe_redirect( wp_get_referer() );
1305
+ die();
1306
+ }
1307
+
1308
+ public function checkQuotaAndAlert($quotaData = null, $recheck = false) {
1309
+ if(!$quotaData) {
1310
+ $quotaData = $this->getQuotaInformation();
1311
+ }
1312
+ if ( !$quotaData['APIKeyValid']) {
1313
+ return $quotaData;
1314
+ }
1315
+ //$tempus = microtime(true);
1316
+ $imageCount = WpShortPixelMediaLbraryAdapter::countAllProcessableFiles($this->_settings->optimizePdfs);
1317
+
1318
+ $this->_settings->currentTotalFiles = $imageCount['totalFiles'];
1319
+
1320
+ //echo("Count took (seconds): " . (microtime(true) - $tempus));
1321
+ foreach($imageCount as $key => $val) {
1322
+ $quotaData[$key] = $val;
1323
+ }
1324
+
1325
+ if($this->_settings->hasCustomFolders) {
1326
+ $customImageCount = $this->spMetaDao->countAllProcessableFiles();
1327
+ foreach($customImageCount as $key => $val) {
1328
+ $quotaData[$key] = isset($quotaData[$key])
1329
+ ? (is_array($quotaData[$key]) ? array_merge($quotaData[$key], $val) : $quotaData[$key] + $val)
1330
+ : $val;
1331
+ }
1332
+ }
1333
+
1334
+ if($quotaData['APICallsQuotaNumeric'] + $quotaData['APICallsQuotaOneTimeNumeric'] > $quotaData['APICallsMadeNumeric'] + $quotaData['APICallsMadeOneTimeNumeric']) {
1335
+ $this->_settings->quotaExceeded = '0';
1336
+ $this->_settings->prioritySkip = NULL;
1337
+ self::log("CHECK QUOTA: Skipped: ".json_encode($this->prioQ->getSkipped()));
1338
+
1339
+ ?><script>var shortPixelQuotaExceeded = 0;</script><?php
1340
+ }
1341
+ else {
1342
+ $this->view->displayQuotaExceededAlert($quotaData, self::getAverageCompression(), $recheck);
1343
+ ?><script>var shortPixelQuotaExceeded = 1;</script><?php
1344
+ }
1345
+ return $quotaData;
1346
+ }
1347
+
1348
+ public function isValidMetaId($id) {
1349
+ return substr($id, 0, 2 ) == "C-" ? $this->spMetaDao->getMeta(substr($id, 2)) : wp_get_attachment_url($id);
1350
+ }
1351
+
1352
+ public function listCustomMedia() {
1353
+ if( ! class_exists( 'ShortPixelListTable' ) ) {
1354
+ require_once('view/shortpixel-list-table.php');
1355
+ }
1356
+ if(isset($_REQUEST['refresh']) && esc_attr($_REQUEST['refresh']) == 1) {
1357
+ $notice = null;
1358
+ $this->refreshCustomFolders($notice);
1359
+ }
1360
+ if(isset($_REQUEST['action']) && esc_attr($_REQUEST['action']) == 'optimize' && isset($_REQUEST['image'])) {
1361
+ //die(ShortPixelMetaFacade::queuedId(ShortPixelMetaFacade::CUSTOM_TYPE, $_REQUEST['image']));
1362
+ $this->prioQ->push(ShortPixelMetaFacade::queuedId(ShortPixelMetaFacade::CUSTOM_TYPE, $_REQUEST['image']));
1363
+ }
1364
+ $customMediaListTable = new ShortPixelListTable($this, $this->spMetaDao, $this->hasNextGen);
1365
+ $items = $customMediaListTable->prepare_items();
1366
+ if ( isset($_GET['noheader']) ) {
1367
+ require_once(ABSPATH . 'wp-admin/admin-header.php');
1368
+ }
1369
+
1370
+ ?>
1371
+ <div class="wrap shortpixel-other-media">
1372
+ <h2>
1373
+ <div style="float:right;">
1374
+ <a href="upload.php?page=wp-short-pixel-custom&refresh=1" id="refresh" class="button button-primary" title="<?php _e('Refresh custom folders content','shortpixel-image-optimiser');?>">
1375
+ <?php _e('Refresh folders','shortpixel-image-optimiser');?>
1376
+ </a>
1377
+ </div>
1378
+ <?php _e('Other Media optimized by ShortPixel','shortpixel-image-optimiser');?>
1379
+ </h2>
1380
+
1381
+ <div id="poststuff">
1382
+ <div id="post-body" class="metabox-holder columns-2">
1383
+ <div id="post-body-content">
1384
+ <div class="meta-box-sortables ui-sortable">
1385
+ <form method="post" class="shortpixel-table">
1386
+ <?php
1387
+ $customMediaListTable->display();
1388
+ //push to the processing list the pending ones, just in case
1389
+ //$count = $this->spMetaDao->getCustomMetaCount();
1390
+ foreach ($items as $item) {
1391
+ if($item->status == 1){
1392
+ $this->prioQ->push(ShortPixelMetaFacade::queuedId(ShortPixelMetaFacade::CUSTOM_TYPE, $item->id));
1393
+ }
1394
+ }
1395
+ ?>
1396
+ </form>
1397
+ </div>
1398
+ </div>
1399
+ </div>
1400
+ <br class="clear">
1401
+ </div>
1402
+ </div> <?php
1403
+ }
1404
+ public function bulkProcess() {
1405
+ global $wpdb;
1406
+
1407
+ if( $this->_settings->verifiedKey == false ) {//invalid API Key
1408
+ ShortPixelView::displayActivationNotice();
1409
+ return;
1410
+ }
1411
+
1412
+ $quotaData = $this->checkQuotaAndAlert(null, isset($_GET['checkquota']));
1413
+ if($this->_settings->quotaExceeded != 0) {
1414
+ return;
1415
+ }
1416
+
1417
+ if(isset($_POST['bulkProcessPause']))
1418
+ {//pause an ongoing bulk processing, it might be needed sometimes
1419
+ $this->prioQ->pauseBulk();
1420
+ if($this->_settings->hasCustomFolders && $this->spMetaDao->getPendingMetaCount()) {
1421
+ $this->_settings->customBulkPaused = 1;
1422
+ }
1423
+ }
1424
+
1425
+ if(isset($_POST['bulkProcessStop']))
1426
+ {//stop an ongoing bulk processing
1427
+ $this->prioQ->cancelBulk();
1428
+ if($this->_settings->hasCustomFolders && $this->spMetaDao->getPendingMetaCount()) {
1429
+ $this->_settings->customBulkPaused = 1;
1430
+ }
1431
+ }
1432
+
1433
+ if(isset($_POST["bulkProcess"]))
1434
+ {
1435
+ //set the thumbnails option
1436
+ if ( isset($_POST['thumbnails']) ) {
1437
+ $this->_settings->processThumbnails = 1;
1438
+ } else {
1439
+ $this->_settings->processThumbnails = 0;
1440
+ }
1441
+ //clean the custom files errors in order to process them again
1442
+ if($this->_settings->hasCustomFolders) {
1443
+ $this->spMetaDao->resetFailed();
1444
+ }
1445
+
1446
+ $this->prioQ->startBulk();
1447
+ $this->_settings->customBulkPaused = 0;
1448
+ self::log("BULK: Start: " . $this->prioQ->getStartBulkId() . ", stop: " . $this->prioQ->getStopBulkId() . " PrioQ: "
1449
+ .json_encode($this->prioQ->get()));
1450
+ }//end bulk process was clicked
1451
+
1452
+ if(isset($_POST["bulkProcessResume"]))
1453
+ {
1454
+ $this->prioQ->resumeBulk();
1455
+ $this->_settings->customBulkPaused = 0;
1456
+ }//resume was clicked
1457
+
1458
+ if(isset($_POST["skipToCustom"]))
1459
+ {
1460
+ $this->_settings->skipToCustom = true;
1461
+ }//resume was clicked
1462
+
1463
+ //figure out the files that are left to be processed
1464
+ $qry_left = "SELECT count(*) FilesLeftToBeProcessed FROM " . $wpdb->prefix . "postmeta
1465
+ WHERE meta_key = '_wp_attached_file' AND post_id <= " . (0 + $this->prioQ->getStartBulkId());
1466
+ $filesLeft = $wpdb->get_results($qry_left);
1467
+
1468
+ //check the custom bulk
1469
+ $pendingMeta = $this->_settings->hasCustomFolders ? $this->spMetaDao->getPendingMetaCount() : 0;
1470
+
1471
+ if ( ($filesLeft[0]->FilesLeftToBeProcessed > 0 && $this->prioQ->bulkRunning())
1472
+ || (0 + $pendingMeta > 0 && !$this->_settings->customBulkPaused && $this->prioQ->bulkRan())//bulk processing was started
1473
+ && (!$this->prioQ->bulkPaused() || $this->_settings->skipToCustom)) //bulk not paused or if paused, user pressed Process Custom button
1474
+ {
1475
+ $msg = $this->bulkProgressMessage($this->prioQ->getDeltaBulkPercent(), $this->prioQ->getTimeRemaining());
1476
+
1477
+ $this->view->displayBulkProcessingRunning($this->getPercent($quotaData), $msg, $quotaData['APICallsRemaining'], $this->getAverageCompression(),
1478
+ ($pendingMeta !== null ? ($this->prioQ->bulkRunning() ? 3 : 2) : 1));
1479
+
1480
+ } else
1481
+ {
1482
+ if($this->prioQ->bulkRan() && !$this->prioQ->bulkPaused()) {
1483
+ $this->prioQ->markBulkComplete();
1484
+ }
1485
+
1486
+ //image count
1487
+ $thumbsProcessedCount = $this->_settings->thumbsCount;//amount of optimized thumbnails
1488
+ $under5PercentCount = $this->_settings->under5Percent;//amount of under 5% optimized imgs.
1489
+
1490
+ //average compression
1491
+ $averageCompression = self::getAverageCompression();
1492
+ $percent = $this->prioQ->bulkPaused() ? $this->getPercent($quotaData) : false;
1493
+
1494
+ $this->view->displayBulkProcessingForm($quotaData, $thumbsProcessedCount, $under5PercentCount,
1495
+ $this->prioQ->bulkRan(), $averageCompression, $this->_settings->fileCount,
1496
+ self::formatBytes($this->_settings->savedSpace), $percent, $pendingMeta);
1497
+ }
1498
+ }
1499
+ //end bulk processing
1500
+
1501
+ public function getPercent($quotaData) {
1502
+ if($this->_settings->processThumbnails) {
1503
+ return min(99, round($quotaData["totalProcessedFiles"] *100.0 / $quotaData["totalFiles"]));
1504
+ } else {
1505
+ return min(99, round($quotaData["mainProcessedFiles"] *100.0 / $quotaData["mainFiles"]));
1506
+ }
1507
+ }
1508
+
1509
+ public function bulkProgressMessage($percent, $minutes) {
1510
+ $timeEst = "";
1511
+ self::log("bulkProgressMessage(): percent: " . $percent);
1512
+ if($percent < 1 || $minutes == 0) {
1513
+ $timeEst = "";
1514
+ } elseif( $minutes > 2880) {
1515
+ $timeEst = "~ " . round($minutes / 1440) . " days left";
1516
+ } elseif ($minutes > 240) {
1517
+ $timeEst = "~ " . round($minutes / 60) . " hours left";
1518
+ } elseif ($minutes > 60) {
1519
+ $timeEst = "~ " . round($minutes / 60) . " hours " . round($minutes % 60 / 10) * 10 . " min. left";
1520
+ } elseif ($minutes > 20) {
1521
+ $timeEst = "~ " . round($minutes / 10) * 10 . " minutes left";
1522
+ } else {
1523
+ $timeEst = "~ " . $minutes . " minutes left";
1524
+ }
1525
+ return $timeEst;
1526
+ }
1527
+
1528
+ public function emptyBackup(){
1529
+ if(file_exists(SP_BACKUP_FOLDER)) {
1530
+
1531
+ //extract all images from DB in an array. of course
1532
+ $attachments = null;
1533
+ $attachments = get_posts( array(
1534
+ 'numberposts' => -1,
1535
+ 'post_type' => 'attachment',
1536
+ 'post_mime_type' => 'image'
1537
+ ));
1538
+
1539
+
1540
+ //parse all images and set the right flag that the image has no backup
1541
+ /* this is obsolete as the backup exists decision is taken on verfication of the actual backup files
1542
+ foreach($attachments as $attachment)
1543
+ {
1544
+ if(self::isProcessable($attachment->ID) == false) continue;
1545
+
1546
+ $meta = wp_get_attachment_metadata($attachment->ID);
1547
+ $meta['ShortPixel']['NoBackup'] = true;
1548
+ wp_update_attachment_metadata($attachment->ID, $meta);
1549
+ }
1550
+ */
1551
+
1552
+ //delete the actual files on disk
1553
+ $this->deleteDir(SP_BACKUP_FOLDER);//call a recursive function to empty files and sub-dirs in backup dir
1554
+ }
1555
+ }
1556
+
1557
+ public function backupFolderIsEmpty() {
1558
+ return count(scandir(SP_BACKUP_FOLDER)) > 2 ? false : true;
1559
+ }
1560
+
1561
+ public function getBackupSize() {
1562
+ if ( !current_user_can( 'manage_options' ) ) {
1563
+ wp_die(__('You do not have sufficient permissions to access this page.','shortpixel-image-optimiser'));
1564
+ }
1565
+ die(self::formatBytes(self::folderSize(SP_BACKUP_FOLDER)));
1566
+ }
1567
+
1568
+ public function browseContent() {
1569
+ if ( !current_user_can( 'manage_options' ) ) {
1570
+ wp_die(__('You do not have sufficient permissions to access this page.','shortpixel-image-optimiser'));
1571
+ }
1572
+
1573
+ $root = self::getCustomFolderBase();
1574
+
1575
+ $postDir = rawurldecode($root.(isset($_POST['dir']) ? $_POST['dir'] : null ));
1576
+
1577
+ // set checkbox if multiSelect set to true
1578
+ $checkbox = ( isset($_POST['multiSelect']) && $_POST['multiSelect'] == 'true' ) ? "<input type='checkbox' />" : null;
1579
+ $onlyFolders = ($_POST['dir'] == '/' || isset($_POST['onlyFolders']) && $_POST['onlyFolders'] == 'true' ) ? true : false;
1580
+ $onlyFiles = ( isset($_POST['onlyFiles']) && $_POST['onlyFiles'] == 'true' ) ? true : false;
1581
+
1582
+ if( file_exists($postDir) ) {
1583
+
1584
+ $files = scandir($postDir);
1585
+ $returnDir = substr($postDir, strlen($root));
1586
+
1587
+ natcasesort($files);
1588
+
1589
+ if( count($files) > 2 ) { // The 2 accounts for . and ..
1590
+ echo "<ul class='jqueryFileTree'>";
1591
+ foreach( $files as $file ) {
1592
+
1593
+ if($file == 'ShortpixelBackups') continue;
1594
+
1595
+ $htmlRel = str_replace("'", "&apos;", $returnDir . $file);
1596
+ $htmlName = htmlentities($file);
1597
+ $ext = preg_replace('/^.*\./', '', $file);
1598
+
1599
+ if( file_exists($postDir . $file) && $file != '.' && $file != '..' ) {
1600
+ if( is_dir($postDir . $file) && (!$onlyFiles || $onlyFolders) )
1601
+ echo "<li class='directory collapsed'>{$checkbox}<a rel='" .$htmlRel. "/'>" . $htmlName . "</a></li>";
1602
+ else if (!$onlyFolders || $onlyFiles)
1603
+ echo "<li class='file ext_{$ext}'>{$checkbox}<a rel='" . $htmlRel . "'>" . $htmlName . "</a></li>";
1604
+ }
1605
+ }
1606
+
1607
+ echo "</ul>";
1608
+ }
1609
+ }
1610
+ die();
1611
+ }
1612
+
1613
+ public static function getCustomFolderBase() {
1614
+ if(is_main_site()) {
1615
+ $base = get_home_path();
1616
+ return realpath(rtrim($base, '/'));
1617
+ } else {
1618
+ $up = wp_upload_dir();
1619
+ return realpath($up['basedir']);
1620
+ }
1621
+ }
1622
+
1623
+ protected function fullRefreshCustomFolder($path, &$notice) {
1624
+ $folder = $this->spMetaDao->getFolder($path);
1625
+ $diff = $folder->checkFolderContents(array('ShortPixelCustomMetaDao', 'getPathFiles'));
1626
+ }
1627
+
1628
+ protected function refreshCustomFolders(&$notice, $ignore = false) {
1629
+ $customFolders = array();
1630
+ if($this->_settings->hasCustomFolders) {
1631
+ $customFolders = $this->spMetaDao->getFolders();
1632
+ foreach($customFolders as $folder) {
1633
+ if($folder->getPath() === $ignore) continue;
1634
+ try {
1635
+ $mt = $folder->getFolderContentsChangeDate();
1636
+ if($mt > strtotime($folder->getTsUpdated())) {
1637
+ $fileList = $folder->getFileList(strtotime($folder->getTsUpdated()));
1638
+ $this->spMetaDao->batchInsertImages($fileList, $folder->getId());
1639
+ $folder->setTsUpdated(date("Y-m-d H:i:s", $mt));
1640
+ $folder->setFileCount($folder->countFiles());
1641
+ $this->spMetaDao->update($folder);
1642
+ }
1643
+ //echo ("mt: " . $mt);
1644
+ //die(var_dump($folder));
1645
+ } catch(SpFileRightsException $ex) {
1646
+ if(is_array($notice)) {
1647
+ if($notice['status'] == 'error') {
1648
+ $notice['msg'] .= " " . $ex->getMessage();
1649
+ }
1650
+ } else {
1651
+ $notice = array("status" => "error", "msg" => $ex->getMessage());
1652
+ }
1653
+ }
1654
+ }
1655
+ }
1656
+ return $customFolders;
1657
+ }
1658
+
1659
+ public function renderSettingsMenu() {
1660
+ if ( !current_user_can( 'manage_options' ) ) {
1661
+ wp_die(__('You do not have sufficient permissions to access this page.','shortpixel-image-optimiser'));
1662
+ }
1663
+
1664
+ wp_enqueue_style('sp-file-tree.css', plugins_url('/res/css/sp-file-tree.css',SHORTPIXEL_PLUGIN_FILE) );
1665
+ wp_enqueue_script('sp-file-tree.js', plugins_url('/res/js/sp-file-tree.js',SHORTPIXEL_PLUGIN_FILE) );
1666
+
1667
+ //die(var_dump($_POST));
1668
+ $noticeHTML = "";
1669
+ $notice = null;
1670
+ $folderMsg = false;
1671
+ $addedFolder = false;
1672
+
1673
+ $this->_settings->redirectedSettings = 2;
1674
+
1675
+ //by default we try to fetch the API Key from wp-config.php (if defined)
1676
+ if ( defined("SHORTPIXEL_API_KEY") && strlen(SHORTPIXEL_API_KEY) == 20)
1677
+ {
1678
+ if(!isset($_POST['save']) && (strlen($this->getApiKey()) == 0 || SHORTPIXEL_API_KEY != $this->getApiKey())) {
1679
+ $_POST['validate'] = "validate";
1680
+ }
1681
+ $_POST['key'] = SHORTPIXEL_API_KEY;
1682
+ }
1683
+
1684
+ //check all custom folders and update meta table if files appeared
1685
+ $customFolders = $this->refreshCustomFolders($notice, isset($_POST['removeFolder']) ? $_POST['removeFolder'] : null);
1686
+
1687
+ if(isset($_POST['request']) && $_POST['request'] == 'request') {
1688
+ //a new API Key was requested
1689
+ if(filter_var($_POST['email'], FILTER_VALIDATE_EMAIL)) {
1690
+
1691
+ }
1692
+ else {
1693
+ $notice = array("status" => "error",
1694
+ "msg" => __("Please provide a valid e-mail.",'shortpixel-image-optimiser')
1695
+ . "<BR> "
1696
+ . __('For any question regarding obtaining your API Key, please contact us at ','shortpixel-image-optimiser')
1697
+ . "<a href='mailto:help@shortpixel.com?Subject=API Key issues' target='_top'>help@shortpixel.com</a>"
1698
+ . __(' or ','shortpixel-image-optimiser')
1699
+ . "<a href='https://shortpixel.com/contact' target='_blank'>" . __('here','shortpixel-image-optimiser') . "</a>.");
1700
+ }
1701
+ }
1702
+
1703
+ if( isset($_POST['save']) || isset($_POST['saveAdv'])
1704
+ || (isset($_POST['validate']) && $_POST['validate'] == "validate")
1705
+ || isset($_POST['removeFolder']) || isset($_POST['recheckFolder'])) {
1706
+
1707
+ //handle API Key - common for save and validate.
1708
+ $_POST['key'] = trim(str_replace("*", "", isset($_POST['key']) ? $_POST['key'] : $this->_settings->apiKey)); //the API key might not be set if the editing is disabled.
1709
+
1710
+ if ( strlen($_POST['key']) <> 20 )
1711
+ {
1712
+ $KeyLength = strlen($_POST['key']);
1713
+
1714
+ $notice = array("status" => "error",
1715
+ "msg" => sprintf(__("The key you provided has %s characters. The API key should have 20 characters, letters and numbers only.",'shortpixel-image-optimiser'), $KeyLength)
1716
+ . "<BR> <b>"
1717
+ . __('Please check that the API key is the same as the one you received in your confirmation email.','shortpixel-image-optimiser')
1718
+ . "</b><BR> "
1719
+ . __('If this problem persists, please contact us at ','shortpixel-image-optimiser')
1720
+ . "<a href='mailto:help@shortpixel.com?Subject=API Key issues' target='_top'>help@shortpixel.com</a>"
1721
+ . __(' or ','shortpixel-image-optimiser')
1722
+ . "<a href='https://shortpixel.com/contact' target='_blank'>" . __('here','shortpixel-image-optimiser') . "</a>.");
1723
+ }
1724
+ else
1725
+ {
1726
+ $validityData = $this->getQuotaInformation($_POST['key'], true, isset($_POST['validate']) && $_POST['validate'] == "validate");
1727
+
1728
+ $this->_settings->apiKey = $_POST['key'];
1729
+ if($validityData['APIKeyValid']) {
1730
+ if(isset($_POST['validate']) && $_POST['validate'] == "validate") {
1731
+ // delete last status if it was no valid key
1732
+ $lastStatus = $this->_settings->bulkLastStatus;
1733
+ if(isset($lastStatus['Status']) && $lastStatus['Status'] == ShortPixelAPI::STATUS_NO_KEY) {
1734
+ $this->_settings->bulkLastStatus = null;
1735
+ }
1736
+ //display notification
1737
+ $urlParts = explode("/", get_site_url());
1738
+ if( $validityData['DomainCheck'] == 'NOT Accessible'){
1739
+ $notice = array("status" => "warn", "msg" => __("API Key is valid but your site is not accessible from our servers. 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.",'shortpixel-image-optimiser'));
1740
+ } else {
1741
+ if ( function_exists("is_multisite") && is_multisite() && !defined("SHORTPIXEL_API_KEY"))
1742
+ $notice = array("status" => "success", "msg" => __("Great, your API Key is valid! <br>You seem to be running a multisite, please note that API Key can also be configured in wp-config.php like this:",'shortpixel-image-optimiser')
1743
+ . "<BR> <b>define('SHORTPIXEL_API_KEY', '".$this->_settings->apiKey."');</b>");
1744
+ else
1745
+ $notice = array("status" => "success", "msg" => __('Great, your API Key is valid. Please take a few moments to review the plugin settings below before starting to optimize your images.','shortpixel-image-optimiser'));
1746
+ }
1747
+ }
1748
+ $this->_settings->verifiedKey = true;
1749
+ //test that the "uploads" have the right rights and also we can create the backup dir for ShortPixel
1750
+ if ( !file_exists(SP_BACKUP_FOLDER) && !@mkdir(SP_BACKUP_FOLDER, 0777, true) )
1751
+ $notice = array("status" => "error",
1752
+ "msg" => sprintf(__("There is something preventing us to create a new folder for backing up your original files.<BR>Please make sure that folder <b>%s</b> has the necessary write and read rights.",'shortpixel-image-optimiser'),
1753
+ WP_CONTENT_DIR . '/' . SP_UPLOADS_NAME ));
1754
+ } else {
1755
+ if(isset($_POST['validate'])) {
1756
+ //display notification
1757
+ $notice = array("status" => "error", "msg" => $validityData["Message"]);
1758
+ }
1759
+ $this->_settings->verifiedKey = false;
1760
+ }
1761
+ }
1762
+
1763
+ //if save button - we process the rest of the form elements
1764
+ if(isset($_POST['save']) || isset($_POST['saveAdv'])) {
1765
+ $this->_settings->compressionType = $_POST['compressionType'];
1766
+ if(isset($_POST['thumbnails'])) { $this->_settings->processThumbnails = 1; } else { $this->_settings->processThumbnails = 0; }
1767
+ if(isset($_POST['backupImages'])) { $this->_settings->backupImages = 1; } else { $this->_settings->backupImages = 0; }
1768
+ if(isset($_POST['cmyk2rgb'])) { $this->_settings->CMYKtoRGBconversion = 1; } else { $this->_settings->CMYKtoRGBconversion = 0; }
1769
+ $this->_settings->keepExif = isset($_POST['removeExif']) ? 0 : 1;
1770
+ //delete_option('wp-short-pixel-keep-exif');
1771
+ $this->_settings->resizeImages = (isset($_POST['resize']) ? 1: 0);
1772
+ $this->_settings->resizeType = (isset($_POST['resize_type']) ? $_POST['resize_type']: false);
1773
+ $this->_settings->resizeWidth = (isset($_POST['width']) ? $_POST['width']: $this->_settings->resizeWidth);
1774
+ $this->_settings->resizeHeight = (isset($_POST['height']) ? $_POST['height']: $this->_settings->resizeHeight);
1775
+ $this->_settings->siteAuthUser = (isset($_POST['siteAuthUser']) ? $_POST['siteAuthUser']: $this->_settings->siteAuthUser);
1776
+ $this->_settings->siteAuthPass = (isset($_POST['siteAuthPass']) ? $_POST['siteAuthPass']: $this->_settings->siteAuthPass);
1777
+
1778
+ $uploadDir = wp_upload_dir();
1779
+ $uploadPath = realpath($uploadDir["basedir"]);
1780
+
1781
+ if(isset($_POST['nextGen'])) {
1782
+ WpShortPixelDb::checkCustomTables(); // check if custom tables are created, if not, create them
1783
+ $prevNextGen = $this->_settings->includeNextGen;
1784
+ $this->_settings->includeNextGen = 1;
1785
+ $ret = $this->addNextGenGalleriesToCustom($prevNextGen);
1786
+ $folderMsg = $ret["message"];
1787
+ $customFolders = $ret["customFolders"];
1788
+ } else {
1789
+ $this->_settings->includeNextGen = 0;
1790
+ }
1791
+ if(isset($_POST['addCustomFolder']) && strlen($_POST['addCustomFolder']) > 0) {
1792
+ $folderMsg = $this->spMetaDao->newFolderFromPath(stripslashes($_POST['addCustomFolder']), $uploadPath, self::getCustomFolderBase());
1793
+ if(!$folderMsg) {
1794
+ $notice = array("status" => "success", "msg" => __('Folder added successfully.','shortpixel-image-optimiser'));
1795
+ }
1796
+ $customFolders = $this->spMetaDao->getFolders();
1797
+ $this->_settings->hasCustomFolders = true;
1798
+ }
1799
+
1800
+ $this->_settings->createWebp = (isset($_POST['createWebp']) ? 1: 0);
1801
+ $this->_settings->optimizeRetina = (isset($_POST['optimizeRetina']) ? 1: 0);
1802
+ $this->_settings->optimizePdfs = (isset($_POST['optimizePdfs']) ? 1: 0);
1803
+ $this->_settings->frontBootstrap = (isset($_POST['frontBootstrap']) ? 1: 0);
1804
+ $this->_settings->autoMediaLibrary = (isset($_POST['autoMediaLibrary']) ? 1: 0);
1805
+
1806
+ //Redirect to bulk processing if requested
1807
+ if( isset($_POST['save']) && $_POST['save'] == __("Save and Go to Bulk Process",'shortpixel-image-optimiser')
1808
+ || isset($_POST['saveAdv']) && $_POST['saveAdv'] == __("Save and Go to Bulk Process",'shortpixel-image-optimiser')) {
1809
+ wp_redirect("upload.php?page=wp-short-pixel-bulk");
1810
+ exit();
1811
+ }
1812
+ }
1813
+ if(isset($_POST['removeFolder']) && strlen(($_POST['removeFolder']))) {
1814
+ $this->spMetaDao->removeFolder($_POST['removeFolder']);
1815
+ $customFolders = $this->spMetaDao->getFolders();
1816
+ $_POST["saveAdv"] = true;
1817
+ }
1818
+ if(isset($_POST['recheckFolder']) && strlen(($_POST['recheckFolder']))) {
1819
+ //$folder->fullRefreshCustomFolder($_POST['recheckFolder']); //aici singura solutie pare callback care spune daca exita url-ul complet
1820
+ }
1821
+ }
1822
+
1823
+ //now output headers. They were prevented with noheaders=true in the form url in order to be able to redirect if bulk was pressed
1824
+ if(isset($_REQUEST['noheader'])) {
1825
+ require_once(ABSPATH . 'wp-admin/admin-header.php');
1826
+ }
1827
+
1828
+ //empty backup
1829
+ if(isset($_POST['emptyBackup'])) {
1830
+ $this->emptyBackup();
1831
+ }
1832
+
1833
+ $quotaData = $this->checkQuotaAndAlert(isset($validityData) ? $validityData : null, isset($_GET['checkquota']));
1834
+
1835
+ if($this->hasNextGen) {
1836
+ $ngg = array_map(array('ShortPixelNextGenAdapter','pathToAbsolute'), ShortPixelNextGenAdapter::getGalleries());
1837
+ //die(var_dump($ngg));
1838
+ for($i = 0; $i < count($customFolders); $i++) {
1839
+ if(in_array($customFolders[$i]->getPath(), $ngg )) {
1840
+ $customFolders[$i]->setType("NextGen");
1841
+ }
1842
+ }
1843
+ }
1844
+
1845
+ $showApiKey = is_main_site() || (function_exists("is_multisite") && is_multisite() && !defined("SHORTPIXEL_API_KEY"));
1846
+ $editApiKey = !defined("SHORTPIXEL_API_KEY") && $showApiKey;
1847
+
1848
+ if($this->_settings->verifiedKey) {
1849
+ $fileCount = number_format($this->_settings->fileCount);
1850
+ $savedSpace = self::formatBytes($this->_settings->savedSpace,2);
1851
+ $averageCompression = $this->getAverageCompression();
1852
+ $savedBandwidth = self::formatBytes($this->_settings->savedSpace * 10000,2);
1853
+ if (is_numeric($quotaData['APICallsQuota'])) {
1854
+ $quotaData['APICallsQuota'] .= "/month";
1855
+ }
1856
+ $remainingImages = $quotaData['APICallsRemaining'];
1857
+ $remainingImages = ( $remainingImages < 0 ) ? 0 : number_format($remainingImages);
1858
+ $totalCallsMade = number_format($quotaData['APICallsMadeNumeric'] + $quotaData['APICallsMadeOneTimeNumeric']);
1859
+
1860
+ $resources = wp_remote_post($this->_settings->httpProto . "://shortpixel.com/resources-frag");
1861
+ if(is_wp_error( $resources )) {
1862
+ $resources = array();
1863
+ }
1864
+ $this->view->displaySettings($showApiKey, $editApiKey,
1865
+ $quotaData, $notice, $resources, $averageCompression, $savedSpace, $savedBandwidth, $remainingImages,
1866
+ $totalCallsMade, $fileCount, null /*folder size now on AJAX*/, $customFolders,
1867
+ $folderMsg, $folderMsg ? $addedFolder : false, isset($_POST['saveAdv']));
1868
+ } else {
1869
+ $this->view->displaySettings($showApiKey, $editApiKey, $quotaData, $notice);
1870
+ }
1871
+
1872
+ }
1873
+
1874
+ public function addNextGenGalleriesToCustom($silent) {
1875
+ $customFolders = array();
1876
+ $folderMsg = "";
1877
+ if($this->_settings->includeNextGen) {
1878
+ //add the NextGen galleries to custom folders
1879
+ $ngGalleries = ShortPixelNextGenAdapter::getGalleries();
1880
+ foreach($ngGalleries as $gallery) {
1881
+ $folderMsg = $this->spMetaDao->newFolderFromPath($gallery, get_home_path(), self::getCustomFolderBase());
1882
+ $this->_settings->hasCustomFolders = true;
1883
+ }
1884
+ $customFolders = $this->spMetaDao->getFolders();
1885
+ }
1886
+ return array("message" => $silent? "" : $folderMsg, "customFolders" => $customFolders);
1887
+ }
1888
+
1889
+ public function getAverageCompression(){
1890
+ return $this->_settings->totalOptimized > 0
1891
+ ? round(( 1 - ( $this->_settings->totalOptimized / $this->_settings->totalOriginal ) ) * 100, 2)
1892
+ : 0;
1893
+ }
1894
+
1895
+ /**
1896
+ *
1897
+ * @param type $apiKey
1898
+ * @param type $appendUserAgent
1899
+ * @param type $validate - true if we are validating the api key, send also the domain name and number of pics
1900
+ * @return type
1901
+ */
1902
+ public function getQuotaInformation($apiKey = null, $appendUserAgent = false, $validate = false) {
1903
+
1904
+ if(is_null($apiKey)) { $apiKey = $this->_settings->apiKey; }
1905
+
1906
+ if($this->_settings->httpProto != 'https' && $this->_settings->httpProto != 'http') {
1907
+ $this->_settings->httpProto = 'https';
1908
+ }
1909
+
1910
+ $requestURL = $this->_settings->httpProto . '://api.shortpixel.com/v2/api-status.php';
1911
+ $args = array(
1912
+ 'timeout'=> SP_VALIDATE_MAX_TIMEOUT,
1913
+ 'body' => array('key' => $apiKey)
1914
+ );
1915
+ $argsStr = "?key=".$apiKey;
1916
+
1917
+ if($appendUserAgent) {
1918
+ $args['body']['useragent'] = "Agent" . urlencode($_SERVER['HTTP_USER_AGENT']);
1919
+ $argsStr .= "&useragent=Agent".$args['body']['useragent'];
1920
+ }
1921
+ if($validate) {
1922
+ $args['body']['DomainCheck'] = get_site_url();
1923
+ $args['body']['Info'] = get_bloginfo('version') . '|' . phpversion();
1924
+ $imageCount = WpShortPixelMediaLbraryAdapter::countAllProcessableFiles($this->_settings->optimizePdfs);
1925
+ $args['body']['ImagesCount'] = $imageCount['mainFiles'];
1926
+ $args['body']['ThumbsCount'] = $imageCount['totalFiles'] - $imageCount['mainFiles'];
1927
+ $argsStr .= "&DomainCheck={$args['body']['DomainCheck']}&Info={$args['body']['Info']}&ImagesCount={$imageCount['mainFiles']}&ThumbsCount={$args['body']['ThumbsCount']}";
1928
+ }
1929
+ if(strlen($this->_settings->siteAuthUser)) {
1930
+ $args['body']['url'] = parse_url(get_site_url(),PHP_URL_HOST);
1931
+ $args['body']['user'] = $this->_settings->siteAuthUser;
1932
+ $args['body']['pass'] = urlencode($this->_settings->siteAuthPass);
1933
+ $argsStr .= "&url={$args['body']['url']}&user={$args['body']['user']}&pass={$args['body']['pass']}";
1934
+ }
1935
+
1936
+ $comm = array();
1937
+
1938
+ //Try first HTTPS post. add the sslverify = false if https
1939
+ if($this->_settings->httpProto === 'https') {
1940
+ $args['sslverify'] = false;
1941
+ }
1942
+ $response = wp_remote_post($requestURL, $args);
1943
+ $comm[] = array("sent" => "POST: " . $requestURL, "args" => $args, "received" => $response);
1944
+
1945
+ //some hosting providers won't allow https:// POST connections so we try http:// as well
1946
+ if(is_wp_error( $response )) {
1947
+ //echo("protocol " . $this->_settings->httpProto . " failed. switching...");
1948
+ $requestURL = $this->_settings->httpProto == 'https' ?
1949
+ str_replace('https://', 'http://', $requestURL) :
1950
+ str_replace('http://', 'https://', $requestURL);
1951
+ // add or remove the sslverify
1952
+ if($this->_settings->httpProto === 'http') {
1953
+ $args['sslverify'] = false;
1954
+ } else {
1955
+ unset($args['sslverify']);
1956
+ }
1957
+ $response = wp_remote_post($requestURL, $args);
1958
+ $comm[] = array("sent" => "POST: " . $requestURL, "args" => $args, "received" => $response);
1959
+
1960
+ if(!is_wp_error( $response )){
1961
+ $this->_settings->httpProto = ($this->_settings->httpProto == 'https' ? 'http' : 'https');
1962
+ //echo("protocol " . $this->_settings->httpProto . " succeeded");
1963
+ } else {
1964
+ //echo("protocol " . $this->_settings->httpProto . " failed too");
1965
+ }
1966
+ }
1967
+ //Second fallback to HTTP get
1968
+ if(is_wp_error( $response )){
1969
+ $args['body'] = null;
1970
+ $requestURL .= $argsStr;
1971
+ $response = wp_remote_get($requestURL, $args);
1972
+ $comm[] = array("sent" => "POST: " . $requestURL, "args" => $args, "received" => $response);
1973
+ }
1974
+
1975
+ $defaultData = array(
1976
+ "APIKeyValid" => false,
1977
+ "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. ','shortpixel-image-optimiser'),
1978
+ "APICallsMade" => __('Information unavailable. Please check your API key.','shortpixel-image-optimiser'),
1979
+ "APICallsQuota" => __('Information unavailable. Please check your API key.','shortpixel-image-optimiser'),
1980
+ "DomainCheck" => 'NOT Accessible');
1981
+
1982
+ if(is_object($response) && get_class($response) == 'WP_Error') {
1983
+
1984
+ $urlElements = parse_url($requestURL);
1985
+ $portConnect = @fsockopen($urlElements['host'],8,$errno,$errstr,15);
1986
+ if(!$portConnect) {
1987
+ $defaultData['Message'] .= "<BR>Debug info: <i>$errstr</i>";
1988
+ }
1989
+ return $defaultData;
1990
+ }
1991
+
1992
+ if($response['response']['code'] != 200) {
1993
+ //$defaultData['Message'] .= "<BR><i>Debug info: response code {$response['response']['code']} URL $requestURL , Response ".json_encode($response)."</i>";
1994
+ return $defaultData;
1995
+ }
1996
+
1997
+ $data = $response['body'];
1998
+ $data = ShortPixelTools::parseJSON($data);
1999
+
2000
+ if(empty($data)) { return $defaultData; }
2001
+
2002
+ if($data->Status->Code != 2) {
2003
+ $defaultData['Message'] = $data->Status->Message;
2004
+ return $defaultData;
2005
+ }
2006
+
2007
+ if ( ( $data->APICallsMade + $data->APICallsMadeOneTime ) < ( $data->APICallsQuota + $data->APICallsQuotaOneTime ) ) //reset quota exceeded flag -> user is allowed to process more images.
2008
+ $this->resetQuotaExceeded();
2009
+ else
2010
+ $this->_settings->quotaExceeded = 1;//activate quota limiting
2011
+
2012
+ //if a non-valid status exists, delete it
2013
+ $lastStatus = $this->_settings->bulkLastStatus = null;
2014
+ if($lastStatus && $lastStatus['Status'] == ShortPixelAPI::STATUS_NO_KEY) {
2015
+ $this->_settings->bulkLastStatus = null;
2016
+ }
2017
+
2018
+ return array(
2019
+ "APIKeyValid" => true,
2020
+ "APICallsMade" => number_format($data->APICallsMade) . __(' images','shortpixel-image-optimiser'),
2021
+ "APICallsQuota" => number_format($data->APICallsQuota) . __(' images','shortpixel-image-optimiser'),
2022
+ "APICallsMadeOneTime" => number_format($data->APICallsMadeOneTime) . __(' images','shortpixel-image-optimiser'),
2023
+ "APICallsQuotaOneTime" => number_format($data->APICallsQuotaOneTime) . __(' images','shortpixel-image-optimiser'),
2024
+ "APICallsMadeNumeric" => $data->APICallsMade,
2025
+ "APICallsQuotaNumeric" => $data->APICallsQuota,
2026
+ "APICallsMadeOneTimeNumeric" => $data->APICallsMadeOneTime,
2027
+ "APICallsQuotaOneTimeNumeric" => $data->APICallsQuotaOneTime,
2028
+ "APICallsRemaining" => $data->APICallsQuota + $data->APICallsQuotaOneTime - $data->APICallsMade - $data->APICallsMadeOneTime,
2029
+ "APILastRenewalDate" => $data->DateSubscription,
2030
+ "DomainCheck" => (isset($data->DomainCheck) ? $data->DomainCheck : null)
2031
+ );
2032
+ }
2033
+
2034
+ public function resetQuotaExceeded() {
2035
+ if( $this->_settings->quotaExceeded == 1) {
2036
+ $dismissed = $this->_settings->dismissedNotices ? $this->_settings->dismissedNotices : array();
2037
+ unset($dismissed['exceed']);
2038
+ $this->_settings->dismissedNotices = $dismissed;
2039
+ }
2040
+ $this->_settings->quotaExceeded = 0;
2041
+ }
2042
+
2043
+ public function generateCustomColumn( $column_name, $id, $extended = false ) {
2044
+ if( 'wp-shortPixel' == $column_name ) {
2045
+
2046
+ $file = get_attached_file($id);
2047
+ if(!self::isProcessablePath($file)) {
2048
+ $renderData['status'] = 'n/a';
2049
+ $this->view->renderCustomColumn($id, $renderData, $extended);
2050
+ return;
2051
+ }
2052
+
2053
+ $data = wp_get_attachment_metadata($id);
2054
+ $fileExtension = strtolower(pathinfo($file, PATHINFO_EXTENSION));
2055
+ $invalidKey = !$this->_settings->verifiedKey;
2056
+ $quotaExceeded = $this->_settings->quotaExceeded;
2057
+ $renderData = array("id" => $id, "showActions" => (current_user_can( 'manage_options' ) || current_user_can( 'upload_files' ) || current_user_can( 'edit_posts' )));
2058
+
2059
+ if($invalidKey) { //invalid key - let the user first register and only then
2060
+ $renderData['status'] = 'invalidKey';
2061
+ $this->view->renderCustomColumn($id, $renderData, $extended);
2062
+ return;
2063
+ }
2064
+
2065
+ //empty data means document, we handle only PDF
2066
+ elseif (empty($data)) { //TODO asta devine if si decomentam returnurile
2067
+ if($fileExtension == "pdf") {
2068
+ $renderData['status'] = $quotaExceeded ? 'quotaExceeded' : 'optimizeNow';
2069
+ $renderData['message'] = __('PDF not processed.','shortpixel-image-optimiser');
2070
+ }
2071
+ else { //Optimization N/A
2072
+ $renderData['status'] = 'n/a';
2073
+ }
2074
+ $this->view->renderCustomColumn($id, $renderData, $extended);
2075
+ return;
2076
+ }
2077
+
2078
+ if(!isset($data['ShortPixelImprovement'])) { //new image
2079
+ $data['ShortPixelImprovement'] = '';
2080
+ }
2081
+
2082
+ if(is_numeric($data['ShortPixelImprovement'])) { //already optimized
2083
+ $sizesCount = isset($data['sizes']) ? WpShortPixelMediaLbraryAdapter::countNonWebpSizes($data['sizes']) : 0;
2084
+
2085
+ $renderData['status'] = $fileExtension == "pdf" ? 'pdfOptimized' : 'imgOptimized';
2086
+ $renderData['percent'] = $data['ShortPixelImprovement'];
2087
+ $renderData['bonus'] = ($data['ShortPixelImprovement'] < 5);
2088
+ $renderData['backup'] = $this->getBackupFolderAny(get_attached_file($id), $sizesCount? $data['sizes'] : array());
2089
+ $renderData['type'] = isset($data['ShortPixel']['type']) ? $data['ShortPixel']['type'] : '';
2090
+ $renderData['thumbsTotal'] = $sizesCount;
2091
+ $renderData['thumbsOpt'] = isset($data['ShortPixel']['thumbsOpt']) ? $data['ShortPixel']['thumbsOpt'] : $sizesCount;
2092
+ $renderData['thumbsMissing'] = isset($data['ShortPixel']['thumbsMissing']) ? $data['ShortPixel']['thumbsMissing'] : array();
2093
+ $renderData['retinasOpt'] = isset($data['ShortPixel']['retinasOpt']) ? $data['ShortPixel']['retinasOpt'] : null;
2094
+ $renderData['exifKept'] = isset($data['ShortPixel']['exifKept']) ? $data['ShortPixel']['exifKept'] : null;
2095
+ $renderData['date'] = isset($data['ShortPixel']['date']) ? $data['ShortPixel']['date'] : null;
2096
+ $renderData['quotaExceeded'] = $quotaExceeded;
2097
+ $webP = 0;
2098
+ if($extended) {
2099
+ if(file_exists(dirname($file) . '/' . ShortPixelAPI::MB_basename($file, '.'.$fileExtension) . '.webp' )){
2100
+ $webP++;
2101
+ }
2102
+ if(isset($data['sizes'])) {
2103
+ foreach($data['sizes'] as $key => $size) {
2104
+ if (strpos($key, ShortPixelMeta::WEBP_THUMB_PREFIX) === 0) continue;
2105
+ $sizeName = $size['file'];
2106
+ if(file_exists(dirname($file) . '/' . ShortPixelAPI::MB_basename($sizeName, '.'.$fileExtension) . '.webp' )){
2107
+ $webP++;
2108
+ }
2109
+ }
2110
+ }
2111
+ }
2112
+ $renderData['webpCount'] = $webP;
2113
+ }
2114
+ elseif($data['ShortPixelImprovement'] == __('Optimization N/A','shortpixel-image-optimiser')) { //We don't optimize this
2115
+ $renderData['status'] = 'n/a';
2116
+ }
2117
+ elseif(isset($meta['ShortPixel']['BulkProcessing'])) { //Scheduled to bulk.
2118
+ $renderData['status'] = $quotaExceeded ? 'quotaExceeded' : 'optimizeNow';
2119
+ $renderData['message'] = 'Waiting for bulk processing.';
2120
+ }
2121
+ elseif( trim(strip_tags($data['ShortPixelImprovement'])) == __("Cannot write optimized file",'shortpixel-image-optimiser') ) {
2122
+ $renderData['status'] = $quotaExceeded ? 'quotaExceeded' : 'retry';
2123
+ $renderData['message'] = __("Cannot write optimized file",'shortpixel-image-optimiser') . " - <a href='https://shortpixel.com/faq#cannot-write-optimized-file' target='_blank'>"
2124
+ . __("Why?",'shortpixel-image-optimiser') . "</a>";
2125
+ }
2126
+ elseif( strlen(trim(strip_tags($data['ShortPixelImprovement']))) > 0 ) {
2127
+ $renderData['status'] = $quotaExceeded ? 'quotaExceeded' : 'retry';
2128
+ $renderData['message'] = $data['ShortPixelImprovement'];
2129
+ if(strpos($renderData['message'], __('The file(s) do not exist on disk: ','shortpixel-image-optimiser')) !== false) {
2130
+ $renderData['cleanup'] = true;
2131
+ }
2132
+ }
2133
+ elseif(isset($data['ShortPixel']['NoFileOnDisk'])) {
2134
+ $renderData['status'] = 'notFound';
2135
+ $renderData['message'] = __('Image does not exist','shortpixel-image-optimiser');
2136
+ }
2137
+ elseif(isset($data['ShortPixel']['WaitingProcessing'])) {
2138
+ $renderData['status'] = $quotaExceeded ? 'quotaExceeded' : 'retry';
2139
+ $renderData['message'] = "<img src=\"" . plugins_url( 'res/img/loading.gif', SHORTPIXEL_PLUGIN_FILE ) . "\" class='sp-loading-small'>&nbsp;" . __("Image waiting to be processed.",'shortpixel-image-optimiser');
2140
+ if($id > $this->prioQ->getFlagBulkId() || !$this->prioQ->bulkRunning()) $this->prioQ->push($id); //should be there but just to make sure
2141
+ }
2142
+ else { //finally
2143
+ $renderData['status'] = $quotaExceeded ? 'quotaExceeded' : 'optimizeNow';
2144
+ $sizes = isset($data['sizes']) ? WpShortPixelMediaLbraryAdapter::countNonWebpSizes($data['sizes']) : 0;
2145
+ $renderData['thumbsTotal'] = $sizes;
2146
+ $renderData['message'] = ($fileExtension == "pdf" ? 'PDF' : 'Image') . ' not processed.';
2147
+ }
2148
+
2149
+ $this->view->renderCustomColumn($id, $renderData, $extended);
2150
+ }
2151
+ }
2152
+
2153
+ function shortpixelInfoBox() {
2154
+ if(get_post_type( ) == 'attachment') {
2155
+ add_meta_box(
2156
+ 'shortpixel_info_box', // this is HTML id of the box on edit screen
2157
+ __('ShortPixel Info', 'shortpixel-image-optimiser'), // title of the box
2158
+ array( &$this, 'shortpixelInfoBoxContent'), // function to be called to display the info
2159
+ null,//, // on which edit screen the box should appear
2160
+ 'side'//'normal', // part of page where the box should appear
2161
+ //'default' // priority of the box
2162
+ );
2163
+ }
2164
+ }
2165
+
2166
+ function shortpixelInfoBoxContent( $post ) {
2167
+ $this->generateCustomColumn( 'wp-shortPixel', $post->ID, true );
2168
+ }
2169
+
2170
+ function onDeleteImage($post_id) {
2171
+ $itemHandler = new ShortPixelMetaFacade($post_id);
2172
+ $urlsPaths = $itemHandler->getURLsAndPATHs(true, false, false);
2173
+ foreach($urlsPaths['PATHs'] as $path) {
2174
+ $pos = strrpos($path, ".");
2175
+ if ($pos !== false) {
2176
+ //$webpPath = substr($path, 0, $pos) . ".webp";
2177
+ //echo($webpPath . "<br>");
2178
+ @unlink(substr($path, 0, $pos) . ".webp");
2179
+ @unlink(substr($path, 0, $pos) . "@2x.webp");
2180
+ }
2181
+ }
2182
+ }
2183
+
2184
+ public function columns( $defaults ) {
2185
+ $defaults['wp-shortPixel'] = 'ShortPixel Compression';
2186
+ if(current_user_can( 'manage_options' )) {
2187
+ $defaults['wp-shortPixel'] .= '&nbsp;<a href="options-general.php?page=wp-shortpixel#stats" title="'
2188
+ . __('ShortPixel Statistics','shortpixel-image-optimiser') . '"><span class="dashicons dashicons-dashboard"></span></a>';
2189
+ }
2190
+ return $defaults;
2191
+ }
2192
+
2193
+ public function nggColumns( $defaults ) {
2194
+ $this->nggColumnIndex = count($defaults) + 1;
2195
+ add_filter( 'ngg_manage_images_column_' . $this->nggColumnIndex . '_header', array( &$this, 'nggColumnHeader' ) );
2196
+ add_filter( 'ngg_manage_images_column_' . $this->nggColumnIndex . '_content', array( &$this, 'nggColumnContent' ), 10, 2 );
2197
+ $defaults['wp-shortPixelNgg'] = 'ShortPixel Compression';
2198
+ return $defaults;
2199
+ }
2200
+
2201
+ public function nggCountColumns( $count ) {
2202
+ return $count + 1;
2203
+ }
2204
+
2205
+ public function nggColumnHeader( $default ) {
2206
+ return __('ShortPixel Compression','shortpixel-image-optimiser');
2207
+ }
2208
+
2209
+ public function nggColumnContent( $unknown, $picture ) {
2210
+
2211
+ $meta = $this->spMetaDao->getMetaForPath($picture->imagePath);
2212
+ if($meta) {
2213
+ switch($meta->getStatus()) {
2214
+ case "0": echo("<div id='sp-msg-C-{$meta->getId()}' class='column-wp-shortPixel' style='color: #928B1E'>Waiting</div>"); break;
2215
+ case "1": echo("<div id='sp-msg-C-{$meta->getId()}' class='column-wp-shortPixel' style='color: #1919E2'>Pending</div>"); break;
2216
+ case "2": $this->view->renderCustomColumn("C-" . $meta->getId(), array(
2217
+ 'showActions' => false && current_user_can( 'manage_options' ),
2218
+ 'status' => 'imgOptimized',
2219
+ 'type' => ShortPixelAPI::getCompressionTypeName($meta->getCompressionType()),
2220
+ 'percent' => $meta->getImprovementPercent(),
2221
+ 'bonus' => $meta->getImprovementPercent() < 5,
2222
+ 'thumbsOpt' => 0,
2223
+ 'thumbsTotal' => 0,
2224
+ 'retinasOpt' => 0,
2225
+ 'backup' => true
2226
+ ));
2227
+ break;
2228
+ }
2229
+ } else {
2230
+ $this->view->renderCustomColumn($meta ? "C-" . $meta->getId() : "N-" . $picture->pid, array(
2231
+ 'showActions' => false && current_user_can( 'manage_options' ),
2232
+ 'status' => 'optimizeNow',
2233
+ 'thumbsOpt' => 0,
2234
+ 'thumbsTotal' => 0,
2235
+ 'retinasOpt' => 0,
2236
+ 'message' => "Not optimized"
2237
+ ));
2238
+ }
2239
+ // return var_dump($meta);
2240
+ }
2241
+
2242
+ public function generatePluginLinks($links) {
2243
+ $in = '<a href="options-general.php?page=wp-shortpixel">Settings</a>';
2244
+ array_unshift($links, $in);
2245
+ return $links;
2246
+ }
2247
+
2248
+ static public function formatBytes($bytes, $precision = 2) {
2249
+ $units = array('B', 'KB', 'MB', 'GB', 'TB');
2250
+
2251
+ $bytes = max($bytes, 0);
2252
+ $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
2253
+ $pow = min($pow, count($units) - 1);
2254
+
2255
+ $bytes /= pow(1024, $pow);
2256
+
2257
+ return round($bytes, $precision) . ' ' . $units[$pow];
2258
+ }
2259
+
2260
+ static public function isProcessable($ID, $exclude = array()) {
2261
+ $path = get_attached_file($ID);//get the full file PATH
2262
+ return $path ? self::isProcessablePath($path, $exclude) : false;
2263
+ }
2264
+
2265
+ static public function isProcessablePath($path, $exclude = array()) {
2266
+ $pathParts = pathinfo($path);
2267
+ $ext = $pathParts['extension'];
2268
+ if( isset($ext) && in_array(strtolower($ext), array_diff(self::$PROCESSABLE_EXTENSIONS, $exclude))) {
2269
+ return true;
2270
+ } else {
2271
+ return false;
2272
+ }
2273
+ }
2274
+
2275
+
2276
+ //return an array with URL(s) and PATH(s) for this file
2277
+ public function getURLsAndPATHs($itemHandler, $meta = NULL, $onlyThumbs = false) {
2278
+ return $itemHandler->getURLsAndPATHs($this->_settings->processThumbnails, $onlyThumbs, $this->_settings->optimizeRetina);
2279
+ }
2280
+
2281
+
2282
+ public static function deleteDir($dirPath) {
2283
+ if (substr($dirPath, strlen($dirPath) - 1, 1) != '/') {
2284
+ $dirPath .= '/';
2285
+ }
2286
+ $files = glob($dirPath . '*', GLOB_MARK);
2287
+ foreach ($files as $file) {
2288
+ if (is_dir($file)) {
2289
+ self::deleteDir($file);
2290
+ @rmdir($file);//remove empty dir
2291
+ } else {
2292
+ @unlink($file);//remove file
2293
+ }
2294
+ }
2295
+ }
2296
+
2297
+ static public function folderSize($path) {
2298
+ $total_size = 0;
2299
+ if(file_exists($path)) {
2300
+ $files = scandir($path);
2301
+ } else {
2302
+ return $total_size;
2303
+ }
2304
+ $cleanPath = rtrim($path, '/'). '/';
2305
+ foreach($files as $t) {
2306
+ if ($t<>"." && $t<>"..")
2307
+ {
2308
+ $currentFile = $cleanPath . $t;
2309
+ if (is_dir($currentFile)) {
2310
+ $size = self::folderSize($currentFile);
2311
+ $total_size += $size;
2312
+ }
2313
+ else {
2314
+ $size = filesize($currentFile);
2315
+ $total_size += $size;
2316
+ }
2317
+ }
2318
+ }
2319
+ return $total_size;
2320
+ }
2321
+
2322
+ public function migrateBackupFolder() {
2323
+ $oldBackupFolder = WP_CONTENT_DIR . '/' . SP_BACKUP;
2324
+
2325
+ if(file_exists($oldBackupFolder)) { //if old backup folder does not exist then there is nothing to do
2326
+
2327
+ if(!file_exists(SP_BACKUP_FOLDER)) {
2328
+ //we check that the backup folder exists, if not we create it so we can copy into it
2329
+ if(!mkdir(SP_BACKUP_FOLDER, 0777, true)) return;
2330
+ }
2331
+
2332
+ $scannedDirectory = array_diff(scandir($oldBackupFolder), array('..', '.'));
2333
+ foreach($scannedDirectory as $file) {
2334
+ @rename($oldBackupFolder.'/'.$file, SP_BACKUP_FOLDER.'/'.$file);
2335
+ }
2336
+ $scannedDirectory = array_diff(scandir($oldBackupFolder), array('..', '.'));
2337
+ if(empty($scannedDirectory)) {
2338
+ @rmdir($oldBackupFolder);
2339
+ }
2340
+ }
2341
+ //now if the backup folder does not contain the uploads level, create it
2342
+ if( !is_dir(SP_BACKUP_FOLDER . '/' . SP_UPLOADS_NAME )
2343
+ && !is_dir(SP_BACKUP_FOLDER . '/' . basename(WP_CONTENT_DIR))) {
2344
+ @rename(SP_BACKUP_FOLDER, SP_BACKUP_FOLDER."_tmp");
2345
+ @mkdir(SP_BACKUP_FOLDER);
2346
+ @rename(SP_BACKUP_FOLDER."_tmp", SP_BACKUP_FOLDER.'/'.SP_UPLOADS_NAME);
2347
+ if(!file_exists(SP_BACKUP_FOLDER)) {//just in case..
2348
+ @rename(SP_BACKUP_FOLDER."_tmp", SP_BACKUP_FOLDER);
2349
+ }
2350
+ }
2351
+ //then create the wp-content level if not present
2352
+ if(!is_dir(SP_BACKUP_FOLDER . '/' . basename(WP_CONTENT_DIR))) {
2353
+ @rename(SP_BACKUP_FOLDER, SP_BACKUP_FOLDER."_tmp");
2354
+ @mkdir(SP_BACKUP_FOLDER);
2355
+ @rename(SP_BACKUP_FOLDER."_tmp", SP_BACKUP_FOLDER.'/' . basename(WP_CONTENT_DIR));
2356
+ if(!file_exists(SP_BACKUP_FOLDER)) {//just in case..
2357
+ @rename(SP_BACKUP_FOLDER."_tmp", SP_BACKUP_FOLDER);
2358
+ }
2359
+ }
2360
+ return;
2361
+ }
2362
+
2363
+ function getMaxIntermediateImageSize() {
2364
+ global $_wp_additional_image_sizes;
2365
+
2366
+ $width = 0;
2367
+ $height = 0;
2368
+ $get_intermediate_image_sizes = get_intermediate_image_sizes();
2369
+
2370
+ // Create the full array with sizes and crop info
2371
+ foreach( $get_intermediate_image_sizes as $_size ) {
2372
+ if ( in_array( $_size, array( 'thumbnail', 'medium', 'large' ) ) ) {
2373
+ $width = max($width, get_option( $_size . '_size_w' ));
2374
+ $height = max($height, get_option( $_size . '_size_h' ));
2375
+ //$sizes[ $_size ]['crop'] = (bool) get_option( $_size . '_crop' );
2376
+ } elseif ( isset( $_wp_additional_image_sizes[ $_size ] ) ) {
2377
+ $width = max($width, $_wp_additional_image_sizes[ $_size ]['width']);
2378
+ $height = max($height, $_wp_additional_image_sizes[ $_size ]['height']);
2379
+ //'crop' => $_wp_additional_image_sizes[ $_size ]['crop']
2380
+ }
2381
+ }
2382
+ return array('width' => $width, 'height' => $height);
2383
+ }
2384
+
2385
+ /* public function getEncryptedData() {
2386
+ return base64_encode(self::encrypt($this->getApiKey() . "|" . get_site_url(), "sh0r+Pix3l8im1N3r"));
2387
+ }
2388
+ */
2389
+
2390
+ /**
2391
+ * Returns an encrypted & utf8-encoded
2392
+ */
2393
+ /* public static function encrypt($pure_string, $encryption_key)
2394
+ {
2395
+ if(!function_exists("mcrypt_get_iv_size") || !function_exists('utf8_encode')) {
2396
+ return "";
2397
+ }
2398
+ $iv_size = \mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB);
2399
+ $iv = \mcrypt_create_iv($iv_size, MCRYPT_RAND);
2400
+ $encrypted_string = \mcrypt_encrypt(MCRYPT_BLOWFISH, $encryption_key, utf8_encode($pure_string), MCRYPT_MODE_ECB, $iv);
2401
+ return $encrypted_string;
2402
+ }
2403
+ */
2404
+
2405
+ public function getApiKey() {
2406
+ return $this->_settings->apiKey;
2407
+ }
2408
+
2409
+ public function getPrioQ() {
2410
+ return $this->prioQ;
2411
+ }
2412
+
2413
+ public function backupImages() {
2414
+ return $this->_settings->backupImages;
2415
+ }
2416
+
2417
+ public function processThumbnails() {
2418
+ return $this->_settings->processThumbnails;
2419
+ }
2420
+
2421
+ public function getCMYKtoRGBconversion() {
2422
+ return $this->_settings->CMYKtoRGBconversion;
2423
+ }
2424
+
2425
+ public function getSettings() {
2426
+ return $this->_settings;
2427
+ }
2428
+
2429
+ public function getResizeImages() {
2430
+ return $this->_settings->resizeImages;
2431
+ }
2432
+
2433
+ public function getResizeWidth() {
2434
+ return $this->_settings->resizeWidth;
2435
+ }
2436
+
2437
+ public function getResizeHeight() {
2438
+ return $this->_settings->resizeHeight;
2439
+ }
2440
+ public function getAffiliateSufix() {
2441
+ return $this->_affiliateSufix;
2442
+ }
2443
+ public function getVerifiedKey() {
2444
+ return $this->_settings->verifiedKey;
2445
+ }
2446
+ public function getCompressionType() {
2447
+ return $this->_settings->compressionType;
2448
+ }
2449
+ public function hasNextGen() {
2450
+ return $this->hasNextGen;
2451
+ }
2452
+
2453
+ public function getSpMetaDao() {
2454
+ return $this->spMetaDao;
2455
+ }
2456
+
2457
+ }
readme.txt CHANGED
@@ -5,7 +5,7 @@ Tags: image optimizer, image optimization, compress pdf, compress jpeg, compress
5
 
6
  Requires at least: 3.2.0
7
  Tested up to: 4.7
8
- Stable tag: 4.2.7
9
  License: GPLv2 or later
10
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
11
 
@@ -217,6 +217,11 @@ The ShortPixel team is here to help. <a href="https://shortpixel.com/contact">Co
217
 
218
  == Changelog ==
219
 
 
 
 
 
 
220
  = 4.2.7 =
221
 
222
  * fix bug when quota expires
5
 
6
  Requires at least: 3.2.0
7
  Tested up to: 4.7
8
+ Stable tag: 4.2.8
9
  License: GPLv2 or later
10
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
11
 
217
 
218
  == Changelog ==
219
 
220
+ = 4.2.8 =
221
+
222
+ * fix bug when searching for thumbanils of files with same prefix
223
+ * fix bug when several successive images have all files missing
224
+
225
  = 4.2.7 =
226
 
227
  * fix bug when quota expires
shortpixel_api.php CHANGED
@@ -43,6 +43,11 @@ class ShortPixelAPI {
43
  * @return response from wp_remote_post or error
44
  */
45
  public function doRequests($URLs, $Blocking, $itemHandler, $compressionType = false, $refresh = false) {
 
 
 
 
 
46
  $requestParameters = array(
47
  'plugin_version' => PLUGIN_VERSION,
48
  'key' => $this->_settings->apiKey,
43
  * @return response from wp_remote_post or error
44
  */
45
  public function doRequests($URLs, $Blocking, $itemHandler, $compressionType = false, $refresh = false) {
46
+
47
+ if(!count($URLs)) {
48
+ throw new Exception(__('Image files are missing.','shortpixel-image-optimiser'));
49
+ }
50
+
51
  $requestParameters = array(
52
  'plugin_version' => PLUGIN_VERSION,
53
  'key' => $this->_settings->apiKey,
wp-shortpixel-req.php CHANGED
@@ -5,6 +5,7 @@ if(defined('SHORTPIXEL_DEBUG') && SHORTPIXEL_DEBUG === true) {
5
  define('SHORTPIXEL_DEBUG', false);
6
  }
7
 
 
8
  require_once('class/wp-shortpixel-settings.php');
9
  require_once('shortpixel_api.php');
10
  require_once('class/shortpixel_queue.php');
5
  define('SHORTPIXEL_DEBUG', false);
6
  }
7
 
8
+ require_once('class/wp-short-pixel.php');
9
  require_once('class/wp-shortpixel-settings.php');
10
  require_once('shortpixel_api.php');
11
  require_once('class/shortpixel_queue.php');
wp-shortpixel.php CHANGED
@@ -3,7 +3,7 @@
3
  * Plugin Name: ShortPixel Image Optimizer
4
  * Plugin URI: https://shortpixel.com/
5
  * Description: ShortPixel optimizes images automatically, while guarding the quality of your images. Check your <a href="options-general.php?page=wp-shortpixel" target="_blank">Settings &gt; ShortPixel</a> page on how to start optimizing your image library and make your website load faster.
6
- * Version: 4.2.7
7
  * Author: ShortPixel
8
  * Author URI: https://shortpixel.com
9
  * Text Domain: shortpixel-image-optimiser
@@ -14,9 +14,11 @@ define('SP_RESET_ON_ACTIVATE', false); //if true TODO set false
14
 
15
  //define('SHORTPIXEL_DEBUG', true);
16
 
 
 
17
  define('SP_AFFILIATE_CODE', '');
18
 
19
- define('PLUGIN_VERSION', "4.2.7");
20
  define('SP_MAX_TIMEOUT', 10);
21
  define('SP_VALIDATE_MAX_TIMEOUT', 15);
22
  define('SP_BACKUP', 'ShortpixelBackups');
@@ -44,2457 +46,6 @@ else
44
  define('MAX_EXECUTION_TIME', 2 );
45
  define("SP_MAX_RESULTS_QUERY", 6);
46
 
47
- class WPShortPixel {
48
-
49
- const BULK_EMPTY_QUEUE = 0;
50
-
51
- private $_affiliateSufix;
52
-
53
- private $_apiInterface = null;
54
- private $_settings = null;
55
- private $prioQ = null;
56
- private $view = null;
57
-
58
- private $hasNextGen = false;
59
- private $spMetaDao = null;
60
-
61
- public static $PROCESSABLE_EXTENSIONS = array('jpg', 'jpeg', 'gif', 'png', 'pdf');
62
-
63
- public function __construct() {
64
- if (!session_id()) {
65
- session_start();
66
- }
67
-
68
- require_once('wp-shortpixel-req.php');
69
- load_plugin_textdomain('shortpixel-image-optimiser', false, plugin_basename(dirname( __FILE__ )).'/lang');
70
-
71
- $isAdminUser = current_user_can( 'manage_options' );
72
-
73
- $this->_affiliateSufix = (strlen(SP_AFFILIATE_CODE)) ? "/affiliate/" . SP_AFFILIATE_CODE : "";
74
- $this->_settings = new WPShortPixelSettings();
75
- $this->_apiInterface = new ShortPixelAPI($this->_settings);
76
- $this->hasNextGen = ShortPixelNextGenAdapter::hasNextGen();
77
- $this->spMetaDao = new ShortPixelCustomMetaDao(new WpShortPixelDb(), $this->_settings->hasCustomFolders);
78
- $this->prioQ = new ShortPixelQueue($this, $this->_settings);
79
- $this->view = new ShortPixelView($this);
80
-
81
- if(!$this->_settings->optimizePdfs) {
82
- self::$PROCESSABLE_EXTENSIONS = array_diff(self::$PROCESSABLE_EXTENSIONS, array('pdf'));
83
- }
84
-
85
- define('QUOTA_EXCEEDED', $this->view->getQuotaExceededHTML());
86
-
87
- $this->setDefaultViewModeList();//set default mode as list. only @ first run
88
-
89
- //add hook for image upload processing
90
- //add_filter( 'wp_generate_attachment_metadata', array( &$this, 'handleMediaLibraryImageUpload' ), 10, 2 ); // now external
91
- add_filter( 'plugin_action_links_' . plugin_basename(__FILE__), array(&$this, 'generatePluginLinks'));//for plugin settings page
92
-
93
- //add_action( 'admin_footer', array(&$this, 'handleImageProcessing'));
94
-
95
- //Media custom column
96
- add_filter( 'manage_media_columns', array( &$this, 'columns' ) );//add media library column header
97
- add_action( 'manage_media_custom_column', array( &$this, 'generateCustomColumn' ), 10, 2 );//generate the media library column
98
- //Edit media meta box
99
- add_action( 'add_meta_boxes', array( &$this, 'shortpixelInfoBox') );
100
- //for cleaning up the WebP images when an attachment is deleted
101
- add_action( 'delete_attachment', array( &$this, 'onDeleteImage') );
102
-
103
- //for NextGen
104
- if($this->_settings->hasCustomFolders) {
105
- add_filter( 'ngg_manage_images_columns', array( &$this, 'nggColumns' ) );
106
- add_filter( 'ngg_manage_images_number_of_columns', array( &$this, 'nggCountColumns' ) );
107
- add_filter( 'ngg_manage_images_column_7_header', array( &$this, 'nggColumnHeader' ) );
108
- add_filter( 'ngg_manage_images_column_7_content', array( &$this, 'nggColumnContent' ) );
109
- // hook on the NextGen gallery list update
110
- add_action('ngg_update_addgallery_page', array( &$this, 'addNextGenGalleriesToCustom'));
111
- }
112
-
113
- // integration with WP/LR Sync plugin
114
- add_action( 'wplr_update_media', array( &$this, 'onWpLrUpdateMedia' ), 10, 2);
115
-
116
- //custom hook
117
- add_action( 'shortpixel-optimize-now', array( &$this, 'optimizeNowHook' ), 10, 1);
118
-
119
- if($isAdminUser) {
120
- //add settings page
121
- add_action( 'admin_menu', array( &$this, 'registerSettingsPage' ) );//display SP in Settings menu
122
- add_action( 'admin_menu', array( &$this, 'registerAdminPage' ) );
123
-
124
- add_action('wp_ajax_shortpixel_browse_content', array(&$this, 'browseContent'));
125
- add_action('wp_ajax_shortpixel_get_backup_size', array(&$this, 'getBackupSize'));
126
-
127
- add_action( 'delete_attachment', array( &$this, 'handleDeleteAttachmentInBackup' ) );
128
- add_action( 'load-upload.php', array( &$this, 'handleCustomBulk'));
129
-
130
- //backup restore
131
- add_action('admin_action_shortpixel_restore_backup', array(&$this, 'handleRestoreBackup'));
132
- //reoptimize with a different algorithm (losless/lossy)
133
- add_action('wp_ajax_shortpixel_redo', array(&$this, 'handleRedo'));
134
- //optimize thumbnails
135
- add_action('wp_ajax_shortpixel_optimize_thumbs', array(&$this, 'handleOptimizeThumbs'));
136
-
137
- //toolbar notifications
138
- add_action( 'admin_bar_menu', array( &$this, 'toolbar_shortpixel_processing'), 999 );
139
- //deactivate plugin
140
- add_action( 'admin_post_shortpixel_deactivate_plugin', array(&$this, 'deactivatePlugin'));
141
- }
142
-
143
- //automatic optimization
144
- add_action( 'wp_ajax_shortpixel_image_processing', array( &$this, 'handleImageProcessing') );
145
- //manual optimization
146
- add_action( 'wp_ajax_shortpixel_manual_optimization', array(&$this, 'handleManualOptimization'));
147
- //dismiss notices
148
- add_action( 'wp_ajax_shortpixel_dismiss_notice', array(&$this, 'dismissAdminNotice'));
149
- add_action( 'wp_ajax_shortpixel_dismiss_media_alert', array(&$this, 'dismissMediaAlert'));
150
- //check quota
151
- add_action('admin_action_shortpixel_check_quota', array(&$this, 'handleCheckQuota'));
152
- //This adds the constants used in PHP to be available also in JS
153
- add_action( 'admin_footer', array( &$this, 'shortPixelJS') );
154
-
155
- if($this->_settings->frontBootstrap) {
156
- //also need to have it in the front footer then
157
- add_action( 'wp_footer', array( &$this, 'shortPixelJS') );
158
- //need to add the nopriv action for when items exist in the queue and no user is logged in
159
- add_action( 'wp_ajax_nopriv_shortpixel_image_processing', array( &$this, 'handleImageProcessing') );
160
- }
161
- //register a method to display admin notices if necessary
162
- add_action('admin_notices', array( &$this, 'displayAdminNotices'));
163
-
164
- $this->migrateBackupFolder();
165
-
166
- if(!$this->_settings->redirectedSettings && !$this->_settings->verifiedKey && (!function_exists("is_multisite") || !is_multisite())) {
167
- $this->_settings->redirectedSettings = 1;
168
- wp_redirect(admin_url("options-general.php?page=wp-shortpixel"));
169
- exit();
170
- }
171
- }
172
-
173
- //handling older
174
- public function WPShortPixel() {
175
- $this->__construct();
176
- }
177
-
178
- public function registerSettingsPage() {
179
- add_options_page( __('ShortPixel Settings','shortpixel-image-optimiser'), 'ShortPixel', 'manage_options', 'wp-shortpixel', array($this, 'renderSettingsMenu'));
180
- }
181
-
182
- function registerAdminPage( ) {
183
- if($this->spMetaDao->hasFoldersTable() && count($this->spMetaDao->getFolders())) {
184
- /*translators: title and menu name for the Other media page*/
185
- add_media_page( __('Other Media Optimized by ShortPixel','shortpixel-image-optimiser'), __('Other Media','shortpixel-image-optimiser'), 'edit_others_posts', 'wp-short-pixel-custom', array( &$this, 'listCustomMedia' ) );
186
- }
187
- /*translators: title and menu name for the Bulk Processing page*/
188
- add_media_page( __('ShortPixel Bulk Process','shortpixel-image-optimiser'), __('Bulk ShortPixel','shortpixel-image-optimiser'), 'edit_others_posts', 'wp-short-pixel-bulk', array( &$this, 'bulkProcess' ) );
189
- }
190
-
191
- public static function shortPixelActivatePlugin()//reset some params to avoid trouble for plugins that were activated/deactivated/activated
192
- {
193
- self::shortPixelDeactivatePlugin();
194
- if(SP_RESET_ON_ACTIVATE === true && WP_DEBUG === true) { //force reset plugin counters, only on specific occasions and on test environments
195
- WPShortPixelSettings::debugResetOptions();
196
-
197
- $settings = new WPShortPixelSettings();
198
- $spMetaDao = new ShortPixelCustomMetaDao(new WpShortPixelDb(), $settings->hasCustomFolders);
199
- $spMetaDao->dropTables();
200
- }
201
- WPShortPixelSettings::onActivate();
202
- }
203
-
204
- public static function shortPixelDeactivatePlugin()//reset some params to avoid trouble for plugins that were activated/deactivated/activated
205
- {
206
- include_once dirname( __FILE__ ) . '/wp-shortpixel-req.php';
207
- ShortPixelQueue::resetBulk();
208
- ShortPixelQueue::resetPrio();
209
- WPShortPixelSettings::onDeactivate();
210
- }
211
-
212
- public static function getConflictingPlugins() {
213
- $conflictPlugins = array(
214
- 'WP Smush - Image Optimization' => 'wp-smushit/wp-smush.php',
215
- 'Imagify Image Optimizer' => 'imagify/imagify.php',
216
- 'Compress JPEG & PNG images (TinyPNG)' => 'tiny-compress-images/tiny-compress-images.php',
217
- 'Kraken.io Image Optimizer' => 'kraken-image-optimizer/kraken.php',
218
- 'Optimus - WordPress Image Optimizer' => 'optimus/optimus.php',
219
- 'EWWW Image Optimizer' => 'ewww-image-optimizer/ewww-image-optimizer.php',
220
- 'ImageRecycle pdf & image compression' => 'imagerecycle-pdf-image-compression/wp-image-recycle.php',
221
- 'CheetahO Image Optimizer' => 'cheetaho-image-optimizer/cheetaho.php',
222
- 'Zara 4 Image Compression' => 'zara-4/zara-4.php',
223
- 'Prizm Image' => 'prizm-image/wp-prizmimage.php',
224
- 'CW Image Optimizer' => 'cw-image-optimizer/cw-image-optimizer.php'
225
- );
226
- $found = array();
227
- foreach($conflictPlugins as $name => $path) {
228
- if(is_plugin_active($path)) {
229
- $found[] = array('name' => $name, 'path' => $path);
230
- }
231
- }
232
- return $found;
233
- }
234
-
235
- public function displayAdminNotices() {
236
- $dismissed = $this->_settings->dismissedNotices ? $this->_settings->dismissedNotices : array();
237
- if(!$this->_settings->verifiedKey) {
238
- $now = time();
239
- $act = $this->_settings->activationDate ? $this->_settings->activationDate : $now;
240
- if($this->_settings->activationNotice && $this->_settings->redirectedSettings >= 2) {
241
- ShortPixelView::displayActivationNotice();
242
- $this->_settings->activationNotice = null;
243
- }
244
- if( ($now > $act + 7200) && !isset($dismissed['2h'])) {
245
- ShortPixelView::displayActivationNotice('2h');
246
- } else if( ($now > $act + 72 * 3600) && !isset($dismissed['3d'])) {
247
- ShortPixelView::displayActivationNotice('3d');
248
- }
249
- }
250
- if(!isset($dismissed['compat'])) {
251
- $conflictPlugins = self::getConflictingPlugins();
252
- if(count($conflictPlugins)) {
253
- ShortPixelView::displayActivationNotice('compat', $conflictPlugins);
254
- }
255
- }
256
- }
257
-
258
- public function dismissAdminNotice() {
259
- $noticeId = preg_replace('|[^a-z0-9]|i', '', $_GET['notice_id']);
260
- $dismissed = $this->_settings->dismissedNotices ? $this->_settings->dismissedNotices : array();
261
- $dismissed[$noticeId] = true;
262
- $this->_settings->dismissedNotices = $dismissed;
263
- die(json_encode(array("Status" => 'success', "Message" => 'Notice ID: ' . $noticeId . ' dismissed')));
264
- }
265
-
266
- public function dismissMediaAlert() {
267
- $this->_settings->mediaAlert = 1;
268
- die(json_encode(array("Status" => 'success', "Message" => __('Media alert dismissed','shortpixel-image-optimiser'))));
269
- }
270
-
271
- //set default move as "list". only set once, it won't try to set the default mode again.
272
- public function setDefaultViewModeList()
273
- {
274
- if($this->_settings->mediaLibraryViewMode === false)
275
- {
276
- $this->_settings->mediaLibraryViewMode = 1;
277
- $currentUserID = false;
278
- if ( function_exists('wp_get_current_user') ) {
279
- $current_user = wp_get_current_user();
280
- $currentUserID = $current_user->ID;
281
- update_user_meta($currentUserID, "wp_media_library_mode", "list");
282
- }
283
- }
284
-
285
- }
286
-
287
- static function log($message) {
288
- if (SHORTPIXEL_DEBUG === true) {
289
- if (is_array($message) || is_object($message)) {
290
- error_log(print_r($message, true));
291
- } else {
292
- error_log($message);
293
- }
294
- }
295
- }
296
-
297
- function shortPixelJS() { ?>
298
- <script type="text/javascript" >
299
- var ShortPixelConstants = {
300
- STATUS_SUCCESS: <?php echo ShortPixelAPI::STATUS_SUCCESS; ?>,
301
- STATUS_EMPTY_QUEUE: <?php echo self::BULK_EMPTY_QUEUE; ?>,
302
- STATUS_ERROR: <?php echo ShortPixelAPI::STATUS_ERROR; ?>,
303
- STATUS_FAIL: <?php echo ShortPixelAPI::STATUS_FAIL; ?>,
304
- STATUS_QUOTA_EXCEEDED: <?php echo ShortPixelAPI::STATUS_QUOTA_EXCEEDED; ?>,
305
- STATUS_SKIP: <?php echo ShortPixelAPI::STATUS_SKIP; ?>,
306
- STATUS_NO_KEY: <?php echo ShortPixelAPI::STATUS_NO_KEY; ?>,
307
- STATUS_RETRY: <?php echo ShortPixelAPI::STATUS_RETRY; ?>,
308
- STATUS_QUEUE_FULL: <?php echo ShortPixelAPI::STATUS_QUEUE_FULL; ?>,
309
- STATUS_MAINTENANCE: <?php echo ShortPixelAPI::STATUS_MAINTENANCE; ?>,
310
- WP_PLUGIN_URL: '<?php echo plugins_url( '', __FILE__ ); ?>',
311
- WP_ADMIN_URL: '<?php echo admin_url(); ?>',
312
- API_KEY: "<?php echo $this->_settings->apiKey; ?>",
313
- MEDIA_ALERT: '<?php echo $this->_settings->mediaAlert ? "done" : "todo"; ?>',
314
- FRONT_BOOTSTRAP: <?php echo $this->_settings->frontBootstrap && (!isset($this->_settings->lastBackAction) || (time() - $this->_settings->lastBackAction > 600)) ? 1 : 0; ?>,
315
- AJAX_URL: '<?php echo admin_url('admin-ajax.php'); ?>'
316
- };
317
- </script> <?php
318
- wp_enqueue_style('short-pixel.css', plugins_url('/res/css/short-pixel.css',__FILE__) );
319
-
320
- wp_register_script('short-pixel.js', plugins_url('/res/js/short-pixel.js',__FILE__) );
321
- $jsTranslation = array(
322
- 'optimizeWithSP' => __( 'Optimize with ShortPixel', 'shortpixel-image-optimiser' ),
323
- 'changeMLToListMode' => __( 'In order to access the ShortPixel Optimization actions and info, please change to {0}List View{1}List View{2}Dismiss{3}', 'shortpixel-image-optimiser' ),
324
- 'alertOnlyAppliesToNewImages' => __( 'This type of optimization will apply to new uploaded images. Images that were already processed will not be re-optimized unless you restart the bulk process.', 'shortpixel-image-optimiser' ),
325
- 'areYouSureStopOptimizing' => __( 'Are you sure you want to stop optimizing the folder {0}?', 'shortpixel-image-optimiser' ),
326
- 'reducedBy' => __( 'Reduced by', 'shortpixel-image-optimiser' ),
327
- 'bonusProcessing' => __( 'Bonus processing', 'shortpixel-image-optimiser' ),
328
- 'plusXthumbsOpt' => __( '+{0} thumbnails optimized', 'shortpixel-image-optimiser' ),
329
- 'plusXretinasOpt' => __( '+{0} Retina images optimized', 'shortpixel-image-optimiser' ),
330
- 'optXThumbs' => __( 'Optimize {0} thumbnails', 'shortpixel-image-optimiser' ),
331
- 'reOptimizeAs' => __( 'Reoptimize {0}', 'shortpixel-image-optimiser' ),
332
- 'restoreBackup' => __( 'Restore backup', 'shortpixel-image-optimiser' ),
333
- 'getApiKey' => __( 'Get API Key', 'shortpixel-image-optimiser' ),
334
- 'extendQuota' => __( 'Extend Quota', 'shortpixel-image-optimiser' ),
335
- 'check__Quota' => __( 'Check&nbsp;&nbsp;Quota', 'shortpixel-image-optimiser' ),
336
- 'retry' => __( 'Retry', 'shortpixel-image-optimiser' ),
337
- 'thisContentNotProcessable' => __( 'This content is not processable.', 'shortpixel-image-optimiser' ),
338
- 'imageWaitOptThumbs' => __( 'Image waiting to optimize thumbnails', 'shortpixel-image-optimiser' ),
339
- 'pleaseDoNotSetLesserSize' => __( "Please do not set a {0} less than the {1} of the largest thumbnail which is {2}, to be able to still regenerate all your thumbnails in case you'll ever need this.", 'shortpixel-image-optimiser' ),
340
- 'pleaseDoNotSetLesser1024' => __( "Please do not set a {0} less than 1024, to be able to still regenerate all your thumbnails in case you'll ever need this.", 'shortpixel-image-optimiser' )
341
- );
342
- wp_localize_script( 'short-pixel.js', '_spTr', $jsTranslation );
343
- wp_enqueue_script('short-pixel.js');
344
-
345
- wp_enqueue_script('jquery.knob.js', plugins_url('/res/js/jquery.knob.js',__FILE__) );
346
- wp_enqueue_script('jquery.tooltip.js', plugins_url('/res/js/jquery.tooltip.js',__FILE__) );
347
- wp_enqueue_script('punycode.js', plugins_url('/res/js/punycode.js',__FILE__) );
348
- }
349
-
350
- function toolbar_shortpixel_processing( $wp_admin_bar ) {
351
-
352
- $extraClasses = " shortpixel-hide";
353
- /*translators: toolbar icon tooltip*/
354
- $id = 'short-pixel-notice-toolbar';
355
- $tooltip = __('ShortPixel optimizing...','shortpixel-image-optimiser');
356
- $icon = "shortpixel.png";
357
- $successLink = $link = current_user_can( 'edit_others_posts')? 'upload.php?page=wp-short-pixel-bulk' : 'upload.php';
358
- $blank = "";
359
- if($this->prioQ->processing()) {
360
- $extraClasses = " shortpixel-processing";
361
- }
362
- if($this->_settings->quotaExceeded && !isset($this->_settings->dismissedNotices['exceed'])) {
363
- $extraClasses = " shortpixel-alert shortpixel-quota-exceeded";
364
- /*translators: toolbar icon tooltip*/
365
- $id = 'short-pixel-notice-exceed';
366
- $tooltip = '';
367
- $exceedTooltip = __('ShortPixel quota exceeded. Click for details.','shortpixel-image-optimiser');
368
- //$link = "http://shortpixel.com/login/" . $this->_settings->apiKey;
369
- $link = "options-general.php?page=wp-shortpixel";
370
- //$blank = '_blank';
371
- //$icon = "shortpixel-alert.png";
372
- }
373
- $lastStatus = $this->_settings->bulkLastStatus;
374
- if($lastStatus && $lastStatus['Status'] != ShortPixelAPI::STATUS_SUCCESS) {
375
- $extraClasses = " shortpixel-alert shortpixel-processing";
376
- $tooltip = $lastStatus['Message'];
377
- }
378
-
379
- $args = array(
380
- 'id' => 'shortpixel_processing',
381
- 'title' => '<div id="' . $id . '" title="' . $tooltip . '" ><img src="'
382
- . plugins_url( 'res/img/'.$icon, __FILE__ ) . '" success-url="' . $successLink . '"><span class="shp-alert">!</span></div>',
383
- 'href' => $link,
384
- 'meta' => array('target'=> $blank, 'class' => 'shortpixel-toolbar-processing' . $extraClasses)
385
- );
386
- $wp_admin_bar->add_node( $args );
387
- if($this->_settings->quotaExceeded && !isset($this->_settings->dismissedNotices['exceed'])) {
388
- $wp_admin_bar->add_node( array(
389
- 'id' => 'shortpixel_processing-title',
390
- 'parent' => 'shortpixel_processing',
391
- 'title' => $exceedTooltip,
392
- 'href' => $link
393
- ));
394
- $wp_admin_bar->add_node( array(
395
- 'id' => 'shortpixel_processing-dismiss',
396
- 'parent' => 'shortpixel_processing',
397
- 'title' => '<div style="text-align: right;">Dismiss</div>',
398
- 'href' => "#",
399
- 'meta' => array('onclick'=> 'dismissShortPixelNoticeExceed(event)')
400
- ));
401
- }
402
- }
403
-
404
- public function handleCustomBulk() {
405
- // 1. get the action
406
- $wp_list_table = _get_list_table('WP_Media_List_Table');
407
- $action = $wp_list_table->current_action();
408
-
409
- switch($action) {
410
- // 2. Perform the action
411
- case 'short-pixel-bulk':
412
- // security check
413
- check_admin_referer('bulk-media');
414
- if(!is_array($_GET['media'])) {
415
- break;
416
- }
417
- $mediaIds = array_reverse($_GET['media']);
418
- foreach( $mediaIds as $ID ) {
419
- $meta = wp_get_attachment_metadata($ID);
420
- if( ( !isset($meta['ShortPixel']) //never touched by ShortPixel
421
- || (isset($meta['ShortPixel']['WaitingProcessing']) && $meta['ShortPixel']['WaitingProcessing'] == true))
422
- && (!isset($meta['ShortPixelImprovement']) || $meta['ShortPixelImprovement'] == __('Optimization N/A','shortpixel-image-optimiser'))) {
423
- $this->prioQ->push($ID);
424
- $meta['ShortPixel']['WaitingProcessing'] = true;
425
- wp_update_attachment_metadata($ID, $meta);
426
- }
427
- }
428
- break;
429
- }
430
- }
431
-
432
- /**
433
- * this is hooked onto the MediaLibrary image upload
434
- * @param array $meta - the wordpress postmeta structure
435
- * @param type $ID - the Media Library ID
436
- * @return the meta structure updated with ShortPixel info if case
437
- */
438
- public function handleMediaLibraryImageUpload($meta, $ID = null)
439
- {
440
- if( !$this->_settings->verifiedKey) {// no API Key set/verified -> do nothing here, just return
441
- return $meta;
442
- }
443
- //else
444
- //self::log("IMG: Auto-analyzing file ID #{$ID}");
445
-
446
- if( self::isProcessable($ID) == false )
447
- {//not a file that we can process
448
- $meta['ShortPixelImprovement'] = __('Optimization N/A','shortpixel-image-optimiser');
449
- return $meta;
450
- }
451
- else
452
- {//the kind of file we can process. goody.
453
- $this->prioQ->push($ID);
454
- //that's a hack for watermarking plugins, don't send the image right away to processing, only add it in the queue
455
- include_once( ABSPATH . 'wp-admin/includes/plugin.php' );
456
- if( !is_plugin_active('image-watermark/image-watermark.php')
457
- && !is_plugin_active('easy-watermark/index.php')) {
458
- $itemHandler = new ShortPixelMetaFacade($ID);
459
- $itemHandler->setRawMeta($meta);
460
- try {
461
- $URLsAndPATHs = $this->getURLsAndPATHs($itemHandler);
462
- } catch(Exception $e) {
463
- $meta['ShortPixelImprovement'] = $e->getMessage();
464
- return $meta;
465
- }
466
- //send a processing request right after a file was uploaded, do NOT wait for response
467
- $this->_apiInterface->doRequests($URLsAndPATHs['URLs'], false, $ID);
468
- //self::log("IMG: sent: " . json_encode($URLsAndPATHs));
469
- }
470
- $meta['ShortPixel']['WaitingProcessing'] = true;
471
- return $meta;
472
- }
473
- }//end handleMediaLibraryImageUpload
474
-
475
- /**
476
- * this is hooked onto the NextGen upload
477
- * @param type $image
478
- */
479
- public function handleNextGenImageUpload($image) {
480
- if($this->_settings->includeNextGen == 1) {
481
- $imageFsPath = ShortPixelNextGenAdapter::getImageAbspath($image);
482
-
483
- $customFolders = $this->spMetaDao->getFolders();
484
-
485
- $folderId = -1;
486
- foreach($customFolders as $folder) {
487
- if(strpos($imageFsPath, $folder->getPath()) === 0) {
488
- $folderId = $folder->getId();
489
- break;
490
- }
491
- }
492
- if($folderId == -1) { //if not found, create
493
- $galleryPath = dirname($imageFsPath);
494
- $folder = new ShortPixelFolder(array("path" => $galleryPath));
495
- $folderMsg = $this->spMetaDao->saveFolder($folder);
496
- $folderId = $folder->getId();
497
- //self::log("NG Image Upload: created folder from path $galleryPath : Folder info: " . json_encode($folder));
498
- }
499
- $pathParts = explode('/', trim($imageFsPath));
500
- //Add the main image
501
- $meta = new ShortPixelMeta();
502
- $meta->setPath($imageFsPath);
503
- $meta->setName($pathParts[count($pathParts) - 1]);
504
- $meta->setFolderId($folderId);
505
- $meta->setExtMetaId($image->pid); // do this only for main image, not for thumbnais.
506
- $meta->setCompressionType($this->_settings->compressionType);
507
- $meta->setKeepExif($this->_settings->keepExif);
508
- $meta->setCmyk2rgb($this->_settings->CMYKtoRGBconversion);
509
- $meta->setResize($this->_settings->resizeImages);
510
- $meta->setResizeWidth($this->_settings->resizeWidth);
511
- $meta->setResizeHeight($this->_settings->resizeHeight);
512
- $ID = $this->spMetaDao->addImage($meta);
513
- $meta->setId($ID);
514
- $this->prioQ->push('C-' . $ID);
515
- //add the thumb image if exists
516
- $pathParts[] = "thumbs_" . $pathParts[count($pathParts) - 1];
517
- $pathParts[count($pathParts) - 2] = "thumbs";
518
- $thumbPath = implode('/', $pathParts);
519
- if(file_exists($thumbPath)) {
520
- $metaThumb = new ShortPixelMeta();
521
- $metaThumb->setPath($thumbPath);
522
- $metaThumb->setName($pathParts[count($pathParts) - 1]);
523
- $metaThumb->setFolderId($folderId);
524
- $metaThumb->setCompressionType($this->_settings->compressionType);
525
- $metaThumb->setKeepExif($this->_settings->keepExif);
526
- $metaThumb->setCmyk2rgb($this->_settings->CMYKtoRGBconversion);
527
- $metaThumb->setResize($this->_settings->resizeImages);
528
- $metaThumb->setResizeWidth($this->_settings->resizeWidth);
529
- $metaThumb->setResizeHeight($this->_settings->resizeHeight);
530
- $ID = $this->spMetaDao->addImage($metaThumb);
531
- $metaThumb->setId($ID);
532
- $this->prioQ->push('C-' . $ID);
533
- }
534
- return $meta;
535
- }
536
- }
537
-
538
- public function optimizeCustomImage($id) {
539
- $meta = $this->spMetaDao->getMeta($id);
540
- if($meta->getStatus() != 2) {
541
- $meta->setStatus(1);
542
- $meta->setRetries(0);
543
- $this->spMetaDao->update($meta);
544
- $this->prioQ->push('C-' . $id);
545
- }
546
- }
547
-
548
- //TODO muta in bulkProvider
549
- public function getBulkItemsFromDb(){
550
- global $wpdb;
551
-
552
- $startQueryID = $this->prioQ->getStartBulkId();
553
- $endQueryID = $this->prioQ->getStopBulkId();
554
- $skippedAlreadyProcessed = 0;
555
-
556
- if ( $startQueryID <= $endQueryID ) {
557
- return false;
558
- }
559
- $idList = array();
560
- $itemList = array();
561
- for ($sanityCheck = 0, $crtStartQueryID = $startQueryID;
562
- ($crtStartQueryID >= $endQueryID) && (count($itemList) < 3) && ($sanityCheck < 150); $sanityCheck++) {
563
-
564
- self::log("GETDB: current StartID: " . $crtStartQueryID);
565
-
566
- $queryPostMeta = "SELECT * FROM " . $wpdb->prefix . "postmeta
567
- WHERE ( post_id <= $crtStartQueryID AND post_id >= $endQueryID )
568
- AND ( meta_key = '_wp_attached_file' OR meta_key = '_wp_attachment_metadata' )
569
- ORDER BY post_id DESC
570
- LIMIT " . SP_MAX_RESULTS_QUERY;
571
- $resultsPostMeta = $wpdb->get_results($queryPostMeta);
572
-
573
- if ( empty($resultsPostMeta) ) {
574
- $crtStartQueryID -= SP_MAX_RESULTS_QUERY;
575
- $startQueryID = $crtStartQueryID;
576
- $this->prioQ->setStartBulkId($startQueryID);
577
- continue;
578
- }
579
-
580
- foreach ( $resultsPostMeta as $itemMetaData ) {
581
- $crtStartQueryID = $itemMetaData->post_id;
582
- if(!in_array($crtStartQueryID, $idList) && self::isProcessable($crtStartQueryID)) {
583
- $item = new ShortPixelMetaFacade($crtStartQueryID);
584
- $meta = $item->getMeta();//wp_get_attachment_metadata($crtStartQueryID);
585
-
586
- if($meta->getStatus() != 2) {
587
- $itemList[] = $item;
588
- $idList[] = $crtStartQueryID;
589
- }
590
- elseif($meta->getCompressionType() !== null && $meta->getCompressionType() != $this->_settings->compressionType) {//a different type of compression was chosen in settings
591
- if($this->doRestore($crtStartQueryID)) {
592
- $itemList[] = $item = new ShortPixelMetaFacade($crtStartQueryID); //force reload after restore
593
- $idList[] = $crtStartQueryID;
594
- } else {
595
- $skippedAlreadyProcessed++;
596
- }
597
- }
598
- elseif( $this->_settings->processThumbnails && $meta->getThumbsOpt() !== null
599
- && $meta->getThumbsOpt() == 0 && count($meta->getThumbs()) > 0) { //thumbs were chosen in settings
600
- //if($crtStartQueryID == 44 || $crtStartQueryID == 49) {echo("No THuMBS?");die(var_dump($meta));}
601
- $meta->setThumbsTodo(true);
602
- $item->updateMeta($meta);//wp_update_attachment_metadata($crtStartQueryID, $meta);
603
- $itemList[] = $item;
604
- $idList[] = $crtStartQueryID;
605
- }
606
- elseif($itemMetaData->meta_key == '_wp_attachment_metadata') { //count skipped
607
- $skippedAlreadyProcessed++;
608
- }
609
- }
610
- }
611
- if(!count($idList) && $crtStartQueryID <= $startQueryID) {
612
- //daca n-am adaugat niciuna pana acum, n-are sens sa mai selectez zona asta de id-uri in bulk-ul asta.
613
- $leapStart = $this->prioQ->getStartBulkId();
614
- $crtStartQueryID = $startQueryID = $itemMetaData->post_id - 1; //decrement it so we don't select it again
615
- $res = WpShortPixelMediaLbraryAdapter::countAllProcessableFiles($this->_settings->optimizePdfs, $leapStart, $crtStartQueryID);
616
- $skippedAlreadyProcessed += $res["mainProcessedFiles"] - $res["mainProc".($this->getCompressionType() == 1 ? "Lossy" : "Lossless")."Files"];
617
- $this->prioQ->setStartBulkId($startQueryID);
618
- } else {
619
- $crtStartQueryID--;
620
- }
621
- }
622
- return array("items" => $itemList, "skipped" => $skippedAlreadyProcessed, "searching" => ($sanityCheck >= 150));
623
- }
624
-
625
- /**
626
- * Get last added items from priority
627
- * @return type
628
- */
629
- //TODO muta in bulkProvider - prio
630
- public function getFromPrioAndCheck() {
631
- $items = array();
632
- foreach ($this->prioQ->getFromPrioAndCheck() as $id) {
633
- $items[] = new ShortPixelMetaFacade($id);
634
- }
635
- return $items;
636
- }
637
-
638
- public function handleImageProcessing($ID = null) {
639
- //if(rand(1,2) == 2) {
640
- // header($_SERVER['SERVER_PROTOCOL'] . ' 500 Internal Server Error', true, 500);
641
- // die("za stop");
642
- //}
643
- //0: check key
644
- if( $this->_settings->verifiedKey == false) {
645
- if($ID == null){
646
- $ids = $this->getFromPrioAndCheck();
647
- $itemHandler = (count($ids) > 0 ? $ids[0] : null);
648
- }
649
- $response = array("Status" => ShortPixelAPI::STATUS_NO_KEY, "ImageID" => $itemHandler ? $itemHandler->getId() : "-1", "Message" => __('Missing API Key','shortpixel-image-optimiser'));
650
- $this->_settings->bulkLastStatus = $response;
651
- die(json_encode($response));
652
- }
653
-
654
- if($this->_settings->frontBootstrap && is_admin() && !ShortPixelTools::requestIsFrontendAjax()) {
655
- //if in backend, and front-end is activated, mark processing from backend to shut off the front-end for 10 min.
656
- $this->_settings->lastBackAction = time();
657
- }
658
-
659
- self::log("HIP: 0 Priority Queue: ".json_encode($this->prioQ->get()));
660
- //self::log("HIP: 0 Bulk running? " . $this->prioQ->bulkRunning() . " START " . $this->_settings->startBulkId . " STOP " . $this->_settings->stopBulkId);
661
-
662
- //1: get 3 ids to process. Take them with priority from the queue
663
- $ids = $this->getFromPrioAndCheck();
664
- if(count($ids) < 3 ) { //take from bulk if bulk processing active
665
- if($this->prioQ->bulkRunning()) {
666
- $res = $this->getBulkItemsFromDb();
667
- $bulkItems = $res['items'];
668
- //merge them into the $ids array based on the ID (the same ID could be in prio also)
669
- if($bulkItems){
670
- foreach($bulkItems as $bi) {
671
- $add = true;
672
- foreach($ids as $pi) {
673
- if($pi->getType() == ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE && $bi->getId() == $pi->getId()) {
674
- $add = false;
675
- }
676
- }
677
- $ids[] = $bi;
678
- }
679
- }
680
- }
681
- }
682
-
683
- self::log("HIP: 0 Bulk ran: " . $this->prioQ->bulkRan());
684
- $customIds = false;
685
- if(count($ids) < 3 && $this->prioQ->bulkRan() && $this->_settings->hasCustomFolders
686
- && (!$this->_settings->cancelPointer || $this->_settings->skipToCustom)
687
- && !$this->_settings->customBulkPaused)
688
- { //take from custom images if any left to optimize - only if bulk was ever started
689
- $customIds = $this->spMetaDao->getPendingMetas( 3 - count($ids));
690
- if(is_array($customIds)) {
691
- $ids = array_merge($ids, array_map(array('ShortPixelMetaFacade', 'getNewFromRow'), $customIds));
692
- }
693
- }
694
- //var_dump($ids);
695
- //die("za stop 2");
696
-
697
- self::log("HIP: 1 Prio Queue: ".json_encode($this->prioQ->get()));
698
- self::log("HIP: 1 Selected IDs count: ".count($ids));
699
-
700
- //2: Send up to 3 files to the server for processing
701
- for($i = 0, $first = true; $ids !== false && $i < min(3, count($ids)); $i++) {
702
- $itemHandler = $ids[$i];
703
- $tmpMeta = $itemHandler->getMeta();
704
- $compType = ($tmpMeta->getCompressionType() !== null ? $tmpMeta->getCompressionType() : $this->_settings->compressionType);
705
- try {
706
- self::log("HIP: 1 sendToProcessing: ".$itemHandler->getId());
707
- $URLsAndPATHs = $this->sendToProcessing($itemHandler, $compType, $tmpMeta->getThumbsTodo());
708
- //make sure it gets processed even if the user stops the bulk or the bulk skips somehow
709
- $this->prioQ->enqueue($itemHandler->getId()); //this adds it to the end of the queue instead as first as push does
710
- if(!count($URLsAndPATHs['PATHs'])) {
711
- throw new Exception(__('Image files are missing.','shortpixel-image-optimiser'));
712
- }
713
- } catch(Exception $e) { // Exception("Post metadata is corrupt (No attachment URL)")
714
- $meta = $itemHandler->setError(ShortPixelAPI::ERR_FILE_NOT_FOUND, $e->getMessage());
715
- unset($ids[$i]);
716
- }
717
- if($first) { //save for later use
718
- $firstUrlAndPaths = $URLsAndPATHs;
719
- $first = false;
720
- }
721
- }
722
-
723
- if ($ids === false || count( $ids ) == 0 ){
724
- //if searching, than the script is searching for not processed items and found none yet, should be relaunced
725
- if(isset($res['searching']) && $res['searching']) {
726
- die(json_encode(array("Status" => ShortPixelAPI::STATUS_RETRY,
727
- "Message" => __('Searching images to optimize... ','shortpixel-image-optimiser') . $this->prioQ->getStartBulkId() . '->' . $this->prioQ->getStopBulkId() )));
728
- }
729
- //in this case the queue is really empty
730
- self::log("HIP: 1 STOP BULK");
731
- $bulkEverRan = $this->prioQ->stopBulk();
732
- $avg = $this->getAverageCompression();
733
- $fileCount = $this->_settings->fileCount;
734
- $response = array("Status" => self::BULK_EMPTY_QUEUE,
735
- /* translators: console message Empty queue 1234 -> 1234 */
736
- "Message" => __('Empty queue ','shortpixel-image-optimiser') . $this->prioQ->getStartBulkId() . '->' . $this->prioQ->getStopBulkId(),
737
- "BulkStatus" => ($this->prioQ->bulkRunning()
738
- ? "1" : ($this->prioQ->bulkPaused() ? "2" : "0")),
739
- "AverageCompression" => $avg,
740
- "FileCount" => $fileCount,
741
- "BulkPercent" => $this->prioQ->getBulkPercent());
742
- die(json_encode($response));
743
- }
744
-
745
- self::log("HIP: 2 Prio Queue: ".json_encode($this->prioQ->get()));
746
- //3: Retrieve the file for the first element of the list
747
- $itemHandler = $ids[0];
748
- $itemId = $itemHandler->getQueuedId();
749
- $result = $this->_apiInterface->processImage($firstUrlAndPaths['URLs'], $firstUrlAndPaths['PATHs'], $itemHandler);
750
-
751
- $result["ImageID"] = $itemId;
752
- $meta = $itemHandler->getMeta();
753
- $result["Filename"] = basename($meta->getPath());
754
-
755
- self::log("HIP: 3 Prio Queue: ".json_encode($this->prioQ->get()));
756
-
757
- //4: update counters and priority list
758
- if( $result["Status"] == ShortPixelAPI::STATUS_SUCCESS) {
759
- self::log("HIP: Image ID " . $itemId . " optimized successfully: ".json_encode($result));
760
- $prio = $this->prioQ->remove($itemId);
761
- //remove also from the failed list if it failed in the past
762
- $prio = $this->prioQ->removeFromFailed($itemId);
763
- $result["Type"] = $meta->getCompressionType() !== null ? ShortPixelAPI::getCompressionTypeName($meta->getCompressionType()) : '';
764
- $result["ThumbsTotal"] = $meta->getThumbs() && is_array($meta->getThumbs()) ? WpShortPixelMediaLbraryAdapter::countNonWebpSizes($meta->getThumbs()): 0;
765
- $result["ThumbsTotal"] -= count($meta->getThumbsMissing());
766
- $result["ThumbsCount"] = $meta->getThumbsOpt()
767
- ? $meta->getThumbsOpt() //below is the fallback for old optimized images that don't have thumbsOpt
768
- : ($this->_settings->processThumbnails ? $result["ThumbsTotal"] : 0);
769
-
770
- $result["RetinasCount"] = $meta->getRetinasOpt();
771
- $result["BackupEnabled"] = ($this->getBackupFolderAny($meta->getPath(), $meta->getThumbs()) ? true : false);//$this->_settings->backupImages;
772
-
773
- if(!$prio && $itemId <= $this->prioQ->getStartBulkId()) {
774
- $this->advanceBulk($itemId, $result);
775
- $this->setBulkInfo($itemId, $result);
776
- }
777
-
778
- $result["AverageCompression"] = $this->getAverageCompression();
779
-
780
- if($itemHandler->getType() == ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE) {
781
-
782
- $thumb = $bkThumb = "";
783
- //$percent = 0;
784
- $percent = $meta->getImprovementPercent();
785
- if($percent){
786
- $filePath = explode("/", $meta->getPath());
787
-
788
- //Get a suitable thumb
789
- $sizes = $meta->getThumbs();
790
- if('pdf' == strtolower(pathinfo($result["Filename"], PATHINFO_EXTENSION))) {
791
- // echo($result["Filename"] . " ESTE --> "); die(var_dump(strtolower(pathinfo($result["Filename"], PATHINFO_EXTENSION))));
792
- $thumb = plugins_url( 'shortpixel-image-optimiser/res/img/logo-pdf.png' );
793
- $bkThumb = '';
794
- } else {
795
- if(count($sizes)) {
796
- $thumb = (isset($sizes["medium"]) ? $sizes["medium"]["file"] : (isset($sizes["thumbnail"]) ? $sizes["thumbnail"]["file"]: ""));
797
- if(!strlen($thumb)) { //fallback to the first in the list
798
- $sizeVals = array_values($sizes);
799
- $thumb = count($sizeVals) ? $sizeVals[0]['file'] : '';
800
- }
801
- } else { //fallback to the image itself
802
- $thumb = is_array($filePath) ? $filePath[count($filePath) - 1] : $filePath;
803
- }
804
-
805
- if(strlen($thumb) && $this->_settings->backupImages && $this->_settings->processThumbnails) {
806
- $backupUrl = content_url() . "/" . SP_UPLOADS_NAME . "/" . SP_BACKUP . "/";
807
- //$urlBkPath = $this->_apiInterface->returnSubDir(get_attached_file($ID));
808
- $urlBkPath = ShortPixelMetaFacade::returnSubDir($meta->getPath(), ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE);
809
- $bkThumb = $backupUrl . $urlBkPath . $thumb;
810
- }
811
- if(strlen($thumb)) {
812
- $uploadsUrl = ShortPixelMetaFacade::getHomeUrl2();
813
- $urlPath = ShortPixelMetaFacade::returnSubDir($meta->getPath(), ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE);
814
- //$urlPath = implode("/", array_slice($filePath, 0, count($filePath) - 1));
815
- $thumb = $uploadsUrl . $urlPath . $thumb;
816
- }
817
- }
818
-
819
- $result["Thumb"] = $thumb;
820
- $result["BkThumb"] = $bkThumb;
821
- }
822
- }
823
- elseif( is_array($customIds)) { // this item is from custom bulk
824
- foreach($customIds as $customId) {
825
- $rootUrl = ShortPixelMetaFacade::getHomeUrl();
826
- if($customId->id == $itemHandler->getId()) {
827
- if('pdf' == strtolower(pathinfo($meta->getName(), PATHINFO_EXTENSION))) {
828
- $result["Thumb"] = plugins_url( 'shortpixel-image-optimiser/res/img/logo-pdf.png' );
829
- $result["BkThumb"] = "";
830
- } else {
831
- $result["Thumb"] = $thumb = $rootUrl . $meta->getWebPath();
832
- if($this->_settings->backupImages) {
833
- $result["BkThumb"] = str_replace($rootUrl, $rootUrl. "/" . basename(dirname(dirname(SP_BACKUP_FOLDER))) . "/" . SP_UPLOADS_NAME . "/" . SP_BACKUP . "/", $thumb);
834
- }
835
- }
836
- $this->setBulkInfo($itemId, $result);
837
- break;
838
- }
839
- }
840
- }
841
- }
842
- elseif ($result["Status"] == ShortPixelAPI::STATUS_ERROR) {
843
- if($meta->getRetries() > MAX_ERR_RETRIES) {
844
- if(! $this->prioQ->remove($itemId) ){
845
- $this->advanceBulk($meta->getId(), $result);
846
- }
847
- if($itemHandler->getType() == ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE) {
848
- $itemHandler->deleteMeta(); //this deletes only the ShortPixel fields from meta, in case of WP Media library
849
- }
850
- $result["Status"] = ShortPixelAPI::STATUS_SKIP;
851
- $result["Message"] .= __(' Retry limit reached. Skipping file ID ','shortpixel-image-optimiser') . $itemId . ".";
852
- $itemHandler->setError(isset($result['Code']) ? $result['Code'] : ShortPixelAPI::ERR_INCORRECT_FILE_SIZE, $result["Message"] );
853
- }
854
- else {
855
- if(isset($result['Code'])) {
856
- $itemHandler->setError($result['Code'], $result["Message"] );
857
- }
858
- $itemHandler->incrementRetries();
859
- }
860
- }
861
- elseif ($result["Status"] == ShortPixelAPI::STATUS_SKIP
862
- || $result["Status"] == ShortPixelAPI::STATUS_FAIL) {
863
- $meta = $itemHandler->getMeta();
864
- //$prio = $this->prioQ->remove($ID);
865
- $prio = $this->prioQ->remove($itemId);
866
- if(isset($result["Code"])
867
- && ( $result["Code"] == "write-fail" //could not write
868
- || (in_array(0+$result["Code"], array(-201)) && $meta->getRetries() >= 3))) { //for -201 (invalid image format) we retry only 3 times.
869
- //put this one in the failed images list - to show the user at the end
870
- $prio = $this->prioQ->addToFailed($itemHandler->getQueuedId());
871
- }
872
- $this->advanceBulk($meta->getId(), $result);
873
- if($itemHandler->getType() == ShortPixelMetaFacade::CUSTOM_TYPE) {
874
- $result["CustomImageLink"] = ShortPixelMetaFacade::getHomeUrl() . $meta->getWebPath();
875
- }
876
- }
877
- elseif($result["Status"] == ShortPixelAPI::STATUS_QUEUE_FULL) {
878
- //nimic?
879
- }
880
- elseif($result["Status"] == ShortPixelAPI::STATUS_MAINTENANCE) {
881
- //nimic?
882
- }
883
- elseif ($this->prioQ->isPrio($itemId) && $result["Status"] == ShortPixelAPI::STATUS_QUOTA_EXCEEDED) {
884
- if(!$this->prioQ->skippedCount()) {
885
- $this->prioQ->reverse(); //for the first prio item with quota exceeded, revert the prio queue as probably the bottom ones were processed
886
- }
887
- if($this->prioQ->allSkipped()) {
888
- $result["Stop"] = true;
889
- } else {
890
- $result["Stop"] = false;
891
- $this->prioQ->skip($itemId);
892
- }
893
- self::log("HIP: 5 Prio Skipped: ".json_encode($this->prioQ->getSkipped()));
894
- }
895
- elseif($result["Status"] == ShortPixelAPI::STATUS_RETRY && is_array($customIds)) {
896
- $result["CustomImageLink"] = $thumb = ShortPixelMetaFacade::getHomeUrl() . $meta->getWebPath();
897
- }
898
-
899
- if($result["Status"] !== ShortPixelAPI::STATUS_RETRY) {
900
- $this->_settings->bulkLastStatus = $result;
901
- }
902
- die(json_encode($result));
903
- }
904
-
905
-
906
- private function advanceBulk($processedID, &$result) {
907
- //echo("ADVANCE BULK: ");die(var_dump($result));
908
- if($processedID <= $this->prioQ->getStartBulkId()) {
909
- $this->prioQ->setStartBulkId($processedID - 1);
910
- $this->prioQ->logBulkProgress();
911
- }
912
- }
913
-
914
- private function setBulkInfo($processedID, &$result) {
915
- $deltaBulkPercent = $this->prioQ->getDeltaBulkPercent();
916
- $minutesRemaining = $this->prioQ->getTimeRemaining();
917
- $pendingMeta = $this->_settings->hasCustomFolders ? $this->spMetaDao->getPendingMetaCount() : 0;
918
- $percent = $this->prioQ->getBulkPercent();
919
- if(0 + $pendingMeta > 0) {
920
- $customMeta = $this->spMetaDao->getCustomMetaCount();
921
- $totalPercent = round(($percent * $this->_settings->currentTotalFiles + ($customMeta - $pendingMeta) * 100) / ($this->_settings->currentTotalFiles + $customMeta));
922
- $minutesRemaining = round($minutesRemaining * (100 - $totalPercent) / max(1, 100 - $percent));
923
- $percent = $totalPercent;
924
- }
925
- $result["BulkPercent"] = $percent;
926
- $result["BulkMsg"] = $this->bulkProgressMessage($deltaBulkPercent, $minutesRemaining);
927
- }
928
-
929
-
930
-
931
- private function sendToProcessing($itemHandler, $compressionType = false, $onlyThumbs = false) {
932
- $URLsAndPATHs = $this->getURLsAndPATHs($itemHandler, NULL, $onlyThumbs);
933
-
934
- $meta = $itemHandler->getMeta();
935
- //find thumbs that are not listed in the metadata and add them in the sizes array
936
- if($itemHandler->getType() == ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE) {
937
- $mainFile = $meta->getPath();
938
-
939
- $foundThumbs = @glob(WpShortPixelMediaLbraryAdapter::thumbsSearchPattern($mainFile));
940
- //first identify which thumbs are not in the sizes
941
- $sizes = $meta->getThumbs();
942
- foreach($foundThumbs as $id => $found) {
943
- //get the mime-type from one of the thumbs metas
944
- foreach($sizes as $size) {
945
- if(pathinfo($mainFile, PATHINFO_EXTENSION) !== pathinfo($size['file'], PATHINFO_EXTENSION)){
946
- continue;
947
- }
948
- $mimeType = $size['mime-type'];
949
- if($size['file'] === ShortPixelAPI::MB_basename($found)) {
950
- $foundThumbs[$id] = false;
951
- }
952
- }
953
- }
954
- // add the unfound ones to the sizes array
955
- $ind = 1;
956
- while (isset($sizes[ShortPixelMeta::FOUND_THUMB_PREFIX . str_pad("".$ind, 2, '0', STR_PAD_LEFT)])) $ind++;
957
- $start = $ind;
958
- foreach($foundThumbs as $found) {
959
- if($found !== false) {
960
- $size = getimagesize($found);
961
- $sizes[ShortPixelMeta::FOUND_THUMB_PREFIX . str_pad("".$ind, 2, '0', STR_PAD_LEFT)]= array( // it's a file that has no corresponding thumb so it's the WEBP for the main file
962
- 'file' => ShortPixelAPI::MB_basename($found),
963
- 'width' => $size[0],
964
- 'height' => $size[1],
965
- 'mime-type' => $mimeType
966
- );
967
- $ind++;
968
- }
969
- }
970
- if($ind > $start) { // at least one thumbnail added, update
971
- $meta->setThumbs($sizes);
972
- $itemHandler->updateMeta($meta);
973
- $URLsAndPATHs = $this->getURLsAndPATHs($itemHandler, NULL, $onlyThumbs);
974
- }
975
- }
976
-
977
- //find any missing thumbs files and mark them as such
978
- if( isset($URLsAndPATHs['sizesMissing']) && count($URLsAndPATHs['sizesMissing'])
979
- && (null === $meta->getThumbsMissing() || count(array_diff_key($meta->getThumbsMissing(), array_merge($URLsAndPATHs['sizesMissing'], $meta->getThumbsMissing()))))) {
980
- //fix missing thumbs in the metadata before sending to processing
981
- $meta->setThumbsMissing($URLsAndPATHs['sizesMissing']);
982
- $itemHandler->updateMeta();
983
- }
984
- //die(var_dump($itemHandler));
985
- $refresh = $meta->getStatus() === ShortPixelAPI::ERR_INCORRECT_FILE_SIZE;
986
- //echo("URLS: "); die(var_dump($URLsAndPATHs));
987
- $this->_apiInterface->doRequests($URLsAndPATHs['URLs'], false, $itemHandler,
988
- $compressionType === false ? $this->_settings->compressionType : $compressionType, $refresh);//send a request, do NOT wait for response
989
- $itemHandler->setWaitingProcessing();
990
- //$meta = wp_get_attachment_metadata($ID);
991
- //$meta['ShortPixel']['WaitingProcessing'] = true;
992
- //wp_update_attachment_metadata($ID, $meta);
993
- return $URLsAndPATHs;
994
- }
995
-
996
- public function handleManualOptimization() {
997
- $imageId = $_GET['image_id'];
998
- $cleanup = $_GET['cleanup'];
999
- switch(substr($imageId, 0, 2)) {
1000
- case "N-":
1001
- return "Add the gallery to the custom folders list in ShortPixel settings.";
1002
- // Later
1003
- if(class_exists("C_Image_Mapper")) { //this is a NextGen image but not added to our tables, so add it now.
1004
- $image_mapper = C_Image_Mapper::get_instance();
1005
- $image = $image_mapper->find(intval(substr($imageId, 2)));
1006
- if($image) {
1007
- $this->handleNextGenImageUpload($image, true);
1008
- return array("Status" => ShortPixelAPI::STATUS_SUCCESS, "message" => "");
1009
- }
1010
- }
1011
- return array("Status" => ShortPixelAPI::STATUS_FAIL, "message" => __('NextGen image not found','shortpixel-image-optimiser'));
1012
- break;
1013
- case "C-":
1014
- throw new Exception("HandleManualOptimization for custom images not implemented");
1015
- default:
1016
- $this->optimizeNowHook(intval($imageId));
1017
- break;
1018
- }
1019
- //do_action('shortpixel-optimize-now', $imageId);
1020
-
1021
- }
1022
-
1023
- //custom hook
1024
- public function optimizeNowHook($imageId) {
1025
- if(self::isProcessable($imageId)) {
1026
- $this->prioQ->push($imageId);
1027
- $itemHandler = new ShortPixelMetaFacade($imageId);
1028
- try {
1029
- $this->sendToProcessing($itemHandler);
1030
- $ret = array("Status" => ShortPixelAPI::STATUS_SUCCESS, "Message" => "");
1031
- } catch(Exception $e) { // Exception("Post metadata is corrupt (No attachment URL)")
1032
- $itemHandler->getMeta();
1033
- $itemHandler->setError(ShortPixelAPI::ERR_FILE_NOT_FOUND, $e->getMessage());
1034
- $ret = array("Status" => ShortPixelAPI::STATUS_FAIL, "Message" => $e->getMessage());
1035
- }
1036
- } else {
1037
- $ret = array("Status" => ShortPixelAPI::STATUS_SKIP, "Message" => $imageId);
1038
- }
1039
- die(json_encode($ret));
1040
- }
1041
-
1042
- //WP/LR Sync plugin integration
1043
- public function onWpLrUpdateMedia($imageId, $galleryIdsUnused) {
1044
- $meta = wp_get_attachment_metadata($imageId);
1045
- if(is_array($meta)) {
1046
- unset($meta['ShortPixel']);
1047
- $meta['ShortPixel'] = array();
1048
- $meta['ShortPixel']['WaitingProcessing'] = true;
1049
- $this->prioQ->push($imageId);
1050
- wp_update_attachment_metadata($imageId, $meta);
1051
- }
1052
- }
1053
-
1054
-
1055
- //save error in file's meta data
1056
- public function handleError($ID, $result)
1057
- {
1058
- $meta = wp_get_attachment_metadata($ID);
1059
- $meta['ShortPixelImprovement'] = $result;
1060
- wp_update_attachment_metadata($ID, $meta);
1061
- }
1062
-
1063
- public function getBackupFolder($file) {
1064
- if(realpath($file)) {
1065
- $file = realpath($file); //found cases when $file contains for example /wp/../wp-content - clean it up
1066
- }
1067
- $fileExtension = strtolower(substr($file,strrpos($file,".")+1));
1068
- $SubDir = ShortPixelMetaFacade::returnSubDir($file, ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE);
1069
- $SubDirOld = ShortPixelMetaFacade::returnSubDirOld($file, ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE);
1070
-
1071
- if ( !file_exists(SP_BACKUP_FOLDER . '/' . $SubDir . ShortPixelAPI::MB_basename($file))
1072
- && !file_exists(SP_BACKUP_FOLDER . '/' . date("Y") . "/" . date("m") . "/" . ShortPixelAPI::MB_basename($file)) ) {
1073
- $SubDir = $SubDirOld; //maybe the folder was saved with the old method that returned the full path if the wp-content was not inside the root of the site.
1074
- }
1075
- if ( !file_exists(SP_BACKUP_FOLDER . '/' . $SubDir . ShortPixelAPI::MB_basename($file))
1076
- && !file_exists(SP_BACKUP_FOLDER . '/' . date("Y") . "/" . date("m") . "/" . ShortPixelAPI::MB_basename($file)) ) {
1077
- $SubDir = trailingslashit(substr(dirname($file), 1)); //try this too
1078
- }
1079
- //sometimes the month of original file and backup can differ
1080
- if ( !file_exists(SP_BACKUP_FOLDER . '/' . $SubDir . ShortPixelAPI::MB_basename($file)) ) {
1081
- $SubDir = date("Y") . "/" . date("m") . "/";
1082
- if( !file_exists(SP_BACKUP_FOLDER . '/' . $SubDir . ShortPixelAPI::MB_basename($file)) ) {
1083
- return false;
1084
- }
1085
- }
1086
- return SP_BACKUP_FOLDER . '/' . $SubDir;
1087
- }
1088
-
1089
- public function getBackupFolderAny($file, $thumbs) {
1090
- if(!file_exists($file)) {
1091
- //try with the thumbnails
1092
- if(isset($thumbs)) foreach($thumbs as $size) {
1093
- $backup = $this->getBackupFolder(trailingslashit(dirname($file)) . $size['file']);
1094
- if($backup) return $backup;
1095
- }
1096
- } else {
1097
- return $this->getBackupFolder($file);
1098
- }
1099
- }
1100
-
1101
- protected function setFilePerms($file) {
1102
- //die(getenv('USERNAME') ? getenv('USERNAME') : getenv('USER'));
1103
- if(strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') {
1104
- //on *nix platforms check also the owner
1105
- $owner = fileowner($file);
1106
- if($owner !== false && $owner != posix_getuid()) { //files with changed owner
1107
- return false;
1108
- }
1109
- }
1110
- $perms = @fileperms($file);
1111
- if(!($perms & 0x0100) || !($perms & 0x0080)) {
1112
- if(!@chmod($file, $perms | 0x0100 | 0x0080)) {
1113
- return false;
1114
- }
1115
- }
1116
- return true;
1117
- }
1118
-
1119
- protected function doRestore($attachmentID, $meta = null) {
1120
- $file = $origFile = get_attached_file($attachmentID);
1121
- if(!$meta) {
1122
- $meta = wp_get_attachment_metadata($attachmentID);
1123
- }
1124
- $pathInfo = pathinfo($file);
1125
-
1126
- $bkFolder = $this->getBackupFolderAny($file, $meta["sizes"]);
1127
- $bkFile = trailingslashit($bkFolder) . ShortPixelAPI::MB_basename($file);
1128
-
1129
- //first check if the file is readable by the current user - otherwise it will be unaccessible for the web browser
1130
- // - collect the thumbs paths in the process
1131
- $bkCount = 0; $main = false;
1132
- if(file_exists($bkFile)) {
1133
- if(!$this->setFilePerms($bkFile) || (file_exists($file) && !$this->setFilePerms($file)) ) {
1134
- return false;
1135
- }
1136
- $bkCount++;
1137
- $main = true;
1138
- }
1139
- $thumbsPaths = array();
1140
- if( !empty($meta['file']) && is_array($meta["sizes"]) ) {
1141
- foreach($meta["sizes"] as $size => $imageData) {
1142
- $dest = $pathInfo['dirname'] . '/' . $imageData['file'];
1143
- $source = trailingslashit($bkFolder) . $imageData['file'];
1144
- if(!file_exists($source)) continue; // if thumbs were not optimized, then the backups will not be there.
1145
- if(!$this->setFilePerms($source) || (file_exists($dest) && !$this->setFilePerms($dest))) {
1146
- return false;
1147
- }
1148
- $bkCount++;
1149
- $thumbsPaths[$source] = $dest;
1150
- }
1151
- }
1152
- if(!$bkCount) {
1153
- return false;
1154
- }
1155
-
1156
- if($bkFolder) {
1157
- try {
1158
- //main file
1159
- if($main) {
1160
- $this->renameWithRetina($bkFile, $file);
1161
- }
1162
- //getSize to update meta if image was resized by ShortPixel
1163
- $width = false;
1164
- if(file_exists($file)) {
1165
- $size = getimagesize($file);
1166
- $width = $size[0];
1167
- $height = $size[1];
1168
- }
1169
-
1170
- //overwriting thumbnails
1171
- foreach($thumbsPaths as $source => $destination) {
1172
- $this->renameWithRetina($source, $destination);
1173
- }
1174
- $duplicates = ShortPixelMetaFacade::getWPMLDuplicates($attachmentID);
1175
- foreach($duplicates as $ID) {
1176
- $crtMeta = $attachmentID == $ID ? $meta : wp_get_attachment_metadata($ID);
1177
- if(is_numeric($crtMeta["ShortPixelImprovement"]) && 0 + $crtMeta["ShortPixelImprovement"] < 5 && $this->_settings->under5Percent > 0) {
1178
- $this->_settings->under5Percent = $this->_settings->under5Percent - 1; // - (isset($crtMeta["ShortPixel"]["thumbsOpt"]) ? $crtMeta["ShortPixel"]["thumbsOpt"] : 0);
1179
- }
1180
- unset($crtMeta["ShortPixelImprovement"]);
1181
- unset($crtMeta['ShortPixel']);
1182
- if($width && $height) {
1183
- $crtMeta['width'] = $width;
1184
- $crtMeta['height'] = $height;
1185
- }
1186
- wp_update_attachment_metadata($ID, $crtMeta);
1187
- }
1188
- unset($meta["ShortPixelImprovement"]);
1189
- unset($meta['ShortPixel']);
1190
-
1191
- } catch(Exception $e) {
1192
- //what to do, what to do?
1193
- return false;
1194
- }
1195
- } else {
1196
- return false;
1197
- }
1198
-
1199
- return $meta;
1200
- }
1201
-
1202
- protected function renameWithRetina($bkFile, $file) {
1203
- @rename($bkFile, $file);
1204
- $ext = pathinfo($file, PATHINFO_EXTENSION);
1205
- @rename(substr($bkFile, 0, strlen($bkFile) - 1 - strlen($ext)) . "@2x." . $ext, substr($file, 0, strlen($file) - 1 - strlen($ext)) . "@2x." . $ext);
1206
-
1207
- }
1208
-
1209
- public function doCustomRestore($ID) {
1210
- $meta = $this->spMetaDao->getMeta($ID);
1211
- if(!$meta || $meta->getStatus() != 2) return false;
1212
-
1213
- $file = $meta->getPath();
1214
- $fullSubDir = str_replace(get_home_path(), "", dirname($file)) . '/';
1215
- $bkFile = SP_BACKUP_FOLDER . '/' . $fullSubDir . ShortPixelAPI::MB_basename($file);
1216
-
1217
- if(file_exists($bkFile)) {
1218
- @rename($bkFile, $file);
1219
- $meta->setStatus(3);
1220
- $this->spMetaDao->update($meta);
1221
- }
1222
-
1223
- return $meta;
1224
- }
1225
-
1226
- public function handleRestoreBackup() {
1227
- $attachmentID = intval($_GET['attachment_ID']);
1228
-
1229
- $this->doRestore($attachmentID);
1230
-
1231
- // get the referring webpage location
1232
- $sendback = wp_get_referer();
1233
- // sanitize the referring webpage location
1234
- $sendback = preg_replace('|[^a-z0-9-~+_.?#=&;,/:]|i', '', $sendback);
1235
- // send the user back where they came from
1236
- wp_redirect($sendback);
1237
- // we are done
1238
- }
1239
-
1240
- public function handleRedo() {
1241
- die(json_encode($this->redo($_GET['attachment_ID'], $_GET['type'])));
1242
- }
1243
-
1244
- public function redo($qID, $type = false) {
1245
- if(ShortPixelMetaFacade::isCustomQueuedId($qID)) {
1246
- $ID = ShortPixelMetaFacade::stripQueuedIdType($qID);
1247
- $meta = $this->doCustomRestore($ID);
1248
- if($meta) {
1249
- $meta->setCompressionType(1 - $meta->getCompressionType());
1250
- $meta->setStatus(1);
1251
- $this->spMetaDao->update($meta);
1252
- $this->prioQ->push($qID);
1253
- $ret = array("Status" => ShortPixelAPI::STATUS_SUCCESS, "Message" => "");
1254
- } else {
1255
- $ret = array("Status" => ShortPixelAPI::STATUS_SKIP, "Message" => __('Could not restore from backup: ','shortpixel-image-optimiser') . $qID);
1256
- }
1257
- } else {
1258
- $ID = intval($qID);
1259
- $compressionType = ($type == 'lossless' ? 'lossless' : 'lossy'); //sanity check
1260
-
1261
- $meta = $this->doRestore($ID);
1262
- if($meta) { //restore succeeded
1263
- $meta['ShortPixel'] = array("type" => $compressionType);
1264
- wp_update_attachment_metadata($ID, $meta);
1265
- $this->prioQ->push($ID);
1266
- $this->sendToProcessing(new ShortPixelMetaFacade($ID), $compressionType == 'lossy' ? 1 : 0);
1267
- $ret = array("Status" => ShortPixelAPI::STATUS_SUCCESS, "Message" => "");
1268
- } else {
1269
- $ret = array("Status" => ShortPixelAPI::STATUS_SKIP, "Message" => __('Could not restore from backup: ','shortpixel-image-optimiser') . $ID);
1270
- }
1271
- }
1272
- return $ret;
1273
- }
1274
-
1275
- public function handleOptimizeThumbs() {
1276
- $ID = intval($_GET['attachment_ID']);
1277
- $meta = wp_get_attachment_metadata($ID);
1278
- //die(var_dump($meta));
1279
- if( isset($meta['ShortPixelImprovement'])
1280
- && isset($meta['sizes']) && WpShortPixelMediaLbraryAdapter::countNonWebpSizes($meta['sizes'])
1281
- && ( !isset($meta['ShortPixel']['thumbsOpt']) || $meta['ShortPixel']['thumbsOpt'] == 0)) { //optimized without thumbs, thumbs exist
1282
- $meta['ShortPixel']['thumbsTodo'] = true;
1283
- wp_update_attachment_metadata($ID, $meta);
1284
- $this->prioQ->push($ID);
1285
- $this->sendToProcessing(new ShortPixelMetaFacade($ID));
1286
- $ret = array("Status" => ShortPixelAPI::STATUS_SUCCESS, "message" => "");
1287
- } else {
1288
- $ret = array("Status" => ShortPixelAPI::STATUS_SKIP, "message" => (isset($meta['ShortPixelImprovement']) ? __('No thumbnails to optimize for ID: ','shortpixel-image-optimiser') : __('Please optimize image for ID: ','shortpixel-image-optimiser')) . $ID);
1289
- }
1290
- die(json_encode($ret));
1291
- }
1292
-
1293
- public function handleCheckQuota() {
1294
- $this->getQuotaInformation();
1295
- // store the referring webpage location
1296
- $sendback = wp_get_referer();
1297
- // sanitize the referring webpage location
1298
- $sendback = preg_replace('|[^a-z0-9-~+_.?#=&;,/:]|i', '', $sendback);
1299
- // send the user back where they came from
1300
- wp_redirect($sendback);
1301
- // we are done
1302
- }
1303
-
1304
- public function handleDeleteAttachmentInBackup($ID) {
1305
- $file = get_attached_file($ID);
1306
- $meta = wp_get_attachment_metadata($ID);
1307
-
1308
- if(self::isProcessable($ID) != false)
1309
- {
1310
- try {
1311
- $SubDir = ShortPixelMetaFacade::returnSubDir($file, ShortPixelMetaFacade::MEDIA_LIBRARY_TYPE);
1312
-
1313
- @unlink(SP_BACKUP_FOLDER . '/' . $SubDir . ShortPixelAPI::MB_basename($file));
1314
-
1315
- if ( !empty($meta['file']) )
1316
- {
1317
- $filesPath = SP_BACKUP_FOLDER . '/' . $SubDir;//base BACKUP path
1318
- //remove thumbs thumbnails
1319
- if(isset($meta["sizes"])) {
1320
- foreach($meta["sizes"] as $size => $imageData) {
1321
- @unlink($filesPath . ShortPixelAPI::MB_basename($imageData['file']));//remove thumbs
1322
- }
1323
- }
1324
- }
1325
-
1326
- } catch(Exception $e) {
1327
- //what to do, what to do?
1328
- }
1329
- }
1330
- }
1331
-
1332
- public function deactivatePlugin() {
1333
- if ( ! wp_verify_nonce( $_GET['_wpnonce'], 'sp_deactivate_plugin_nonce' ) ) {
1334
- wp_nonce_ays( '' );
1335
- }
1336
- deactivate_plugins( $_GET['plugin'] );
1337
- wp_safe_redirect( wp_get_referer() );
1338
- die();
1339
- }
1340
-
1341
- public function checkQuotaAndAlert($quotaData = null, $recheck = false) {
1342
- if(!$quotaData) {
1343
- $quotaData = $this->getQuotaInformation();
1344
- }
1345
- if ( !$quotaData['APIKeyValid']) {
1346
- return $quotaData;
1347
- }
1348
- //$tempus = microtime(true);
1349
- $imageCount = WpShortPixelMediaLbraryAdapter::countAllProcessableFiles($this->_settings->optimizePdfs);
1350
-
1351
- $this->_settings->currentTotalFiles = $imageCount['totalFiles'];
1352
-
1353
- //echo("Count took (seconds): " . (microtime(true) - $tempus));
1354
- foreach($imageCount as $key => $val) {
1355
- $quotaData[$key] = $val;
1356
- }
1357
-
1358
- if($this->_settings->hasCustomFolders) {
1359
- $customImageCount = $this->spMetaDao->countAllProcessableFiles();
1360
- foreach($customImageCount as $key => $val) {
1361
- $quotaData[$key] = isset($quotaData[$key])
1362
- ? (is_array($quotaData[$key]) ? array_merge($quotaData[$key], $val) : $quotaData[$key] + $val)
1363
- : $val;
1364
- }
1365
- }
1366
-
1367
- if($quotaData['APICallsQuotaNumeric'] + $quotaData['APICallsQuotaOneTimeNumeric'] > $quotaData['APICallsMadeNumeric'] + $quotaData['APICallsMadeOneTimeNumeric']) {
1368
- $this->_settings->quotaExceeded = '0';
1369
- $this->_settings->prioritySkip = NULL;
1370
- self::log("CHECK QUOTA: Skipped: ".json_encode($this->prioQ->getSkipped()));
1371
-
1372
- ?><script>var shortPixelQuotaExceeded = 0;</script><?php
1373
- }
1374
- else {
1375
- $this->view->displayQuotaExceededAlert($quotaData, self::getAverageCompression(), $recheck);
1376
- ?><script>var shortPixelQuotaExceeded = 1;</script><?php
1377
- }
1378
- return $quotaData;
1379
- }
1380
-
1381
- public function isValidMetaId($id) {
1382
- return substr($id, 0, 2 ) == "C-" ? $this->spMetaDao->getMeta(substr($id, 2)) : wp_get_attachment_url($id);
1383
- }
1384
-
1385
- public function listCustomMedia() {
1386
- if( ! class_exists( 'ShortPixelListTable' ) ) {
1387
- require_once('class/view/shortpixel-list-table.php');
1388
- }
1389
- if(isset($_REQUEST['refresh']) && esc_attr($_REQUEST['refresh']) == 1) {
1390
- $notice = null;
1391
- $this->refreshCustomFolders($notice);
1392
- }
1393
- if(isset($_REQUEST['action']) && esc_attr($_REQUEST['action']) == 'optimize' && isset($_REQUEST['image'])) {
1394
- //die(ShortPixelMetaFacade::queuedId(ShortPixelMetaFacade::CUSTOM_TYPE, $_REQUEST['image']));
1395
- $this->prioQ->push(ShortPixelMetaFacade::queuedId(ShortPixelMetaFacade::CUSTOM_TYPE, $_REQUEST['image']));
1396
- }
1397
- $customMediaListTable = new ShortPixelListTable($this, $this->spMetaDao, $this->hasNextGen);
1398
- $items = $customMediaListTable->prepare_items();
1399
- if ( isset($_GET['noheader']) ) {
1400
- require_once(ABSPATH . 'wp-admin/admin-header.php');
1401
- }
1402
-
1403
- ?>
1404
- <div class="wrap shortpixel-other-media">
1405
- <h2>
1406
- <div style="float:right;">
1407
- <a href="upload.php?page=wp-short-pixel-custom&refresh=1" id="refresh" class="button button-primary" title="<?php _e('Refresh custom folders content','shortpixel-image-optimiser');?>">
1408
- <?php _e('Refresh folders','shortpixel-image-optimiser');?>
1409
- </a>
1410
- </div>
1411
- <?php _e('Other Media optimized by ShortPixel','shortpixel-image-optimiser');?>
1412
- </h2>
1413
-
1414
- <div id="poststuff">
1415
- <div id="post-body" class="metabox-holder columns-2">
1416
- <div id="post-body-content">
1417
- <div class="meta-box-sortables ui-sortable">
1418
- <form method="post" class="shortpixel-table">
1419
- <?php
1420
- $customMediaListTable->display();
1421
- //push to the processing list the pending ones, just in case
1422
- //$count = $this->spMetaDao->getCustomMetaCount();
1423
- foreach ($items as $item) {
1424
- if($item->status == 1){
1425
- $this->prioQ->push(ShortPixelMetaFacade::queuedId(ShortPixelMetaFacade::CUSTOM_TYPE, $item->id));
1426
- }
1427
- }
1428
- ?>
1429
- </form>
1430
- </div>
1431
- </div>
1432
- </div>
1433
- <br class="clear">
1434
- </div>
1435
- </div> <?php
1436
- }
1437
- public function bulkProcess() {
1438
- global $wpdb;
1439
-
1440
- if( $this->_settings->verifiedKey == false ) {//invalid API Key
1441
- ShortPixelView::displayActivationNotice();
1442
- return;
1443
- }
1444
-
1445
- $quotaData = $this->checkQuotaAndAlert(null, isset($_GET['checkquota']));
1446
- if($this->_settings->quotaExceeded != 0) {
1447
- return;
1448
- }
1449
-
1450
- if(isset($_POST['bulkProcessPause']))
1451
- {//pause an ongoing bulk processing, it might be needed sometimes
1452
- $this->prioQ->pauseBulk();
1453
- if($this->_settings->hasCustomFolders && $this->spMetaDao->getPendingMetaCount()) {
1454
- $this->_settings->customBulkPaused = 1;
1455
- }
1456
- }
1457
-
1458
- if(isset($_POST['bulkProcessStop']))
1459
- {//stop an ongoing bulk processing
1460
- $this->prioQ->cancelBulk();
1461
- if($this->_settings->hasCustomFolders && $this->spMetaDao->getPendingMetaCount()) {
1462
- $this->_settings->customBulkPaused = 1;
1463
- }
1464
- }
1465
-
1466
- if(isset($_POST["bulkProcess"]))
1467
- {
1468
- //set the thumbnails option
1469
- if ( isset($_POST['thumbnails']) ) {
1470
- $this->_settings->processThumbnails = 1;
1471
- } else {
1472
- $this->_settings->processThumbnails = 0;
1473
- }
1474
- //clean the custom files errors in order to process them again
1475
- if($this->_settings->hasCustomFolders) {
1476
- $this->spMetaDao->resetFailed();
1477
- }
1478
-
1479
- $this->prioQ->startBulk();
1480
- $this->_settings->customBulkPaused = 0;
1481
- self::log("BULK: Start: " . $this->prioQ->getStartBulkId() . ", stop: " . $this->prioQ->getStopBulkId() . " PrioQ: "
1482
- .json_encode($this->prioQ->get()));
1483
- }//end bulk process was clicked
1484
-
1485
- if(isset($_POST["bulkProcessResume"]))
1486
- {
1487
- $this->prioQ->resumeBulk();
1488
- $this->_settings->customBulkPaused = 0;
1489
- }//resume was clicked
1490
-
1491
- if(isset($_POST["skipToCustom"]))
1492
- {
1493
- $this->_settings->skipToCustom = true;
1494
- }//resume was clicked
1495
-
1496
- //figure out the files that are left to be processed
1497
- $qry_left = "SELECT count(*) FilesLeftToBeProcessed FROM " . $wpdb->prefix . "postmeta
1498
- WHERE meta_key = '_wp_attached_file' AND post_id <= " . (0 + $this->prioQ->getStartBulkId());
1499
- $filesLeft = $wpdb->get_results($qry_left);
1500
-
1501
- //check the custom bulk
1502
- $pendingMeta = $this->_settings->hasCustomFolders ? $this->spMetaDao->getPendingMetaCount() : 0;
1503
-
1504
- if ( ($filesLeft[0]->FilesLeftToBeProcessed > 0 && $this->prioQ->bulkRunning())
1505
- || (0 + $pendingMeta > 0 && !$this->_settings->customBulkPaused && $this->prioQ->bulkRan())//bulk processing was started
1506
- && (!$this->prioQ->bulkPaused() || $this->_settings->skipToCustom)) //bulk not paused or if paused, user pressed Process Custom button
1507
- {
1508
- $msg = $this->bulkProgressMessage($this->prioQ->getDeltaBulkPercent(), $this->prioQ->getTimeRemaining());
1509
-
1510
- $this->view->displayBulkProcessingRunning($this->getPercent($quotaData), $msg, $quotaData['APICallsRemaining'], $this->getAverageCompression(),
1511
- ($pendingMeta !== null ? ($this->prioQ->bulkRunning() ? 3 : 2) : 1));
1512
-
1513
- } else
1514
- {
1515
- if($this->prioQ->bulkRan() && !$this->prioQ->bulkPaused()) {
1516
- $this->prioQ->markBulkComplete();
1517
- }
1518
-
1519
- //image count
1520
- $thumbsProcessedCount = $this->_settings->thumbsCount;//amount of optimized thumbnails
1521
- $under5PercentCount = $this->_settings->under5Percent;//amount of under 5% optimized imgs.
1522
-
1523
- //average compression
1524
- $averageCompression = self::getAverageCompression();
1525
- $percent = $this->prioQ->bulkPaused() ? $this->getPercent($quotaData) : false;
1526
-
1527
- $this->view->displayBulkProcessingForm($quotaData, $thumbsProcessedCount, $under5PercentCount,
1528
- $this->prioQ->bulkRan(), $averageCompression, $this->_settings->fileCount,
1529
- self::formatBytes($this->_settings->savedSpace), $percent, $pendingMeta);
1530
- }
1531
- }
1532
- //end bulk processing
1533
-
1534
- public function getPercent($quotaData) {
1535
- if($this->_settings->processThumbnails) {
1536
- return min(99, round($quotaData["totalProcessedFiles"] *100.0 / $quotaData["totalFiles"]));
1537
- } else {
1538
- return min(99, round($quotaData["mainProcessedFiles"] *100.0 / $quotaData["mainFiles"]));
1539
- }
1540
- }
1541
-
1542
- public function bulkProgressMessage($percent, $minutes) {
1543
- $timeEst = "";
1544
- self::log("bulkProgressMessage(): percent: " . $percent);
1545
- if($percent < 1 || $minutes == 0) {
1546
- $timeEst = "";
1547
- } elseif( $minutes > 2880) {
1548
- $timeEst = "~ " . round($minutes / 1440) . " days left";
1549
- } elseif ($minutes > 240) {
1550
- $timeEst = "~ " . round($minutes / 60) . " hours left";
1551
- } elseif ($minutes > 60) {
1552
- $timeEst = "~ " . round($minutes / 60) . " hours " . round($minutes % 60 / 10) * 10 . " min. left";
1553
- } elseif ($minutes > 20) {
1554
- $timeEst = "~ " . round($minutes / 10) * 10 . " minutes left";
1555
- } else {
1556
- $timeEst = "~ " . $minutes . " minutes left";
1557
- }
1558
- return $timeEst;
1559
- }
1560
-
1561
- public function emptyBackup(){
1562
- if(file_exists(SP_BACKUP_FOLDER)) {
1563
-
1564
- //extract all images from DB in an array. of course
1565
- $attachments = null;
1566
- $attachments = get_posts( array(
1567
- 'numberposts' => -1,
1568
- 'post_type' => 'attachment',
1569
- 'post_mime_type' => 'image'
1570
- ));
1571
-
1572
-
1573
- //parse all images and set the right flag that the image has no backup
1574
- /* this is obsolete as the backup exists decision is taken on verfication of the actual backup files
1575
- foreach($attachments as $attachment)
1576
- {
1577
- if(self::isProcessable($attachment->ID) == false) continue;
1578
-
1579
- $meta = wp_get_attachment_metadata($attachment->ID);
1580
- $meta['ShortPixel']['NoBackup'] = true;
1581
- wp_update_attachment_metadata($attachment->ID, $meta);
1582
- }
1583
- */
1584
-
1585
- //delete the actual files on disk
1586
- $this->deleteDir(SP_BACKUP_FOLDER);//call a recursive function to empty files and sub-dirs in backup dir
1587
- }
1588
- }
1589
-
1590
- public function backupFolderIsEmpty() {
1591
- return count(scandir(SP_BACKUP_FOLDER)) > 2 ? false : true;
1592
- }
1593
-
1594
- public function getBackupSize() {
1595
- if ( !current_user_can( 'manage_options' ) ) {
1596
- wp_die(__('You do not have sufficient permissions to access this page.','shortpixel-image-optimiser'));
1597
- }
1598
- die(self::formatBytes(self::folderSize(SP_BACKUP_FOLDER)));
1599
- }
1600
-
1601
- public function browseContent() {
1602
- if ( !current_user_can( 'manage_options' ) ) {
1603
- wp_die(__('You do not have sufficient permissions to access this page.','shortpixel-image-optimiser'));
1604
- }
1605
-
1606
- $root = self::getCustomFolderBase();
1607
-
1608
- $postDir = rawurldecode($root.(isset($_POST['dir']) ? $_POST['dir'] : null ));
1609
-
1610
- // set checkbox if multiSelect set to true
1611
- $checkbox = ( isset($_POST['multiSelect']) && $_POST['multiSelect'] == 'true' ) ? "<input type='checkbox' />" : null;
1612
- $onlyFolders = ($_POST['dir'] == '/' || isset($_POST['onlyFolders']) && $_POST['onlyFolders'] == 'true' ) ? true : false;
1613
- $onlyFiles = ( isset($_POST['onlyFiles']) && $_POST['onlyFiles'] == 'true' ) ? true : false;
1614
-
1615
- if( file_exists($postDir) ) {
1616
-
1617
- $files = scandir($postDir);
1618
- $returnDir = substr($postDir, strlen($root));
1619
-
1620
- natcasesort($files);
1621
-
1622
- if( count($files) > 2 ) { // The 2 accounts for . and ..
1623
- echo "<ul class='jqueryFileTree'>";
1624
- foreach( $files as $file ) {
1625
-
1626
- if($file == 'ShortpixelBackups') continue;
1627
-
1628
- $htmlRel = str_replace("'", "&apos;", $returnDir . $file);
1629
- $htmlName = htmlentities($file);
1630
- $ext = preg_replace('/^.*\./', '', $file);
1631
-
1632
- if( file_exists($postDir . $file) && $file != '.' && $file != '..' ) {
1633
- if( is_dir($postDir . $file) && (!$onlyFiles || $onlyFolders) )
1634
- echo "<li class='directory collapsed'>{$checkbox}<a rel='" .$htmlRel. "/'>" . $htmlName . "</a></li>";
1635
- else if (!$onlyFolders || $onlyFiles)
1636
- echo "<li class='file ext_{$ext}'>{$checkbox}<a rel='" . $htmlRel . "'>" . $htmlName . "</a></li>";
1637
- }
1638
- }
1639
-
1640
- echo "</ul>";
1641
- }
1642
- }
1643
- die();
1644
- }
1645
-
1646
- public static function getCustomFolderBase() {
1647
- if(is_main_site()) {
1648
- $base = get_home_path();
1649
- return realpath(rtrim($base, '/'));
1650
- } else {
1651
- $up = wp_upload_dir();
1652
- return realpath($up['basedir']);
1653
- }
1654
- }
1655
-
1656
- protected function fullRefreshCustomFolder($path, &$notice) {
1657
- $folder = $this->spMetaDao->getFolder($path);
1658
- $diff = $folder->checkFolderContents(array('ShortPixelCustomMetaDao', 'getPathFiles'));
1659
- }
1660
-
1661
- protected function refreshCustomFolders(&$notice, $ignore = false) {
1662
- $customFolders = array();
1663
- if($this->_settings->hasCustomFolders) {
1664
- $customFolders = $this->spMetaDao->getFolders();
1665
- foreach($customFolders as $folder) {
1666
- if($folder->getPath() === $ignore) continue;
1667
- try {
1668
- $mt = $folder->getFolderContentsChangeDate();
1669
- if($mt > strtotime($folder->getTsUpdated())) {
1670
- $fileList = $folder->getFileList(strtotime($folder->getTsUpdated()));
1671
- $this->spMetaDao->batchInsertImages($fileList, $folder->getId());
1672
- $folder->setTsUpdated(date("Y-m-d H:i:s", $mt));
1673
- $folder->setFileCount($folder->countFiles());
1674
- $this->spMetaDao->update($folder);
1675
- }
1676
- //echo ("mt: " . $mt);
1677
- //die(var_dump($folder));
1678
- } catch(SpFileRightsException $ex) {
1679
- if(is_array($notice)) {
1680
- if($notice['status'] == 'error') {
1681
- $notice['msg'] .= " " . $ex->getMessage();
1682
- }
1683
- } else {
1684
- $notice = array("status" => "error", "msg" => $ex->getMessage());
1685
- }
1686
- }
1687
- }
1688
- }
1689
- return $customFolders;
1690
- }
1691
-
1692
- public function renderSettingsMenu() {
1693
- if ( !current_user_can( 'manage_options' ) ) {
1694
- wp_die(__('You do not have sufficient permissions to access this page.','shortpixel-image-optimiser'));
1695
- }
1696
-
1697
- wp_enqueue_style('sp-file-tree.css', plugins_url('/res/css/sp-file-tree.css',__FILE__) );
1698
- wp_enqueue_script('sp-file-tree.js', plugins_url('/res/js/sp-file-tree.js',__FILE__) );
1699
-
1700
- //die(var_dump($_POST));
1701
- $noticeHTML = "";
1702
- $notice = null;
1703
- $folderMsg = false;
1704
- $addedFolder = false;
1705
-
1706
- $this->_settings->redirectedSettings = 2;
1707
-
1708
- //by default we try to fetch the API Key from wp-config.php (if defined)
1709
- if ( defined("SHORTPIXEL_API_KEY") && strlen(SHORTPIXEL_API_KEY) == 20)
1710
- {
1711
- if(!isset($_POST['save']) && (strlen($this->getApiKey()) == 0 || SHORTPIXEL_API_KEY != $this->getApiKey())) {
1712
- $_POST['validate'] = "validate";
1713
- }
1714
- $_POST['key'] = SHORTPIXEL_API_KEY;
1715
- }
1716
-
1717
- //check all custom folders and update meta table if files appeared
1718
- $customFolders = $this->refreshCustomFolders($notice, isset($_POST['removeFolder']) ? $_POST['removeFolder'] : null);
1719
-
1720
- if(isset($_POST['request']) && $_POST['request'] == 'request') {
1721
- //a new API Key was requested
1722
- if(filter_var($_POST['email'], FILTER_VALIDATE_EMAIL)) {
1723
-
1724
- }
1725
- else {
1726
- $notice = array("status" => "error",
1727
- "msg" => __("Please provide a valid e-mail.",'shortpixel-image-optimiser')
1728
- . "<BR> "
1729
- . __('For any question regarding obtaining your API Key, please contact us at ','shortpixel-image-optimiser')
1730
- . "<a href='mailto:help@shortpixel.com?Subject=API Key issues' target='_top'>help@shortpixel.com</a>"
1731
- . __(' or ','shortpixel-image-optimiser')
1732
- . "<a href='https://shortpixel.com/contact' target='_blank'>" . __('here','shortpixel-image-optimiser') . "</a>.");
1733
- }
1734
- }
1735
-
1736
- if( isset($_POST['save']) || isset($_POST['saveAdv'])
1737
- || (isset($_POST['validate']) && $_POST['validate'] == "validate")
1738
- || isset($_POST['removeFolder']) || isset($_POST['recheckFolder'])) {
1739
-
1740
- //handle API Key - common for save and validate.
1741
- $_POST['key'] = trim(str_replace("*", "", isset($_POST['key']) ? $_POST['key'] : $this->_settings->apiKey)); //the API key might not be set if the editing is disabled.
1742
-
1743
- if ( strlen($_POST['key']) <> 20 )
1744
- {
1745
- $KeyLength = strlen($_POST['key']);
1746
-
1747
- $notice = array("status" => "error",
1748
- "msg" => sprintf(__("The key you provided has %s characters. The API key should have 20 characters, letters and numbers only.",'shortpixel-image-optimiser'), $KeyLength)
1749
- . "<BR> <b>"
1750
- . __('Please check that the API key is the same as the one you received in your confirmation email.','shortpixel-image-optimiser')
1751
- . "</b><BR> "
1752
- . __('If this problem persists, please contact us at ','shortpixel-image-optimiser')
1753
- . "<a href='mailto:help@shortpixel.com?Subject=API Key issues' target='_top'>help@shortpixel.com</a>"
1754
- . __(' or ','shortpixel-image-optimiser')
1755
- . "<a href='https://shortpixel.com/contact' target='_blank'>" . __('here','shortpixel-image-optimiser') . "</a>.");
1756
- }
1757
- else
1758
- {
1759
- $validityData = $this->getQuotaInformation($_POST['key'], true, isset($_POST['validate']) && $_POST['validate'] == "validate");
1760
-
1761
- $this->_settings->apiKey = $_POST['key'];
1762
- if($validityData['APIKeyValid']) {
1763
- if(isset($_POST['validate']) && $_POST['validate'] == "validate") {
1764
- // delete last status if it was no valid key
1765
- $lastStatus = $this->_settings->bulkLastStatus;
1766
- if(isset($lastStatus['Status']) && $lastStatus['Status'] == ShortPixelAPI::STATUS_NO_KEY) {
1767
- $this->_settings->bulkLastStatus = null;
1768
- }
1769
- //display notification
1770
- $urlParts = explode("/", get_site_url());
1771
- if( $validityData['DomainCheck'] == 'NOT Accessible'){
1772
- $notice = array("status" => "warn", "msg" => __("API Key is valid but your site is not accessible from our servers. 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.",'shortpixel-image-optimiser'));
1773
- } else {
1774
- if ( function_exists("is_multisite") && is_multisite() && !defined("SHORTPIXEL_API_KEY"))
1775
- $notice = array("status" => "success", "msg" => __("Great, your API Key is valid! <br>You seem to be running a multisite, please note that API Key can also be configured in wp-config.php like this:",'shortpixel-image-optimiser')
1776
- . "<BR> <b>define('SHORTPIXEL_API_KEY', '".$this->_settings->apiKey."');</b>");
1777
- else
1778
- $notice = array("status" => "success", "msg" => __('Great, your API Key is valid. Please take a few moments to review the plugin settings below before starting to optimize your images.','shortpixel-image-optimiser'));
1779
- }
1780
- }
1781
- $this->_settings->verifiedKey = true;
1782
- //test that the "uploads" have the right rights and also we can create the backup dir for ShortPixel
1783
- if ( !file_exists(SP_BACKUP_FOLDER) && !@mkdir(SP_BACKUP_FOLDER, 0777, true) )
1784
- $notice = array("status" => "error",
1785
- "msg" => sprintf(__("There is something preventing us to create a new folder for backing up your original files.<BR>Please make sure that folder <b>%s</b> has the necessary write and read rights.",'shortpixel-image-optimiser'),
1786
- WP_CONTENT_DIR . '/' . SP_UPLOADS_NAME ));
1787
- } else {
1788
- if(isset($_POST['validate'])) {
1789
- //display notification
1790
- $notice = array("status" => "error", "msg" => $validityData["Message"]);
1791
- }
1792
- $this->_settings->verifiedKey = false;
1793
- }
1794
- }
1795
-
1796
- //if save button - we process the rest of the form elements
1797
- if(isset($_POST['save']) || isset($_POST['saveAdv'])) {
1798
- $this->_settings->compressionType = $_POST['compressionType'];
1799
- if(isset($_POST['thumbnails'])) { $this->_settings->processThumbnails = 1; } else { $this->_settings->processThumbnails = 0; }
1800
- if(isset($_POST['backupImages'])) { $this->_settings->backupImages = 1; } else { $this->_settings->backupImages = 0; }
1801
- if(isset($_POST['cmyk2rgb'])) { $this->_settings->CMYKtoRGBconversion = 1; } else { $this->_settings->CMYKtoRGBconversion = 0; }
1802
- $this->_settings->keepExif = isset($_POST['removeExif']) ? 0 : 1;
1803
- //delete_option('wp-short-pixel-keep-exif');
1804
- $this->_settings->resizeImages = (isset($_POST['resize']) ? 1: 0);
1805
- $this->_settings->resizeType = (isset($_POST['resize_type']) ? $_POST['resize_type']: false);
1806
- $this->_settings->resizeWidth = (isset($_POST['width']) ? $_POST['width']: $this->_settings->resizeWidth);
1807
- $this->_settings->resizeHeight = (isset($_POST['height']) ? $_POST['height']: $this->_settings->resizeHeight);
1808
- $this->_settings->siteAuthUser = (isset($_POST['siteAuthUser']) ? $_POST['siteAuthUser']: $this->_settings->siteAuthUser);
1809
- $this->_settings->siteAuthPass = (isset($_POST['siteAuthPass']) ? $_POST['siteAuthPass']: $this->_settings->siteAuthPass);
1810
-
1811
- $uploadDir = wp_upload_dir();
1812
- $uploadPath = realpath($uploadDir["basedir"]);
1813
-
1814
- if(isset($_POST['nextGen'])) {
1815
- WpShortPixelDb::checkCustomTables(); // check if custom tables are created, if not, create them
1816
- $prevNextGen = $this->_settings->includeNextGen;
1817
- $this->_settings->includeNextGen = 1;
1818
- $ret = $this->addNextGenGalleriesToCustom($prevNextGen);
1819
- $folderMsg = $ret["message"];
1820
- $customFolders = $ret["customFolders"];
1821
- } else {
1822
- $this->_settings->includeNextGen = 0;
1823
- }
1824
- if(isset($_POST['addCustomFolder']) && strlen($_POST['addCustomFolder']) > 0) {
1825
- $folderMsg = $this->spMetaDao->newFolderFromPath(stripslashes($_POST['addCustomFolder']), $uploadPath, self::getCustomFolderBase());
1826
- if(!$folderMsg) {
1827
- $notice = array("status" => "success", "msg" => __('Folder added successfully.','shortpixel-image-optimiser'));
1828
- }
1829
- $customFolders = $this->spMetaDao->getFolders();
1830
- $this->_settings->hasCustomFolders = true;
1831
- }
1832
-
1833
- $this->_settings->createWebp = (isset($_POST['createWebp']) ? 1: 0);
1834
- $this->_settings->optimizeRetina = (isset($_POST['optimizeRetina']) ? 1: 0);
1835
- $this->_settings->optimizePdfs = (isset($_POST['optimizePdfs']) ? 1: 0);
1836
- $this->_settings->frontBootstrap = (isset($_POST['frontBootstrap']) ? 1: 0);
1837
- $this->_settings->autoMediaLibrary = (isset($_POST['autoMediaLibrary']) ? 1: 0);
1838
-
1839
- //Redirect to bulk processing if requested
1840
- if( isset($_POST['save']) && $_POST['save'] == __("Save and Go to Bulk Process",'shortpixel-image-optimiser')
1841
- || isset($_POST['saveAdv']) && $_POST['saveAdv'] == __("Save and Go to Bulk Process",'shortpixel-image-optimiser')) {
1842
- wp_redirect("upload.php?page=wp-short-pixel-bulk");
1843
- exit();
1844
- }
1845
- }
1846
- if(isset($_POST['removeFolder']) && strlen(($_POST['removeFolder']))) {
1847
- $this->spMetaDao->removeFolder($_POST['removeFolder']);
1848
- $customFolders = $this->spMetaDao->getFolders();
1849
- $_POST["saveAdv"] = true;
1850
- }
1851
- if(isset($_POST['recheckFolder']) && strlen(($_POST['recheckFolder']))) {
1852
- //$folder->fullRefreshCustomFolder($_POST['recheckFolder']); //aici singura solutie pare callback care spune daca exita url-ul complet
1853
- }
1854
- }
1855
-
1856
- //now output headers. They were prevented with noheaders=true in the form url in order to be able to redirect if bulk was pressed
1857
- if(isset($_REQUEST['noheader'])) {
1858
- require_once(ABSPATH . 'wp-admin/admin-header.php');
1859
- }
1860
-
1861
- //empty backup
1862
- if(isset($_POST['emptyBackup'])) {
1863
- $this->emptyBackup();
1864
- }
1865
-
1866
- $quotaData = $this->checkQuotaAndAlert(isset($validityData) ? $validityData : null, isset($_GET['checkquota']));
1867
-
1868
- if($this->hasNextGen) {
1869
- $ngg = array_map(array('ShortPixelNextGenAdapter','pathToAbsolute'), ShortPixelNextGenAdapter::getGalleries());
1870
- //die(var_dump($ngg));
1871
- for($i = 0; $i < count($customFolders); $i++) {
1872
- if(in_array($customFolders[$i]->getPath(), $ngg )) {
1873
- $customFolders[$i]->setType("NextGen");
1874
- }
1875
- }
1876
- }
1877
-
1878
- $showApiKey = is_main_site() || (function_exists("is_multisite") && is_multisite() && !defined("SHORTPIXEL_API_KEY"));
1879
- $editApiKey = !defined("SHORTPIXEL_API_KEY") && $showApiKey;
1880
-
1881
- if($this->_settings->verifiedKey) {
1882
- $fileCount = number_format($this->_settings->fileCount);
1883
- $savedSpace = self::formatBytes($this->_settings->savedSpace,2);
1884
- $averageCompression = $this->getAverageCompression();
1885
- $savedBandwidth = self::formatBytes($this->_settings->savedSpace * 10000,2);
1886
- if (is_numeric($quotaData['APICallsQuota'])) {
1887
- $quotaData['APICallsQuota'] .= "/month";
1888
- }
1889
- $remainingImages = $quotaData['APICallsRemaining'];
1890
- $remainingImages = ( $remainingImages < 0 ) ? 0 : number_format($remainingImages);
1891
- $totalCallsMade = number_format($quotaData['APICallsMadeNumeric'] + $quotaData['APICallsMadeOneTimeNumeric']);
1892
-
1893
- $resources = wp_remote_post($this->_settings->httpProto . "://shortpixel.com/resources-frag");
1894
- if(is_wp_error( $resources )) {
1895
- $resources = array();
1896
- }
1897
- $this->view->displaySettings($showApiKey, $editApiKey,
1898
- $quotaData, $notice, $resources, $averageCompression, $savedSpace, $savedBandwidth, $remainingImages,
1899
- $totalCallsMade, $fileCount, null /*folder size now on AJAX*/, $customFolders,
1900
- $folderMsg, $folderMsg ? $addedFolder : false, isset($_POST['saveAdv']));
1901
- } else {
1902
- $this->view->displaySettings($showApiKey, $editApiKey, $quotaData, $notice);
1903
- }
1904
-
1905
- }
1906
-
1907
- public function addNextGenGalleriesToCustom($silent) {
1908
- $customFolders = array();
1909
- $folderMsg = "";
1910
- if($this->_settings->includeNextGen) {
1911
- //add the NextGen galleries to custom folders
1912
- $ngGalleries = ShortPixelNextGenAdapter::getGalleries();
1913
- foreach($ngGalleries as $gallery) {
1914
- $folderMsg = $this->spMetaDao->newFolderFromPath($gallery, get_home_path(), self::getCustomFolderBase());
1915
- $this->_settings->hasCustomFolders = true;
1916
- }
1917
- $customFolders = $this->spMetaDao->getFolders();
1918
- }
1919
- return array("message" => $silent? "" : $folderMsg, "customFolders" => $customFolders);
1920
- }
1921
-
1922
- public function getAverageCompression(){
1923
- return $this->_settings->totalOptimized > 0
1924
- ? round(( 1 - ( $this->_settings->totalOptimized / $this->_settings->totalOriginal ) ) * 100, 2)
1925
- : 0;
1926
- }
1927
-
1928
- /**
1929
- *
1930
- * @param type $apiKey
1931
- * @param type $appendUserAgent
1932
- * @param type $validate - true if we are validating the api key, send also the domain name and number of pics
1933
- * @return type
1934
- */
1935
- public function getQuotaInformation($apiKey = null, $appendUserAgent = false, $validate = false) {
1936
-
1937
- if(is_null($apiKey)) { $apiKey = $this->_settings->apiKey; }
1938
-
1939
- if($this->_settings->httpProto != 'https' && $this->_settings->httpProto != 'http') {
1940
- $this->_settings->httpProto = 'https';
1941
- }
1942
-
1943
- $requestURL = $this->_settings->httpProto . '://api.shortpixel.com/v2/api-status.php';
1944
- $args = array(
1945
- 'timeout'=> SP_VALIDATE_MAX_TIMEOUT,
1946
- 'body' => array('key' => $apiKey)
1947
- );
1948
- $argsStr = "?key=".$apiKey;
1949
-
1950
- if($appendUserAgent) {
1951
- $args['body']['useragent'] = "Agent" . urlencode($_SERVER['HTTP_USER_AGENT']);
1952
- $argsStr .= "&useragent=Agent".$args['body']['useragent'];
1953
- }
1954
- if($validate) {
1955
- $args['body']['DomainCheck'] = get_site_url();
1956
- $args['body']['Info'] = get_bloginfo('version') . '|' . phpversion();
1957
- $imageCount = WpShortPixelMediaLbraryAdapter::countAllProcessableFiles($this->_settings->optimizePdfs);
1958
- $args['body']['ImagesCount'] = $imageCount['mainFiles'];
1959
- $args['body']['ThumbsCount'] = $imageCount['totalFiles'] - $imageCount['mainFiles'];
1960
- $argsStr .= "&DomainCheck={$args['body']['DomainCheck']}&Info={$args['body']['Info']}&ImagesCount={$imageCount['mainFiles']}&ThumbsCount={$args['body']['ThumbsCount']}";
1961
- }
1962
- if(strlen($this->_settings->siteAuthUser)) {
1963
- $args['body']['url'] = parse_url(get_site_url(),PHP_URL_HOST);
1964
- $args['body']['user'] = $this->_settings->siteAuthUser;
1965
- $args['body']['pass'] = urlencode($this->_settings->siteAuthPass);
1966
- $argsStr .= "&url={$args['body']['url']}&user={$args['body']['user']}&pass={$args['body']['pass']}";
1967
- }
1968
-
1969
- $comm = array();
1970
-
1971
- //Try first HTTPS post. add the sslverify = false if https
1972
- if($this->_settings->httpProto === 'https') {
1973
- $args['sslverify'] = false;
1974
- }
1975
- $response = wp_remote_post($requestURL, $args);
1976
- $comm[] = array("sent" => "POST: " . $requestURL, "args" => $args, "received" => $response);
1977
-
1978
- //some hosting providers won't allow https:// POST connections so we try http:// as well
1979
- if(is_wp_error( $response )) {
1980
- //echo("protocol " . $this->_settings->httpProto . " failed. switching...");
1981
- $requestURL = $this->_settings->httpProto == 'https' ?
1982
- str_replace('https://', 'http://', $requestURL) :
1983
- str_replace('http://', 'https://', $requestURL);
1984
- // add or remove the sslverify
1985
- if($this->_settings->httpProto === 'http') {
1986
- $args['sslverify'] = false;
1987
- } else {
1988
- unset($args['sslverify']);
1989
- }
1990
- $response = wp_remote_post($requestURL, $args);
1991
- $comm[] = array("sent" => "POST: " . $requestURL, "args" => $args, "received" => $response);
1992
-
1993
- if(!is_wp_error( $response )){
1994
- $this->_settings->httpProto = ($this->_settings->httpProto == 'https' ? 'http' : 'https');
1995
- //echo("protocol " . $this->_settings->httpProto . " succeeded");
1996
- } else {
1997
- //echo("protocol " . $this->_settings->httpProto . " failed too");
1998
- }
1999
- }
2000
- //Second fallback to HTTP get
2001
- if(is_wp_error( $response )){
2002
- $args['body'] = null;
2003
- $requestURL .= $argsStr;
2004
- $response = wp_remote_get($requestURL, $args);
2005
- $comm[] = array("sent" => "POST: " . $requestURL, "args" => $args, "received" => $response);
2006
- }
2007
-
2008
- $defaultData = array(
2009
- "APIKeyValid" => false,
2010
- "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. ','shortpixel-image-optimiser'),
2011
- "APICallsMade" => __('Information unavailable. Please check your API key.','shortpixel-image-optimiser'),
2012
- "APICallsQuota" => __('Information unavailable. Please check your API key.','shortpixel-image-optimiser'),
2013
- "DomainCheck" => 'NOT Accessible');
2014
-
2015
- if(is_object($response) && get_class($response) == 'WP_Error') {
2016
-
2017
- $urlElements = parse_url($requestURL);
2018
- $portConnect = @fsockopen($urlElements['host'],8,$errno,$errstr,15);
2019
- if(!$portConnect) {
2020
- $defaultData['Message'] .= "<BR>Debug info: <i>$errstr</i>";
2021
- }
2022
- return $defaultData;
2023
- }
2024
-
2025
- if($response['response']['code'] != 200) {
2026
- //$defaultData['Message'] .= "<BR><i>Debug info: response code {$response['response']['code']} URL $requestURL , Response ".json_encode($response)."</i>";
2027
- return $defaultData;
2028
- }
2029
-
2030
- $data = $response['body'];
2031
- $data = ShortPixelTools::parseJSON($data);
2032
-
2033
- if(empty($data)) { return $defaultData; }
2034
-
2035
- if($data->Status->Code != 2) {
2036
- $defaultData['Message'] = $data->Status->Message;
2037
- return $defaultData;
2038
- }
2039
-
2040
- if ( ( $data->APICallsMade + $data->APICallsMadeOneTime ) < ( $data->APICallsQuota + $data->APICallsQuotaOneTime ) ) //reset quota exceeded flag -> user is allowed to process more images.
2041
- $this->resetQuotaExceeded();
2042
- else
2043
- $this->_settings->quotaExceeded = 1;//activate quota limiting
2044
-
2045
- //if a non-valid status exists, delete it
2046
- $lastStatus = $this->_settings->bulkLastStatus = null;
2047
- if($lastStatus && $lastStatus['Status'] == ShortPixelAPI::STATUS_NO_KEY) {
2048
- $this->_settings->bulkLastStatus = null;
2049
- }
2050
-
2051
- return array(
2052
- "APIKeyValid" => true,
2053
- "APICallsMade" => number_format($data->APICallsMade) . __(' images','shortpixel-image-optimiser'),
2054
- "APICallsQuota" => number_format($data->APICallsQuota) . __(' images','shortpixel-image-optimiser'),
2055
- "APICallsMadeOneTime" => number_format($data->APICallsMadeOneTime) . __(' images','shortpixel-image-optimiser'),
2056
- "APICallsQuotaOneTime" => number_format($data->APICallsQuotaOneTime) . __(' images','shortpixel-image-optimiser'),
2057
- "APICallsMadeNumeric" => $data->APICallsMade,
2058
- "APICallsQuotaNumeric" => $data->APICallsQuota,
2059
- "APICallsMadeOneTimeNumeric" => $data->APICallsMadeOneTime,
2060
- "APICallsQuotaOneTimeNumeric" => $data->APICallsQuotaOneTime,
2061
- "APICallsRemaining" => $data->APICallsQuota + $data->APICallsQuotaOneTime - $data->APICallsMade - $data->APICallsMadeOneTime,
2062
- "APILastRenewalDate" => $data->DateSubscription,
2063
- "DomainCheck" => (isset($data->DomainCheck) ? $data->DomainCheck : null)
2064
- );
2065
- }
2066
-
2067
- public function resetQuotaExceeded() {
2068
- if( $this->_settings->quotaExceeded == 1) {
2069
- $dismissed = $this->_settings->dismissedNotices ? $this->_settings->dismissedNotices : array();
2070
- unset($dismissed['exceed']);
2071
- $this->_settings->dismissedNotices = $dismissed;
2072
- }
2073
- $this->_settings->quotaExceeded = 0;
2074
- }
2075
-
2076
- public function generateCustomColumn( $column_name, $id, $extended = false ) {
2077
- if( 'wp-shortPixel' == $column_name ) {
2078
-
2079
- $file = get_attached_file($id);
2080
- if(!self::isProcessablePath($file)) {
2081
- $renderData['status'] = 'n/a';
2082
- $this->view->renderCustomColumn($id, $renderData, $extended);
2083
- return;
2084
- }
2085
-
2086
- $data = wp_get_attachment_metadata($id);
2087
- $fileExtension = strtolower(pathinfo($file, PATHINFO_EXTENSION));
2088
- $invalidKey = !$this->_settings->verifiedKey;
2089
- $quotaExceeded = $this->_settings->quotaExceeded;
2090
- $renderData = array("id" => $id, "showActions" => (current_user_can( 'manage_options' ) || current_user_can( 'upload_files' ) || current_user_can( 'edit_posts' )));
2091
-
2092
- if($invalidKey) { //invalid key - let the user first register and only then
2093
- $renderData['status'] = 'invalidKey';
2094
- $this->view->renderCustomColumn($id, $renderData, $extended);
2095
- return;
2096
- }
2097
-
2098
- //empty data means document, we handle only PDF
2099
- elseif (empty($data)) { //TODO asta devine if si decomentam returnurile
2100
- if($fileExtension == "pdf") {
2101
- $renderData['status'] = $quotaExceeded ? 'quotaExceeded' : 'optimizeNow';
2102
- $renderData['message'] = __('PDF not processed.','shortpixel-image-optimiser');
2103
- }
2104
- else { //Optimization N/A
2105
- $renderData['status'] = 'n/a';
2106
- }
2107
- $this->view->renderCustomColumn($id, $renderData, $extended);
2108
- return;
2109
- }
2110
-
2111
- if(!isset($data['ShortPixelImprovement'])) { //new image
2112
- $data['ShortPixelImprovement'] = '';
2113
- }
2114
-
2115
- if(is_numeric($data['ShortPixelImprovement'])) { //already optimized
2116
- $sizesCount = isset($data['sizes']) ? WpShortPixelMediaLbraryAdapter::countNonWebpSizes($data['sizes']) : 0;
2117
-
2118
- $renderData['status'] = $fileExtension == "pdf" ? 'pdfOptimized' : 'imgOptimized';
2119
- $renderData['percent'] = $data['ShortPixelImprovement'];
2120
- $renderData['bonus'] = ($data['ShortPixelImprovement'] < 5);
2121
- $renderData['backup'] = $this->getBackupFolderAny(get_attached_file($id), $sizesCount? $data['sizes'] : array());
2122
- $renderData['type'] = isset($data['ShortPixel']['type']) ? $data['ShortPixel']['type'] : '';
2123
- $renderData['thumbsTotal'] = $sizesCount;
2124
- $renderData['thumbsOpt'] = isset($data['ShortPixel']['thumbsOpt']) ? $data['ShortPixel']['thumbsOpt'] : $sizesCount;
2125
- $renderData['thumbsMissing'] = isset($data['ShortPixel']['thumbsMissing']) ? $data['ShortPixel']['thumbsMissing'] : array();
2126
- $renderData['retinasOpt'] = isset($data['ShortPixel']['retinasOpt']) ? $data['ShortPixel']['retinasOpt'] : null;
2127
- $renderData['exifKept'] = isset($data['ShortPixel']['exifKept']) ? $data['ShortPixel']['exifKept'] : null;
2128
- $renderData['date'] = isset($data['ShortPixel']['date']) ? $data['ShortPixel']['date'] : null;
2129
- $renderData['quotaExceeded'] = $quotaExceeded;
2130
- $webP = 0;
2131
- if($extended) {
2132
- if(file_exists(dirname($file) . '/' . basename($file, '.'.$fileExtension) . '.webp' )){
2133
- $webP++;
2134
- }
2135
- if(isset($data['sizes'])) {
2136
- foreach($data['sizes'] as $key => $size) {
2137
- if (strpos($key, ShortPixelMeta::WEBP_THUMB_PREFIX) === 0) continue;
2138
- $sizeName = $size['file'];
2139
- if(file_exists(dirname($file) . '/' . basename($sizeName, '.'.$fileExtension) . '.webp' )){
2140
- $webP++;
2141
- }
2142
- }
2143
- }
2144
- }
2145
- $renderData['webpCount'] = $webP;
2146
- }
2147
- elseif($data['ShortPixelImprovement'] == __('Optimization N/A','shortpixel-image-optimiser')) { //We don't optimize this
2148
- if('pdf' === $fileExtension && $this->_settings->optimizePdfs) {
2149
- $renderData['status'] = $quotaExceeded ? 'quotaExceeded' : 'optimizeNow';
2150
- $renderData['message'] = 'PDF not processed.';
2151
- } else {
2152
- $renderData['status'] = 'n/a';
2153
- }
2154
- }
2155
- elseif(isset($meta['ShortPixel']['BulkProcessing'])) { //Scheduled to bulk.
2156
- $renderData['status'] = $quotaExceeded ? 'quotaExceeded' : 'optimizeNow';
2157
- $renderData['message'] = 'Waiting for bulk processing.';
2158
- }
2159
- elseif( trim(strip_tags($data['ShortPixelImprovement'])) == __("Cannot write optimized file",'shortpixel-image-optimiser') ) {
2160
- $renderData['status'] = $quotaExceeded ? 'quotaExceeded' : 'retry';
2161
- $renderData['message'] = __("Cannot write optimized file",'shortpixel-image-optimiser') . " - <a href='https://shortpixel.com/faq#cannot-write-optimized-file' target='_blank'>"
2162
- . __("Why?",'shortpixel-image-optimiser') . "</a>";
2163
- }
2164
- elseif( strlen(trim(strip_tags($data['ShortPixelImprovement']))) > 0 ) {
2165
- $renderData['status'] = $quotaExceeded ? 'quotaExceeded' : 'retry';
2166
- $renderData['message'] = $data['ShortPixelImprovement'];
2167
- if(strpos($renderData['message'], __('The file(s) do not exist on disk: ','shortpixel-image-optimiser')) !== false) {
2168
- $renderData['cleanup'] = true;
2169
- }
2170
- }
2171
- elseif(isset($data['ShortPixel']['NoFileOnDisk'])) {
2172
- $renderData['status'] = 'notFound';
2173
- $renderData['message'] = __('Image does not exist','shortpixel-image-optimiser');
2174
- }
2175
- elseif(isset($data['ShortPixel']['WaitingProcessing'])) {
2176
- $renderData['status'] = $quotaExceeded ? 'quotaExceeded' : 'retry';
2177
- $renderData['message'] = "<img src=\"" . plugins_url( 'res/img/loading.gif', __FILE__ ) . "\" class='sp-loading-small'>&nbsp;" . __("Image waiting to be processed.",'shortpixel-image-optimiser');
2178
- if($id > $this->prioQ->getFlagBulkId() || !$this->prioQ->bulkRunning()) $this->prioQ->push($id); //should be there but just to make sure
2179
- }
2180
- else { //finally
2181
- $renderData['status'] = $quotaExceeded ? 'quotaExceeded' : 'optimizeNow';
2182
- $sizes = isset($data['sizes']) ? WpShortPixelMediaLbraryAdapter::countNonWebpSizes($data['sizes']) : 0;
2183
- $renderData['thumbsTotal'] = $sizes;
2184
- $renderData['message'] = ($fileExtension == "pdf" ? 'PDF' : 'Image') . ' not processed.';
2185
- }
2186
-
2187
- $this->view->renderCustomColumn($id, $renderData, $extended);
2188
- }
2189
- }
2190
-
2191
- function shortpixelInfoBox() {
2192
- if(get_post_type( ) == 'attachment') {
2193
- add_meta_box(
2194
- 'shortpixel_info_box', // this is HTML id of the box on edit screen
2195
- __('ShortPixel Info', 'shortpixel-image-optimiser'), // title of the box
2196
- array( &$this, 'shortpixelInfoBoxContent'), // function to be called to display the info
2197
- null,//, // on which edit screen the box should appear
2198
- 'side'//'normal', // part of page where the box should appear
2199
- //'default' // priority of the box
2200
- );
2201
- }
2202
- }
2203
-
2204
- function shortpixelInfoBoxContent( $post ) {
2205
- $this->generateCustomColumn( 'wp-shortPixel', $post->ID, true );
2206
- }
2207
-
2208
- function onDeleteImage($post_id) {
2209
- $itemHandler = new ShortPixelMetaFacade($post_id);
2210
- $urlsPaths = $itemHandler->getURLsAndPATHs(true, false, false);
2211
- foreach($urlsPaths['PATHs'] as $path) {
2212
- $pos = strrpos($path, ".");
2213
- if ($pos !== false) {
2214
- //$webpPath = substr($path, 0, $pos) . ".webp";
2215
- //echo($webpPath . "<br>");
2216
- @unlink(substr($path, 0, $pos) . ".webp");
2217
- @unlink(substr($path, 0, $pos) . "@2x.webp");
2218
- }
2219
- }
2220
- }
2221
-
2222
- public function columns( $defaults ) {
2223
- $defaults['wp-shortPixel'] = 'ShortPixel Compression';
2224
- if(current_user_can( 'manage_options' )) {
2225
- $defaults['wp-shortPixel'] .= '&nbsp;<a href="options-general.php?page=wp-shortpixel#stats" title="'
2226
- . __('ShortPixel Statistics','shortpixel-image-optimiser') . '"><span class="dashicons dashicons-dashboard"></span></a>';
2227
- }
2228
- return $defaults;
2229
- }
2230
-
2231
- public function nggColumns( $defaults ) {
2232
- $this->nggColumnIndex = count($defaults) + 1;
2233
- add_filter( 'ngg_manage_images_column_' . $this->nggColumnIndex . '_header', array( &$this, 'nggColumnHeader' ) );
2234
- add_filter( 'ngg_manage_images_column_' . $this->nggColumnIndex . '_content', array( &$this, 'nggColumnContent' ), 10, 2 );
2235
- $defaults['wp-shortPixelNgg'] = 'ShortPixel Compression';
2236
- return $defaults;
2237
- }
2238
-
2239
- public function nggCountColumns( $count ) {
2240
- return $count + 1;
2241
- }
2242
-
2243
- public function nggColumnHeader( $default ) {
2244
- return __('ShortPixel Compression','shortpixel-image-optimiser');
2245
- }
2246
-
2247
- public function nggColumnContent( $unknown, $picture ) {
2248
-
2249
- $meta = $this->spMetaDao->getMetaForPath($picture->imagePath);
2250
- if($meta) {
2251
- switch($meta->getStatus()) {
2252
- case "0": echo("<div id='sp-msg-C-{$meta->getId()}' class='column-wp-shortPixel' style='color: #928B1E'>Waiting</div>"); break;
2253
- case "1": echo("<div id='sp-msg-C-{$meta->getId()}' class='column-wp-shortPixel' style='color: #1919E2'>Pending</div>"); break;
2254
- case "2": $this->view->renderCustomColumn("C-" . $meta->getId(), array(
2255
- 'showActions' => false && current_user_can( 'manage_options' ),
2256
- 'status' => 'imgOptimized',
2257
- 'type' => ShortPixelAPI::getCompressionTypeName($meta->getCompressionType()),
2258
- 'percent' => $meta->getImprovementPercent(),
2259
- 'bonus' => $meta->getImprovementPercent() < 5,
2260
- 'thumbsOpt' => 0,
2261
- 'thumbsTotal' => 0,
2262
- 'retinasOpt' => 0,
2263
- 'backup' => true
2264
- ));
2265
- break;
2266
- }
2267
- } else {
2268
- $this->view->renderCustomColumn($meta ? "C-" . $meta->getId() : "N-" . $picture->pid, array(
2269
- 'showActions' => false && current_user_can( 'manage_options' ),
2270
- 'status' => 'optimizeNow',
2271
- 'thumbsOpt' => 0,
2272
- 'thumbsTotal' => 0,
2273
- 'retinasOpt' => 0,
2274
- 'message' => "Not optimized"
2275
- ));
2276
- }
2277
- // return var_dump($meta);
2278
- }
2279
-
2280
- public function generatePluginLinks($links) {
2281
- $in = '<a href="options-general.php?page=wp-shortpixel">Settings</a>';
2282
- array_unshift($links, $in);
2283
- return $links;
2284
- }
2285
-
2286
- static public function formatBytes($bytes, $precision = 2) {
2287
- $units = array('B', 'KB', 'MB', 'GB', 'TB');
2288
-
2289
- $bytes = max($bytes, 0);
2290
- $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
2291
- $pow = min($pow, count($units) - 1);
2292
-
2293
- $bytes /= pow(1024, $pow);
2294
-
2295
- return round($bytes, $precision) . ' ' . $units[$pow];
2296
- }
2297
-
2298
- static public function isProcessable($ID) {
2299
- $path = get_attached_file($ID);//get the full file PATH
2300
- return $path ? self::isProcessablePath($path) : false;
2301
- }
2302
-
2303
- static public function isProcessablePath($path) {
2304
- $pathParts = pathinfo($path);
2305
- $ext = $pathParts['extension'];
2306
- if( isset($ext) && in_array(strtolower($ext), self::$PROCESSABLE_EXTENSIONS)) {
2307
- return true;
2308
- } else {
2309
- return false;
2310
- }
2311
- }
2312
-
2313
-
2314
- //return an array with URL(s) and PATH(s) for this file
2315
- public function getURLsAndPATHs($itemHandler, $meta = NULL, $onlyThumbs = false) {
2316
- return $itemHandler->getURLsAndPATHs($this->_settings->processThumbnails, $onlyThumbs, $this->_settings->optimizeRetina);
2317
- }
2318
-
2319
-
2320
- public static function deleteDir($dirPath) {
2321
- if (substr($dirPath, strlen($dirPath) - 1, 1) != '/') {
2322
- $dirPath .= '/';
2323
- }
2324
- $files = glob($dirPath . '*', GLOB_MARK);
2325
- foreach ($files as $file) {
2326
- if (is_dir($file)) {
2327
- self::deleteDir($file);
2328
- @rmdir($file);//remove empty dir
2329
- } else {
2330
- @unlink($file);//remove file
2331
- }
2332
- }
2333
- }
2334
-
2335
- static public function folderSize($path) {
2336
- $total_size = 0;
2337
- if(file_exists($path)) {
2338
- $files = scandir($path);
2339
- } else {
2340
- return $total_size;
2341
- }
2342
- $cleanPath = rtrim($path, '/'). '/';
2343
- foreach($files as $t) {
2344
- if ($t<>"." && $t<>"..")
2345
- {
2346
- $currentFile = $cleanPath . $t;
2347
- if (is_dir($currentFile)) {
2348
- $size = self::folderSize($currentFile);
2349
- $total_size += $size;
2350
- }
2351
- else {
2352
- $size = filesize($currentFile);
2353
- $total_size += $size;
2354
- }
2355
- }
2356
- }
2357
- return $total_size;
2358
- }
2359
-
2360
- public function migrateBackupFolder() {
2361
- $oldBackupFolder = WP_CONTENT_DIR . '/' . SP_BACKUP;
2362
-
2363
- if(file_exists($oldBackupFolder)) { //if old backup folder does not exist then there is nothing to do
2364
-
2365
- if(!file_exists(SP_BACKUP_FOLDER)) {
2366
- //we check that the backup folder exists, if not we create it so we can copy into it
2367
- if(!mkdir(SP_BACKUP_FOLDER, 0777, true)) return;
2368
- }
2369
-
2370
- $scannedDirectory = array_diff(scandir($oldBackupFolder), array('..', '.'));
2371
- foreach($scannedDirectory as $file) {
2372
- @rename($oldBackupFolder.'/'.$file, SP_BACKUP_FOLDER.'/'.$file);
2373
- }
2374
- $scannedDirectory = array_diff(scandir($oldBackupFolder), array('..', '.'));
2375
- if(empty($scannedDirectory)) {
2376
- @rmdir($oldBackupFolder);
2377
- }
2378
- }
2379
- //now if the backup folder does not contain the uploads level, create it
2380
- if( !is_dir(SP_BACKUP_FOLDER . '/' . SP_UPLOADS_NAME )
2381
- && !is_dir(SP_BACKUP_FOLDER . '/' . basename(WP_CONTENT_DIR))) {
2382
- @rename(SP_BACKUP_FOLDER, SP_BACKUP_FOLDER."_tmp");
2383
- @mkdir(SP_BACKUP_FOLDER);
2384
- @rename(SP_BACKUP_FOLDER."_tmp", SP_BACKUP_FOLDER.'/'.SP_UPLOADS_NAME);
2385
- if(!file_exists(SP_BACKUP_FOLDER)) {//just in case..
2386
- @rename(SP_BACKUP_FOLDER."_tmp", SP_BACKUP_FOLDER);
2387
- }
2388
- }
2389
- //then create the wp-content level if not present
2390
- if(!is_dir(SP_BACKUP_FOLDER . '/' . basename(WP_CONTENT_DIR))) {
2391
- @rename(SP_BACKUP_FOLDER, SP_BACKUP_FOLDER."_tmp");
2392
- @mkdir(SP_BACKUP_FOLDER);
2393
- @rename(SP_BACKUP_FOLDER."_tmp", SP_BACKUP_FOLDER.'/' . basename(WP_CONTENT_DIR));
2394
- if(!file_exists(SP_BACKUP_FOLDER)) {//just in case..
2395
- @rename(SP_BACKUP_FOLDER."_tmp", SP_BACKUP_FOLDER);
2396
- }
2397
- }
2398
- return;
2399
- }
2400
-
2401
- function getMaxIntermediateImageSize() {
2402
- global $_wp_additional_image_sizes;
2403
-
2404
- $width = 0;
2405
- $height = 0;
2406
- $get_intermediate_image_sizes = get_intermediate_image_sizes();
2407
-
2408
- // Create the full array with sizes and crop info
2409
- foreach( $get_intermediate_image_sizes as $_size ) {
2410
- if ( in_array( $_size, array( 'thumbnail', 'medium', 'large' ) ) ) {
2411
- $width = max($width, get_option( $_size . '_size_w' ));
2412
- $height = max($height, get_option( $_size . '_size_h' ));
2413
- //$sizes[ $_size ]['crop'] = (bool) get_option( $_size . '_crop' );
2414
- } elseif ( isset( $_wp_additional_image_sizes[ $_size ] ) ) {
2415
- $width = max($width, $_wp_additional_image_sizes[ $_size ]['width']);
2416
- $height = max($height, $_wp_additional_image_sizes[ $_size ]['height']);
2417
- //'crop' => $_wp_additional_image_sizes[ $_size ]['crop']
2418
- }
2419
- }
2420
- return array('width' => $width, 'height' => $height);
2421
- }
2422
-
2423
- /* public function getEncryptedData() {
2424
- return base64_encode(self::encrypt($this->getApiKey() . "|" . get_site_url(), "sh0r+Pix3l8im1N3r"));
2425
- }
2426
- */
2427
-
2428
- /**
2429
- * Returns an encrypted & utf8-encoded
2430
- */
2431
- /* public static function encrypt($pure_string, $encryption_key)
2432
- {
2433
- if(!function_exists("mcrypt_get_iv_size") || !function_exists('utf8_encode')) {
2434
- return "";
2435
- }
2436
- $iv_size = \mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB);
2437
- $iv = \mcrypt_create_iv($iv_size, MCRYPT_RAND);
2438
- $encrypted_string = \mcrypt_encrypt(MCRYPT_BLOWFISH, $encryption_key, utf8_encode($pure_string), MCRYPT_MODE_ECB, $iv);
2439
- return $encrypted_string;
2440
- }
2441
- */
2442
-
2443
- public function getApiKey() {
2444
- return $this->_settings->apiKey;
2445
- }
2446
-
2447
- public function getPrioQ() {
2448
- return $this->prioQ;
2449
- }
2450
-
2451
- public function backupImages() {
2452
- return $this->_settings->backupImages;
2453
- }
2454
-
2455
- public function processThumbnails() {
2456
- return $this->_settings->processThumbnails;
2457
- }
2458
-
2459
- public function getCMYKtoRGBconversion() {
2460
- return $this->_settings->CMYKtoRGBconversion;
2461
- }
2462
-
2463
- public function getSettings() {
2464
- return $this->_settings;
2465
- }
2466
-
2467
- public function getResizeImages() {
2468
- return $this->_settings->resizeImages;
2469
- }
2470
-
2471
- public function getResizeWidth() {
2472
- return $this->_settings->resizeWidth;
2473
- }
2474
-
2475
- public function getResizeHeight() {
2476
- return $this->_settings->resizeHeight;
2477
- }
2478
- public function getAffiliateSufix() {
2479
- return $this->_affiliateSufix;
2480
- }
2481
- public function getVerifiedKey() {
2482
- return $this->_settings->verifiedKey;
2483
- }
2484
- public function getCompressionType() {
2485
- return $this->_settings->compressionType;
2486
- }
2487
- public function hasNextGen() {
2488
- return $this->hasNextGen;
2489
- }
2490
-
2491
- public function getSpMetaDao() {
2492
- return $this->spMetaDao;
2493
- }
2494
-
2495
- }
2496
-
2497
-
2498
  function shortpixelInit() {
2499
  global $pluginInstance;
2500
  //is admin, is logged in - :) seems funny but it's not, ajax scripts are admin even if no admin is logged in.
@@ -2510,6 +61,7 @@ function shortpixelInit() {
2510
  )
2511
  )
2512
  {
 
2513
  $pluginInstance = new WPShortPixel;
2514
  }
2515
  }
@@ -2517,6 +69,7 @@ function shortpixelInit() {
2517
  function handleImageUploadHook($meta, $ID = null) {
2518
  global $pluginInstance;
2519
  if(!isset($pluginInstance)) {
 
2520
  $pluginInstance = new WPShortPixel;
2521
  }
2522
  return $pluginInstance->handleMediaLibraryImageUpload($meta, $ID);
@@ -2525,6 +78,7 @@ function handleImageUploadHook($meta, $ID = null) {
2525
  function shortpixelNggAdd($image) {
2526
  global $pluginInstance;
2527
  if(!isset($pluginInstance)) {
 
2528
  $pluginInstance = new WPShortPixel;
2529
  }
2530
  $pluginInstance->handleNextGenImageUpload($image);
@@ -2543,4 +97,4 @@ if ( !function_exists( 'vc_action' ) || vc_action() !== 'vc_inline' ) { //handle
2543
  register_deactivation_hook( __FILE__, array( 'WPShortPixel', 'shortPixelDeactivatePlugin' ) );
2544
 
2545
  }
2546
- ?>
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 &gt; ShortPixel</a> page on how to start optimizing your image library and make your website load faster.
6
+ * Version: 4.2.8
7
  * Author: ShortPixel
8
  * Author URI: https://shortpixel.com
9
  * Text Domain: shortpixel-image-optimiser
14
 
15
  //define('SHORTPIXEL_DEBUG', true);
16
 
17
+ define('SHORTPIXEL_PLUGIN_FILE', __FILE__);
18
+
19
  define('SP_AFFILIATE_CODE', '');
20
 
21
+ define('PLUGIN_VERSION', "4.2.8");
22
  define('SP_MAX_TIMEOUT', 10);
23
  define('SP_VALIDATE_MAX_TIMEOUT', 15);
24
  define('SP_BACKUP', 'ShortpixelBackups');
46
  define('MAX_EXECUTION_TIME', 2 );
47
  define("SP_MAX_RESULTS_QUERY", 6);
48
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
  function shortpixelInit() {
50
  global $pluginInstance;
51
  //is admin, is logged in - :) seems funny but it's not, ajax scripts are admin even if no admin is logged in.
61
  )
62
  )
63
  {
64
+ require_once('wp-shortpixel-req.php');
65
  $pluginInstance = new WPShortPixel;
66
  }
67
  }
69
  function handleImageUploadHook($meta, $ID = null) {
70
  global $pluginInstance;
71
  if(!isset($pluginInstance)) {
72
+ require_once('wp-shortpixel-req.php');
73
  $pluginInstance = new WPShortPixel;
74
  }
75
  return $pluginInstance->handleMediaLibraryImageUpload($meta, $ID);
78
  function shortpixelNggAdd($image) {
79
  global $pluginInstance;
80
  if(!isset($pluginInstance)) {
81
+ require_once('wp-shortpixel-req.php');
82
  $pluginInstance = new WPShortPixel;
83
  }
84
  $pluginInstance->handleNextGenImageUpload($image);
97
  register_deactivation_hook( __FILE__, array( 'WPShortPixel', 'shortPixelDeactivatePlugin' ) );
98
 
99
  }
100
+ ?>