PluginProbe ʕ •ᴥ•ʔ
ShortPixel Image Optimizer – Optimize Images, Convert WebP & AVIF / 6.5.3
ShortPixel Image Optimizer – Optimize Images, Convert WebP & AVIF v6.5.3
6.5.3 6.5.2 6.5.1 trunk 1.0 1.0.1 1.0.2 1.0.3 1.0.4 1.0.6 1.2.0 1.3.1 1.3.5 1.4.0 1.4.1 1.5.0 1.5.3 1.6.0 1.6.1 1.6.10 1.6.2 1.6.3 1.6.4 1.6.6 1.6.7 1.6.8 1.6.9 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8 2.0.9 2.1.0 2.1.1 2.1.10 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.1.9 3.0.0 3.0.2 3.0.3 3.0.5 3.0.6 3.0.7 3.0.8 3.1.0 3.1.1 3.1.2 3.1.3 3.1.4 3.1.5 3.1.6 3.1.7 3.1.8 3.1.9 3.2.0 3.2.1 3.3.0 3.3.1 3.3.2 3.3.3 3.3.4 3.3.5 3.3.6 3.3.7 3.3.8 4.0.0 4.0.1 4.0.2 4.1.0 4.1.1 4.1.2 4.1.3 4.1.4 4.1.5 4.1.7 4.10.0 4.10.1 4.10.2 4.10.3 4.10.4 4.10.5 4.11.0 4.11.1 4.11.2 4.11.3 4.12.0 4.12.1 4.12.2 4.12.3 4.12.4 4.12.5 4.12.6 4.12.7 4.12.8 4.13.0 4.13.1 4.14.0 4.14.1 4.14.2 4.14.3 4.14.4 4.14.5 4.14.6 4.15.0 4.15.1 4.15.2 4.15.3 4.15.4 4.16.0 4.16.1 4.16.2 4.16.3 4.16.4 4.17.0 4.17.1 4.17.2 4.17.3 4.17.4 4.18.0 4.18.1 4.19.0 4.19.1 4.19.2 4.19.3 4.2.0 4.2.1 4.2.2 4.2.4 4.2.5 4.2.6 4.2.7 4.2.8 4.2.9 4.20.0 4.20.1 4.20.2 4.21.0 4.21.1 4.21.2 4.22.0 4.22.1 4.22.10 4.22.2 4.22.3 4.22.4 4.22.5 4.22.6 4.22.7 4.22.8 4.22.9 4.3.0 4.3.1 4.4.0 4.4.1 4.4.2 4.5.0 4.5.1 4.5.2 4.5.3 4.5.5 4.6.0 4.7.0 4.7.1 4.7.2 4.8.0 4.8.1 4.8.2 4.8.4 4.8.5 4.8.6 4.8.7 4.8.8 4.8.9 4.9.0 4.9.1 5.0.0 5.0.1 5.0.2 5.0.3 5.0.4 5.0.5 5.0.6 5.0.7 5.0.8 5.0.9 5.1.0 5.1.1 5.1.2 5.1.3 5.1.4 5.1.5 5.1.6 5.2.0 5.2.1 5.2.2 5.2.3 5.3.0 5.4.0 5.4.1 5.4.2 5.4.3 5.5.0 5.5.1 5.5.2 5.5.3 5.5.4 5.5.5 5.6.0 5.6.1 5.6.2 5.6.3 5.6.4 6.0.0 6.0.1 6.0.2 6.0.3 6.0.4 6.0.5 6.1.0 6.1.1 6.1.2 6.1.3 6.1.4 6.2.0 6.2.1 6.2.2 6.3.0 6.3.1 6.3.2 6.3.3 6.3.4 6.3.5 6.4.0 6.4.1 6.4.2 6.4.3 6.4.4 6.5.0
shortpixel-image-optimiser / shortpixel-plugin.php
shortpixel-image-optimiser Last commit date
build 6 days ago class 6 days ago res 1 month ago changelog.txt 1 month ago readme.txt 6 days ago shortpixel-plugin.php 1 month ago wp-shortpixel.php 6 days ago
shortpixel-plugin.php
801 lines
1 <?php
2 namespace ShortPixel;
3
4 if ( ! defined( 'ABSPATH' ) ) {
5 exit; // Exit if accessed directly.
6 }
7
8 use ShortPixel\ShortPixelLogger\ShortPixelLogger as Log;
9 use ShortPixel\Notices\NoticeController as Notices;
10 use ShortPixel\Controller\QueueController as QueueController;
11 use ShortPixel\Controller\QuotaController as QuotaController;
12 use ShortPixel\Controller\AjaxController as AjaxController;
13 use ShortPixel\Controller\AdminController as AdminController;
14 use ShortPixel\Controller\ImageEditorController as ImageEditorController;
15 use ShortPixel\Controller\ApiKeyController as ApiKeyController;
16 use ShortPixel\Controller\FileSystemController;
17 use ShortPixel\Controller\Optimizer\OptimizeAiController;
18 use ShortPixel\Controller\OtherMediaController as OtherMediaController;
19 use ShortPixel\NextGenController as NextGenController;
20
21 use ShortPixel\Controller\Queue\MediaLibraryQueue as MediaLibraryQueue;
22 use ShortPixel\Controller\Queue\CustomQueue as CustomQueue;
23 use ShortPixel\Controller\View\OtherMediaViewController;
24 use ShortPixel\Helper\InstallHelper as InstallHelper;
25 use ShortPixel\Helper\UiHelper as UiHelper;
26
27 use ShortPixel\Model\AccessModel as AccessModel;
28 use ShortPixel\Model\SettingsModel as SettingsModel;
29
30 /** Plugin class
31 * This class is meant for: WP Hooks, init of runtime and Controller Routing.
32 */
33 class ShortPixelPlugin {
34
35
36 private static $instance;
37 protected static $modelsLoaded = array(); // don't require twice, limit amount of require looksups..
38
39 protected $is_noheaders = false;
40
41 protected $plugin_path;
42 protected $plugin_url;
43
44 protected $shortPixel; // shortpixel megaclass
45
46 protected $admin_pages = array(); // admin page hooks.
47
48 public function __construct() {
49 // $this->initHooks();
50 add_action( 'plugins_loaded', [$this, 'lowInit'], 5 ); // early as possible init.
51
52 }
53
54 /** LowInit after all Plugins are loaded. Core WP function can still be missing. This should mostly add hooks */
55 public function lowInit() {
56
57 $this->plugin_path = plugin_dir_path( SHORTPIXEL_PLUGIN_FILE );
58 $this->plugin_url = plugin_dir_url( SHORTPIXEL_PLUGIN_FILE );
59
60 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- This is not a form
61 if ( isset( $_REQUEST['noheader'] ) ) {
62 $this->is_noheaders = true;
63 }
64
65 /*
66 Filter to prevent SPIO from starting. This can be used by third-parties to prevent init when needed for a particular situation.
67 * Hook into plugins_loaded with priority lower than 5 */
68 $init = apply_filters( 'shortpixel/plugin/init', true );
69
70 if (false === $init ) {
71 return;
72 }
73
74
75 $front = new Controller\FrontController(); // init front checkers
76 $admin = Controller\AdminController::getInstance();
77 $adminNotices = Controller\AdminNoticesController::getInstance(); // Hook in the admin notices.
78
79 // $this->initHooks();
80 $this->ajaxHooks();
81
82 if ( defined( 'WP_CLI' ) && \WP_CLI ) {
83 WPCliController::getInstance();
84 }
85
86 add_action ('init', [$this, 'init']);
87 add_action('init', [$this, 'initHooks']);
88 add_action( 'admin_init', [ $this, 'admin_init' ] );
89 }
90
91 public function init()
92 {
93 Controller\CronController::getInstance(); // cron jobs - must be init to function!
94
95 $access = AccessModel::getInstance();
96
97 $isAdminUser = $access->userIsAllowed('is_admin_user');
98
99 if ( $isAdminUser ) {
100 // toolbar notifications
101
102 // deactivate conflicting plugins if found
103 add_action( 'admin_post_shortpixel_deactivate_conflict_plugin', array( '\ShortPixel\Helper\InstallHelper', 'deactivateConflictingPlugin' ) );
104
105 // only if the key is not yet valid or the user hasn't bought any credits.
106 // @todo This should not be done here.
107 $settings = $this->settings();
108 $stats = $settings->currentStats;
109 $totalCredits = isset( $stats['APICallsQuotaNumeric'] ) ? $stats['APICallsQuotaNumeric'] + $stats['APICallsQuotaOneTimeNumeric'] : 0;
110 $keyControl = ApiKeyController::getInstance();
111
112
113 if ( true || false === $keyControl->keyIsVerified() || $totalCredits < 4000 ) {
114 require_once 'class/view/shortpixel-feedback.php';
115 new ShortPixelFeedback( SHORTPIXEL_PLUGIN_FILE, 'shortpixel-image-optimiser' );
116 }
117 }
118
119 }
120
121
122 /** Mainline Admin Init. Tasks that can be loaded later should go here */
123 public function admin_init() {
124 // This runs activation thing. Should be -after- init
125 $this->check_plugin_version();
126
127
128 $notices = Notices::getInstance(); // This hooks the ajax listener
129 $quotaController = QuotaController::getInstance();
130 $quotaController->getQuota();
131 }
132
133 /** Function to get plugin settings
134 *
135 * @return SettingsModel The settings model object.
136 */
137 public function settings() {
138 return SettingsModel::getInstance();
139 }
140
141 /** Function to get all enviromental variables
142 *
143 * @return EnvironmentModel
144 */
145 public function env() {
146 return Model\EnvironmentModel::getInstance();
147 }
148
149 /** Get the SPIO FileSystemController
150 *
151 * @return FileSystemController
152 */
153 public function fileSystem() {
154 return new Controller\FileSystemController();
155 }
156
157 /** Create instance. This should not be needed to call anywhere else than main plugin file
158 * This should not be called *after* plugins_loaded action
159 **/
160 public static function getInstance() {
161 if ( is_null( self::$instance ) ) {
162 self::$instance = new ShortPixelPlugin();
163 }
164 return self::$instance;
165
166 }
167
168 /** Hooks for all WordPress related hooks
169 * For now hooks in the lowInit, asap.
170 */
171 public function initHooks() {
172
173 add_action( 'admin_menu', array( $this, 'admin_pages' ) );
174 add_action( 'admin_enqueue_scripts', array( $this, 'admin_scripts' ) ); // admin scripts
175 add_action( 'admin_enqueue_scripts', array( $this, 'admin_styles' ) ); // admin styles
176 add_action( 'admin_enqueue_scripts', array( $this, 'load_admin_scripts' ), 90 ); // loader via route.
177 add_action( 'enqueue_block_assets', array($this, 'load_admin_scripts'), 90);
178
179 // defer notices a little to allow other hooks ( notable adminnotices )
180
181 $queueController = new QueueController();
182 add_action( 'shortpixel-thumbnails-regenerated', array( $queueController, 'thumbnailsChangedHookLegacy' ), 10, 4 );
183 add_action( 'rta/image/thumbnails_regenerated', array( $queueController, 'thumbnailsChangedHook' ), 10, 2 );
184 add_action( 'rta/image/thumbnails_removed', array( $queueController, 'thumbnailsChangedHook' ), 10, 2 );
185 add_action('rta/image/scaled_image_regenerated', array($queueController, 'scaledImageChangedHook'), 10, 2);
186
187
188 // Media Library - Actions to route screen
189 add_action( 'load-upload.php', array( $this, 'route' ) );
190 add_action( 'load-post.php', array( $this, 'route' ) );
191
192 $admin = AdminController::getInstance();
193 $imageEditor = ImageEditorController::getInstance();
194
195 // Handle for EMR
196 add_action( 'wp_handle_replace', array( $admin, 'handleReplaceHook' ) );
197
198 // Action / hook for who wants to use CRON. Please refer to manual / support to prevent loss of credits.
199 add_action( 'shortpixel/hook/processqueue', array( $admin, 'processQueueHook' ) );
200 add_action( 'shortpixel/hook/scancustomfolders', array($admin, 'scanCustomFoldersHook'));
201
202 // Action for media library gallery view
203 //add_filter('attachment_fields_to_edit', array($admin, 'editAttachmentScreen'), 10, 2);
204 add_action('print_media_templates', array($admin, 'printComparer'));
205
206 // Placeholder function for heic and such, return placeholder URL in image to help w/ database replacements after conversion.
207 add_filter('wp_get_attachment_url', array($admin, 'checkPlaceHolder'), 10, 2);
208
209 add_filter('rest_post_dispatch', [$admin, 'checkRestMedia'],10, 3);
210
211 /** When automagically process images when uploaded is on */
212 if ( $this->env()->is_autoprocess ) {
213 // compat filter to shortcircuit this in cases. (see external - visualcomposer)
214 if ( apply_filters( 'shortpixel/init/automedialibrary', true ) ) {
215
216 add_action( 'shortpixel-thumbnails-before-regenerate', array( $admin, 'preventImageHook' ), 10, 1 );
217
218 add_action( 'enable-media-replace-upload-done', array( $admin, 'handleReplaceEnqueue' ), 10, 3 );
219
220 add_filter( 'wp_generate_attachment_metadata', array( $admin, 'handleImageUploadHook' ), 5, 2 );
221 add_action('add_attachment', array($admin, 'addAttachmentHook'));
222
223 // @integration MediaPress
224 add_filter( 'mpp_generate_metadata', array( $admin, 'handleImageUploadHook' ), 10, 2 );
225 }
226 }
227
228 $optimizeAiController = OptimizeAiController::getInstance();
229 if (true === $optimizeAiController->isAutoAiEnabled())
230 {
231
232 // Run one hit earlier than optimization, to do this action first if needed.
233 add_filter( 'wp_generate_attachment_metadata', array( $admin, 'handleAiImageUploadHook' ), 4, 2 );
234 add_filter( 'mpp_generate_metadata', array( $admin, 'handleAiImageUploadHook' ), 9, 2 );
235 add_action( 'enable-media-replace-upload-done', array( $admin, 'handleAiReplaceEnqueue' ), 10, 3 );
236
237 }
238
239
240 $this->env()->setDefaultViewModeList();// set default mode as list. only @ first run
241
242 add_filter( 'plugin_action_links_' . plugin_basename( SHORTPIXEL_PLUGIN_FILE ), array( $admin, 'generatePluginLinks' ) );// for plugin settings page
243
244 // for cleaning up the WebP images when an attachment is deleted . Loading this early because it's possible other plugins delete files in the uploads, but we need those to remove backups.
245 add_action( 'delete_attachment', array( $admin, 'onDeleteAttachment' ), 5 );
246 add_action( 'mime_types', array( $admin, 'addMimes' ) );
247
248 // integration with WP/LR Sync plugin
249 //add_action( 'wplr_update_media', array( AjaxController::getInstance(), 'onWpLrUpdateMedia' ), 10, 2 );
250 add_action( 'wplr_sync_media', array( AjaxController::getInstance(), 'onWpLrSyncMedia' ), 10, 2 );
251
252 add_action( 'admin_bar_menu', array( $admin, 'toolbar_shortpixel_processing' ), 999 );
253
254 // Image Editor Actions
255 add_filter('load_image_to_edit_path', array($imageEditor, 'getImageForEditor'), 10, 3);
256 add_filter('wp_save_image_editor_file', array($imageEditor, 'saveImageFile'), 10, 5); // hook when saving
257 // add_action('update_post_meta', array($imageEditor, 'checkUpdateMeta'), 10, 4 );
258
259
260 if (is_admin())
261 {
262 add_filter('pre_get_posts', array($admin, 'filter_listener'));
263
264 add_action( 'load-media_page_wp-short-pixel-custom', array( OtherMediaViewController::getInstance(), 'addOtherMediaScreenOptions' ) );
265 add_filter( 'set-screen-option', array( OtherMediaViewController::getInstance() , 'setScreenOption' ), 10, 3 );
266 }
267
268 if ($this->env()->is_multisite)
269 {
270 add_action('network_admin_menu', [$this, 'admin_network_pages']) ;
271 }
272
273 }
274
275 protected function ajaxHooks() {
276
277 // Ajax hooks. Should always be prepended with ajax_ and *must* check on nonce in function
278 add_action( 'wp_ajax_shortpixel_image_processing', array( AjaxController::getInstance(), 'ajax_processQueue' ) );
279
280 // Custom Media
281
282 //add_action( 'wp_ajax_shortpixel_get_backup_size', array( AjaxController::getInstance(), 'ajax_getBackupFolderSize' ) );
283
284 add_action( 'wp_ajax_shortpixel_propose_upgrade', array( AjaxController::getInstance(), 'ajax_proposeQuotaUpgrade' ) );
285 add_action( 'wp_ajax_shortpixel_check_quota', array( AjaxController::getInstance(), 'ajax_checkquota' ) );
286
287
288 add_action( 'wp_ajax_shortpixel_ajaxRequest', array( AjaxController::getInstance(), 'ajaxRequest' ) );
289 add_action( 'wp_ajax_shortpixel_settingsRequest', array( AjaxController::getInstance(), 'settingsRequest'));
290
291 }
292
293
294
295 /** Hook in our admin pages */
296 public function admin_pages() {
297 $admin_pages = array();
298 // settings page
299 $admin_pages[] = add_options_page( __( 'ShortPixel Settings', 'shortpixel-image-optimiser' ), 'ShortPixel', 'manage_options', 'wp-shortpixel-settings', array( $this, 'route' ) );
300
301 $otherMediaController = OtherMediaController::getInstance();
302 if ( $otherMediaController->showMenuItem() ) {
303 /*translators: title and menu name for the Other media page*/
304 $admin_pages[] = add_media_page( __( 'Custom Media Optimized by ShortPixel', 'shortpixel-image-optimiser' ), __( 'Custom Media', 'shortpixel-image-optimiser' ), 'edit_others_posts', 'wp-short-pixel-custom', array( $this, 'route' ) );
305 }
306 /*translators: title and menu name for the Bulk Processing page*/
307 $admin_pages[] = add_media_page( __( 'ShortPixel Bulk Process', 'shortpixel-image-optimiser' ), __( 'Bulk ShortPixel', 'shortpixel-image-optimiser' ), 'edit_others_posts', 'wp-short-pixel-bulk', array( $this, 'route' ) );
308
309 $this->admin_pages = $admin_pages;
310 }
311
312 public function admin_network_pages()
313 {
314 // add_menu_page(__('Shortpixel MU', 'shortpixel-image-optimiser'), __('Shortpixel', 'shortpixel_image_optimiser'), 'manage_sites', 'shortpixel-network-settings', [$this, 'route'], $this->plugin_url('res/img/shortpixel.png') );
315 }
316
317 /** All scripts should be registed, not enqueued here (unless global wp-admin is needed )
318 *
319 * Not all those registered must be enqueued however.
320 */
321 public function admin_scripts( $hook_suffix ) {
322
323 $settings = \wpSPIO()->settings();
324 $env = \wpSPIO()->env();
325 $ajaxController = AjaxController::getInstance();
326
327 $secretKey = $ajaxController->getProcessorKey();
328
329 $keyControl = \ShortPixel\Controller\ApiKeyController::getInstance();
330 $apikey = $keyControl->getKeyForDisplay();
331
332 $is_bulk_page = \wpSPIO()->env()->is_bulk_page;
333
334 $queueController = new QueueController(['is_bulk' => $is_bulk_page ]);
335 $quotaController = QuotaController::getInstance();
336
337 $OptimizeAiController = OptimizeAiController::getInstance();
338
339 $wp_script_debug = ( defined("SCRIPT_DEBUG") && true === \SCRIPT_DEBUG) ? true : false;
340
341 $args_footer_async = ['strategy' => 'async', 'in_footer' => true];
342
343 wp_register_script('shortpixel-folderbrowser', plugins_url('/res/js/shortpixel-folderbrowser.js', SHORTPIXEL_PLUGIN_FILE), array(), SHORTPIXEL_IMAGE_OPTIMISER_VERSION, true );
344
345 wp_localize_script('shortpixel-folderbrowser', 'spio_folderbrowser', array(
346 'strings' => array(
347 'loading' => __('Loading', 'shortpixel-image-optimiser'),
348 'empty_result' => __('No Directories found that can be added to Custom Folders', 'shortpixel-image-optimiser'),
349 ),
350 'icons' => array(
351 'folder_closed' => plugins_url('res/img/filebrowser/folder-closed.svg', SHORTPIXEL_PLUGIN_FILE),
352 'folder_open' => plugins_url('res/img/filebrowser/folder-closed.svg', SHORTPIXEL_PLUGIN_FILE),
353 ),
354 ));
355
356 wp_register_script( 'jquery.knob.min.js', plugins_url( ($wp_script_debug) ? '/res/js/jquery.knob.js' : '/res/js/jquery.knob.min.js', SHORTPIXEL_PLUGIN_FILE ), array(), SHORTPIXEL_IMAGE_OPTIMISER_VERSION, true );
357
358 wp_register_script( 'shortpixel-debug', plugins_url( '/res/js/debug.js', SHORTPIXEL_PLUGIN_FILE ), array( 'jquery', 'jquery-ui-draggable' ), SHORTPIXEL_IMAGE_OPTIMISER_VERSION, true );
359
360 wp_register_script( 'shortpixel-tooltip', plugins_url( '/res/js/shortpixel-tooltip.js', SHORTPIXEL_PLUGIN_FILE ), array( 'jquery' ), SHORTPIXEL_IMAGE_OPTIMISER_VERSION, true );
361
362 $tooltip_localize = array(
363 'processing' => __('Processing... ','shortpixel-image-optimiser'),
364 'pause' => __('Click to pause', 'shortpixel-image-optimiser'),
365 'resume' => __('Click to resume', 'shortpixel-image-optimiser'),
366 'item' => __('item in queue', 'shortpixel-image-optimiser'),
367 'items' => __('items in queue', 'shortpixel-image-optimiser'),
368 );
369
370 wp_localize_script( 'shortpixel-tooltip', 'spio_tooltipStrings', $tooltip_localize);
371
372 wp_register_script( 'shortpixel-settings', plugins_url( 'res/js/shortpixel-settings.js', SHORTPIXEL_PLUGIN_FILE ), array('shortpixel-shiftselect', 'shortpixel-inline-help'), SHORTPIXEL_IMAGE_OPTIMISER_VERSION, true );
373
374 wp_register_script('shortpixel-shiftselect', plugins_url('res/js/shift-select.js', SHORTPIXEL_PLUGIN_FILE), array(), SHORTPIXEL_IMAGE_OPTIMISER_VERSION, true);
375
376 wp_localize_script('shortpixel-settings', 'settings_strings', UiHelper::getSettingsStrings(false));
377
378
379 wp_register_script( 'shortpixel-onboarding', plugins_url( 'res/js/shortpixel-onboarding.js', SHORTPIXEL_PLUGIN_FILE ), array('shortpixel-settings'), SHORTPIXEL_IMAGE_OPTIMISER_VERSION, true );
380
381 wp_register_script('shortpixel-media', plugins_url('res/js/shortpixel-media.js', SHORTPIXEL_PLUGIN_FILE), array('jquery'), SHORTPIXEL_IMAGE_OPTIMISER_VERSION, true);
382
383 wp_register_script('shortpixel-inline-help', plugins_url('res/js/shortpixel-inline-help.js', SHORTPIXEL_PLUGIN_FILE), [], SHORTPIXEL_IMAGE_OPTIMISER_VERSION, true);
384 wp_register_script('shortpixel-chatbot',
385 apply_filters('shortpixel/plugin/nohelp', 'https://spcdn.shortpixel.ai/assets/js/ext/ai-chat-agent.js'), [], SHORTPIXEL_IMAGE_OPTIMISER_VERSION, $args_footer_async);
386
387 // This filter is from ListMediaViewController for the media library grid display, executive script in shortpixel-media.js.
388
389 $filters = array('optimized' => array(
390 'all' => __('Any ShortPixel State', 'shortpixel-image-optimiser'),
391 'optimized' => __('Optimized', 'shortpixel-image-optimiser'),
392 'unoptimized' => __('Unoptimized', 'shortpixel-image-optimiser'),
393 'prevented' => __('Optimization Error', 'shortpixel-image-optimiser'),
394 ));
395
396 $editor_localize = ImageEditorController::localizeScript();
397 $editor_localize['mediafilters'] = $filters;
398 wp_localize_script('shortpixel-media', 'spio_media', $editor_localize);
399
400 wp_register_script( 'shortpixel-processor', plugins_url( '/res/js/shortpixel-processor.js', SHORTPIXEL_PLUGIN_FILE ), array( 'jquery', 'shortpixel-tooltip' ), SHORTPIXEL_IMAGE_OPTIMISER_VERSION, true );
401
402 // How often JS processor asks for next tick on server. Low for fastestness and high loads, high number for surviving servers.
403 $interval = apply_filters( 'shortpixel/processor/interval', 3000 );
404
405 // If the queue is empty how often to check if something new appeared from somewhere. Excluding the manual items added by current processor user.
406 $deferInterval = apply_filters( 'shortpixel/process/deferInterval', 60000 );
407
408 wp_localize_script(
409 'shortpixel-processor',
410 'ShortPixelProcessorData',
411 array(
412 'bulkSecret' => $secretKey,
413 'isBulkPage' => (bool) $is_bulk_page,
414 'workerURL' => plugins_url( 'res/js/shortpixel-worker.js', SHORTPIXEL_PLUGIN_FILE ),
415 'nonce_process' => wp_create_nonce( 'processing' ),
416 'nonce_exit' => wp_create_nonce( 'exit_process' ),
417 'nonce_ajaxrequest' => wp_create_nonce( 'ajax_request' ),
418 'nonce_settingsrequest' => wp_create_nonce('settings_request'),
419 'startData' => ( \wpSPIO()->env()->is_screen_to_use ) ? $queueController->getStartupData() : false,
420 'interval' => $interval,
421 'deferInterval' => $deferInterval,
422 'debugIsActive' => (\wpSPIO()->env()->is_debug) ? 'true' : 'false',
423 'autoMediaLibrary' => ($settings->autoMediaLibrary) ? 'true' : 'false',
424 'disable_processor' => apply_filters('shortpixel/processorjs/disable', false),
425 )
426 );
427
428 //https://github.com/thedatepicker/thedatepicker
429 wp_register_script('shortpixel-datepicker', plugins_url('res/js/the-datepicker.min.js', SHORTPIXEL_PLUGIN_FILE), ['wp-components', 'wp-i18n', 'wp-element', 'wp-hooks'], SHORTPIXEL_IMAGE_OPTIMISER_VERSION, true);
430
431
432 /*** SCREENS */
433 wp_register_script('shortpixel-screen-base', plugins_url( '/res/js/screens/screen-base.js', SHORTPIXEL_PLUGIN_FILE ), array( 'jquery', 'shortpixel-processor' ), SHORTPIXEL_IMAGE_OPTIMISER_VERSION, true );
434
435 wp_register_script('shortpixel-screen-item-base', plugins_url( '/res/js/screens/screen-item-base.js', SHORTPIXEL_PLUGIN_FILE ), array( 'jquery', 'shortpixel-processor', 'shortpixel-screen-base'), SHORTPIXEL_IMAGE_OPTIMISER_VERSION, true );
436
437 wp_register_script( 'shortpixel-screen-media', plugins_url( '/res/js/screens/screen-media.js', SHORTPIXEL_PLUGIN_FILE ), array( 'jquery', 'shortpixel-processor', 'shortpixel-screen-base', 'shortpixel-screen-item-base' ), SHORTPIXEL_IMAGE_OPTIMISER_VERSION, true );
438
439 wp_register_script( 'shortpixel-screen-custom', plugins_url( '/res/js/screens/screen-custom.js', SHORTPIXEL_PLUGIN_FILE ), array( 'jquery', 'shortpixel-processor', 'shortpixel-screen-base', 'shortpixel-screen-item-base' ), SHORTPIXEL_IMAGE_OPTIMISER_VERSION, true );
440
441 wp_register_script( 'shortpixel-screen-nolist', plugins_url( '/res/js/screens/screen-nolist.js', SHORTPIXEL_PLUGIN_FILE ), array( 'jquery', 'shortpixel-processor', 'shortpixel-screen-base' ), SHORTPIXEL_IMAGE_OPTIMISER_VERSION, true );
442
443 $screen_localize = array( // Item Base
444 'startAction' => __('Processing... ','shortpixel-image-optimiser'),
445 'startActionAI' => __('Generating image SEO data', 'shortpixel-image-optimiser'),
446 'fatalError' => __('ShortPixel encountered a fatal error when optimizing images. Please check the issue below. If this is caused by a bug please contact our support', 'shortpixel-image-optimiser'),
447 'fatalErrorStop' => __('ShortPixel has encounted multiple errors and has now stopped processing', 'shortpixel-image-optimiser'),
448 'fatalErrorStopText' => __('No items are being processed. To try again after solving the issues, please reload the page ', 'shortpixel-image-optimiser'),
449 'fatalError500' => __('A fatal error HTTP 500 has occurred. On the bulk screen, this may be caused by the script running out of memory. Check your error log, increase memory or disable heavy plugins.'),
450
451 );
452
453
454 $screen_localize_custom = array( // Custom Screen
455 'stopActionMessage' => __('Folder scan has stopped', 'shortpixel-image-optimiser'),
456 );
457
458 $screen_localize_media = [
459 'hide_ai' => ! $OptimizeAiController->isAiEnabled(), // turn around negative setting
460 'hide_spio_in_popups' => apply_filters('shortpixel/js/media/hide_in_popups', false),
461 'modalcss' => plugins_url('res/css/shortpixel-media-modal.css', SHORTPIXEL_PLUGIN_FILE),
462 'remove_background_title' => __('AI Background Removal', 'shortpixel-image-optimiser'),
463 'scale_title' => __('AI Image Upscale', 'shortpixel-image-optimiser'),
464 'upscale_max_width' => 1200, // Scale X and max width pin Pixels.
465 'popup_load_preview' => true, // Upon opening, load Preview or not.
466 'too_big_for_scale_title' => __('Image too big for scaling', 'shortpixel-image-optimiser'),
467 'wp_screen_id' => $env->screen_id,
468 ];
469
470 wp_localize_script('shortpixel-screen-media', 'spio_mediascreen_settings', $screen_localize_media);
471
472 wp_localize_script( 'shortpixel-screen-base', 'spio_screenStrings', array_merge($screen_localize, $screen_localize_custom));
473
474 wp_register_script( 'shortpixel-screen-bulk', plugins_url( '/res/js/screens/screen-bulk.js', SHORTPIXEL_PLUGIN_FILE ), array( 'jquery', 'shortpixel-processor', 'shortpixel-screen-base'), SHORTPIXEL_IMAGE_OPTIMISER_VERSION, true );
475
476 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- This is not a form
477 $panel = isset( $_GET['panel'] ) ? sanitize_text_field( wp_unslash($_GET['panel']) ) : false;
478
479 $bulkLocalize = [
480 'endBulk' => __( 'This will stop the bulk processing and take you back to the start. Are you sure you want to do this?', 'shortpixel-image-optimiser' ),
481 'reloadURL' => admin_url( 'upload.php?page=wp-short-pixel-bulk'),
482 ];
483 if ( $panel ) {
484 $bulkLocalize['panel'] = $panel;
485 }
486
487 // screen translations. Can all be loaded on the same var, since only one screen can be active.
488 wp_localize_script( 'shortpixel-screen-bulk', 'shortPixelScreen', $bulkLocalize );
489
490 wp_register_script( 'shortpixel', plugins_url( '/res/js/shortpixel.js', SHORTPIXEL_PLUGIN_FILE ), array( 'jquery', 'jquery.knob.min.js' ), SHORTPIXEL_IMAGE_OPTIMISER_VERSION, true );
491
492 // Using an Array within another Array to protect the primitive values from being cast to strings
493 $ShortPixelConstants = array(
494 array(
495 'WP_PLUGIN_URL' => plugins_url( '', SHORTPIXEL_PLUGIN_FILE ),
496 'WP_ADMIN_URL' => admin_url(),
497 'API_IS_ACTIVE' => $keyControl->keyIsVerified(),
498 'AJAX_URL' => admin_url( 'admin-ajax.php' ),
499 'BULK_SECRET' => $secretKey,
500 'nonce_ajaxrequest' => wp_create_nonce( 'ajax_request' ),
501 'HAS_QUOTA' => ( $quotaController->hasQuota() ) ? 1 : 0,
502
503 ),
504 );
505
506 if ( Log::isManualDebug() ) {
507 Log::addInfo( 'Ajax Manual Debug Mode' );
508 $logLevel = Log::getLogLevel();
509 $ShortPixelConstants[0]['AJAX_URL'] = admin_url( 'admin-ajax.php?SHORTPIXEL_DEBUG=' . $logLevel );
510 }
511
512 $jsTranslation = array(
513 'optimizeWithSP' => __( 'ShortPixel', 'shortpixel-image-optimiser' ),
514 'optimize' => __( 'Optimize', 'shortpixel-image-optimiser' ),
515 'redoLossy' => __( 'Re-optimize Lossy', 'shortpixel-image-optimiser' ),
516 'redoGlossy' => __( 'Re-optimize Glossy', 'shortpixel-image-optimiser' ),
517 'redoLossless' => __( 'Re-optimize Lossless', 'shortpixel-image-optimiser' ),
518 'redoSmartcrop' => __( 'Re-optimize with SmartCrop', 'shortpixel-image-optimiser'),
519 'redoSmartcropless' => __( 'Re-optimize without SmartCrop', 'shortpixel-image-optimiser'),
520 'restoreOriginal' => __( 'Restore Originals', 'shortpixel-image-optimiser' ),
521 'generateAI' => __( 'Generate image SEO data', 'shortpixel-image-optimiser'),
522 'markCompleted' => __('Mark as completed' ,'shortpixel-image-optimiser'),
523 'areYouSureStopOptimizing' => __( 'Are you sure you want to stop optimizing the folder {0}?', 'shortpixel-image-optimiser' ),
524 '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' ),
525 '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' ),
526 'confirmBulkRestore' => __( 'Are you sure you want to restore from backup all the images in your Media Library optimized with ShortPixel?', 'shortpixel-image-optimiser' ),
527 'confirmBulkCleanup' => __( "Are you sure you want to cleanup the ShortPixel metadata info for the images in your Media Library optimized with ShortPixel? This will make ShortPixel 'forget' that it optimized them and will optimize them again if you re-run the Bulk Optimization process.", 'shortpixel-image-optimiser' ),
528 'alertDeliverWebPAltered' => __( "Warning: Using this method alters the structure of the rendered HTML code (IMG tags get included in PICTURE tags), which, in some rare \ncases, can lead to CSS/JS inconsistencies.\n\nPlease test this functionality thoroughly after activating!\n\nIf you notice any issue, just deactivate it and the HTML will will revert to the previous state.", 'shortpixel-image-optimiser' ),
529 'alertDeliverWebPUnaltered' => __( 'This option will serve both WebP and the original image using the same URL, based on the web browser capabilities, please make sure you\'re serving the images from your server and not using a CDN which caches the images.', 'shortpixel-image-optimiser' ),
530 'originalImage' => __( 'Original image', 'shortpixel-image-optimiser' ),
531 'optimizedImage' => __( 'Optimized image', 'shortpixel-image-optimiser' ),
532 'loading' => __( 'Loading...', 'shortpixel-image-optimiser' ),
533
534 );
535
536 wp_localize_script( 'shortpixel', '_spTr', $jsTranslation );
537 wp_localize_script( 'shortpixel', 'ShortPixelConstants', $ShortPixelConstants );
538
539 }
540
541 public function admin_styles() {
542
543 wp_register_style( 'shortpixel-folderbrowser', plugins_url( '/res/css/shortpixel-folderbrowser.css', SHORTPIXEL_PLUGIN_FILE ),[], SHORTPIXEL_IMAGE_OPTIMISER_VERSION );
544
545 //wp_register_style( 'shortpixel', plugins_url( '/res/css/short-pixel.css', SHORTPIXEL_PLUGIN_FILE ), array(), SHORTPIXEL_IMAGE_OPTIMISER_VERSION );
546
547 // notices. additional styles for SPIO.
548 wp_register_style( 'shortpixel-notices', plugins_url( '/res/css/shortpixel-notices.css', SHORTPIXEL_PLUGIN_FILE ), array( 'shortpixel-admin' ), SHORTPIXEL_IMAGE_OPTIMISER_VERSION );
549
550 wp_register_style('notices-module', plugins_url('/build/shortpixel/notices/src/css/notices.css', SHORTPIXEL_PLUGIN_FILE), array(), SHORTPIXEL_IMAGE_OPTIMISER_VERSION);
551
552 // other media screen
553 wp_register_style( 'shortpixel-othermedia', plugins_url( '/res/css/shortpixel-othermedia.css', SHORTPIXEL_PLUGIN_FILE ), array(), SHORTPIXEL_IMAGE_OPTIMISER_VERSION );
554
555 // load everywhere, because we are inconsistent.
556 wp_register_style( 'shortpixel-toolbar', plugins_url( '/res/css/shortpixel-toolbar.css', SHORTPIXEL_PLUGIN_FILE ), array( 'dashicons' ), SHORTPIXEL_IMAGE_OPTIMISER_VERSION );
557
558 // @todo Might need to be removed later on
559 wp_register_style( 'shortpixel-admin', plugins_url( '/res/css/shortpixel-admin.css', SHORTPIXEL_PLUGIN_FILE ), array(), SHORTPIXEL_IMAGE_OPTIMISER_VERSION );
560
561 wp_register_style( 'shortpixel-bulk', plugins_url( '/res/css/shortpixel-bulk.css', SHORTPIXEL_PLUGIN_FILE ), array(), SHORTPIXEL_IMAGE_OPTIMISER_VERSION );
562
563 wp_register_style( 'shortpixel-nextgen', plugins_url( '/res/css/shortpixel-nextgen.css', SHORTPIXEL_PLUGIN_FILE ), array(), SHORTPIXEL_IMAGE_OPTIMISER_VERSION );
564
565 wp_register_style( 'shortpixel-settings', plugins_url( '/res/css/shortpixel-settings.css', SHORTPIXEL_PLUGIN_FILE ), array(), SHORTPIXEL_IMAGE_OPTIMISER_VERSION );
566
567 wp_register_style('shortpixel-datepicker', plugins_url('res/css/the-datepicker.css', SHORTPIXEL_PLUGIN_FILE), [], SHORTPIXEL_IMAGE_OPTIMISER_VERSION );
568 }
569
570
571 /** Load Style via Route, on demand */
572 public function load_style( $name ) {
573 if ( $this->is_noheaders ) { // fail silently, if this is a no-headers request.
574 return;
575 }
576
577 if ( wp_style_is( $name, 'registered' ) ) {
578 wp_enqueue_style( $name );
579 } else {
580 Log::addWarn( "Style $name was asked for, but not registered", $_SERVER['REQUEST_URI'] );
581 }
582 }
583
584 /** Load Style via Route, on demand */
585 public function load_script( $script ) {
586 if ( $this->is_noheaders ) { // fail silently, if this is a no-headers request.
587 return;
588 }
589
590 if ( ! is_array( $script ) ) {
591 $script = array( $script );
592 }
593
594 foreach ( $script as $index => $name ) {
595 if ( wp_script_is( $name, 'registered' ) ) {
596 wp_enqueue_script( $name );
597 } else {
598 Log::addWarn( "Script $name was asked for, but not registered", $_SERVER['REQUEST_URI'] );
599 }
600 }
601 }
602
603 /** This is separated from route to load in head, preventing unstyled content all the time */
604 public function load_admin_scripts( $hook_suffix ) {
605 global $plugin_page;
606 $screen_id = $this->env()->screen_id;
607
608 $load_processor = array( 'shortpixel', 'shortpixel-processor' ); // a whole suit needed for processing, not more. Always needs a screen as well!
609 $load_bulk = array(); // the whole suit needed for bulking.
610 if ( \wpSPIO()->env()->is_screen_to_use ) {
611 $this->load_script( $load_processor );
612 $this->load_style( 'shortpixel-toolbar' );
613 $this->load_style('shortpixel-notices');
614 $this->load_style('notices-module');
615 }
616
617 if ( $plugin_page == 'wp-shortpixel-settings' || $plugin_page == 'shortpixel-network-settings' ) {
618
619 $this->load_script( 'shortpixel-screen-nolist' ); // screen
620 $this->load_script( 'shortpixel-settings' );
621 $this->load_script('shortpixel-chatbot');
622
623 // @todo Load onboarding only when no api key / onboarding required
624 $this->load_script('shortpixel-onboarding');
625
626 $this->load_style( 'shortpixel-admin' );
627
628 $this->load_style( 'shortpixel-settings' );
629
630 } elseif ( $plugin_page == 'wp-short-pixel-bulk' ) {
631 $this->load_script( 'shortpixel-screen-bulk' );
632 $this->load_script('shortpixel-chatbot');
633 $this->load_script('shortpixel-datepicker');
634
635 $this->load_style('shortpixel-datepicker');
636 $this->load_style( 'shortpixel-admin' );
637 $this->load_style( 'shortpixel-bulk' );
638 } elseif ( $screen_id == 'upload' || $screen_id == 'attachment' ) {
639
640 $this->load_script( 'shortpixel-screen-media' ); // screen
641 $this->load_script( 'shortpixel-media' );
642
643 $this->load_style( 'shortpixel-admin' );
644 $this->load_style( 'notices-module');
645 // $this->load_style( 'shortpixel' );
646
647 if ( $this->env()->is_debug ) {
648 $this->load_script( 'shortpixel-debug' );
649 }
650
651 } elseif ( $plugin_page == 'wp-short-pixel-custom' ) { // custom media
652 // $this->load_style( 'shortpixel' );
653
654 $this->load_script( 'shortpixel-folderbrowser' );
655 $this->load_script('shortpixel-chatbot');
656
657 $this->load_style( 'shortpixel-admin' );
658 $this->load_style( 'shortpixel-folderbrowser' );
659 $this->load_style( 'shortpixel-othermedia' );
660 $this->load_script( 'shortpixel-screen-custom' ); // screen
661
662 } elseif ( NextGenController::getInstance()->isNextGenScreen() ) {
663
664 $this->load_script( 'shortpixel-screen-custom' ); // screen
665 $this->load_style( 'shortpixel-admin' );
666
667 // $this->load_style( 'shortpixel' );
668 $this->load_style( 'shortpixel-nextgen' );
669 }
670 elseif (true === $this->env()->is_gutenberg_editor || true === $this->env()->is_classic_editor)
671 {
672 $this->load_script( $load_processor );
673 $this->load_script( 'shortpixel-screen-media' ); // screen
674 $this->load_script( 'shortpixel-media' );
675
676 $this->load_style( 'shortpixel-admin' );
677 }
678 elseif (true === \wpSPIO()->env()->is_screen_to_use )
679 {
680 // If our screen, but we don't have a specific handler for it, do the no-list screen.
681 $this->load_script( 'shortpixel-screen-nolist' ); // screen
682 }
683
684 }
685
686 /** Route, based on the page slug
687 *
688 * Principially all page controller should be routed from here.
689 */
690 public function route() {
691 global $plugin_page;
692
693 $default_action = 'load'; // generic action on controller.
694 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- This is not a form
695 $action = isset( $_REQUEST['sp-action'] ) ? sanitize_text_field( wp_unslash($_REQUEST['sp-action']) ) : $default_action;
696 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- This is not a form
697 $template_part = isset( $_GET['part'] ) ? sanitize_text_field( wp_unslash($_GET['part']) ) : false;
698
699 $controller = false;
700
701 $url = '';
702 if (! is_null($plugin_page))
703 {
704 $url = menu_page_url( $plugin_page, false );
705 }
706 $screen_id = \wpSPIO()->env()->screen_id;
707
708 switch ( $plugin_page ) {
709 case 'wp-shortpixel-settings': // settings
710 $controller = 'ShortPixel\Controller\View\SettingsViewController';
711 wp_enqueue_media();
712 break;
713 case 'shortpixel-network-settings':
714 $controller = 'ShortPixel\Controller\View\MultiSiteViewController';
715 break;
716 case 'wp-short-pixel-custom': // other media
717 if ('folders' === $template_part )
718 {
719 $controller = 'ShortPixel\Controller\View\OtherMediaFolderViewController';
720 }
721 elseif('scan' === $template_part)
722 {
723 $controller = 'ShortPixel\Controller\View\OtherMediaScanViewController';
724 }
725 else {
726 $controller = 'ShortPixel\Controller\View\OtherMediaViewController';
727 }
728
729 break;
730 case 'wp-short-pixel-bulk':
731 $controller = '\ShortPixel\Controller\View\BulkViewController';
732 break;
733 case null:
734 default:
735 switch ( $screen_id ) {
736 case 'upload':
737 $controller = '\ShortPixel\Controller\View\ListMediaViewController';
738 break;
739 case 'attachment': // edit-media
740 $controller = '\ShortPixel\Controller\View\EditMediaViewController';
741 break;
742 }
743 break;
744
745 }
746 if ( $controller !== false ) {
747 $c = $controller::getInstance();
748 $c->setControllerURL( $url );
749 if ( method_exists( $c, $action ) ) {
750 $c->$action();
751 } else {
752 Log::addWarn( "Attempted Action $action on $controller does not exist!" );
753 $c->$default_action();
754 }
755 }
756 }
757
758
759 // Get the plugin URL, based on real URL.
760 public function plugin_url( $urlpath = '' ) {
761 $url = trailingslashit( $this->plugin_url );
762 if ( strlen( $urlpath ) > 0 ) {
763 $url .= $urlpath;
764 }
765 return $url;
766 }
767
768 // Get the plugin path.
769 public function plugin_path( $path = '' ) {
770 $plugin_path = trailingslashit( $this->plugin_path );
771 if ( strlen( $path ) > 0 ) {
772 $plugin_path .= $path;
773 }
774
775 return $plugin_path;
776 }
777
778 /** Returns defined admin page hooks. Internal use - check states via environmentmodel
779 *
780 * @returns Array
781 */
782 public function get_admin_pages() {
783 return $this->admin_pages;
784 }
785
786 protected function check_plugin_version() {
787 $version = SHORTPIXEL_IMAGE_OPTIMISER_VERSION;
788 $db_version = $this->settings()->currentVersion;
789
790 if ( $version !== $db_version ) {
791 InstallHelper::activatePlugin();
792 $this->settings()->currentVersion = $version;
793
794 }
795 }
796
797
798
799
800 } // class plugin
801