PluginProbe
Autoptimize / 2.9.3
Autoptimize v2.9.3
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.9.3, at classes/autoptimizeMain.php

763 lines 33.1 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' ), 15 );
63 add_action( 'autoptimize_setup_done', array( $this, 'maybe_run_admin_only_trinkets' ), 20 );
64 add_action( 'autoptimize_setup_done', array( $this, 'maybe_run_criticalcss' ), 11 );
65 add_action( 'autoptimize_setup_done', array( $this, 'maybe_run_notfound_fallback' ), 10 );
66
67 add_action( 'init', array( $this, 'load_textdomain' ) );
68
69 if ( is_multisite() && is_admin() ) {
70 // Only if multisite and if in admin we want to check if we need to save options on network level.
71 add_action( 'init', 'autoptimizeOptionWrapper::check_multisite_on_saving_options' );
72 }
73
74 // register uninstall & deactivation hooks.
75 register_uninstall_hook( $this->filepath, 'autoptimizeMain::on_uninstall' );
76 register_deactivation_hook( $this->filepath, 'autoptimizeMain::on_deactivation' );
77 }
78
79 public function load_textdomain()
80 {
81 load_plugin_textdomain( 'autoptimize' );
82 }
83
84 public function setup()
85 {
86 // Do we gzip in php when caching or is the webserver doing it?
87 define( 'AUTOPTIMIZE_CACHE_NOGZIP', (bool) autoptimizeOptionWrapper::get_option( 'autoptimize_cache_nogzip' ) );
88
89 // These can be overridden by specifying them in wp-config.php or such.
90 if ( ! defined( 'AUTOPTIMIZE_WP_CONTENT_NAME' ) ) {
91 define( 'AUTOPTIMIZE_WP_CONTENT_NAME', '/' . wp_basename( WP_CONTENT_DIR ) );
92 }
93 if ( ! defined( 'AUTOPTIMIZE_CACHE_CHILD_DIR' ) ) {
94 define( 'AUTOPTIMIZE_CACHE_CHILD_DIR', '/cache/autoptimize/' );
95 }
96 if ( ! defined( 'AUTOPTIMIZE_CACHEFILE_PREFIX' ) ) {
97 define( 'AUTOPTIMIZE_CACHEFILE_PREFIX', 'autoptimize_' );
98 }
99 // Note: trailing slash is not optional!
100 if ( ! defined( 'AUTOPTIMIZE_CACHE_DIR' ) ) {
101 define( 'AUTOPTIMIZE_CACHE_DIR', autoptimizeCache::get_pathname() );
102 }
103
104 define( 'WP_ROOT_DIR', substr( WP_CONTENT_DIR, 0, strlen( WP_CONTENT_DIR ) - strlen( AUTOPTIMIZE_WP_CONTENT_NAME ) ) );
105
106 if ( ! defined( 'AUTOPTIMIZE_WP_SITE_URL' ) ) {
107 if ( function_exists( 'domain_mapping_siteurl' ) ) {
108 define( 'AUTOPTIMIZE_WP_SITE_URL', domain_mapping_siteurl( get_current_blog_id() ) );
109 } else {
110 define( 'AUTOPTIMIZE_WP_SITE_URL', site_url() );
111 }
112 }
113 if ( ! defined( 'AUTOPTIMIZE_WP_CONTENT_URL' ) ) {
114 if ( function_exists( 'get_original_url' ) ) {
115 define( 'AUTOPTIMIZE_WP_CONTENT_URL', str_replace( get_original_url( AUTOPTIMIZE_WP_SITE_URL ), AUTOPTIMIZE_WP_SITE_URL, content_url() ) );
116 } else {
117 define( 'AUTOPTIMIZE_WP_CONTENT_URL', content_url() );
118 }
119 }
120 if ( ! defined( 'AUTOPTIMIZE_CACHE_URL' ) ) {
121 if ( is_multisite() && apply_filters( 'autoptimize_separate_blog_caches', true ) ) {
122 $blog_id = get_current_blog_id();
123 define( 'AUTOPTIMIZE_CACHE_URL', AUTOPTIMIZE_WP_CONTENT_URL . AUTOPTIMIZE_CACHE_CHILD_DIR . $blog_id . '/' );
124 } else {
125 define( 'AUTOPTIMIZE_CACHE_URL', AUTOPTIMIZE_WP_CONTENT_URL . AUTOPTIMIZE_CACHE_CHILD_DIR );
126 }
127 }
128 if ( ! defined( 'AUTOPTIMIZE_WP_ROOT_URL' ) ) {
129 define( 'AUTOPTIMIZE_WP_ROOT_URL', str_replace( AUTOPTIMIZE_WP_CONTENT_NAME, '', AUTOPTIMIZE_WP_CONTENT_URL ) );
130 }
131 if ( ! defined( 'AUTOPTIMIZE_HASH' ) ) {
132 define( 'AUTOPTIMIZE_HASH', wp_hash( AUTOPTIMIZE_CACHE_URL ) );
133 }
134 if ( ! defined( 'AUTOPTIMIZE_SITE_DOMAIN' ) ) {
135 define( 'AUTOPTIMIZE_SITE_DOMAIN', parse_url( AUTOPTIMIZE_WP_SITE_URL, PHP_URL_HOST ) );
136 }
137
138 // Multibyte-capable string replacements are available with a filter.
139 // Also requires 'mbstring' extension.
140 $with_mbstring = apply_filters( 'autoptimize_filter_main_use_mbstring', false );
141 if ( $with_mbstring ) {
142 autoptimizeUtils::mbstring_available( \extension_loaded( 'mbstring' ) );
143 } else {
144 autoptimizeUtils::mbstring_available( false );
145 }
146
147 do_action( 'autoptimize_setup_done' );
148 }
149
150 /**
151 * Checks if there's a need to upgrade/update options and whatnot,
152 * in which case we might need to do stuff and flush the cache
153 * to avoid old versions of aggregated files lingering around.
154 */
155 public function version_upgrades_check()
156 {
157 autoptimizeVersionUpdatesHandler::check_installed_and_update( $this->version );
158 }
159
160 public function check_cache_and_run()
161 {
162 if ( autoptimizeCache::cacheavail() ) {
163 $conf = autoptimizeConfig::instance();
164 if ( $conf->get( 'autoptimize_html' ) || $conf->get( 'autoptimize_js' ) || $conf->get( 'autoptimize_css' ) || autoptimizeImages::imgopt_active() || autoptimizeImages::should_lazyload_wrapper() ) {
165 if ( ! defined( 'AUTOPTIMIZE_NOBUFFER_OPTIMIZE' ) ) {
166 // Hook into WordPress frontend.
167 if ( defined( 'AUTOPTIMIZE_INIT_EARLIER' ) ) {
168 add_action(
169 'init',
170 array( $this, 'start_buffering' ),
171 self::INIT_EARLIER_PRIORITY
172 );
173 } else {
174 if ( ! defined( 'AUTOPTIMIZE_HOOK_INTO' ) ) {
175 define( 'AUTOPTIMIZE_HOOK_INTO', 'template_redirect' );
176 }
177 add_action(
178 constant( 'AUTOPTIMIZE_HOOK_INTO' ),
179 array( $this, 'start_buffering' ),
180 self::DEFAULT_HOOK_PRIORITY
181 );
182 }
183 }
184
185 // And disable Jetpack's site accelerator if JS or CSS opt. are active.
186 if ( class_exists( 'Jetpack' ) && apply_filters( 'autoptimize_filter_main_disable_jetpack_cdn', true ) && ( $conf->get( 'autoptimize_js' ) || $conf->get( 'autoptimize_css' ) ) ) {
187 add_filter( 'jetpack_force_disable_site_accelerator', '__return_true' );
188 }
189
190 // Add "no cache found" notice.
191 add_action( 'admin_notices', 'autoptimizeMain::notice_nopagecache', 99 );
192 add_action( 'admin_notices', 'autoptimizeMain::notice_potential_conflict', 99 );
193 }
194 } else {
195 add_action( 'admin_notices', 'autoptimizeMain::notice_cache_unavailable' );
196 }
197 }
198
199 public function maybe_run_ao_extra()
200 {
201 if ( apply_filters( 'autoptimize_filter_extra_activate', true ) ) {
202 $ao_imgopt = new autoptimizeImages();
203 $ao_imgopt->run();
204 $ao_extra = new autoptimizeExtra();
205 $ao_extra->run();
206
207 // And show the imgopt notice.
208 add_action( 'admin_notices', 'autoptimizeMain::notice_plug_imgopt' );
209 }
210 }
211
212 public function maybe_run_admin_only_trinkets()
213 {
214 // Loads partners tab and exit survey code if in admin (and not in admin-ajax.php)!
215 if ( autoptimizeConfig::is_admin_and_not_ajax() ) {
216 new autoptimizePartners();
217 new autoptimizeExitSurvey();
218 }
219 }
220
221 public function maybe_run_criticalcss()
222 {
223 // Loads criticalcss if the power-up is not active and if the filter returns true.
224 if ( apply_filters( 'autoptimize_filter_criticalcss_active', true ) && ! autoptimizeUtils::is_plugin_active( 'autoptimize-criticalcss/ao_criticss_aas.php' ) ) {
225 new autoptimizeCriticalCSSBase();
226 }
227 }
228
229 public function maybe_run_notfound_fallback()
230 {
231 if ( autoptimizeCache::do_fallback() ) {
232 add_action( 'template_redirect', array( 'autoptimizeCache', 'wordpress_notfound_fallback' ) );
233 }
234 }
235
236 public function hook_page_cache_purge()
237 {
238 // hook into a collection of page cache purge actions if filter allows.
239 if ( apply_filters( 'autoptimize_filter_main_hookpagecachepurge', true ) ) {
240 $page_cache_purge_actions = array(
241 'after_rocket_clean_domain', // exists.
242 'hyper_cache_purged', // Stefano confirmed this will be added.
243 'w3tc_flush_posts', // exits.
244 'w3tc_flush_all', // exists.
245 'ce_action_cache_cleared', // Sven confirmed this will be added.
246 'aoce_action_cache_cleared', // Some other cache enabler.
247 'comet_cache_wipe_cache', // still to be confirmed by Raam.
248 'wp_cache_cleared', // cfr. https://github.com/Automattic/wp-super-cache/pull/537.
249 'wpfc_delete_cache', // Emre confirmed this will be added this.
250 'swift_performance_after_clear_all_cache', // swift perf. yeah!
251 'wpo_cache_flush', // wp-optimize.
252 'rt_nginx_helper_after_fastcgi_purge_all', // nginx helper.
253 );
254 $page_cache_purge_actions = apply_filters( 'autoptimize_filter_main_pagecachepurgeactions', $page_cache_purge_actions );
255 foreach ( $page_cache_purge_actions as $purge_action ) {
256 add_action( $purge_action, 'autoptimizeCache::clearall_actionless' );
257 }
258 }
259 }
260
261 /**
262 * Setup output buffering if needed.
263 *
264 * @return void
265 */
266 public function start_buffering()
267 {
268 if ( $this->should_buffer() ) {
269
270 // Load speedupper conditionally (true by default).
271 if ( apply_filters( 'autoptimize_filter_speedupper', true ) ) {
272 $ao_speedupper = new autoptimizeSpeedupper();
273 }
274
275 $conf = autoptimizeConfig::instance();
276
277 if ( $conf->get( 'autoptimize_js' ) ) {
278 if ( ! defined( 'CONCATENATE_SCRIPTS' ) ) {
279 define( 'CONCATENATE_SCRIPTS', false );
280 }
281 if ( ! defined( 'COMPRESS_SCRIPTS' ) ) {
282 define( 'COMPRESS_SCRIPTS', false );
283 }
284 }
285
286 if ( $conf->get( 'autoptimize_css' ) ) {
287 if ( ! defined( 'COMPRESS_CSS' ) ) {
288 define( 'COMPRESS_CSS', false );
289 }
290 }
291
292 if ( apply_filters( 'autoptimize_filter_obkiller', false ) ) {
293 while ( ob_get_level() > 0 ) {
294 ob_end_clean();
295 }
296 }
297
298 // Now, start the real thing!
299 ob_start( array( $this, 'end_buffering' ) );
300 }
301 }
302
303 /**
304 * Returns true if all the conditions to start output buffering are satisfied.
305 *
306 * @param bool $doing_tests Allows overriding the optimization of only
307 * deciding once per request (for use in tests).
308 * @return bool
309 */
310 public static function should_buffer( $doing_tests = false )
311 {
312 static $do_buffering = null;
313
314 // Only check once in case we're called multiple times by others but
315 // still allows multiple calls when doing tests.
316 if ( null === $do_buffering || $doing_tests ) {
317
318 $ao_noptimize = false;
319
320 // Checking for DONOTMINIFY constant as used by e.g. WooCommerce POS.
321 if ( defined( 'DONOTMINIFY' ) && ( constant( 'DONOTMINIFY' ) === true || constant( 'DONOTMINIFY' ) === 'true' ) ) {
322 $ao_noptimize = true;
323 }
324
325 // Skip checking query strings if they're disabled.
326 if ( apply_filters( 'autoptimize_filter_honor_qs_noptimize', true ) ) {
327 // Check for `ao_noptimize` (and other) keys in the query string
328 // to get non-optimized page for debugging.
329 $keys = array(
330 'ao_noptimize',
331 'ao_noptirocket',
332 );
333 foreach ( $keys as $key ) {
334 if ( array_key_exists( $key, $_GET ) && '1' === $_GET[ $key ] ) {
335 $ao_noptimize = true;
336 break;
337 }
338 }
339 }
340
341 // If setting says not to optimize logged in user and user is logged in...
342 if ( false === $ao_noptimize && 'on' !== autoptimizeOptionWrapper::get_option( 'autoptimize_optimize_logged', 'on' ) && is_user_logged_in() && current_user_can( 'edit_posts' ) ) {
343 $ao_noptimize = true;
344 }
345
346 // If setting says not to optimize cart/checkout.
347 if ( false === $ao_noptimize && 'on' !== autoptimizeOptionWrapper::get_option( 'autoptimize_optimize_checkout', 'off' ) ) {
348 // Checking for woocommerce, easy digital downloads and wp ecommerce...
349 foreach ( array( 'is_checkout', 'is_cart', 'is_account_page', 'edd_is_checkout', 'wpsc_is_cart', 'wpsc_is_checkout' ) as $func ) {
350 if ( function_exists( $func ) && $func() ) {
351 $ao_noptimize = true;
352 break;
353 }
354 }
355 }
356
357 // And make sure pagebuilder previews don't get optimized HTML/ JS/ CSS/ ...
358 if ( false === $ao_noptimize ) {
359 $_qs_pagebuilders = array( 'tve', 'elementor-preview', 'fl_builder', 'vc_action', 'et_fb', 'bt-beaverbuildertheme', 'ct_builder', 'fb-edit', 'siteorigin_panels_live_editor' );
360 foreach ( $_qs_pagebuilders as $_pagebuilder ) {
361 if ( array_key_exists( $_pagebuilder, $_GET ) ) {
362 $ao_noptimize = true;
363 break;
364 }
365 }
366 }
367
368 // Also honor PageSpeed=off parameter as used by mod_pagespeed, in use by some pagebuilders,
369 // see https://www.modpagespeed.com/doc/experiment#ModPagespeed for info on that.
370 if ( false === $ao_noptimize && array_key_exists( 'PageSpeed', $_GET ) && 'off' === $_GET['PageSpeed'] ) {
371 $ao_noptimize = true;
372 }
373
374 // If page/ post check post_meta to see if optimize is off.
375 if ( false === autoptimizeConfig::get_post_meta_ao_settings( 'ao_post_optimize' ) ) {
376 $ao_noptimize = true;
377 }
378
379 // And finally allows blocking of autoptimization on your own terms regardless of above decisions.
380 $ao_noptimize = (bool) apply_filters( 'autoptimize_filter_noptimize', $ao_noptimize );
381
382 // Check for site being previewed in the Customizer (available since WP 4.0).
383 $is_customize_preview = false;
384 if ( function_exists( 'is_customize_preview' ) && is_customize_preview() ) {
385 $is_customize_preview = is_customize_preview();
386 }
387
388 /**
389 * We only buffer the frontend requests (and then only if not a feed
390 * and not turned off explicitly and not when being previewed in Customizer)!
391 * NOTE: Tests throw a notice here due to is_feed() being called
392 * while the main query hasn't been ran yet. Thats why we use
393 * AUTOPTIMIZE_INIT_EARLIER in tests.
394 */
395 $do_buffering = ( ! is_admin() && ! is_feed() && ! is_embed() && ! $ao_noptimize && ! $is_customize_preview );
396 }
397
398 return $do_buffering;
399 }
400
401 /**
402 * Returns true if given markup is considered valid/processable/optimizable.
403 *
404 * @param string $content Markup.
405 *
406 * @return bool
407 */
408 public function is_valid_buffer( $content )
409 {
410 // Defaults to true.
411 $valid = true;
412
413 $has_no_html_tag = ( false === stripos( $content, '<html' ) );
414 $has_xsl_stylesheet = ( false !== stripos( $content, '<xsl:stylesheet' ) || false !== stripos( $content, '<?xml-stylesheet' ) );
415 $has_html5_doctype = ( preg_match( '/^<!DOCTYPE.+html>/i', ltrim( $content ) ) > 0 );
416 $has_noptimize_page = ( false !== stripos( $content, '<!-- noptimize-page -->' ) );
417
418 if ( $has_no_html_tag ) {
419 // Can't be valid amp markup without an html tag preceding it.
420 $is_amp_markup = false;
421 } else {
422 $is_amp_markup = self::is_amp_markup( $content );
423 }
424
425 // If it's not html, or if it's amp or contains xsl stylesheets we don't touch it.
426 if ( $has_no_html_tag && ! $has_html5_doctype || $is_amp_markup || $has_xsl_stylesheet || $has_noptimize_page ) {
427 $valid = false;
428 }
429
430 return $valid;
431 }
432
433 /**
434 * Returns true if given $content is considered to be AMP markup.
435 * This is far from actual validation against AMP spec, but it'll do for now.
436 *
437 * @param string $content Markup to check.
438 *
439 * @return bool
440 */
441 public static function is_amp_markup( $content )
442 {
443 // Short-circuit if the page is already AMP from the start.
444 if (
445 preg_match(
446 sprintf(
447 '#^(?:<!.*?>|\s+)*+<html(?=\s)[^>]*?\s(%1$s|%2$s|%3$s)(\s|=|>)#is',
448 'amp',
449 "\xE2\x9A\xA1", // From \AmpProject\Attribute::AMP_EMOJI.
450 "\xE2\x9A\xA1\xEF\xB8\x8F" // From \AmpProject\Attribute::AMP_EMOJI_ALT, per https://github.com/ampproject/amphtml/issues/25990.
451 ),
452 $content
453 )
454 ) {
455 return true;
456 }
457
458 // Or else short-circuit if the AMP plugin will be processing the output to be an AMP page.
459 if ( function_exists( 'amp_is_request' ) ) {
460 return amp_is_request(); // For AMP plugin v2.0+.
461 } elseif ( function_exists( 'is_amp_endpoint' ) ) {
462 return is_amp_endpoint(); // For older/other AMP plugins (still supported in 2.0 as an alias).
463 }
464
465 return false;
466 }
467
468 /**
469 * Processes/optimizes the output-buffered content and returns it.
470 * If the content is not processable, it is returned unmodified.
471 *
472 * @param string $content Buffered content.
473 *
474 * @return string
475 */
476 public function end_buffering( $content )
477 {
478 // Bail early without modifying anything if we can't handle the content.
479 if ( ! $this->is_valid_buffer( $content ) ) {
480 return $content;
481 }
482
483 $conf = autoptimizeConfig::instance();
484
485 // Determine what needs to be ran.
486 $classes = array();
487 if ( $conf->get( 'autoptimize_js' ) ) {
488 $classes[] = 'autoptimizeScripts';
489 }
490 if ( $conf->get( 'autoptimize_css' ) ) {
491 $classes[] = 'autoptimizeStyles';
492 }
493 if ( $conf->get( 'autoptimize_html' ) ) {
494 $classes[] = 'autoptimizeHTML';
495 }
496
497 $classoptions = array(
498 'autoptimizeScripts' => array(
499 'aggregate' => $conf->get( 'autoptimize_js_aggregate' ),
500 'defer_not_aggregate' => $conf->get( 'autoptimize_js_defer_not_aggregate' ),
501 'defer_inline' => $conf->get( 'autoptimize_js_defer_inline' ),
502 'justhead' => $conf->get( 'autoptimize_js_justhead' ),
503 'forcehead' => $conf->get( 'autoptimize_js_forcehead' ),
504 'trycatch' => $conf->get( 'autoptimize_js_trycatch' ),
505 'js_exclude' => $conf->get( 'autoptimize_js_exclude' ),
506 'cdn_url' => $conf->get( 'autoptimize_cdn_url' ),
507 'include_inline' => $conf->get( 'autoptimize_js_include_inline' ),
508 'minify_excluded' => $conf->get( 'autoptimize_minify_excluded' ),
509 ),
510 'autoptimizeStyles' => array(
511 'aggregate' => $conf->get( 'autoptimize_css_aggregate' ),
512 'justhead' => $conf->get( 'autoptimize_css_justhead' ),
513 'datauris' => $conf->get( 'autoptimize_css_datauris' ),
514 'defer' => $conf->get( 'autoptimize_css_defer' ),
515 'defer_inline' => $conf->get( 'autoptimize_css_defer_inline' ),
516 'inline' => $conf->get( 'autoptimize_css_inline' ),
517 'css_exclude' => $conf->get( 'autoptimize_css_exclude' ),
518 'cdn_url' => $conf->get( 'autoptimize_cdn_url' ),
519 'include_inline' => $conf->get( 'autoptimize_css_include_inline' ),
520 'nogooglefont' => $conf->get( 'autoptimize_css_nogooglefont' ),
521 'minify_excluded' => $conf->get( 'autoptimize_minify_excluded' ),
522 ),
523 'autoptimizeHTML' => array(
524 'keepcomments' => $conf->get( 'autoptimize_html_keepcomments' ),
525 ),
526 );
527
528 $content = apply_filters( 'autoptimize_filter_html_before_minify', $content );
529
530 // Run the classes!
531 foreach ( $classes as $name ) {
532 $instance = new $name( $content );
533 if ( $instance->read( $classoptions[ $name ] ) ) {
534 $instance->minify();
535 $instance->cache();
536 $content = $instance->getcontent();
537 }
538 unset( $instance );
539 }
540
541 $content = apply_filters( 'autoptimize_html_after_minify', $content );
542
543 return $content;
544 }
545
546 public static function autoptimize_nobuffer_optimize( $html_in ) {
547 $html_out = $html_in;
548
549 if ( apply_filters( 'autoptimize_filter_speedupper', true ) ) {
550 $ao_speedupper = new autoptimizeSpeedupper();
551 }
552
553 $self = new self( AUTOPTIMIZE_PLUGIN_VERSION, AUTOPTIMIZE_PLUGIN_FILE );
554 if ( $self->should_buffer() ) {
555 $html_out = $self->end_buffering( $html_in );
556 }
557 return $html_out;
558 }
559
560 public static function on_uninstall()
561 {
562 autoptimizeCache::clearall();
563
564 $delete_options = array(
565 'autoptimize_cache_clean',
566 'autoptimize_cache_nogzip',
567 'autoptimize_css',
568 'autoptimize_css_aggregate',
569 'autoptimize_css_datauris',
570 'autoptimize_css_justhead',
571 'autoptimize_css_defer',
572 'autoptimize_css_defer_inline',
573 'autoptimize_css_inline',
574 'autoptimize_css_exclude',
575 'autoptimize_html',
576 'autoptimize_html_keepcomments',
577 'autoptimize_enable_site_config',
578 'autoptimize_enable_meta_ao_settings',
579 'autoptimize_js',
580 'autoptimize_js_aggregate',
581 'autoptimize_js_defer_not_aggregate',
582 'autoptimize_js_defer_inline',
583 'autoptimize_js_exclude',
584 'autoptimize_js_forcehead',
585 'autoptimize_js_justhead',
586 'autoptimize_js_trycatch',
587 'autoptimize_version',
588 'autoptimize_show_adv',
589 'autoptimize_cdn_url',
590 'autoptimize_cachesize_notice',
591 'autoptimize_css_include_inline',
592 'autoptimize_js_include_inline',
593 'autoptimize_optimize_logged',
594 'autoptimize_optimize_checkout',
595 'autoptimize_extra_settings',
596 'autoptimize_service_availablity',
597 'autoptimize_imgopt_provider_stat',
598 'autoptimize_imgopt_launched',
599 'autoptimize_imgopt_settings',
600 'autoptimize_minify_excluded',
601 'autoptimize_cache_fallback',
602 'autoptimize_ccss_rules',
603 'autoptimize_ccss_additional',
604 'autoptimize_ccss_queue',
605 'autoptimize_ccss_viewport',
606 'autoptimize_ccss_finclude',
607 'autoptimize_ccss_rlimit',
608 'autoptimize_ccss_rtimelimit',
609 'autoptimize_ccss_noptimize',
610 'autoptimize_ccss_debug',
611 'autoptimize_ccss_key',
612 'autoptimize_ccss_keyst',
613 'autoptimize_ccss_version',
614 'autoptimize_ccss_loggedin',
615 'autoptimize_ccss_forcepath',
616 'autoptimize_ccss_deferjquery',
617 'autoptimize_ccss_domain',
618 'autoptimize_ccss_unloadccss',
619 );
620
621 if ( ! is_multisite() ) {
622 foreach ( $delete_options as $del_opt ) {
623 delete_option( $del_opt );
624 }
625 autoptimizeMain::remove_cronjobs();
626 } else {
627 global $wpdb;
628 $blog_ids = $wpdb->get_col( "SELECT blog_id FROM $wpdb->blogs" );
629 $original_blog_id = get_current_blog_id();
630 foreach ( $blog_ids as $blog_id ) {
631 switch_to_blog( $blog_id );
632 foreach ( $delete_options as $del_opt ) {
633 delete_option( $del_opt );
634 }
635 autoptimizeMain::remove_cronjobs();
636 }
637 switch_to_blog( $original_blog_id );
638 }
639
640 // Remove AO CCSS cached files and directory.
641 $ao_ccss_dir = WP_CONTENT_DIR . '/uploads/ao_ccss/';
642 if ( file_exists( $ao_ccss_dir ) && is_dir( $ao_ccss_dir ) ) {
643 // fixme: should check for subdirs when in multisite and remove contents of those as well.
644 array_map( 'unlink', glob( $ao_ccss_dir . '*.{css,html,json,log,zip,lock}', GLOB_BRACE ) );
645 rmdir( $ao_ccss_dir );
646 }
647
648 // Remove 404-handler (although that should have been removed in clearall already).
649 $_fallback_php = trailingslashit( WP_CONTENT_DIR ) . 'autoptimize_404_handler.php';
650 if ( file_exists( $_fallback_php ) ) {
651 unlink( $_fallback_php );
652 }
653 }
654
655 public static function on_deactivation()
656 {
657 if ( is_multisite() && is_network_admin() ) {
658 global $wpdb;
659 $blog_ids = $wpdb->get_col( "SELECT blog_id FROM $wpdb->blogs" );
660 $original_blog_id = get_current_blog_id();
661 foreach ( $blog_ids as $blog_id ) {
662 switch_to_blog( $blog_id );
663 autoptimizeMain::remove_cronjobs();
664 }
665 switch_to_blog( $original_blog_id );
666 } else {
667 autoptimizeMain::remove_cronjobs();
668 }
669 autoptimizeCache::clearall();
670 }
671
672 public static function remove_cronjobs() {
673 // Remove scheduled events.
674 foreach ( array( 'ao_cachechecker', 'ao_ccss_queue', 'ao_ccss_maintenance' ) as $_event ) {
675 if ( wp_get_schedule( $_event ) ) {
676 wp_clear_scheduled_hook( $_event );
677 }
678 }
679 }
680
681 public static function notice_cache_unavailable()
682 {
683 echo '<div class="error"><p>';
684 // Translators: %s is the cache directory location.
685 printf( __( 'Autoptimize cannot write to the cache directory (%s), please fix to enable CSS/ JS optimization!', 'autoptimize' ), AUTOPTIMIZE_CACHE_DIR );
686 echo '</p></div>';
687 }
688
689 public static function notice_installed()
690 {
691 echo '<div class="updated"><p>';
692 _e( 'Thank you for installing and activating Autoptimize. Please configure it under "Settings" -> "Autoptimize" to start improving your site\'s performance.', 'autoptimize' );
693 echo '</p></div>';
694 }
695
696 public static function notice_updated()
697 {
698 echo '<div class="updated"><p>';
699 _e( 'Autoptimize has just been updated. Please <strong>test your site now</strong> and adapt Autoptimize config if needed.', 'autoptimize' );
700 echo '</p></div>';
701 }
702
703 public static function notice_plug_imgopt()
704 {
705 // Translators: the URL added points to the Autopmize Extra settings.
706 $_ao_imgopt_plug_notice = sprintf( __( 'Did you know Autoptimize includes on-the-fly image optimization (with support for WebP and AVIF) 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>' );
707 $_ao_imgopt_plug_notice = apply_filters( 'autoptimize_filter_main_imgopt_plug_notice', $_ao_imgopt_plug_notice );
708 $_ao_imgopt_launch_ok = autoptimizeImages::launch_ok_wrapper();
709 $_ao_imgopt_plug_dismissible = 'ao-img-opt-plug-123';
710 $_ao_imgopt_active = autoptimizeImages::imgopt_active();
711 $_is_ao_settings_page = autoptimizeUtils::is_ao_settings();
712
713 if ( current_user_can( 'manage_options' ) && $_is_ao_settings_page && '' !== $_ao_imgopt_plug_notice && ! $_ao_imgopt_active && $_ao_imgopt_launch_ok && PAnD::is_admin_notice_active( $_ao_imgopt_plug_dismissible ) ) {
714 echo '<div class="notice notice-info is-dismissible" data-dismissible="' . $_ao_imgopt_plug_dismissible . '"><p>';
715 echo $_ao_imgopt_plug_notice;
716 echo '</p></div>';
717 }
718 }
719
720 public static function notice_nopagecache()
721 {
722 /*
723 * Autoptimize does not do page caching (yet) but not everyone knows, so below logic tries to find out if page caching is available and if not show a notice on the AO Settings pages.
724 *
725 * uses helper function in autoptimizeUtils.php
726 */
727 $_ao_nopagecache_notice = __( 'It looks like your site might not have <strong>page caching</strong> which is a <strong>must-have for performance</strong>. If you are sure you have a page cache, you can close this notice, but when in doubt check with your host if they offer this or install a page caching plugin like for example', 'autoptimize' );
728 $_ao_pagecache_install_url = network_admin_url() . 'plugin-install.php?tab=search&type=term&s=';
729 $_ao_nopagecache_notice .= ' <a href="' . $_ao_pagecache_install_url . 'wp+super+cache' . '">WP Super Cache</a>, <a href="' . $_ao_pagecache_install_url . 'keycdn+cache+enabler' . '">KeyCDN Cache Enabler</a>, ...';
730 $_ao_nopagecache_dismissible = 'ao-nopagecache-forever'; // the notice is only shown once and will not re-appear when dismissed.
731 $_is_ao_settings_page = autoptimizeUtils::is_ao_settings();
732
733 if ( current_user_can( 'manage_options' ) && $_is_ao_settings_page && PAnD::is_admin_notice_active( $_ao_nopagecache_dismissible ) && true === apply_filters( 'autoptimize_filter_main_show_pagecache_notice', true ) ) {
734 if ( false === autoptimizeUtils::find_pagecache() ) {
735 echo '<div class="notice notice-info is-dismissible" data-dismissible="' . $_ao_nopagecache_dismissible . '"><p>';
736 echo $_ao_nopagecache_notice;
737 echo '</p></div>';
738 }
739 }
740 }
741
742 public static function notice_potential_conflict()
743 {
744 /*
745 * Using other plugins to do CSS/ JS optimization can cause unexpected and hard to troubleshoot issues, warn users who seem to be in that situation.
746 */
747 // Translators: the sentence will be finished with the name of the offending plugin and a final stop.
748 $_ao_potential_conflict_notice = __( 'It looks like you have <strong>another plugin also doing CSS and/ or JS optimization</strong>, which can result in hard to troubleshoot <strong>conflicts</strong>. For this reason it is recommended to disable this functionality in', 'autoptimize' ) . ' ';
749 $_ao_potential_conflict_dismissible = 'ao-potential-conflict-forever'; // the notice is only shown once and will not re-appear when dismissed.
750 $_is_ao_settings_page = autoptimizeUtils::is_ao_settings();
751
752 if ( current_user_can( 'manage_options' ) && $_is_ao_settings_page && PAnD::is_admin_notice_active( $_ao_potential_conflict_dismissible ) && true === apply_filters( 'autoptimize_filter_main_show_potential_conclict_notice', true ) ) {
753 $_potential_conflicts = autoptimizeUtils::find_potential_conflicts();
754 if ( false !== $_potential_conflicts ) {
755 $_ao_potential_conflict_notice .= '<strong>' . $_potential_conflicts . '</strong>.';
756 echo '<div class="notice notice-info is-dismissible" data-dismissible="' . $_ao_potential_conflict_dismissible . '"><p>';
757 echo $_ao_potential_conflict_notice;
758 echo '</p></div>';
759 }
760 }
761 }
762 }
763