PluginProbe
Image Optimizer – Compress Images and Convert to WebP or AVIF / 1.7.7
Image Optimizer – Compress Images and Convert to WebP or AVIF v1.7.7
1.7.7 1.7.6 1.7.5 1.7.4 trunk 1.0.0 1.0.1 1.0.2 1.1.0 1.2.0 1.2.1 1.3.0 1.4.0 1.4.1 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 All 33 releases
image-optimization / modules / core / module.php

module.php in Image Optimizer – Compress Images and Convert to WebP or AVIF 1.7.7, at modules/core/module.php

493 lines 14.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace ImageOptimization\Modules\Core;
3
4 use ImageOptimization\Modules\Optimization\{
5 Classes\Validate_Image,
6 Rest\Cancel_Bulk_Optimization,
7 Rest\Optimize_Bulk,
8 };
9 use ImageOptimization\Modules\Settings\Classes\Settings;
10 use ImageOptimization\Modules\Backups\Rest\{
11 Restore_All,
12 Remove_Backups,
13 };
14 use ImageOptimization\Classes\{
15 Async_Operation\Async_Operation,
16 Async_Operation\Async_Operation_Queue,
17 Async_Operation\Queries\Operation_Query,
18 Image\Image_Meta,
19 Image\Image_Optimization_Error_Type,
20 Image\Image_Status,
21 Migration\Migration_Manager,
22 Module_Base,
23 Utils,
24 };
25
26 use ImageOptimization\Modules\Connect\Module as Connect_Module;
27 use ImageOptimization\Modules\Connect\Classes\Config;
28
29 use ImageOptimization\Plugin;
30
31 if ( ! defined( 'ABSPATH' ) ) {
32 exit; // Exit if accessed directly.
33 }
34
35 class Module extends Module_Base {
36
37 const ONE_MISMATCH_URL = '/wp-admin/admin.php?page=elementor-home#/home/url-mismatch';
38
39 public function get_name(): string {
40 return 'core';
41 }
42
43 public static function component_list(): array {
44 return [
45 'Pointers',
46 'Migrations',
47 'Conflicts',
48 'User_Feedback',
49 'Not_Connected',
50 'Not_Connected_Modal',
51 'Renewal_Notice',
52 'Notificator',
53 ];
54 }
55
56 private function render_top_bar() {
57 ?>
58 <div id="image-optimization-top-bar"></div>
59 <?php
60 }
61
62 private function render_app() {
63 ?>
64 <div class="clear"></div>
65 <div id="image-optimization-app"></div>
66 <?php
67 }
68
69 public function maybe_add_quota_reached_notice() {
70
71 // @var ImageOptimizer/Modules/ConnectManager/Module
72 $module = Plugin::instance()->modules_manager->get_modules( 'connect-manager' );
73 $upgrade_link = Utils::get_upgrade_link( 'https://go.elementor.com/io-quota-upgrade/' );
74
75 if ( ! $module->connect_instance->get_connect_status() || $module->connect_instance->images_left() > 0 ) {
76 return;
77 }
78
79 ?>
80 <div class="notice notice-warning notice image-optimizer__notice image-optimizer__notice--warning">
81 <p>
82 <b>
83 <?php esc_html_e(
84 'You’ve reached your plan quota.',
85 'image-optimization'
86 ); ?>
87 </b>
88
89 <span>
90 <?php esc_html_e(
91 'You have no images left to optimize in your current plan.',
92 'image-optimization'
93 ); ?>
94
95 <a href="<?php echo esc_url( $upgrade_link ); ?>">
96 <?php esc_html_e(
97 'Upgrade plan now',
98 'image-optimization'
99 ); ?>
100 </a>
101 </span>
102 </p>
103 </div>
104 <?php
105 }
106
107 public function maybe_add_80_quota_reached_notice() {
108 // @var ImageOptimizer/Modules/ConnectManager/Module
109 $module = Plugin::instance()->modules_manager->get_modules( 'connect-manager' );
110
111 $connect_status = $module->connect_instance->get_connect_status();
112
113 if ( ! isset( $connect_status->quota ) || ! isset( $connect_status->used_quota ) ) {
114 return;
115 }
116
117 $usage = $connect_status->used_quota / $connect_status->quota * 100;
118
119 if ( $usage < 80 || 100 === $usage ) {
120 return;
121 }
122
123 $upgrade_link = Utils::get_upgrade_link( 'https://go.elementor.com/io-quota-upgrade/' );
124
125 ?>
126 <div class="notice notice-warning notice image-optimizer__notice image-optimizer__notice--warning">
127 <p>
128 <b>
129 <?php esc_html_e(
130 'You’ve used 80% of your plan quota.',
131 'image-optimization'
132 ); ?>
133 </b>
134
135 <span>
136 <?php esc_html_e(
137 'Upgrade now to avoid interruptions.',
138 'image-optimization'
139 ); ?>
140
141 <a href="<?php echo esc_url( $upgrade_link ); ?>">
142 <?php esc_html_e(
143 'Upgrade plan now',
144 'image-optimization'
145 ); ?>
146 </a>
147 </span>
148 </p>
149 </div>
150 <?php
151 }
152
153 public function maybe_add_url_mismatch_notice() {
154 // @var ImageOptimizer/Modules/ConnectManager/Module
155 $module = Plugin::instance()->modules_manager->get_modules( 'connect-manager' );
156
157 if ( $module->connect_instance->is_valid_home_url() ) {
158 return;
159 }
160
161 $onclick = self::is_elementor_one() ? 'window.location.href = "' . self::ONE_MISMATCH_URL . '";' : 'document.dispatchEvent( new Event( "image-optimizer/auth/url-mismatch-modal/open" ) );';
162
163 ?>
164 <div class="notice notice-error notice image-optimizer__notice image-optimizer__notice--error">
165 <p>
166 <b>
167 <?php esc_html_e(
168 'Your license key does not match your current domain, causing a mismatch.',
169 'image-optimization'
170 ); ?>
171 </b>
172
173 <span>
174 <?php esc_html_e(
175 'This is most likely due to a change in the domain URL of your site (including HTTP/SSL migration).',
176 'image-optimization'
177 ); ?>
178
179 <button type="button" onclick="<?php echo esc_js( $onclick ); ?>">
180 <?php esc_html_e(
181 'Fix mismatched URL',
182 'image-optimization'
183 ); ?>
184 </button>
185 </span>
186 </p>
187 </div>
188 <?php
189 }
190
191 public function add_plugin_links( $links, $plugin_file_name ) {
192 if ( ! is_array( $links ) ) {
193 return $links;
194 }
195
196 if ( ! str_ends_with( $plugin_file_name, '/image-optimization.php' ) ) {
197 return $links;
198 }
199
200 $custom_links = [
201 'settings' => sprintf(
202 '<a href="%s">%s</a>',
203 admin_url( 'admin.php?page=' . \ImageOptimization\Modules\Settings\Module::SETTING_BASE_SLUG ),
204 esc_html__( 'Settings', 'image-optimization' )
205 ),
206 ];
207 // @var ImageOptimizer/Modules/ConnectManager/Module
208 $module = Plugin::instance()->modules_manager->get_modules( 'connect-manager' );
209
210 if ( $module->connect_instance->is_connected() && ! self::is_elementor_one() ) {
211 $custom_links['upgrade'] = sprintf(
212 '<a href="%s" style="color: #524cff; font-weight: 700;" target="_blank" rel="noopener noreferrer">%s</a>',
213 Utils::get_upgrade_link( 'https://go.elementor.com/io-plugins-upgrade/' ),
214 esc_html__( 'Upgrade', 'image-optimization' )
215 );
216 }
217 if ( ! $module->connect_instance->is_connected() ) {
218 $custom_links['connect'] = sprintf(
219 '<a href="%s" style="color: #524cff; font-weight: 700;">%s</a>',
220 admin_url( 'admin.php?page=' . \ImageOptimization\Modules\Settings\Module::SETTING_BASE_SLUG ),
221 esc_html__( 'Connect', 'image-optimization' )
222 );
223 }
224
225 return array_merge( $custom_links, $links );
226 }
227
228 public function enqueue_global_assets() {
229 wp_enqueue_style(
230 'image-optimization-admin-fonts',
231 'https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap',
232 [],
233 IMAGE_OPTIMIZATION_VERSION
234 );
235
236 wp_enqueue_style(
237 'image-optimization-core-style-admin',
238 $this->get_css_assets_url( 'style-admin', 'assets/build/' ),
239 [],
240 IMAGE_OPTIMIZATION_VERSION,
241 );
242 }
243
244 /**
245 * Enqueue styles and scripts
246 */
247 private function enqueue_scripts() {
248 $asset_file = require IMAGE_OPTIMIZATION_ASSETS_PATH . 'build/admin.asset.php';
249
250 foreach ( $asset_file['dependencies'] as $style ) {
251 wp_enqueue_style( $style );
252 }
253
254 wp_enqueue_script(
255 'image-optimization-admin',
256 $this->get_js_assets_url( 'admin' ),
257 array_merge( $asset_file['dependencies'], [ 'wp-util' ] ),
258 $asset_file['version'],
259 true
260 );
261
262 wp_localize_script(
263 'image-optimization-admin',
264 'imageOptimizerAppSettings',
265 [
266 'siteUrl' => wp_parse_url( get_site_url(), PHP_URL_HOST ),
267 'thumbnailSizes' => wp_get_registered_image_subsizes(),
268 'isDevelopment' => defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG,
269 'isRTL' => is_rtl(),
270 'version' => IMAGE_OPTIMIZATION_VERSION,
271 ]
272 );
273
274 /**
275 * @var ImageOptimizer\Modules\ConnectManager\Module $module
276 */
277 $module = Plugin::instance()->modules_manager->get_modules( 'connect-manager' );
278 $connect_email = $module->connect_instance->get_connect_data()['user']['email'] ?? null;
279 $show_reset = ! $module->connect_instance->is_connected()
280 && ( $module->connect_instance->get_client_id() || $module->connect_instance->get_client_secret() );
281
282 wp_localize_script(
283 'image-optimization-admin',
284 'imageOptimizerUserData',
285 [
286 'isConnectOnFly' => self::is_connect_on_fly(),
287 'isConnected' => $module->connect_instance->is_connected(),
288 'isElementorOne' => self::is_elementor_one(),
289 'hasElementorOneSubscription' => self::has_elementor_one_subscription(),
290 'isMigrationPopupDismissed' => (bool) Settings::get( Settings::MIGRATION_POPUP_DISMISSED ),
291 'currentPage' => get_current_screen()->base,
292 'isActivated' => $module->connect_instance->is_activated(),
293 'isUrlMismatch' => ! $module->connect_instance->is_valid_home_url(),
294 'planData' => $module->connect_instance->is_activated() ? $module->connect_instance->get_connect_status() : null,
295 'licenseKey' => $module->connect_instance->is_activated() ? $module->connect_instance->get_activation_state() : null,
296 'imagesLeft' => $module->connect_instance->is_activated() ? $module->connect_instance->images_left() : null,
297 'isOwner' => $module->connect_instance->is_connected() ? $module->connect_instance->user_is_subscription_owner() : null,
298 'subscriptionEmail' => $connect_email ? $connect_email : null,
299 'showResetButton' => $show_reset,
300 'maxFileSize' => Validate_Image::get_max_file_size(),
301 'helpVideos' => Settings::get( Settings::HELP_VIDEOS ),
302
303 'wpRestNonce' => wp_create_nonce( 'wp_rest' ),
304 'disconnect' => wp_create_nonce( 'wp_rest' ),
305 'authInitNonce' => wp_create_nonce( $module->connect_instance->connect_init_nonce() ),
306 'authDisconnectNonce' => wp_create_nonce( $module->connect_instance->disconnect_nonce() ),
307 'authDeactivateNonce' => wp_create_nonce( $module->connect_instance->deactivate_nonce() ),
308 'authGetSubscriptionsNonce' => wp_create_nonce( $module->connect_instance->get_subscriptions_nonce() ),
309 'authActivateNonce' => wp_create_nonce( $module->connect_instance->activate_nonce() ),
310 'versionNonce' => wp_create_nonce( $module->connect_instance->version_nonce() ),
311 'removeBackupsNonce' => wp_create_nonce( Remove_Backups::NONCE_NAME ),
312 'restoreAllImagesNonce' => wp_create_nonce( Restore_All::NONCE_NAME ),
313 'optimizeBulkNonce' => wp_create_nonce( Optimize_Bulk::NONCE_NAME ),
314 'cancelBulkOptimizationNonce' => wp_create_nonce( Cancel_Bulk_Optimization::NONCE_NAME ),
315 ]
316 );
317
318 wp_set_script_translations( 'image-optimization-admin', 'image-optimization' );
319 }
320
321 private function should_render(): bool {
322 return ( Utils::is_media_page() || Utils::is_plugin_page() ) && Utils::user_is_admin();
323 }
324
325 private static function is_connect_on_fly(): bool {
326 /**
327 * @var ImageOptimizer\Modules\ConnectManager\Module $module
328 */
329 $module = Plugin::instance()->modules_manager->get_modules( 'connect-manager' );
330 return $module->connect_instance->get_is_connect_on_fly();
331 }
332
333 public static function is_elementor_one(): bool {
334
335 if ( ! self::is_connect_on_fly() ) {
336 return false;
337 }
338
339 $connect = Connect_Module::get_connect();
340
341 if ( ! $connect ) {
342 return false;
343 }
344
345 return Connect_Module::get_connect()->get_config( 'app_type' ) !== Config::APP_TYPE;
346 }
347
348 /**
349 * Check if user generally has an active Elementor One subscription.
350 * @return bool
351 */
352 public static function has_elementor_one_subscription(): bool {
353 $one_facade = \ElementorOne\Admin\Helpers\Utils::get_one_connect();
354 return $one_facade && $one_facade->utils()->is_connected();
355 }
356
357 public static function on_deactivation(): void {
358 $optimization_query = ( new Operation_Query() )
359 ->set_queue( Async_Operation_Queue::OPTIMIZE )
360 ->set_status( [ Async_Operation::OPERATION_STATUS_PENDING, Async_Operation::OPERATION_STATUS_RUNNING ] )
361 ->set_limit( -1 );
362
363 $restoring_query = ( new Operation_Query() )
364 ->set_queue( Async_Operation_Queue::RESTORE )
365 ->set_status( [ Async_Operation::OPERATION_STATUS_PENDING, Async_Operation::OPERATION_STATUS_RUNNING ] )
366 ->set_limit( -1 );
367
368 $optimization_operations = Async_Operation::get( $optimization_query );
369 $restoring_operations = Async_Operation::get( $restoring_query );
370
371 foreach ( $optimization_operations as $operation ) {
372 $image_id = $operation->get_args()['attachment_id'];
373
374 if ( ! $image_id ) {
375 continue;
376 }
377
378 Async_Operation::remove( [ $operation->get_id() ] );
379
380 $image_meta = new Image_Meta( $image_id );
381
382 if ( empty( $image_meta->get_optimized_sizes() ) ) {
383 $image_meta->delete();
384 } else {
385 $image_meta
386 ->set_status( Image_Status::OPTIMIZATION_FAILED )
387 ->set_error_type( Image_Optimization_Error_Type::PLUGIN_DEACTIVATION )
388 ->save();
389 }
390 }
391
392 foreach ( $restoring_operations as $operation ) {
393 $image_id = $operation->get_args()['attachment_id'];
394
395 if ( ! $image_id ) {
396 continue;
397 }
398
399 Async_Operation::remove( [ $operation->get_id() ] );
400
401 $image_meta = new Image_Meta( $image_id );
402
403 $image_meta
404 ->set_status( Image_Status::RESTORING_FAILED )
405 ->set_error_type( Image_Optimization_Error_Type::PLUGIN_DEACTIVATION )
406 ->save();
407 }
408 }
409
410 /**
411 * Renders the Bulk Optimization link on the media pages.
412 *
413 * @return void
414 */
415 public function add_bulk_optimization_links(): void {
416 $page_url = add_query_arg(
417 [
418 'page' => 'image-optimization-settings',
419 'tab' => 'image-optimization-bulk-optimization',
420 ],
421 admin_url( 'admin.php' )
422 );
423
424 ?>
425 <script>
426 document.addEventListener( 'DOMContentLoaded', function () {
427 // Grid media is rendered by JS, so the timeout is required
428 setTimeout( () => {
429 const targetButton = document.querySelector( '.filter-items .actions input[type=submit]' ) ||
430 document.querySelector( '.media-toolbar-secondary .select-mode-toggle-button' );
431
432 if ( targetButton ) {
433 const link = document.createElement('a');
434
435 link.href = '<?php echo esc_js( $page_url ); ?>';
436 link.innerText = '<?php echo esc_js( __( 'Bulk Optimization', 'image-optimization' ) ); ?>';
437 link.className = 'button button-compact is-primary image-optimizer__button image-optimizer__button--pink';
438
439 targetButton.insertAdjacentElement( 'afterend', link );
440 }
441 }, 100 )
442 } );
443 </script>
444 <?php
445 }
446
447 /**
448 * Module constructor.
449 */
450 public function __construct() {
451 $this->register_components();
452
453 add_action( 'action_scheduler_init', [ Migration_Manager::class, 'init' ] );
454
455 add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_global_assets' ] );
456 add_filter( 'plugin_action_links', [ $this, 'add_plugin_links' ], 10, 2 );
457
458 add_action('current_screen', function () {
459 if ( ! $this->should_render() ) {
460 return;
461 }
462
463 if ( ! self::is_elementor_one() ) {
464 add_action( 'admin_notices', [ $this, 'maybe_add_quota_reached_notice' ] );
465 add_action( 'admin_notices', [ $this, 'maybe_add_80_quota_reached_notice' ] );
466 }
467
468 add_action( 'admin_notices', [ $this, 'maybe_add_url_mismatch_notice' ] );
469
470 if ( Utils::is_media_page() ) {
471
472 add_action('all_admin_notices', function () {
473 $this->render_app();
474 });
475 }
476
477 if ( Utils::is_plugin_page() ) {
478 add_action('in_admin_header', function () {
479 $this->render_top_bar();
480 });
481 }
482
483 add_action('admin_enqueue_scripts', function () {
484 $this->enqueue_scripts();
485 });
486
487 if ( Utils::is_media_page() ) {
488 add_action( 'admin_enqueue_scripts', [ $this, 'add_bulk_optimization_links' ] );
489 }
490 });
491 }
492 }
493