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 +356 -84 1.0.21.7.7 View file →
@@ -1,48 +1,62 @@
1 1 <?php
2 -namespace ImageOptimizer\Modules\Core;
2 +namespace ImageOptimization\Modules\Core;
3 3
4 -use ImageOptimizer\Modules\Oauth\{
5 - Classes\Data,
6 - Components\Connect,
7 - Rest\Activate,
8 - Rest\ConnectInit,
9 - Rest\Deactivate,
10 - Rest\Disconnect,
11 - Rest\GetSubscriptions,
12 -};
13 -use ImageOptimizer\Modules\Optimization\{
4 +use ImageOptimization\Modules\Optimization\{
5 + Classes\Validate_Image,
14 6 Rest\Cancel_Bulk_Optimization,
15 7 Rest\Optimize_Bulk,
16 8 };
17 -use ImageOptimizer\Modules\Backups\Rest\{
9 +use ImageOptimization\Modules\Settings\Classes\Settings;
10 +use ImageOptimization\Modules\Backups\Rest\{
18 11 Restore_All,
19 12 Remove_Backups,
20 13 };
21 -use ImageOptimizer\Classes\{
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',
48 + 'User_Feedback',
49 + 'Not_Connected',
50 + 'Not_Connected_Modal',
51 + 'Renewal_Notice',
52 + 'Notificator',
39 53 ];
40 54 }
41 55
42 56 private function render_top_bar() {
43 57 ?>
44 - <div id="image-optimizer-top-bar"></div>
58 + <div id="image-optimization-top-bar"></div>
45 59 <?php
46 60 }
47 61
48 62 private function render_app() {
@@ -47,76 +61,184 @@
47 61
48 62 private function render_app() {
49 63 ?>
50 64 <div class="clear"></div>
51 - <div id="image-optimizer-app"></div>
65 + <div id="image-optimization-app"></div>
52 66 <?php
53 67 }
54 68
55 - public function add_plugin_links( $links, $plugin_file_name ): array {
56 - if ( false === strpos( $plugin_file_name, '/image-optimization.php' ) ) {
57 - return (array) $links;
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;
58 77 }
59 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 +
60 200 $custom_links = [
61 201 'settings' => sprintf(
62 202 '<a href="%s">%s</a>',
63 - admin_url( 'admin.php?page=' . \ImageOptimizer\Modules\Settings\Module::SETTING_BASE_SLUG ),
64 - esc_html__( 'Settings', 'image-optimizer' )
203 + admin_url( 'admin.php?page=' . \ImageOptimization\Modules\Settings\Module::SETTING_BASE_SLUG ),
204 + esc_html__( 'Settings', 'image-optimization' )
65 205 ),
66 206 ];
207 + // @var ImageOptimizer/Modules/ConnectManager/Module
208 + $module = Plugin::instance()->modules_manager->get_modules( 'connect-manager' );
67 209
68 - if ( ! Connect::is_connected() ) {
69 - $custom_links['connect'] = sprintf(
70 - '<a href="%s" style="color: #524CFF; font-weight: 700;">%s</a>',
71 - admin_url( 'admin.php?page=' . \ImageOptimizer\Modules\Settings\Module::SETTING_BASE_SLUG . '&action=connect' ),
72 - esc_html__( 'Connect', 'image-optimizer' )
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' )
73 215 );
74 216 }
75 -
76 - if ( Connect::is_connected() && ! Connect::is_activated() ) {
77 - $custom_links['activate'] = sprintf(
78 - '<a href="%s" style="color: #524CFF; font-weight: 700;">%s</a>',
79 - admin_url( 'admin.php?page=' . \ImageOptimizer\Modules\Settings\Module::SETTING_BASE_SLUG ),
80 - esc_html__( 'Activate', 'image-optimizer' )
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' )
81 222 );
82 223 }
83 224
84 - if ( Connect::is_connected() && Connect::is_activated() ) {
85 - $plan_data = Connect::check_connect_status();
86 - $usage_percentage = 0;
87 -
88 - if ( ! empty( $plan_data ) ) {
89 - $usage_percentage = $plan_data->used_quota / $plan_data->quota * 100;
90 - }
91 -
92 - if ( $usage_percentage >= 80 ) {
93 - $custom_links['upgrade'] = sprintf(
94 - '<a href="%s" style="color: #524CFF; font-weight: 700;">%s</a>',
95 - 'https://go.elementor.com/io-panel-upgrade/',
96 - esc_html__( 'Upgrade', 'image-optimizer' )
97 - );
98 - }
99 - }
100 -
101 225 return array_merge( $custom_links, $links );
102 226 }
103 227
104 - /**
105 - * Enqueue fonts
106 - */
107 - public function enqueue_fonts() {
108 - $screen = get_current_screen();
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 + );
109 235
110 - if ( ! $this->should_render() && ( 'attachment' !== $screen->id ) ) {
111 - return;
112 - }
113 -
114 236 wp_enqueue_style(
115 - 'image-optimizer-admin-fonts',
116 - 'https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap',
237 + 'image-optimization-core-style-admin',
238 + $this->get_css_assets_url( 'style-admin', 'assets/build/' ),
117 239 [],
118 - IMAGE_OPTIMIZER_VERSION
240 + IMAGE_OPTIMIZATION_VERSION,
119 241 );
120 242 }
121 243
122 244 /**
@@ -122,9 +244,9 @@
122 244 /**
123 245 * Enqueue styles and scripts
124 246 */
125 247 private function enqueue_scripts() {
126 - $asset_file = include IMAGE_OPTIMIZER_ASSETS_PATH . 'build/admin.asset.php';
248 + $asset_file = require IMAGE_OPTIMIZATION_ASSETS_PATH . 'build/admin.asset.php';
127 249
128 250 foreach ( $asset_file['dependencies'] as $style ) {
129 251 wp_enqueue_style( $style );
130 252 }
@@ -129,46 +251,64 @@
129 251 wp_enqueue_style( $style );
130 252 }
131 253
132 254 wp_enqueue_script(
133 - 'image-optimizer-admin',
255 + 'image-optimization-admin',
134 256 $this->get_js_assets_url( 'admin' ),
135 257 array_merge( $asset_file['dependencies'], [ 'wp-util' ] ),
136 - IMAGE_OPTIMIZER_VERSION,
258 + $asset_file['version'],
137 259 true
138 260 );
139 261
140 262 wp_localize_script(
141 - 'image-optimizer-admin',
263 + 'image-optimization-admin',
142 264 'imageOptimizerAppSettings',
143 265 [
144 266 'siteUrl' => wp_parse_url( get_site_url(), PHP_URL_HOST ),
145 267 'thumbnailSizes' => wp_get_registered_image_subsizes(),
146 268 'isDevelopment' => defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG,
269 + 'isRTL' => is_rtl(),
270 + 'version' => IMAGE_OPTIMIZATION_VERSION,
147 271 ]
148 272 );
149 273
150 - $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() );
151 281
152 282 wp_localize_script(
153 - 'image-optimizer-admin',
283 + 'image-optimization-admin',
154 284 'imageOptimizerUserData',
155 285 [
156 - 'isConnected' => Connect::is_connected(),
157 - 'isActivated' => Connect::is_activated(),
158 - 'planData' => Connect::is_activated() ? Connect::check_connect_status() : null,
159 - 'licenseKey' => Connect::is_activated() ? Data::get_activation_state() : null,
160 - 'imagesLeft' => Connect::is_activated() ? Data::images_left() : null,
161 - 'isOwner' => Connect::is_connected() ? Data::user_is_subscription_owner() : null,
162 - '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 ),
163 302
164 303 'wpRestNonce' => wp_create_nonce( 'wp_rest' ),
165 304 'disconnect' => wp_create_nonce( 'wp_rest' ),
166 - 'authInitNonce' => wp_create_nonce( ConnectInit::NONCE_NAME ),
167 - 'authDisconnectNonce' => wp_create_nonce( Disconnect::NONCE_NAME ),
168 - 'authDeactivateNonce' => wp_create_nonce( Deactivate::NONCE_NAME ),
169 - 'authGetSubscriptionsNonce' => wp_create_nonce( GetSubscriptions::NONCE_NAME ),
170 - '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() ),
171 311 'removeBackupsNonce' => wp_create_nonce( Remove_Backups::NONCE_NAME ),
172 312 'restoreAllImagesNonce' => wp_create_nonce( Restore_All::NONCE_NAME ),
173 313 'optimizeBulkNonce' => wp_create_nonce( Optimize_Bulk::NONCE_NAME ),
174 314 'cancelBulkOptimizationNonce' => wp_create_nonce( Cancel_Bulk_Optimization::NONCE_NAME ),
@@ -174,9 +314,9 @@
174 314 'cancelBulkOptimizationNonce' => wp_create_nonce( Cancel_Bulk_Optimization::NONCE_NAME ),
175 315 ]
176 316 );
177 317
178 - wp_set_script_translations( 'image-optimizer-admin', 'image-optimizer' );
318 + wp_set_script_translations( 'image-optimization-admin', 'image-optimization' );
179 319 }
180 320
181 321 private function should_render(): bool {
182 322 return ( Utils::is_media_page() || Utils::is_plugin_page() ) && Utils::user_is_admin();
@@ -181,16 +321,140 @@
181 321 private function should_render(): bool {
182 322 return ( Utils::is_media_page() || Utils::is_plugin_page() ) && Utils::user_is_admin();
183 323 }
184 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 +
185 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 + /**
186 448 * Module constructor.
187 449 */
188 450 public function __construct() {
189 451 $this->register_components();
190 452
453 + add_action( 'action_scheduler_init', [ Migration_Manager::class, 'init' ] );
454 +
455 + add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_global_assets' ] );
191 456 add_filter( 'plugin_action_links', [ $this, 'add_plugin_links' ], 10, 2 );
192 - add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_fonts' ] );
193 457
194 458 add_action('current_screen', function () {
195 459 if ( ! $this->should_render() ) {
196 460 return;
@@ -195,12 +459,16 @@
195 459 if ( ! $this->should_render() ) {
196 460 return;
197 461 }
198 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 +
199 470 if ( Utils::is_media_page() ) {
200 - add_action('in_admin_header', function () {
201 - $this->render_top_bar();
202 - });
203 471
204 472 add_action('all_admin_notices', function () {
205 473 $this->render_app();
206 474 });
@@ -214,7 +482,11 @@
214 482
215 483 add_action('admin_enqueue_scripts', function () {
216 484 $this->enqueue_scripts();
217 485 });
486 +
487 + if ( Utils::is_media_page() ) {
488 + add_action( 'admin_enqueue_scripts', [ $this, 'add_bulk_optimization_links' ] );
489 + }
218 490 });
219 491 }
220 492 }