PluginProbe
Autoptimize / 2.5.1
Autoptimize v2.5.1
2.2.2 2.3.0 2.3.1 2.3.2 2.3.3 2.3.4 2.4.0 2.4.1 2.4.2 2.4.3 2.4.4 2.5.0 2.5.1 2.6.0 2.6.1 2.6.2 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.7.6 2.7.7 2.7.8 All 107 releases
autoptimize / classes / autoptimizeMain.php

autoptimizeMain.php in Autoptimize 2.5.1, at classes/autoptimizeMain.php

577 lines 22.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Wraps base plugin logic/hooks and handles activation/deactivation/uninstall.
4 */
5
6 if ( ! defined( 'ABSPATH' ) ) {
7 exit;
8 }
9
10 class autoptimizeMain
11 {
12 const INIT_EARLIER_PRIORITY = -1;
13 const DEFAULT_HOOK_PRIORITY = 2;
14
15 /**
16 * Version string.
17 *
18 * @var string
19 */
20 protected $version = null;
21
22 /**
23 * Main plugin filepath.
24 * Used for activation/deactivation/uninstall hooks.
25 *
26 * @var string
27 */
28 protected $filepath = null;
29
30 /**
31 * Constructor.
32 *
33 * @param string $version Version.
34 * @param string $filepath Filepath. Needed for activation/deactivation/uninstall hooks.
35 */
36 public function __construct( $version, $filepath )
37 {
38 $this->version = $version;
39 $this->filepath = $filepath;
40 }
41
42 public function run()
43 {
44 $this->add_hooks();
45
46 // Runs cache size checker.
47 $checker = new autoptimizeCacheChecker();
48 $checker->run();
49 }
50
51 protected function add_hooks()
52 {
53 if ( ! defined( 'AUTOPTIMIZE_SETUP_INITHOOK' ) ) {
54 define( 'AUTOPTIMIZE_SETUP_INITHOOK', 'plugins_loaded' );
55 }
56
57 add_action( AUTOPTIMIZE_SETUP_INITHOOK, array( $this, 'setup' ) );
58 add_action( AUTOPTIMIZE_SETUP_INITHOOK, array( $this, 'hook_page_cache_purge' ) );
59
60 add_action( 'autoptimize_setup_done', array( $this, 'version_upgrades_check' ) );
61 add_action( 'autoptimize_setup_done', array( $this, 'check_cache_and_run' ) );
62 add_action( 'autoptimize_setup_done', array( $this, 'maybe_run_ao_extra' ) );
63 add_action( 'autoptimize_setup_done', array( $this, 'maybe_run_partners_tab' ) );
64
65 add_action( 'init', array( $this, 'load_textdomain' ) );
66 add_action( 'admin_init', array( 'PAnD', 'init' ) );
67
68 register_activation_hook( $this->filepath, array( $this, 'on_activate' ) );
69 }
70
71 public function on_activate()
72 {
73 register_uninstall_hook( $this->filepath, 'autoptimizeMain::on_uninstall' );
74 }
75
76 public function load_textdomain()
77 {
78 load_plugin_textdomain( 'autoptimize' );
79 }
80
81 public function setup()
82 {
83 // Do we gzip in php when caching or is the webserver doing it?
84 define( 'AUTOPTIMIZE_CACHE_NOGZIP', (bool) get_option( 'autoptimize_cache_nogzip' ) );
85
86 // These can be overridden by specifying them in wp-config.php or such.
87 if ( ! defined( 'AUTOPTIMIZE_WP_CONTENT_NAME' ) ) {
88 define( 'AUTOPTIMIZE_WP_CONTENT_NAME', '/' . wp_basename( WP_CONTENT_DIR ) );
89 }
90 if ( ! defined( 'AUTOPTIMIZE_CACHE_CHILD_DIR' ) ) {
91 define( 'AUTOPTIMIZE_CACHE_CHILD_DIR', '/cache/autoptimize/' );
92 }
93 if ( ! defined( 'AUTOPTIMIZE_CACHEFILE_PREFIX' ) ) {
94 define( 'AUTOPTIMIZE_CACHEFILE_PREFIX', 'autoptimize_' );
95 }
96 // Note: trailing slash is not optional!
97 if ( ! defined( 'AUTOPTIMIZE_CACHE_DIR' ) ) {
98 define( 'AUTOPTIMIZE_CACHE_DIR', autoptimizeCache::get_pathname() );
99 }
100
101 define( 'WP_ROOT_DIR', substr( WP_CONTENT_DIR, 0, strlen( WP_CONTENT_DIR ) - strlen( AUTOPTIMIZE_WP_CONTENT_NAME ) ) );
102
103 if ( ! defined( 'AUTOPTIMIZE_WP_SITE_URL' ) ) {
104 if ( function_exists( 'domain_mapping_siteurl' ) ) {
105 define( 'AUTOPTIMIZE_WP_SITE_URL', domain_mapping_siteurl( get_current_blog_id() ) );
106 } else {
107 define( 'AUTOPTIMIZE_WP_SITE_URL', site_url() );
108 }
109 }
110 if ( ! defined( 'AUTOPTIMIZE_WP_CONTENT_URL' ) ) {
111 if ( function_exists( 'get_original_url' ) ) {
112 define( 'AUTOPTIMIZE_WP_CONTENT_URL', str_replace( get_original_url( AUTOPTIMIZE_WP_SITE_URL ), AUTOPTIMIZE_WP_SITE_URL, content_url() ) );
113 } else {
114 define( 'AUTOPTIMIZE_WP_CONTENT_URL', content_url() );
115 }
116 }
117 if ( ! defined( 'AUTOPTIMIZE_CACHE_URL' ) ) {
118 if ( is_multisite() && apply_filters( 'autoptimize_separate_blog_caches', true ) ) {
119 $blog_id = get_current_blog_id();
120 define( 'AUTOPTIMIZE_CACHE_URL', AUTOPTIMIZE_WP_CONTENT_URL . AUTOPTIMIZE_CACHE_CHILD_DIR . $blog_id . '/' );
121 } else {
122 define( 'AUTOPTIMIZE_CACHE_URL', AUTOPTIMIZE_WP_CONTENT_URL . AUTOPTIMIZE_CACHE_CHILD_DIR );
123 }
124 }
125 if ( ! defined( 'AUTOPTIMIZE_WP_ROOT_URL' ) ) {
126 define( 'AUTOPTIMIZE_WP_ROOT_URL', str_replace( AUTOPTIMIZE_WP_CONTENT_NAME, '', AUTOPTIMIZE_WP_CONTENT_URL ) );
127 }
128 if ( ! defined( 'AUTOPTIMIZE_HASH' ) ) {
129 define( 'AUTOPTIMIZE_HASH', wp_hash( AUTOPTIMIZE_CACHE_URL ) );
130 }
131 if ( ! defined( 'AUTOPTIMIZE_SITE_DOMAIN' ) ) {
132 define( 'AUTOPTIMIZE_SITE_DOMAIN', parse_url( AUTOPTIMIZE_WP_SITE_URL, PHP_URL_HOST ) );
133 }
134
135 // Multibyte-capable string replacements are available with a filter.
136 // Also requires 'mbstring' extension.
137 $with_mbstring = apply_filters( 'autoptimize_filter_main_use_mbstring', false );
138 if ( $with_mbstring ) {
139 autoptimizeUtils::mbstring_available( \extension_loaded( 'mbstring' ) );
140 } else {
141 autoptimizeUtils::mbstring_available( false );
142 }
143
144 do_action( 'autoptimize_setup_done' );
145 }
146
147 /**
148 * Checks if there's a need to upgrade/update options and whatnot,
149 * in which case we might need to do stuff and flush the cache
150 * to avoid old versions of aggregated files lingering around.
151 */
152 public function version_upgrades_check()
153 {
154 autoptimizeVersionUpdatesHandler::check_installed_and_update( $this->version );
155 }
156
157 public function check_cache_and_run()
158 {
159 if ( autoptimizeCache::cacheavail() ) {
160 $conf = autoptimizeConfig::instance();
161 if ( $conf->get( 'autoptimize_html' ) || $conf->get( 'autoptimize_js' ) || $conf->get( 'autoptimize_css' ) || autoptimizeImages::imgopt_active() || autoptimizeImages::should_lazyload_wrapper() ) {
162 // Hook into WordPress frontend.
163 if ( defined( 'AUTOPTIMIZE_INIT_EARLIER' ) ) {
164 add_action(
165 'init',
166 array( $this, 'start_buffering' ),
167 self::INIT_EARLIER_PRIORITY
168 );
169 } else {
170 if ( ! defined( 'AUTOPTIMIZE_HOOK_INTO' ) ) {
171 define( 'AUTOPTIMIZE_HOOK_INTO', 'template_redirect' );
172 }
173 add_action(
174 constant( 'AUTOPTIMIZE_HOOK_INTO' ),
175 array( $this, 'start_buffering' ),
176 self::DEFAULT_HOOK_PRIORITY
177 );
178 }
179
180 // And disable Jetpack's site accelerator if JS or CSS opt. are active.
181 if ( class_exists( 'Jetpack' ) && apply_filters( 'autoptimize_filter_main_disable_jetpack_cdn', true ) && ( $conf->get( 'autoptimize_js' ) || $conf->get( 'autoptimize_css' ) ) ) {
182 add_filter( 'jetpack_force_disable_site_accelerator', '__return_true' );
183 }
184 }
185 } else {
186 add_action( 'admin_notices', 'autoptimizeMain::notice_cache_unavailable' );
187 }
188 }
189
190 public function maybe_run_ao_extra()
191 {
192 if ( apply_filters( 'autoptimize_filter_extra_activate', true ) ) {
193 $ao_imgopt = new autoptimizeImages();
194 $ao_imgopt->run();
195 $ao_extra = new autoptimizeExtra();
196 $ao_extra->run();
197
198 // And show the imgopt notice.
199 add_action( 'admin_notices', 'autoptimizeMain::notice_plug_imgopt' );
200 }
201 }
202
203 public function maybe_run_partners_tab()
204 {
205 // Loads partners tab code if in admin (and not in admin-ajax.php)!
206 if ( autoptimizeConfig::is_admin_and_not_ajax() ) {
207 new autoptimizePartners();
208 }
209 }
210
211 public function hook_page_cache_purge()
212 {
213 // hook into a collection of page cache purge actions if filter allows.
214 if ( apply_filters( 'autoptimize_filter_main_hookpagecachepurge', true ) ) {
215 $page_cache_purge_actions = array(
216 'after_rocket_clean_domain', // exists.
217 'hyper_cache_purged', // Stefano confirmed this will be added.
218 'w3tc_flush_posts', // exits.
219 'w3tc_flush_all', // exists.
220 'ce_action_cache_cleared', // Sven confirmed this will be added.
221 'comet_cache_wipe_cache', // still to be confirmed by Raam.
222 'wp_cache_cleared', // cfr. https://github.com/Automattic/wp-super-cache/pull/537.
223 'wpfc_delete_cache', // Emre confirmed this will be added this.
224 'swift_performance_after_clear_all_cache', // swift perf. yeah!
225 );
226 $page_cache_purge_actions = apply_filters( 'autoptimize_filter_main_pagecachepurgeactions', $page_cache_purge_actions );
227 foreach ( $page_cache_purge_actions as $purge_action ) {
228 add_action( $purge_action, 'autoptimizeCache::clearall_actionless' );
229 }
230 }
231 }
232
233 /**
234 * Setup output buffering if needed.
235 *
236 * @return void
237 */
238 public function start_buffering()
239 {
240 if ( $this->should_buffer() ) {
241
242 // Load speedupper conditionally (true by default).
243 if ( apply_filters( 'autoptimize_filter_speedupper', true ) ) {
244 $ao_speedupper = new autoptimizeSpeedupper();
245 }
246
247 $conf = autoptimizeConfig::instance();
248
249 if ( $conf->get( 'autoptimize_js' ) ) {
250 if ( ! defined( 'CONCATENATE_SCRIPTS' ) ) {
251 define( 'CONCATENATE_SCRIPTS', false );
252 }
253 if ( ! defined( 'COMPRESS_SCRIPTS' ) ) {
254 define( 'COMPRESS_SCRIPTS', false );
255 }
256 }
257
258 if ( $conf->get( 'autoptimize_css' ) ) {
259 if ( ! defined( 'COMPRESS_CSS' ) ) {
260 define( 'COMPRESS_CSS', false );
261 }
262 }
263
264 if ( apply_filters( 'autoptimize_filter_obkiller', false ) ) {
265 while ( ob_get_level() > 0 ) {
266 ob_end_clean();
267 }
268 }
269
270 // Now, start the real thing!
271 ob_start( array( $this, 'end_buffering' ) );
272 }
273 }
274
275 /**
276 * Returns true if all the conditions to start output buffering are satisfied.
277 *
278 * @param bool $doing_tests Allows overriding the optimization of only
279 * deciding once per request (for use in tests).
280 * @return bool
281 */
282 public function should_buffer( $doing_tests = false )
283 {
284 static $do_buffering = null;
285
286 // Only check once in case we're called multiple times by others but
287 // still allows multiple calls when doing tests.
288 if ( null === $do_buffering || $doing_tests ) {
289
290 $ao_noptimize = false;
291
292 // Checking for DONOTMINIFY constant as used by e.g. WooCommerce POS.
293 if ( defined( 'DONOTMINIFY' ) && ( constant( 'DONOTMINIFY' ) === true || constant( 'DONOTMINIFY' ) === 'true' ) ) {
294 $ao_noptimize = true;
295 }
296
297 // Skip checking query strings if they're disabled.
298 if ( apply_filters( 'autoptimize_filter_honor_qs_noptimize', true ) ) {
299 // Check for `ao_noptimize` (and other) keys in the query string
300 // to get non-optimized page for debugging.
301 $keys = array(
302 'ao_noptimize',
303 'ao_noptirocket',
304 );
305 foreach ( $keys as $key ) {
306 if ( array_key_exists( $key, $_GET ) && '1' === $_GET[ $key ] ) {
307 $ao_noptimize = true;
308 break;
309 }
310 }
311 }
312
313 // If setting says not to optimize logged in user and user is logged in...
314 if ( 'on' !== get_option( 'autoptimize_optimize_logged', 'on' ) && is_user_logged_in() && current_user_can( 'edit_posts' ) ) {
315 $ao_noptimize = true;
316 }
317
318 // If setting says not to optimize cart/checkout.
319 if ( 'on' !== get_option( 'autoptimize_optimize_checkout', 'on' ) ) {
320 // Checking for woocommerce, easy digital downloads and wp ecommerce...
321 foreach ( array( 'is_checkout', 'is_cart', 'edd_is_checkout', 'wpsc_is_cart', 'wpsc_is_checkout' ) as $func ) {
322 if ( function_exists( $func ) && $func() ) {
323 $ao_noptimize = true;
324 break;
325 }
326 }
327 }
328
329 // Allows blocking of autoptimization on your own terms regardless of above decisions.
330 $ao_noptimize = (bool) apply_filters( 'autoptimize_filter_noptimize', $ao_noptimize );
331
332 // Check for site being previewed in the Customizer (available since WP 4.0).
333 $is_customize_preview = false;
334 if ( function_exists( 'is_customize_preview' ) && is_customize_preview() ) {
335 $is_customize_preview = is_customize_preview();
336 }
337
338 /**
339 * We only buffer the frontend requests (and then only if not a feed
340 * and not turned off explicitly and not when being previewed in Customizer)!
341 * NOTE: Tests throw a notice here due to is_feed() being called
342 * while the main query hasn't been ran yet. Thats why we use
343 * AUTOPTIMIZE_INIT_EARLIER in tests.
344 */
345 $do_buffering = ( ! is_admin() && ! is_feed() && ! $ao_noptimize && ! $is_customize_preview );
346 }
347
348 return $do_buffering;
349 }
350
351 /**
352 * Returns true if given markup is considered valid/processable/optimizable.
353 *
354 * @param string $content Markup.
355 *
356 * @return bool
357 */
358 public function is_valid_buffer( $content )
359 {
360 // Defaults to true.
361 $valid = true;
362
363 $has_no_html_tag = ( false === stripos( $content, '<html' ) );
364 $has_xsl_stylesheet = ( false !== stripos( $content, '<xsl:stylesheet' ) );
365 $has_html5_doctype = ( preg_match( '/^<!DOCTYPE.+html>/i', ltrim( $content ) ) > 0 );
366
367 if ( $has_no_html_tag ) {
368 // Can't be valid amp markup without an html tag preceding it.
369 $is_amp_markup = false;
370 } else {
371 $is_amp_markup = self::is_amp_markup( $content );
372 }
373
374 // If it's not html, or if it's amp or contains xsl stylesheets we don't touch it.
375 if ( $has_no_html_tag && ! $has_html5_doctype || $is_amp_markup || $has_xsl_stylesheet ) {
376 $valid = false;
377 }
378
379 return $valid;
380 }
381
382 /**
383 * Returns true if given $content is considered to be AMP markup.
384 * This is far from actual validation against AMP spec, but it'll do for now.
385 *
386 * @param string $content Markup to check.
387 *
388 * @return bool
389 */
390 public static function is_amp_markup( $content )
391 {
392 // Short-circuit when a function is available to determine whether the response is (or will be) an AMP page.
393 if ( function_exists( 'is_amp_endpoint' ) ) {
394 return is_amp_endpoint();
395 }
396
397 $is_amp_markup = preg_match( '/<html[^>]*(?:amp|âš¡)/i', $content );
398
399 return (bool) $is_amp_markup;
400 }
401
402 /**
403 * Processes/optimizes the output-buffered content and returns it.
404 * If the content is not processable, it is returned unmodified.
405 *
406 * @param string $content Buffered content.
407 *
408 * @return string
409 */
410 public function end_buffering( $content )
411 {
412 // Bail early without modifying anything if we can't handle the content.
413 if ( ! $this->is_valid_buffer( $content ) ) {
414 return $content;
415 }
416
417 $conf = autoptimizeConfig::instance();
418
419 // Determine what needs to be ran.
420 $classes = array();
421 if ( $conf->get( 'autoptimize_js' ) ) {
422 $classes[] = 'autoptimizeScripts';
423 }
424 if ( $conf->get( 'autoptimize_css' ) ) {
425 $classes[] = 'autoptimizeStyles';
426 }
427 if ( $conf->get( 'autoptimize_html' ) ) {
428 $classes[] = 'autoptimizeHTML';
429 }
430
431 $classoptions = array(
432 'autoptimizeScripts' => array(
433 'aggregate' => $conf->get( 'autoptimize_js_aggregate' ),
434 'justhead' => $conf->get( 'autoptimize_js_justhead' ),
435 'forcehead' => $conf->get( 'autoptimize_js_forcehead' ),
436 'trycatch' => $conf->get( 'autoptimize_js_trycatch' ),
437 'js_exclude' => $conf->get( 'autoptimize_js_exclude' ),
438 'cdn_url' => $conf->get( 'autoptimize_cdn_url' ),
439 'include_inline' => $conf->get( 'autoptimize_js_include_inline' ),
440 'minify_excluded' => $conf->get( 'autoptimize_minify_excluded' ),
441 ),
442 'autoptimizeStyles' => array(
443 'aggregate' => $conf->get( 'autoptimize_css_aggregate' ),
444 'justhead' => $conf->get( 'autoptimize_css_justhead' ),
445 'datauris' => $conf->get( 'autoptimize_css_datauris' ),
446 'defer' => $conf->get( 'autoptimize_css_defer' ),
447 'defer_inline' => $conf->get( 'autoptimize_css_defer_inline' ),
448 'inline' => $conf->get( 'autoptimize_css_inline' ),
449 'css_exclude' => $conf->get( 'autoptimize_css_exclude' ),
450 'cdn_url' => $conf->get( 'autoptimize_cdn_url' ),
451 'include_inline' => $conf->get( 'autoptimize_css_include_inline' ),
452 'nogooglefont' => $conf->get( 'autoptimize_css_nogooglefont' ),
453 'minify_excluded' => $conf->get( 'autoptimize_minify_excluded' ),
454 ),
455 'autoptimizeHTML' => array(
456 'keepcomments' => $conf->get( 'autoptimize_html_keepcomments' ),
457 ),
458 );
459
460 $content = apply_filters( 'autoptimize_filter_html_before_minify', $content );
461
462 // Run the classes!
463 foreach ( $classes as $name ) {
464 $instance = new $name( $content );
465 if ( $instance->read( $classoptions[ $name ] ) ) {
466 $instance->minify();
467 $instance->cache();
468 $content = $instance->getcontent();
469 }
470 unset( $instance );
471 }
472
473 $content = apply_filters( 'autoptimize_html_after_minify', $content );
474
475 return $content;
476 }
477
478 public static function on_uninstall()
479 {
480 autoptimizeCache::clearall();
481
482 $delete_options = array(
483 'autoptimize_cache_clean',
484 'autoptimize_cache_nogzip',
485 'autoptimize_css',
486 'autoptimize_css_aggregate',
487 'autoptimize_css_datauris',
488 'autoptimize_css_justhead',
489 'autoptimize_css_defer',
490 'autoptimize_css_defer_inline',
491 'autoptimize_css_inline',
492 'autoptimize_css_exclude',
493 'autoptimize_html',
494 'autoptimize_html_keepcomments',
495 'autoptimize_js',
496 'autoptimize_js_aggregate',
497 'autoptimize_js_exclude',
498 'autoptimize_js_forcehead',
499 'autoptimize_js_justhead',
500 'autoptimize_js_trycatch',
501 'autoptimize_version',
502 'autoptimize_show_adv',
503 'autoptimize_cdn_url',
504 'autoptimize_cachesize_notice',
505 'autoptimize_css_include_inline',
506 'autoptimize_js_include_inline',
507 'autoptimize_optimize_logged',
508 'autoptimize_optimize_checkout',
509 'autoptimize_extra_settings',
510 'autoptimize_service_availablity',
511 'autoptimize_imgopt_provider_stat',
512 'autoptimize_imgopt_launched',
513 'autoptimize_imgopt_settings',
514 'autoptimize_minify_excluded',
515 );
516
517 if ( ! is_multisite() ) {
518 foreach ( $delete_options as $del_opt ) {
519 delete_option( $del_opt );
520 }
521 } else {
522 global $wpdb;
523 $blog_ids = $wpdb->get_col( "SELECT blog_id FROM $wpdb->blogs" );
524 $original_blog_id = get_current_blog_id();
525 foreach ( $blog_ids as $blog_id ) {
526 switch_to_blog( $blog_id );
527 foreach ( $delete_options as $del_opt ) {
528 delete_option( $del_opt );
529 }
530 }
531 switch_to_blog( $original_blog_id );
532 }
533
534 if ( wp_get_schedule( 'ao_cachechecker' ) ) {
535 wp_clear_scheduled_hook( 'ao_cachechecker' );
536 }
537 }
538
539 public static function notice_cache_unavailable()
540 {
541 echo '<div class="error"><p>';
542 // Translators: %s is the cache directory location.
543 printf( __( 'Autoptimize cannot write to the cache directory (%s), please fix to enable CSS/ JS optimization!', 'autoptimize' ), AUTOPTIMIZE_CACHE_DIR );
544 echo '</p></div>';
545 }
546
547 public static function notice_installed()
548 {
549 echo '<div class="updated"><p>';
550 _e( 'Thank you for installing and activating Autoptimize. Please configure it under "Settings" -> "Autoptimize" to start improving your site\'s performance.', 'autoptimize' );
551 echo '</p></div>';
552 }
553
554 public static function notice_updated()
555 {
556 echo '<div class="updated"><p>';
557 _e( 'Autoptimize has just been updated. Please <strong>test your site now</strong> and adapt Autoptimize config if needed.', 'autoptimize' );
558 echo '</p></div>';
559 }
560
561 public static function notice_plug_imgopt()
562 {
563 // Translators: the URL added points to the Autopmize Extra settings.
564 $_ao_imgopt_plug_notice = sprintf( __( 'Did you know Autoptimize includes on-the-fly image optimization (with support for WebP) and CDN via ShortPixel? Check out the %1$sAutoptimize Image settings%2$s to activate this option.', 'autoptimize' ), '<a href="options-general.php?page=autoptimize_imgopt">', '</a>' );
565 $_ao_imgopt_plug_notice = apply_filters( 'autoptimize_filter_main_imgopt_plug_notice', $_ao_imgopt_plug_notice );
566 $_ao_imgopt_launch_ok = autoptimizeImages::launch_ok_wrapper();
567 $_ao_imgopt_plug_dismissible = 'ao-img-opt-plug-123';
568 $_ao_imgopt_active = autoptimizeImages::imgopt_active();
569
570 if ( current_user_can( 'manage_options' ) && '' !== $_ao_imgopt_plug_notice && ! $_ao_imgopt_active && $_ao_imgopt_launch_ok && PAnD::is_admin_notice_active( $_ao_imgopt_plug_dismissible ) ) {
571 echo '<div class="notice notice-info is-dismissible" data-dismissible="' . $_ao_imgopt_plug_dismissible . '"><p>';
572 echo $_ao_imgopt_plug_notice;
573 echo '</p></div>';
574 }
575 }
576 }
577