PluginProbe
Image Optimization – Compress Images and Convert to WebP or AVIF / 1.6.8
Image Optimization – Compress Images and Convert to WebP or AVIF v1.6.8
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 1.6.6 All 32 releases
image-optimization / modules / core / module.php

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

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