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
← All changes | modules/core/module.php +305 -39 1.2.11.7.7 View file →
@@ -1,43 +1,56 @@
1 1 <?php
2 2 namespace ImageOptimization\Modules\Core;
3 3
4 -use ImageOptimization\Modules\Oauth\{
5 - Classes\Data,
6 - Components\Connect,
7 - Rest\Activate,
8 - Rest\Connect_Init,
9 - Rest\Deactivate,
10 - Rest\Disconnect,
11 - Rest\Get_Subscriptions,
12 -};
13 4 use ImageOptimization\Modules\Optimization\{
5 + Classes\Validate_Image,
14 6 Rest\Cancel_Bulk_Optimization,
15 7 Rest\Optimize_Bulk,
16 8 };
9 +use ImageOptimization\Modules\Settings\Classes\Settings;
17 10 use ImageOptimization\Modules\Backups\Rest\{
18 11 Restore_All,
19 12 Remove_Backups,
20 13 };
21 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 22 Module_Base,
23 23 Utils,
24 24 };
25 25
26 +use ImageOptimization\Modules\Connect\Module as Connect_Module;
27 +use ImageOptimization\Modules\Connect\Classes\Config;
28 +
29 +use ImageOptimization\Plugin;
30 +
26 31 if ( ! defined( 'ABSPATH' ) ) {
27 32 exit; // Exit if accessed directly.
28 33 }
29 34
30 35 class Module extends Module_Base {
36 +
37 + const ONE_MISMATCH_URL = '/wp-admin/admin.php?page=elementor-home#/home/url-mismatch';
38 +
31 39 public function get_name(): string {
32 40 return 'core';
33 41 }
34 42
35 - public static function component_list() : array {
43 + public static function component_list(): array {
36 44 return [
37 45 'Pointers',
46 + 'Migrations',
38 47 'Conflicts',
39 48 'User_Feedback',
49 + 'Not_Connected',
50 + 'Not_Connected_Modal',
51 + 'Renewal_Notice',
52 + 'Notificator',
40 53 ];
41 54 }
42 55
43 56 private function render_top_bar() {
@@ -53,9 +66,14 @@
53 66 <?php
54 67 }
55 68
56 69 public function maybe_add_quota_reached_notice() {
57 - if ( ! Connect::is_activated() || Data::images_left() > 0 ) {
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 ) {
58 76 return;
59 77 }
60 78
61 79 ?>
@@ -73,9 +91,9 @@
73 91 'You have no images left to optimize in your current plan.',
74 92 'image-optimization'
75 93 ); ?>
76 94
77 - <a href="https://go.elementor.com/io-panel-upgrade/">
95 + <a href="<?php echo esc_url( $upgrade_link ); ?>">
78 96 <?php esc_html_e(
79 97 'Upgrade plan now',
80 98 'image-optimization'
81 99 ); ?>
@@ -85,11 +103,99 @@
85 103 </div>
86 104 <?php
87 105 }
88 106
89 - public function add_plugin_links( $links, $plugin_file_name ): array {
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 +
90 196 if ( ! str_ends_with( $plugin_file_name, '/image-optimization.php' ) ) {
91 - return (array) $links;
197 + return $links;
92 198 }
93 199
94 200 $custom_links = [
95 201 'settings' => sprintf(
@@ -96,14 +202,26 @@
96 202 '<a href="%s">%s</a>',
97 203 admin_url( 'admin.php?page=' . \ImageOptimization\Modules\Settings\Module::SETTING_BASE_SLUG ),
98 204 esc_html__( 'Settings', 'image-optimization' )
99 205 ),
100 - 'upgrade' => sprintf(
101 - '<a href="%s" style="color: #524CFF; font-weight: 700;" target="_blank" rel="noopener noreferrer">%s</a>',
102 - 'https://go.elementor.com/io-panel-upgrade/',
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/' ),
103 214 esc_html__( 'Upgrade', 'image-optimization' )
104 - ),
105 - ];
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 + }
106 224
107 225 return array_merge( $custom_links, $links );
108 226 }
109 227
@@ -116,9 +234,9 @@
116 234 );
117 235
118 236 wp_enqueue_style(
119 237 'image-optimization-core-style-admin',
120 - $this->get_css_assets_url( 'style-admin', '/assets/build/' ),
238 + $this->get_css_assets_url( 'style-admin', 'assets/build/' ),
121 239 [],
122 240 IMAGE_OPTIMIZATION_VERSION,
123 241 );
124 242 }
@@ -126,9 +244,9 @@
126 244 /**
127 245 * Enqueue styles and scripts
128 246 */
129 247 private function enqueue_scripts() {
130 - $asset_file = include IMAGE_OPTIMIZATION_ASSETS_PATH . 'build/admin.asset.php';
248 + $asset_file = require IMAGE_OPTIMIZATION_ASSETS_PATH . 'build/admin.asset.php';
131 249
132 250 foreach ( $asset_file['dependencies'] as $style ) {
133 251 wp_enqueue_style( $style );
134 252 }
@@ -136,9 +254,9 @@
136 254 wp_enqueue_script(
137 255 'image-optimization-admin',
138 256 $this->get_js_assets_url( 'admin' ),
139 257 array_merge( $asset_file['dependencies'], [ 'wp-util' ] ),
140 - IMAGE_OPTIMIZATION_VERSION,
258 + $asset_file['version'],
141 259 true
142 260 );
143 261
144 262 wp_localize_script(
@@ -147,32 +265,50 @@
147 265 [
148 266 'siteUrl' => wp_parse_url( get_site_url(), PHP_URL_HOST ),
149 267 'thumbnailSizes' => wp_get_registered_image_subsizes(),
150 268 'isDevelopment' => defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG,
269 + 'isRTL' => is_rtl(),
270 + 'version' => IMAGE_OPTIMIZATION_VERSION,
151 271 ]
152 272 );
153 273
154 - $connect_data = Data::get_connect_data();
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() );
155 281
156 282 wp_localize_script(
157 283 'image-optimization-admin',
158 284 'imageOptimizerUserData',
159 285 [
160 - 'isConnected' => Connect::is_connected(),
161 - 'isActivated' => Connect::is_activated(),
162 - 'planData' => Connect::is_activated() ? Connect::get_connect_status() : null,
163 - 'licenseKey' => Connect::is_activated() ? Data::get_activation_state() : null,
164 - 'imagesLeft' => Connect::is_activated() ? Data::images_left() : null,
165 - 'isOwner' => Connect::is_connected() ? Data::user_is_subscription_owner() : null,
166 - 'subscriptionEmail' => $connect_data['user']['email'] ?? null,
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 ),
167 302
168 303 'wpRestNonce' => wp_create_nonce( 'wp_rest' ),
169 304 'disconnect' => wp_create_nonce( 'wp_rest' ),
170 - 'authInitNonce' => wp_create_nonce( Connect_Init::NONCE_NAME ),
171 - 'authDisconnectNonce' => wp_create_nonce( Disconnect::NONCE_NAME ),
172 - 'authDeactivateNonce' => wp_create_nonce( Deactivate::NONCE_NAME ),
173 - 'authGetSubscriptionsNonce' => wp_create_nonce( Get_Subscriptions::NONCE_NAME ),
174 - 'authActivateNonce' => wp_create_nonce( Activate::NONCE_NAME ),
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() ),
175 311 'removeBackupsNonce' => wp_create_nonce( Remove_Backups::NONCE_NAME ),
176 312 'restoreAllImagesNonce' => wp_create_nonce( Restore_All::NONCE_NAME ),
177 313 'optimizeBulkNonce' => wp_create_nonce( Optimize_Bulk::NONCE_NAME ),
178 314 'cancelBulkOptimizationNonce' => wp_create_nonce( Cancel_Bulk_Optimization::NONCE_NAME ),
@@ -185,14 +321,138 @@
185 321 private function should_render(): bool {
186 322 return ( Utils::is_media_page() || Utils::is_plugin_page() ) && Utils::user_is_admin();
187 323 }
188 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 +
189 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 + /**
190 448 * Module constructor.
191 449 */
192 450 public function __construct() {
193 451 $this->register_components();
194 452
453 + add_action( 'action_scheduler_init', [ Migration_Manager::class, 'init' ] );
454 +
195 455 add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_global_assets' ] );
196 456 add_filter( 'plugin_action_links', [ $this, 'add_plugin_links' ], 10, 2 );
197 457
198 458 add_action('current_screen', function () {
@@ -199,14 +459,16 @@
199 459 if ( ! $this->should_render() ) {
200 460 return;
201 461 }
202 462
203 - add_action( 'admin_notices', [ $this, 'maybe_add_quota_reached_notice' ] );
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 + }
204 467
468 + add_action( 'admin_notices', [ $this, 'maybe_add_url_mismatch_notice' ] );
469 +
205 470 if ( Utils::is_media_page() ) {
206 - add_action('in_admin_header', function () {
207 - $this->render_top_bar();
208 - });
209 471
210 472 add_action('all_admin_notices', function () {
211 473 $this->render_app();
212 474 });
@@ -220,7 +482,11 @@
220 482
221 483 add_action('admin_enqueue_scripts', function () {
222 484 $this->enqueue_scripts();
223 485 });
486 +
487 + if ( Utils::is_media_page() ) {
488 + add_action( 'admin_enqueue_scripts', [ $this, 'add_bulk_optimization_links' ] );
489 + }
224 490 });
225 491 }
226 492 }