Autoptimize - Version 2.9.0

Version Description

  • New: per page/ post Autoptimize settings so one can disable specific optimizations (needs to be enabled on the main settings page under "Misc Options").
  • New: "defer inline JS" as sub-option of "do not aggregate but defer" allowing to defer (almost) all JS.
  • Improvement: Image optimization now automatically switches between AVIF & WebP & Jpeg even if lazyload is not active (AVIF has to be explicitly enabled).
  • Improvement: re-ordering of "JavaScript optimization" settings
  • Misc. other minor fixes, see the GitHub commit log

This release coincides with my father's 76th birthday, who continues to be a big inspritation to me. He's a mechanical engineer who after retirement focused his technical insights, experience and never-ending inquisitiveness on fountain pen design and prototyping, inventing a new bulkfiller mechanism in the process. Search the web for Fountainbel to find out more about him (or read this older blogpost I wrote in Dutch). Love you pops!

Download this release

Release Info

Developer futtta
Plugin Icon 128x128 Autoptimize
Version 2.9.0
Comparing to
See all releases

Code changes from version 2.8.4 to 2.9.0

autoptimize.php CHANGED
@@ -3,7 +3,7 @@
3
  * Plugin Name: Autoptimize
4
  * Plugin URI: https://autoptimize.com/
5
  * Description: Makes your site faster by optimizing CSS, JS, Images, Google fonts and more.
6
- * Version: 2.8.4
7
  * Author: Frank Goossens (futtta)
8
  * Author URI: https://autoptimize.com/
9
  * Text Domain: autoptimize
@@ -21,7 +21,7 @@ if ( ! defined( 'ABSPATH' ) ) {
21
  exit;
22
  }
23
 
24
- define( 'AUTOPTIMIZE_PLUGIN_VERSION', '2.8.4' );
25
 
26
  // plugin_dir_path() returns the trailing slash!
27
  define( 'AUTOPTIMIZE_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
3
  * Plugin Name: Autoptimize
4
  * Plugin URI: https://autoptimize.com/
5
  * Description: Makes your site faster by optimizing CSS, JS, Images, Google fonts and more.
6
+ * Version: 2.9.0
7
  * Author: Frank Goossens (futtta)
8
  * Author URI: https://autoptimize.com/
9
  * Text Domain: autoptimize
21
  exit;
22
  }
23
 
24
+ define( 'AUTOPTIMIZE_PLUGIN_VERSION', '2.9.0' );
25
 
26
  // plugin_dir_path() returns the trailing slash!
27
  define( 'AUTOPTIMIZE_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
classes/autoptimizeBase.php CHANGED
@@ -95,6 +95,8 @@ abstract class autoptimizeBase
95
  } elseif ( ( false === $double_slash_position ) && ( false === strpos( $url, $site_host ) ) ) {
96
  if ( AUTOPTIMIZE_WP_SITE_URL === $site_host ) {
97
  $url = AUTOPTIMIZE_WP_SITE_URL . $url;
 
 
98
  } else {
99
  $url = AUTOPTIMIZE_WP_SITE_URL . autoptimizeUtils::path_canonicalize( $url );
100
  }
@@ -145,7 +147,7 @@ abstract class autoptimizeBase
145
  $tmp_ao_root = preg_replace( '/https?:/', '', AUTOPTIMIZE_WP_SITE_URL );
146
  }
147
 
148
- if ( is_multisite() && ! is_main_site() && ! empty( $this->cdn_url ) ) {
149
  // multisite child sites with CDN need the network_site_url as tmp_ao_root but only if directory-based multisite.
150
  $_network_site_url = network_site_url();
151
  if ( strpos( AUTOPTIMIZE_WP_SITE_URL, $_network_site_url ) !== false ) {
@@ -310,12 +312,11 @@ abstract class autoptimizeBase
310
  // Allows API/filter to further tweak the cdn url...
311
  $cdn_url = apply_filters( 'autoptimize_filter_base_cdnurl', $cdn_url );
312
  if ( ! empty( $cdn_url ) ) {
313
- $this->debug_log( 'before=' . $url );
314
 
315
  // Simple str_replace-based approach fails when $url is protocol-or-host-relative.
316
  $is_protocol_relative = autoptimizeUtils::is_protocol_relative( $url );
317
  $is_host_relative = ( ! $is_protocol_relative && ( '/' === $url[0] ) );
318
- $cdn_url = rtrim( $cdn_url, '/' );
319
 
320
  if ( $is_host_relative ) {
321
  // Prepending host-relative urls with the cdn url.
@@ -329,11 +330,8 @@ abstract class autoptimizeBase
329
  } else {
330
  $site_url = AUTOPTIMIZE_WP_SITE_URL;
331
  }
332
- $this->debug_log( '`' . $site_url . '` -> `' . $cdn_url . '` in `' . $url . '`' );
333
  $url = str_replace( $site_url, $cdn_url, $url );
334
  }
335
-
336
- $this->debug_log( 'after=' . $url );
337
  }
338
 
339
  // Allow API filter to take further care of CDN replacement.
95
  } elseif ( ( false === $double_slash_position ) && ( false === strpos( $url, $site_host ) ) ) {
96
  if ( AUTOPTIMIZE_WP_SITE_URL === $site_host ) {
97
  $url = AUTOPTIMIZE_WP_SITE_URL . $url;
98
+ } elseif ( 0 === strpos( $url, '/' ) ) {
99
+ $url = '//' . $site_host . autoptimizeUtils::path_canonicalize( $url );
100
  } else {
101
  $url = AUTOPTIMIZE_WP_SITE_URL . autoptimizeUtils::path_canonicalize( $url );
102
  }
147
  $tmp_ao_root = preg_replace( '/https?:/', '', AUTOPTIMIZE_WP_SITE_URL );
148
  }
149
 
150
+ if ( is_multisite() && ! is_main_site() && ! empty( $this->cdn_url ) && apply_filters( 'autoptimize_filter_base_getpage_multisite_cdn_juggling', true ) ) {
151
  // multisite child sites with CDN need the network_site_url as tmp_ao_root but only if directory-based multisite.
152
  $_network_site_url = network_site_url();
153
  if ( strpos( AUTOPTIMIZE_WP_SITE_URL, $_network_site_url ) !== false ) {
312
  // Allows API/filter to further tweak the cdn url...
313
  $cdn_url = apply_filters( 'autoptimize_filter_base_cdnurl', $cdn_url );
314
  if ( ! empty( $cdn_url ) ) {
 
315
 
316
  // Simple str_replace-based approach fails when $url is protocol-or-host-relative.
317
  $is_protocol_relative = autoptimizeUtils::is_protocol_relative( $url );
318
  $is_host_relative = ( ! $is_protocol_relative && ( '/' === $url[0] ) );
319
+ $cdn_url = esc_url( rtrim( $cdn_url, '/' ) );
320
 
321
  if ( $is_host_relative ) {
322
  // Prepending host-relative urls with the cdn url.
330
  } else {
331
  $site_url = AUTOPTIMIZE_WP_SITE_URL;
332
  }
 
333
  $url = str_replace( $site_url, $cdn_url, $url );
334
  }
 
 
335
  }
336
 
337
  // Allow API filter to take further care of CDN replacement.
classes/autoptimizeConfig.php CHANGED
@@ -62,6 +62,10 @@ class autoptimizeConfig
62
  }
63
 
64
  $this->settings_screen_do_remote_http = apply_filters( 'autoptimize_settingsscreen_remotehttp', $this->settings_screen_do_remote_http );
 
 
 
 
65
  }
66
 
67
  // Adds the Autoptimize Toolbar to the Admin bar.
@@ -116,7 +120,7 @@ class autoptimizeConfig
116
  input[type=url]:invalid {color: red; border-color:red;} .form-table th{font-weight:normal;}
117
  #autoptimize_main .cb_label {display: block; padding-left: 25px; text-indent: -25px;}
118
  #autoptimize_main .form-table th {padding-top: 15px; padding-bottom: 15px;}
119
- #autoptimize_main .js_not_aggregate td, #autoptimize_main .js_not_aggregate th{padding-top:0px;}
120
 
121
  /* rss block */
122
  #futtta_feed ul{list-style:outside;}
@@ -227,22 +231,32 @@ if ( is_network_admin() && autoptimizeOptionWrapper::is_ao_active_for_network()
227
  <tr valign="top" class="js_sub js_aggregate_master">
228
  <th scope="row"><?php _e( 'Aggregate JS-files?', 'autoptimize' ); ?></th>
229
  <td><label class="cb_label"><input type="checkbox" id="autoptimize_js_aggregate" name="autoptimize_js_aggregate" <?php echo $conf->get( 'autoptimize_js_aggregate' ) ? 'checked="checked" ' : ''; ?>/>
230
- <?php _e( 'Aggregate all linked JS-files to have them loaded non-render blocking? If this option is off, the individual JS-files will remain in place but will be minified.', 'autoptimize' ); ?></label></td>
231
- </tr>
232
- <tr valign="top" class="js_sub js_not_aggregate">
233
- <th scope="row"><?php _e( 'Do not aggregate but defer?', 'autoptimize' ); ?></th>
234
- <td><label class="cb_label"><input type="checkbox" id="autoptimize_js_defer_not_aggregate" name="autoptimize_js_defer_not_aggregate" <?php echo $conf->get( 'autoptimize_js_defer_not_aggregate' ) ? 'checked="checked" ' : ''; ?>/>
235
- <?php _e( 'When JS is not aggregated, all linked JS-files can be deferred instead, making them non-render-blocking.', 'autoptimize' ); ?></label></td>
236
  </tr>
237
- <tr valign="top" class="js_sub js_aggregate">
238
- <th scope="row"><?php _e( 'Also aggregate inline JS?', 'autoptimize' ); ?></th>
239
  <td><label class="cb_label"><input type="checkbox" name="autoptimize_js_include_inline" <?php echo autoptimizeOptionWrapper::get_option( 'autoptimize_js_include_inline' ) ? 'checked="checked" ' : ''; ?>/>
240
- <?php _e( 'Let Autoptimize also extract JS from the HTML. <strong>Warning</strong>: this can make Autoptimize\'s cache size grow quickly, so only enable this if you know what you\'re doing.', 'autoptimize' ); ?></label></td>
241
  </tr>
242
- <tr valign="top" class="js_sub js_aggregate">
243
- <th scope="row"><?php _e( 'Force JavaScript in &lt;head&gt;?', 'autoptimize' ); ?></th>
244
  <td><label class="cb_label"><input type="checkbox" name="autoptimize_js_forcehead" <?php echo autoptimizeOptionWrapper::get_option( 'autoptimize_js_forcehead' ) ? 'checked="checked" ' : ''; ?>/>
245
- <?php _e( 'Load JavaScript early, this can potentially fix some JS-errors, but makes the JS render blocking.', 'autoptimize' ); ?></label></td>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
246
  </tr>
247
  <?php if ( autoptimizeOptionWrapper::get_option( 'autoptimize_js_justhead' ) ) { ?>
248
  <tr valign="top" class="js_sub js_aggregate">
@@ -260,14 +274,13 @@ if ( is_network_admin() && autoptimizeOptionWrapper::is_ao_active_for_network()
260
  <th scope="row"><?php _e( 'Exclude scripts from Autoptimize:', 'autoptimize' ); ?></th>
261
  <td><label><input type="text" style="width:100%;" name="autoptimize_js_exclude" value="<?php echo esc_attr( autoptimizeOptionWrapper::get_option( 'autoptimize_js_exclude', 'wp-includes/js/dist/, wp-includes/js/tinymce/, js/jquery/jquery.js, js/jquery/jquery.min.js' ) ); ?>"/><br />
262
  <?php
263
- echo __( 'A comma-separated list of scripts you want to exclude from being optimized, for example \'whatever.js, another.js\' (without the quotes) to exclude those scripts from being aggregated by Autoptimize.', 'autoptimize' ) . ' ' . __( 'Important: excluded non-minified files are still minified by Autoptimize unless that option under "misc" is disabled.', 'autoptimize' );
264
  ?>
265
  </label></td>
266
  </tr>
267
- <tr valign="top" class="js_sub js_aggregate">
268
- <th scope="row"><?php _e( 'Add try-catch wrapping?', 'autoptimize' ); ?></th>
269
- <td><label class="cb_label"><input type="checkbox" name="autoptimize_js_trycatch" <?php echo autoptimizeOptionWrapper::get_option( 'autoptimize_js_trycatch' ) ? 'checked="checked" ' : ''; ?>/>
270
- <?php _e( 'If your scripts break because of a JS-error, you might want to try this.', 'autoptimize' ); ?></label></td>
271
  </tr>
272
  </table>
273
  </li>
@@ -307,7 +320,7 @@ echo ' <i>' . __( '(deprecated)', 'autoptimize' ) . '</i>';
307
  </tr>
308
  <?php } ?>
309
  <tr valign="top" class="css_sub">
310
- <th scope="row"><?php _e( 'Inline and Defer CSS?', 'autoptimize' ); ?></th>
311
  <td><label class="cb_label"><input type="checkbox" name="autoptimize_css_defer" id="autoptimize_css_defer" <?php echo autoptimizeOptionWrapper::get_option( 'autoptimize_css_defer' ) ? 'checked="checked" ' : ''; ?>/>
312
  <?php
313
  _e( 'Inline "above the fold CSS" while loading the main autoptimized CSS only after page load. <a href="https://wordpress.org/plugins/autoptimize/faq/" target="_blank">Check the FAQ</a> for more info.', 'autoptimize' );
@@ -335,6 +348,15 @@ echo __( 'A comma-separated list of CSS you want to exclude from being optimized
335
  ?>
336
  </label></td>
337
  </tr>
 
 
 
 
 
 
 
 
 
338
  </table>
339
  </li>
340
 
@@ -434,6 +456,15 @@ echo __( 'A comma-separated list of CSS you want to exclude from being optimized
434
  </td>
435
  </tr>
436
  <?php } ?>
 
 
 
 
 
 
 
 
 
437
  </table>
438
  </li>
439
 
@@ -528,15 +559,16 @@ echo __( 'A comma-separated list of CSS you want to exclude from being optimized
528
 
529
  jQuery( "#autoptimize_js_aggregate" ).change(function() {
530
  if (this.checked && jQuery("#autoptimize_js").prop('checked')) {
531
- jQuery( ".js_aggregate:visible" ).fadeTo( "fast",1 );
532
- jQuery( "#autoptimize_js_defer_not_aggregate" ).prop( 'checked', false );
533
- jQuery( ".js_not_aggregate:visible" ).fadeTo( "fast", .33 );
534
- jQuery( ".js_aggregate_master:visible" ).fadeTo( "fast", 1 );
535
- jQuery( "#min_excl_row" ).show();
 
536
  } else {
537
- jQuery( ".js_aggregate:visible" ).fadeTo( "fast", .33 );
538
- jQuery( ".js_not_aggregate:visible" ).fadeTo( "fast", 1 );
539
- if ( jQuery( "#autoptimize_css_aggregate" ).prop( 'checked' ) == false ) {
540
  jQuery( "#min_excl_row" ).hide();
541
  }
542
  }
@@ -544,12 +576,14 @@ echo __( 'A comma-separated list of CSS you want to exclude from being optimized
544
 
545
  jQuery( "#autoptimize_js_defer_not_aggregate" ).change(function() {
546
  if (this.checked && jQuery("#autoptimize_js").prop('checked')) {
547
- jQuery( "#autoptimize_js_aggregate" ).prop( 'checked', false );
548
- jQuery( ".js_aggregate:visible" ).fadeTo( "fast", .33 );
549
- jQuery( ".js_aggregate_master:visible" ).fadeTo( "fast", .33 );
550
- jQuery( ".js_not_aggregate:visible" ).fadeTo( "fast", 1 );
 
551
  } else {
552
- jQuery( ".js_aggregate_master:visible" ).fadeTo( "fast", 1 );
 
553
  }
554
  });
555
 
@@ -631,10 +665,13 @@ echo __( 'A comma-separated list of CSS you want to exclude from being optimized
631
  if (!jQuery("#autoptimize_js").prop('checked')) {
632
  jQuery(".js_sub:visible").fadeTo('fast',.33);
633
  }
634
- if (!jQuery("#autoptimize_js_aggregate").prop('checked')) {
635
- jQuery(".js_aggregate:visible").fadeTo('fast',.33);
636
- } else {
637
- jQuery( ".js_not_aggregate:visible" ).fadeTo( 'fast', .33 );
 
 
 
638
  }
639
  if (jQuery("#autoptimize_enable_site_config").prop('checked')) {
640
  jQuery("li.itemDetail:not(.multiSite)").fadeTo('fast',.33);
@@ -689,6 +726,7 @@ echo __( 'A comma-separated list of CSS you want to exclude from being optimized
689
  register_setting( 'autoptimize', 'autoptimize_js' );
690
  register_setting( 'autoptimize', 'autoptimize_js_aggregate' );
691
  register_setting( 'autoptimize', 'autoptimize_js_defer_not_aggregate' );
 
692
  register_setting( 'autoptimize', 'autoptimize_js_exclude' );
693
  register_setting( 'autoptimize', 'autoptimize_js_trycatch' );
694
  register_setting( 'autoptimize', 'autoptimize_js_justhead' );
@@ -710,6 +748,7 @@ echo __( 'A comma-separated list of CSS you want to exclude from being optimized
710
  register_setting( 'autoptimize', 'autoptimize_optimize_checkout' );
711
  register_setting( 'autoptimize', 'autoptimize_minify_excluded' );
712
  register_setting( 'autoptimize', 'autoptimize_cache_fallback' );
 
713
  }
714
 
715
  public function setmeta( $links, $file = null )
@@ -745,32 +784,34 @@ echo __( 'A comma-separated list of CSS you want to exclude from being optimized
745
  public static function get_defaults()
746
  {
747
  static $config = array(
748
- 'autoptimize_html' => 0,
749
- 'autoptimize_html_keepcomments' => 0,
750
- 'autoptimize_enable_site_config' => 1,
751
- 'autoptimize_js' => 0,
752
- 'autoptimize_js_aggregate' => 1,
753
- 'autoptimize_js_defer_not_aggregate' => 0,
754
- 'autoptimize_js_exclude' => 'wp-includes/js/dist/, wp-includes/js/tinymce/, js/jquery/jquery.js, js/jquery/jquery.min.js',
755
- 'autoptimize_js_trycatch' => 0,
756
- 'autoptimize_js_justhead' => 0,
757
- 'autoptimize_js_include_inline' => 0,
758
- 'autoptimize_js_forcehead' => 0,
759
- 'autoptimize_css' => 0,
760
- 'autoptimize_css_aggregate' => 1,
761
- 'autoptimize_css_exclude' => 'admin-bar.min.css, dashicons.min.css, wp-content/cache/, wp-content/uploads/',
762
- 'autoptimize_css_justhead' => 0,
763
- 'autoptimize_css_include_inline' => 1,
764
- 'autoptimize_css_defer' => 0,
765
- 'autoptimize_css_defer_inline' => '',
766
- 'autoptimize_css_inline' => 0,
767
- 'autoptimize_css_datauris' => 0,
768
- 'autoptimize_cdn_url' => '',
769
- 'autoptimize_cache_nogzip' => 1,
770
- 'autoptimize_optimize_logged' => 1,
771
- 'autoptimize_optimize_checkout' => 0,
772
- 'autoptimize_minify_excluded' => 1,
773
- 'autoptimize_cache_fallback' => 1,
 
 
774
  );
775
 
776
  return $config;
@@ -940,10 +981,52 @@ echo __( 'A comma-separated list of CSS you want to exclude from being optimized
940
  * @return bool
941
  */
942
  public static function should_show_menu_tabs() {
943
- if ( ! is_multisite() || is_network_admin() || 'on' === autoptimizeOptionWrapper::get_option( 'autoptimize_enable_site_config' ) ) {
944
  return true;
945
  } else {
946
  return false;
947
  }
948
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
949
  }
62
  }
63
 
64
  $this->settings_screen_do_remote_http = apply_filters( 'autoptimize_settingsscreen_remotehttp', $this->settings_screen_do_remote_http );
65
+
66
+ if ( $this->is_ao_meta_settings_active() ) {
67
+ $metaBox = new autoptimizeMetabox();
68
+ }
69
  }
70
 
71
  // Adds the Autoptimize Toolbar to the Admin bar.
120
  input[type=url]:invalid {color: red; border-color:red;} .form-table th{font-weight:normal;}
121
  #autoptimize_main .cb_label {display: block; padding-left: 25px; text-indent: -25px;}
122
  #autoptimize_main .form-table th {padding-top: 15px; padding-bottom: 15px;}
123
+ #autoptimize_main .js_aggregate td, #autoptimize_main .js_aggregate th, #autoptimize_main .js_not_aggregate td, #autoptimize_main .js_not_aggregate th{padding-top:0px;}
124
 
125
  /* rss block */
126
  #futtta_feed ul{list-style:outside;}
231
  <tr valign="top" class="js_sub js_aggregate_master">
232
  <th scope="row"><?php _e( 'Aggregate JS-files?', 'autoptimize' ); ?></th>
233
  <td><label class="cb_label"><input type="checkbox" id="autoptimize_js_aggregate" name="autoptimize_js_aggregate" <?php echo $conf->get( 'autoptimize_js_aggregate' ) ? 'checked="checked" ' : ''; ?>/>
234
+ <?php _e( 'Aggregate all linked JS-files to have them loaded non-render blocking?', 'autoptimize' ); ?></label></td>
 
 
 
 
 
235
  </tr>
236
+ <tr valign="top" class="js_sub js_aggregate hidden">
237
+ <th scope="row">&emsp;<?php _e( 'Also aggregate inline JS?', 'autoptimize' ); ?></th>
238
  <td><label class="cb_label"><input type="checkbox" name="autoptimize_js_include_inline" <?php echo autoptimizeOptionWrapper::get_option( 'autoptimize_js_include_inline' ) ? 'checked="checked" ' : ''; ?>/>
239
+ <?php _e( 'Let Autoptimize also extract JS from the HTML (discouraged as it can make Autoptimize\'s cache size grow quickly)', 'autoptimize' ); ?></label></td>
240
  </tr>
241
+ <tr valign="top" class="js_sub js_aggregate hidden">
242
+ <th scope="row">&emsp;<?php _e( 'Force JavaScript in &lt;head&gt;?', 'autoptimize' ); ?></th>
243
  <td><label class="cb_label"><input type="checkbox" name="autoptimize_js_forcehead" <?php echo autoptimizeOptionWrapper::get_option( 'autoptimize_js_forcehead' ) ? 'checked="checked" ' : ''; ?>/>
244
+ <?php _e( 'Load JavaScript early (discouraged as it makes the JS render blocking)', 'autoptimize' ); ?></label></td>
245
+ </tr>
246
+ <tr valign="top" class="js_sub js_aggregate hidden">
247
+ <th scope="row">&emsp;<?php _e( 'Add try-catch wrapping?', 'autoptimize' ); ?></th>
248
+ <td><label class="cb_label"><input type="checkbox" name="autoptimize_js_trycatch" <?php echo autoptimizeOptionWrapper::get_option( 'autoptimize_js_trycatch' ) ? 'checked="checked" ' : ''; ?>/>
249
+ <?php _e( 'If your aggregated scripts break because of a JS-error, you might want to try this, but generally discouraged.', 'autoptimize' ); ?></label></td>
250
+ </tr>
251
+ <tr valign="top" class="js_sub js_not_aggregate_master">
252
+ <th scope="row"><?php _e( 'Do not aggregate but defer?', 'autoptimize' ); ?></th>
253
+ <td><label class="cb_label"><input type="checkbox" id="autoptimize_js_defer_not_aggregate" name="autoptimize_js_defer_not_aggregate" <?php echo $conf->get( 'autoptimize_js_defer_not_aggregate' ) ? 'checked="checked" ' : ''; ?>/>
254
+ <?php _e( 'Individual JS-files will be minified and deferred, making them non-render-blocking.', 'autoptimize' ); ?></label></td>
255
+ </tr>
256
+ <tr valign="top" id="js_defer_inline" class="js_sub js_not_aggregate hidden">
257
+ <th scope="row">&emsp;<?php _e( 'Also defer inline JS?', 'autoptimize' ); ?> (beta)</th>
258
+ <td><label class="cb_label"><input type="checkbox" name="autoptimize_js_defer_inline" <?php echo autoptimizeOptionWrapper::get_option( 'autoptimize_js_defer_inline' ) ? 'checked="checked" ' : ''; ?>/>
259
+ <?php _e( 'Also defer inline JS. Generally this will allow all JS to be deferred, so you should remove default exclusions, test and only exclude specific items if still needed.', 'autoptimize' ); ?></label></td>
260
  </tr>
261
  <?php if ( autoptimizeOptionWrapper::get_option( 'autoptimize_js_justhead' ) ) { ?>
262
  <tr valign="top" class="js_sub js_aggregate">
274
  <th scope="row"><?php _e( 'Exclude scripts from Autoptimize:', 'autoptimize' ); ?></th>
275
  <td><label><input type="text" style="width:100%;" name="autoptimize_js_exclude" value="<?php echo esc_attr( autoptimizeOptionWrapper::get_option( 'autoptimize_js_exclude', 'wp-includes/js/dist/, wp-includes/js/tinymce/, js/jquery/jquery.js, js/jquery/jquery.min.js' ) ); ?>"/><br />
276
  <?php
277
+ echo __( 'A comma-separated list of scripts you do not want optimized, for example \'whatever.js, my_var\' (without the quotes).', 'autoptimize' ) . ' ' . __( 'Important: when "aggregate JS-files" is on, excluded non-minified files are still minified by Autoptimize unless that option under "misc" is disabled.', 'autoptimize' );
278
  ?>
279
  </label></td>
280
  </tr>
281
+ <tr valign="top">
282
+ <th scope="row"><?php _e( 'Remove Unused JavaScript?', 'autoptimize' ); ?></th>
283
+ <td><?php _e( 'Autoptimize combines your theme & plugins\' JavaScript, but does not know what is used and what not. If Google Pagespeed Insights detects unused JavaScript, consider using a plugin like "Plugin Organizer" or similar to manage what JavaScript is added where.', 'autoptimize' ); ?></td>
 
284
  </tr>
285
  </table>
286
  </li>
320
  </tr>
321
  <?php } ?>
322
  <tr valign="top" class="css_sub">
323
+ <th scope="row"><?php _e( 'Eliminate render-blocking CSS?', 'autoptimize' ); ?></th>
324
  <td><label class="cb_label"><input type="checkbox" name="autoptimize_css_defer" id="autoptimize_css_defer" <?php echo autoptimizeOptionWrapper::get_option( 'autoptimize_css_defer' ) ? 'checked="checked" ' : ''; ?>/>
325
  <?php
326
  _e( 'Inline "above the fold CSS" while loading the main autoptimized CSS only after page load. <a href="https://wordpress.org/plugins/autoptimize/faq/" target="_blank">Check the FAQ</a> for more info.', 'autoptimize' );
348
  ?>
349
  </label></td>
350
  </tr>
351
+ <?php if ( false === autoptimizeUtils::is_plugin_active( 'unusedcss/unusedcss.php' ) ) { ?>
352
+ <tr valign="top">
353
+ <th scope="row"><?php _e( 'Remove Unused CSS?', 'autoptimize' ); ?></th>
354
+ <?php
355
+ $_rapidload_link = 'https://misc.optimizingmatters.com/partners/?from=csssettings&partner=rapidload';
356
+ ?>
357
+ <td><?php echo sprintf( __( 'If Google Pagespeed Insights detects unused CSS, consider using %s to <strong>reduce your site\'s CSS size to up to 90&#37;</strong>, resulting in a slimmer, faster site!', 'autoptimize' ), '<a href="' . $_rapidload_link . '" target="_blank">the premium Rapidload service</a>' ); ?></td>
358
+ </tr>
359
+ <?php } ?>
360
  </table>
361
  </li>
362
 
456
  </td>
457
  </tr>
458
  <?php } ?>
459
+ <?php
460
+ if ( true === apply_filters( 'autoptimize_filter_enable_meta_ao_settings', true ) ) {
461
+ ?>
462
+ <tr valign="top">
463
+ <th scope="row"><?php _e( 'Enable configuration per post/ page?', 'autoptimize' ); ?></th>
464
+ <td><label class="cb_label"><input type="checkbox" name="autoptimize_enable_meta_ao_settings" <?php echo autoptimizeOptionWrapper::get_option( 'autoptimize_enable_meta_ao_settings', '0' ) ? 'checked="checked" ' : ''; ?>/>
465
+ <?php _e( 'Add a "metabox" to the post/ page edit screen allowing different optimizations to be turned off on a per post/ page level?', 'autoptimize' ); ?></label></td>
466
+ </tr>
467
+ <?php } ?>
468
  </table>
469
  </li>
470
 
559
 
560
  jQuery( "#autoptimize_js_aggregate" ).change(function() {
561
  if (this.checked && jQuery("#autoptimize_js").prop('checked')) {
562
+ jQuery( "#autoptimize_js_defer_not_aggregate" ).prop( 'checked', false ); // uncheck "defer not aggregate"
563
+ jQuery( ".js_aggregate_master:visible" ).fadeTo( 'slow', 1 ); // ungrey self
564
+ jQuery( ".js_aggregate" ).show( 'slow' ); // show sub-items
565
+ jQuery( ".js_not_aggregate_master:visible" ).fadeTo( 'slow', .33 ); // grey out "not aggregate"
566
+ jQuery( ".js_not_aggregate" ).hide( 'slow' ); // hide not aggregate sub-items
567
+ jQuery( "#min_excl_row" ).show(); // make sure "minify excluded" is visible
568
  } else {
569
+ jQuery( ".js_aggregate" ).hide( 'slow' ); // hide sub-itmes
570
+ jQuery( ".js_not_aggregate_master:visible" ).fadeTo( 'slow', 1 ); // un-grey-out "not aggregate"
571
+ if ( jQuery( "#autoptimize_css_aggregate" ).prop( 'checked' ) == false ) { // hide "minify excluded"
572
  jQuery( "#min_excl_row" ).hide();
573
  }
574
  }
576
 
577
  jQuery( "#autoptimize_js_defer_not_aggregate" ).change(function() {
578
  if (this.checked && jQuery("#autoptimize_js").prop('checked')) {
579
+ jQuery( "#autoptimize_js_aggregate" ).prop( 'checked', false ); // uncheck "aggregate JS"
580
+ jQuery( ".js_not_aggregate_master:visible" ).fadeTo( 'slow', 1 ); // ungrey self
581
+ jQuery( ".js_not_aggregate" ).show( 'slow'); // show sub-items
582
+ jQuery( ".js_aggregate_master:visible" ).fadeTo( 'slow', .33 ); // grey out "aggregate"
583
+ jQuery( ".js_aggregate" ).hide( 'slow' ); // hide aggregate sub-items
584
  } else {
585
+ jQuery( ".js_not_aggregate" ).hide( 'slow' ); // hide sub-items
586
+ jQuery( ".js_aggregate_master:visible" ).fadeTo( 'slow', 1 ); // un-grey-out "aggregate"
587
  }
588
  });
589
 
665
  if (!jQuery("#autoptimize_js").prop('checked')) {
666
  jQuery(".js_sub:visible").fadeTo('fast',.33);
667
  }
668
+ if (jQuery("#autoptimize_js_aggregate").prop('checked')) {
669
+ jQuery( ".js_aggregate" ).show( 'fast' );
670
+ jQuery( ".js_not_aggregate_master:visible" ).fadeTo( 'fast', .33 );
671
+ }
672
+ if (jQuery("#autoptimize_js_defer_not_aggregate").prop('checked')) {
673
+ jQuery( ".js_not_aggregate" ).show( 'fast' );
674
+ jQuery( ".js_aggregate_master:visible" ).fadeTo( 'fast', .33 );
675
  }
676
  if (jQuery("#autoptimize_enable_site_config").prop('checked')) {
677
  jQuery("li.itemDetail:not(.multiSite)").fadeTo('fast',.33);
726
  register_setting( 'autoptimize', 'autoptimize_js' );
727
  register_setting( 'autoptimize', 'autoptimize_js_aggregate' );
728
  register_setting( 'autoptimize', 'autoptimize_js_defer_not_aggregate' );
729
+ register_setting( 'autoptimize', 'autoptimize_js_defer_inline' );
730
  register_setting( 'autoptimize', 'autoptimize_js_exclude' );
731
  register_setting( 'autoptimize', 'autoptimize_js_trycatch' );
732
  register_setting( 'autoptimize', 'autoptimize_js_justhead' );
748
  register_setting( 'autoptimize', 'autoptimize_optimize_checkout' );
749
  register_setting( 'autoptimize', 'autoptimize_minify_excluded' );
750
  register_setting( 'autoptimize', 'autoptimize_cache_fallback' );
751
+ register_setting( 'autoptimize', 'autoptimize_enable_meta_ao_settings' );
752
  }
753
 
754
  public function setmeta( $links, $file = null )
784
  public static function get_defaults()
785
  {
786
  static $config = array(
787
+ 'autoptimize_html' => 0,
788
+ 'autoptimize_html_keepcomments' => 0,
789
+ 'autoptimize_enable_site_config' => 1,
790
+ 'autoptimize_js' => 0,
791
+ 'autoptimize_js_aggregate' => 1,
792
+ 'autoptimize_js_defer_not_aggregate' => 0,
793
+ 'autoptimize_js_defer_inline' => 0,
794
+ 'autoptimize_js_exclude' => 'wp-includes/js/dist/, wp-includes/js/tinymce/, js/jquery/jquery.js, js/jquery/jquery.min.js',
795
+ 'autoptimize_js_trycatch' => 0,
796
+ 'autoptimize_js_justhead' => 0,
797
+ 'autoptimize_js_include_inline' => 0,
798
+ 'autoptimize_js_forcehead' => 0,
799
+ 'autoptimize_css' => 0,
800
+ 'autoptimize_css_aggregate' => 1,
801
+ 'autoptimize_css_exclude' => 'admin-bar.min.css, dashicons.min.css, wp-content/cache/, wp-content/uploads/',
802
+ 'autoptimize_css_justhead' => 0,
803
+ 'autoptimize_css_include_inline' => 1,
804
+ 'autoptimize_css_defer' => 0,
805
+ 'autoptimize_css_defer_inline' => '',
806
+ 'autoptimize_css_inline' => 0,
807
+ 'autoptimize_css_datauris' => 0,
808
+ 'autoptimize_cdn_url' => '',
809
+ 'autoptimize_cache_nogzip' => 1,
810
+ 'autoptimize_optimize_logged' => 1,
811
+ 'autoptimize_optimize_checkout' => 0,
812
+ 'autoptimize_minify_excluded' => 1,
813
+ 'autoptimize_cache_fallback' => 1,
814
+ 'autoptimize_enable_meta_ao_settings' => 0,
815
  );
816
 
817
  return $config;
981
  * @return bool
982
  */
983
  public static function should_show_menu_tabs() {
984
+ if ( ! is_multisite() || is_network_admin() || 'on' === autoptimizeOptionWrapper::get_option( 'autoptimize_enable_site_config' ) || false === autoptimizeOptionWrapper::is_ao_active_for_network() ) {
985
  return true;
986
  } else {
987
  return false;
988
  }
989
  }
990
+
991
+ /**
992
+ * Returns the post meta AO settings for reuse in different optimizers.
993
+ *
994
+ * @return bool
995
+ */
996
+ public static function get_post_meta_ao_settings( $optim ) {
997
+ if ( ! autoptimizeConfig::is_ao_meta_settings_active() ) {
998
+ // Per page/post settings not active, so always return true (as in; can be optimized).
999
+ return true;
1000
+ }
1001
+
1002
+ static $_meta_value = null;
1003
+ if ( null === $_meta_value ) {
1004
+ if ( is_page() || is_single() ) {
1005
+ $_meta_value = get_post_meta( get_the_ID(), 'ao_post_optimize', true );
1006
+ } else {
1007
+ $_meta_value = false;
1008
+ }
1009
+ }
1010
+
1011
+ if ( ! empty( $_meta_value ) && is_array( $_meta_value ) && array_key_exists( $optim, $_meta_value ) && $_meta_value[$optim] !== 'on' ) {
1012
+ return false;
1013
+ } else {
1014
+ return true;
1015
+ }
1016
+ }
1017
+
1018
+ /**
1019
+ * Are the post meta AO settings active (default: no)?
1020
+ *
1021
+ * @return bool
1022
+ */
1023
+ public static function is_ao_meta_settings_active() {
1024
+ static $_meta_settings_active = null;
1025
+
1026
+ if ( null === $_meta_settings_active ) {
1027
+ $_meta_settings_active = apply_filters( 'autoptimize_filter_enable_meta_ao_settings', autoptimizeOptionWrapper::get_option( 'autoptimize_enable_meta_ao_settings', '0' ) );
1028
+ }
1029
+
1030
+ return $_meta_settings_active;
1031
+ }
1032
  }
classes/autoptimizeCriticalCSSCore.php CHANGED
@@ -36,8 +36,12 @@ class autoptimizeCriticalCSSCore {
36
  // Add the action to enqueue jobs for CriticalCSS cron.
37
  add_action( 'autoptimize_action_css_hash', array( 'autoptimizeCriticalCSSEnqueue', 'ao_ccss_enqueue' ), 10, 1 );
38
 
39
- // conditionally add the filter to defer jquery and others.
40
- if ( $ao_ccss_deferjquery ) {
 
 
 
 
41
  add_filter( 'autoptimize_html_after_minify', array( $this, 'ao_ccss_defer_jquery' ), 11, 1 );
42
  }
43
 
@@ -85,7 +89,7 @@ class autoptimizeCriticalCSSCore {
85
  if ( ! empty( $ao_ccss_rules['paths'] ) ) {
86
  foreach ( $ao_ccss_rules['paths'] as $path => $rule ) {
87
  // explicit match OR partial match if MANUAL rule.
88
- if ( $req_path == $path || urldecode( $req_path ) == $path || ( false == $rule['hash'] && false != $rule['file'] && strpos( $req_path, str_replace( site_url(), '', $path ) ) !== false ) ) {
89
  if ( file_exists( AO_CCSS_DIR . $rule['file'] ) ) {
90
  $_ccss_contents = file_get_contents( AO_CCSS_DIR . $rule['file'] );
91
  if ( 'none' != $_ccss_contents ) {
@@ -195,7 +199,7 @@ class autoptimizeCriticalCSSCore {
195
 
196
  public function ao_ccss_unloadccss( $html_in ) {
197
  // set media attrib of inline CCSS to none at onLoad to avoid it impacting full CSS (rarely needed).
198
- $_unloadccss_js = apply_filters( 'autoptimize_filter_ccss_core_unloadccss_js', '<script>window.addEventListener("load", function(event) {document.getElementById("aoatfcss").media="none";})</script>' );
199
 
200
  if ( false !== strpos( $html_in, $_unloadccss_js . '</body>' ) ) {
201
  return $html_in;
36
  // Add the action to enqueue jobs for CriticalCSS cron.
37
  add_action( 'autoptimize_action_css_hash', array( 'autoptimizeCriticalCSSEnqueue', 'ao_ccss_enqueue' ), 10, 1 );
38
 
39
+ // conditionally add the filter to defer jquery and others but only if not done so in autoptimizeScripts.
40
+ $_native_defer = false;
41
+ if ( 'on' === autoptimizeOptionWrapper::get_option( 'autoptimize_js_defer_not_aggregate' ) && 'on' === autoptimizeOptionWrapper::get_option( 'autoptimize_js_defer_inline' ) ) {
42
+ $_native_defer = true;
43
+ }
44
+ if ( $ao_ccss_deferjquery && ! $_native_defer ) {
45
  add_filter( 'autoptimize_html_after_minify', array( $this, 'ao_ccss_defer_jquery' ), 11, 1 );
46
  }
47
 
89
  if ( ! empty( $ao_ccss_rules['paths'] ) ) {
90
  foreach ( $ao_ccss_rules['paths'] as $path => $rule ) {
91
  // explicit match OR partial match if MANUAL rule.
92
+ if ( $req_path == $path || urldecode( $req_path ) == $path || ( apply_filters( 'autoptimize_filter_ccss_core_path_partial_match', true ) && false == $rule['hash'] && false != $rule['file'] && strpos( $req_path, str_replace( site_url(), '', $path ) ) !== false ) ) {
93
  if ( file_exists( AO_CCSS_DIR . $rule['file'] ) ) {
94
  $_ccss_contents = file_get_contents( AO_CCSS_DIR . $rule['file'] );
95
  if ( 'none' != $_ccss_contents ) {
199
 
200
  public function ao_ccss_unloadccss( $html_in ) {
201
  // set media attrib of inline CCSS to none at onLoad to avoid it impacting full CSS (rarely needed).
202
+ $_unloadccss_js = apply_filters( 'autoptimize_filter_ccss_core_unloadccss_js', '<script>window.addEventListener("load", function(event) {var el = document.getElementById("aoatfcss"); if(el) el.media = "none";})</script>' );
203
 
204
  if ( false !== strpos( $html_in, $_unloadccss_js . '</body>' ) ) {
205
  return $html_in;
classes/autoptimizeCriticalCSSSettings.php CHANGED
@@ -178,6 +178,17 @@ class autoptimizeCriticalCSSSettings {
178
  <?php
179
  }
180
 
 
 
 
 
 
 
 
 
 
 
 
181
  // warn if it looks as though the queue processing job looks isn't running
182
  // but store result in transient as to not to have to go through 2 arrays each and every time.
183
  $_warn_cron = get_transient( 'ao_ccss_cronwarning' );
178
  <?php
179
  }
180
 
181
+ // check if defer jQuery is active and warn if so.
182
+ if ( 1 == $ao_ccss_deferjquery && PAnD::is_admin_notice_active( 'i-know-about-defer-inline-forever' ) ) {
183
+ ?>
184
+ <div data-dismissible="i-know-about-defer-inline-forever" class="notice-warning notice is-dismissible"><p>
185
+ <?php
186
+ _e( 'You have "defer jQuery and other non-aggregated JS-files" active (under Advanced Settings), but that functionality is deprecated and will be removed in the next major version of Autoptimize. Consider using the new "Do not aggregate but defer" and "Also defer inline JS" options on the main settings page instead.', 'autoptimize' );
187
+ ?>
188
+ </p></div>
189
+ <?php
190
+ }
191
+
192
  // warn if it looks as though the queue processing job looks isn't running
193
  // but store result in transient as to not to have to go through 2 arrays each and every time.
194
  $_warn_cron = get_transient( 'ao_ccss_cronwarning' );
classes/autoptimizeCriticalCSSSettingsAjax.php CHANGED
@@ -27,6 +27,7 @@ class autoptimizeCriticalCSSSettingsAjax {
27
  add_action( 'wp_ajax_rm_critcss_all', array( $this, 'critcss_rm_all_callback' ) );
28
  add_action( 'wp_ajax_ao_ccss_export', array( $this, 'ao_ccss_export_callback' ) );
29
  add_action( 'wp_ajax_ao_ccss_import', array( $this, 'ao_ccss_import_callback' ) );
 
30
  }
31
 
32
  public function critcss_fetch_callback() {
@@ -351,6 +352,32 @@ class autoptimizeCriticalCSSSettingsAjax {
351
  // Close ajax request.
352
  wp_die();
353
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
354
 
355
  public function critcss_check_filename( $filename ) {
356
  // Try to avoid directory traversal when reading/writing/deleting critical CSS files.
27
  add_action( 'wp_ajax_rm_critcss_all', array( $this, 'critcss_rm_all_callback' ) );
28
  add_action( 'wp_ajax_ao_ccss_export', array( $this, 'ao_ccss_export_callback' ) );
29
  add_action( 'wp_ajax_ao_ccss_import', array( $this, 'ao_ccss_import_callback' ) );
30
+ add_action( 'wp_ajax_ao_ccss_queuerunner', array( $this, 'ao_ccss_queuerunner_callback' ) );
31
  }
32
 
33
  public function critcss_fetch_callback() {
352
  // Close ajax request.
353
  wp_die();
354
  }
355
+
356
+ public function ao_ccss_queuerunner_callback() {
357
+ check_ajax_referer( 'ao_ccss_queuerunner_nonce', 'ao_ccss_queuerunner_nonce' );
358
+
359
+ // Process an uploaded file with no errors.
360
+ if ( current_user_can( 'manage_options' ) ) {
361
+ if ( ! file_exists( AO_CCSS_LOCK ) ) {
362
+ $ccss_cron = new autoptimizeCriticalCSSCron();
363
+ $ccss_cron->ao_ccss_queue_control();
364
+ $response['code'] = '200';
365
+ $response['msg'] = 'Queue processing done';
366
+ } else {
367
+ $response['code'] = '302';
368
+ $response['msg'] = 'Lock file found';
369
+ }
370
+ } else {
371
+ $response['code'] = '500';
372
+ $response['msg'] = 'Not allowed';
373
+ }
374
+
375
+ // Dispatch respose.
376
+ echo json_encode( $response );
377
+
378
+ // Close ajax request.
379
+ wp_die();
380
+ }
381
 
382
  public function critcss_check_filename( $filename ) {
383
  // Try to avoid directory traversal when reading/writing/deleting critical CSS files.
classes/autoptimizeExtra.php CHANGED
@@ -129,7 +129,7 @@ class autoptimizeExtra
129
  $exclusions = array_fill_keys( array_filter( array_map( 'trim', explode( ',', $in ) ) ), '' );
130
  }
131
 
132
- $settings = $this->options['autoptimize_extra_text_field_3'];
133
  $async = array_fill_keys( array_filter( array_map( 'trim', explode( ',', $settings ) ) ), '' );
134
  $attr = apply_filters( 'autoptimize_filter_extra_async', 'async' );
135
  foreach ( $async as $k => $v ) {
@@ -345,7 +345,7 @@ class autoptimizeExtra
345
 
346
  // Get settings and store in array.
347
  if ( array_key_exists( 'autoptimize_extra_text_field_2', $options ) ) {
348
- $preconns = array_filter( array_map( 'trim', explode( ',', $options['autoptimize_extra_text_field_2'] ) ) );
349
  }
350
  $preconns = apply_filters( 'autoptimize_extra_filter_tobepreconn', $preconns );
351
 
@@ -400,7 +400,7 @@ class autoptimizeExtra
400
  $options = $this->options;
401
  $preloads = array();
402
  if ( array_key_exists( 'autoptimize_extra_text_field_7', $options ) ) {
403
- $preloads = array_filter( array_map( 'trim', explode( ',', $options['autoptimize_extra_text_field_7'] ) ) );
404
  }
405
  $preloads = apply_filters( 'autoptimize_filter_extra_tobepreloaded', $preloads );
406
 
@@ -412,6 +412,7 @@ class autoptimizeExtra
412
  // iterate through array and add preload link to tmp string.
413
  $preload_output = '';
414
  foreach ( $preloads as $preload ) {
 
415
  $crossorigin = '';
416
  $preload_as = '';
417
  $mime_type = '';
@@ -428,7 +429,7 @@ class autoptimizeExtra
428
  if ( ' type="font/eot"' === $mime_type ) {
429
  $mime_type = 'application/vnd.ms-fontobject';
430
  }
431
- } elseif ( autoptimizeUtils::str_ends_in( $_preload, '.jpeg' ) || autoptimizeUtils::str_ends_in( $_preload, '.jpg' ) || autoptimizeUtils::str_ends_in( $_preload, '.webp' ) || autoptimizeUtils::str_ends_in( $_preload, '.png' ) || autoptimizeUtils::str_ends_in( $_preload, '.gif' ) ) {
432
  $preload_as = 'image';
433
  } else {
434
  $preload_as = 'other';
129
  $exclusions = array_fill_keys( array_filter( array_map( 'trim', explode( ',', $in ) ) ), '' );
130
  }
131
 
132
+ $settings = wp_strip_all_tags( $this->options['autoptimize_extra_text_field_3'] );
133
  $async = array_fill_keys( array_filter( array_map( 'trim', explode( ',', $settings ) ) ), '' );
134
  $attr = apply_filters( 'autoptimize_filter_extra_async', 'async' );
135
  foreach ( $async as $k => $v ) {
345
 
346
  // Get settings and store in array.
347
  if ( array_key_exists( 'autoptimize_extra_text_field_2', $options ) ) {
348
+ $preconns = array_filter( array_map( 'trim', explode( ',', wp_strip_all_tags( $options['autoptimize_extra_text_field_2'] ) ) ) );
349
  }
350
  $preconns = apply_filters( 'autoptimize_extra_filter_tobepreconn', $preconns );
351
 
400
  $options = $this->options;
401
  $preloads = array();
402
  if ( array_key_exists( 'autoptimize_extra_text_field_7', $options ) ) {
403
+ $preloads = array_filter( array_map( 'trim', explode( ',', wp_strip_all_tags( $options['autoptimize_extra_text_field_7'] ) ) ) );
404
  }
405
  $preloads = apply_filters( 'autoptimize_filter_extra_tobepreloaded', $preloads );
406
 
412
  // iterate through array and add preload link to tmp string.
413
  $preload_output = '';
414
  foreach ( $preloads as $preload ) {
415
+ $preload = esc_url_raw( $preload );
416
  $crossorigin = '';
417
  $preload_as = '';
418
  $mime_type = '';
429
  if ( ' type="font/eot"' === $mime_type ) {
430
  $mime_type = 'application/vnd.ms-fontobject';
431
  }
432
+ } elseif ( autoptimizeUtils::str_ends_in( $_preload, '.jpeg' ) || autoptimizeUtils::str_ends_in( $_preload, '.jpg' ) || autoptimizeUtils::str_ends_in( $_preload, '.webp' ) || autoptimizeUtils::str_ends_in( $_preload, '.png' ) || autoptimizeUtils::str_ends_in( $_preload, '.gif' ) || autoptimizeUtils::str_ends_in( $_preload, '.svg' ) ) {
433
  $preload_as = 'image';
434
  } else {
435
  $preload_as = 'other';
classes/autoptimizeImages.php CHANGED
@@ -114,7 +114,9 @@ class autoptimizeImages
114
  if ( $this->should_lazyload() ) {
115
  add_filter(
116
  'wp_lazy_loading_enabled',
117
- '__return_false'
 
 
118
  );
119
  add_filter(
120
  'autoptimize_html_after_minify',
@@ -166,7 +168,9 @@ class autoptimizeImages
166
  if ( $this->should_lazyload() ) {
167
  add_filter(
168
  'wp_lazy_loading_enabled',
169
- '__return_false'
 
 
170
  );
171
  add_action(
172
  'wp_footer',
@@ -177,6 +181,18 @@ class autoptimizeImages
177
  }
178
  }
179
 
 
 
 
 
 
 
 
 
 
 
 
 
180
  /**
181
  * Basic checks before we can run.
182
  *
@@ -390,7 +406,13 @@ class autoptimizeImages
390
  $imgopt_host = $this->get_imgopt_host();
391
  $quality = $this->get_img_quality_string();
392
  $ret_val = apply_filters( 'autoptimize_filter_imgopt_wait', 'ret_img' ); // values: ret_wait, ret_img, ret_json, ret_blank.
393
- $imgopt_base_url = $imgopt_host . 'client/' . $quality . ',' . $ret_val;
 
 
 
 
 
 
394
  $imgopt_base_url = apply_filters( 'autoptimize_filter_imgopt_base_url', $imgopt_base_url );
395
  }
396
 
@@ -724,6 +746,12 @@ class autoptimizeImages
724
  } else {
725
  $lazyload_return = false;
726
  }
 
 
 
 
 
 
727
  $lazyload_return = apply_filters( 'autoptimize_filter_imgopt_should_lazyload', $lazyload_return, $context );
728
 
729
  return $lazyload_return;
@@ -856,21 +884,6 @@ class autoptimizeImages
856
  echo apply_filters( 'autoptimize_filter_imgopt_lazyload_cssoutput', '<noscript><style>.lazyload{display:none;}</style></noscript>' );
857
  echo apply_filters( 'autoptimize_filter_imgopt_lazyload_jsconfig', '<script' . $type_js . $noptimize_flag . '>window.lazySizesConfig=window.lazySizesConfig||{};window.lazySizesConfig.loadMode=1;</script>' );
858
  echo apply_filters( 'autoptimize_filter_imgopt_lazyload_js', '<script async' . $type_js . $noptimize_flag . ' src=\'' . $lazysizes_js . '\'></script>' );
859
-
860
- // And add webp detection and loading JS.
861
- if ( $this->should_ngimg() ) {
862
- // Add AVIF code, can be disabled for now to only do webp.
863
- if ( apply_filters( 'autoptimize_filter_imgopt_do_avif', true ) ) {
864
- $_ngimg_detect = 'function c_img(a,b){src="avif"==b?"data:image/avif;base64,AAAAIGZ0eXBhdmlmAAAAAGF2aWZtaWYxbWlhZk1BMUIAAADybWV0YQAAAAAAAAAoaGRscgAAAAAAAAAAcGljdAAAAAAAAAAAAAAAAGxpYmF2aWYAAAAADnBpdG0AAAAAAAEAAAAeaWxvYwAAAABEAAABAAEAAAABAAABGgAAABoAAAAoaWluZgAAAAAAAQAAABppbmZlAgAAAAABAABhdjAxQ29sb3IAAAAAamlwcnAAAABLaXBjbwAAABRpc3BlAAAAAAAAAAEAAAABAAAAEHBpeGkAAAAAAwgICAAAAAxhdjFDgQ0MAAAAABNjb2xybmNseAACAAIAAYAAAAAXaXBtYQAAAAAAAAABAAEEAQKDBAAAACJtZGF0EgAKCBgADsgQEAwgMgwf8AAAWAAAAACvJ+o=":"data:image/webp;base64,UklGRhoAAABXRUJQVlA4TA0AAAAvAAAAEAcQERGIiP4HAA==";var c=new Image;c.onload=function(){var d=0<c.width&&0<c.height;a(d,b)},c.onerror=function(){a(!1,b)},c.src=src}function s_img(a,b){w=window,"avif"==b?!1==a?c_img(s_img,"webp"):w.ngImg="avif":!1==a?w.ngImg=!1:w.ngImg="webp"}c_img(s_img,"avif");';
865
- $_ngimg_load = 'document.addEventListener("lazybeforeunveil",function({target:a}){window.ngImg&&["data-src","data-srcset"].forEach(function(b){attr=a.getAttribute(b),null!==attr&&-1==attr.indexOf("/client/to_")&&a.setAttribute(b,attr.replace(/\/client\//,"/client/to_"+window.ngImg+","))})});';
866
- } else {
867
- $_ngimg_detect = "function c_webp(A){var n=new Image;n.onload=function(){var e=0<n.width&&0<n.height;A(e)},n.onerror=function(){A(!1)},n.src='data:image/webp;base64,UklGRhoAAABXRUJQVlA4TA0AAAAvAAAAEAcQERGIiP4HAA=='}function s_webp(e){window.supportsWebP=e}c_webp(s_webp);";
868
- $_ngimg_load = "document.addEventListener('lazybeforeunveil',function({target:b}){window.supportsWebP&&['data-src','data-srcset'].forEach(function(c){attr=b.getAttribute(c),null!==attr&&-1==attr.indexOf('/client/to_webp')&&b.setAttribute(c,attr.replace(/\/client\//,'/client/to_webp,'))})});";
869
- }
870
- // Keeping autoptimize_filter_imgopt_webp_js filter for now, but it is deprecated as not only for webp any more.
871
- $_ngimg_output = apply_filters( 'autoptimize_filter_imgopt_webp_js', '<script' . $type_js . $noptimize_flag . '>' . $_ngimg_detect . $_ngimg_load . '</script>' );
872
- echo apply_filters( 'autoptimize_filter_imgopt_ngimg_js', $_ngimg_output );
873
- }
874
  }
875
 
876
  public function get_cdn_url() {
@@ -929,8 +942,8 @@ class autoptimizeImages
929
  static $ngimg_return = null;
930
 
931
  if ( is_null( $ngimg_return ) ) {
932
- // webp only works if imgopt and lazyload are also active.
933
- if ( ! empty( $this->options['autoptimize_imgopt_checkbox_field_4'] ) && ! empty( $this->options['autoptimize_imgopt_checkbox_field_3'] ) && $this->imgopt_active() ) {
934
  $ngimg_return = true;
935
  } else {
936
  $ngimg_return = false;
@@ -993,8 +1006,10 @@ class autoptimizeImages
993
  // get placeholder & lazyload class strings.
994
  $placeholder = apply_filters( 'autoptimize_filter_imgopt_lazyload_placeholder', $this->get_default_lazyload_placeholder( 500, 300 ) );
995
  $lazyload_class = apply_filters( 'autoptimize_filter_imgopt_lazyload_class', 'lazyload' );
 
 
996
  // replace background-image URL with SVG placeholder.
997
- $out = str_replace( 'url(' . $matches[2], 'url(' . $placeholder, $matches[0] );
998
  // sanitize bgimg src for quote sillyness.
999
  $bgimg_src = $this->fix_silly_bgimg_quotes( $matches[2] );
1000
  // add data-bg attribute with real background-image URL for lazyload to pick up.
@@ -1176,9 +1191,9 @@ class autoptimizeImages
1176
  </td>
1177
  </tr>
1178
  <tr id='autoptimize_imgopt_ngimg' <?php if ( ! array_key_exists( 'autoptimize_imgopt_checkbox_field_1', $options ) || ( isset( $options['autoptimize_imgopt_checkbox_field_1'] ) && '1' !== $options['autoptimize_imgopt_checkbox_field_1'] ) ) { echo 'class="hidden"'; } ?>>
1179
- <th scope="row"><?php _e( 'Load WebP or AVIF in supported browsers?', 'autoptimize' ); ?></th>
1180
  <td>
1181
- <label><input type='checkbox' id='autoptimize_imgopt_ngimg_checkbox' name='autoptimize_imgopt_settings[autoptimize_imgopt_checkbox_field_4]' <?php if ( ! empty( $options['autoptimize_imgopt_checkbox_field_4'] ) && '1' === $options['autoptimize_imgopt_checkbox_field_3'] ) { echo 'checked="checked"'; } ?> value='1'><?php _e( 'Automatically serve "next-gen" WebP or AVIF image formats to any browser that supports it (requires lazy load to be active).', 'autoptimize' ); ?></label>
1182
  </td>
1183
  </tr>
1184
  <tr>
@@ -1215,18 +1230,11 @@ class autoptimizeImages
1215
  jQuery("#autoptimize_imgopt_optimization_exclusions").hide("slow");
1216
  }
1217
  });
1218
- jQuery("#autoptimize_imgopt_ngimg_checkbox").change(function() {
1219
- if (this.checked) {
1220
- jQuery("#autoptimize_imgopt_lazyload_checkbox")[0].checked = true;
1221
- jQuery(".autoptimize_lazyload_child").show("slow");
1222
- }
1223
- });
1224
  jQuery("#autoptimize_imgopt_lazyload_checkbox").change(function() {
1225
  if (this.checked) {
1226
  jQuery(".autoptimize_lazyload_child").show("slow");
1227
  } else {
1228
  jQuery(".autoptimize_lazyload_child").hide("slow");
1229
- jQuery("#autoptimize_imgopt_ngimg_checkbox")[0].checked = false;
1230
  }
1231
  });
1232
  });
114
  if ( $this->should_lazyload() ) {
115
  add_filter(
116
  'wp_lazy_loading_enabled',
117
+ array( $this, 'should_disable_core_lazyload' ),
118
+ 10,
119
+ 3
120
  );
121
  add_filter(
122
  'autoptimize_html_after_minify',
168
  if ( $this->should_lazyload() ) {
169
  add_filter(
170
  'wp_lazy_loading_enabled',
171
+ array( $this, 'should_disable_core_lazyload' ),
172
+ 10,
173
+ 3
174
  );
175
  add_action(
176
  'wp_footer',
181
  }
182
  }
183
 
184
+ /**
185
+ * Disables core's native lazyload for images, not for iframes.
186
+ *
187
+ * @return bool
188
+ */
189
+ public function should_disable_core_lazyload( $flag, $tag, $context ) {
190
+ if ( 'img' === $tag ) {
191
+ return false;
192
+ }
193
+ return $flag;
194
+ }
195
+
196
  /**
197
  * Basic checks before we can run.
198
  *
406
  $imgopt_host = $this->get_imgopt_host();
407
  $quality = $this->get_img_quality_string();
408
  $ret_val = apply_filters( 'autoptimize_filter_imgopt_wait', 'ret_img' ); // values: ret_wait, ret_img, ret_json, ret_blank.
409
+ if ( $this->should_ngimg() ) {
410
+ $sp_to_string = 'to_auto';
411
+ } else {
412
+ $sp_to_string = 'to_webp';
413
+ }
414
+ $sp_to_string = apply_filters( 'autoptimize_filter_imgopt_format', $sp_to_string ); // values: empty (= jpeg), to_webp (smart; webp or fallback), to_avif (avif or fallback) or to_auto (smart avif, webp or fallback).
415
+ $imgopt_base_url = $imgopt_host . 'client/' . $sp_to_string . ',' . $quality . ',' . $ret_val;
416
  $imgopt_base_url = apply_filters( 'autoptimize_filter_imgopt_base_url', $imgopt_base_url );
417
  }
418
 
746
  } else {
747
  $lazyload_return = false;
748
  }
749
+
750
+ // If page/ post check post_meta to see if lazyload is off for page.
751
+ if ( false === autoptimizeConfig::get_post_meta_ao_settings( 'ao_post_lazyload' ) ) {
752
+ $lazyload_return = false;
753
+ }
754
+
755
  $lazyload_return = apply_filters( 'autoptimize_filter_imgopt_should_lazyload', $lazyload_return, $context );
756
 
757
  return $lazyload_return;
884
  echo apply_filters( 'autoptimize_filter_imgopt_lazyload_cssoutput', '<noscript><style>.lazyload{display:none;}</style></noscript>' );
885
  echo apply_filters( 'autoptimize_filter_imgopt_lazyload_jsconfig', '<script' . $type_js . $noptimize_flag . '>window.lazySizesConfig=window.lazySizesConfig||{};window.lazySizesConfig.loadMode=1;</script>' );
886
  echo apply_filters( 'autoptimize_filter_imgopt_lazyload_js', '<script async' . $type_js . $noptimize_flag . ' src=\'' . $lazysizes_js . '\'></script>' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
887
  }
888
 
889
  public function get_cdn_url() {
942
  static $ngimg_return = null;
943
 
944
  if ( is_null( $ngimg_return ) ) {
945
+ // nextgen img only works if imgopt is active.
946
+ if ( ! empty( $this->options['autoptimize_imgopt_checkbox_field_4'] ) && $this->imgopt_active() ) {
947
  $ngimg_return = true;
948
  } else {
949
  $ngimg_return = false;
1006
  // get placeholder & lazyload class strings.
1007
  $placeholder = apply_filters( 'autoptimize_filter_imgopt_lazyload_placeholder', $this->get_default_lazyload_placeholder( 500, 300 ) );
1008
  $lazyload_class = apply_filters( 'autoptimize_filter_imgopt_lazyload_class', 'lazyload' );
1009
+ // remove quotes from url() to be able to replace in next step.
1010
+ $out = str_replace( array( "url('" . $matches[2] . "')", 'url("' . $matches[2] . '")' ), 'url(' . $matches[2] . ')', $matches[0] );
1011
  // replace background-image URL with SVG placeholder.
1012
+ $out = str_replace( 'url(' . $matches[2], 'url(' . $placeholder, $out );
1013
  // sanitize bgimg src for quote sillyness.
1014
  $bgimg_src = $this->fix_silly_bgimg_quotes( $matches[2] );
1015
  // add data-bg attribute with real background-image URL for lazyload to pick up.
1191
  </td>
1192
  </tr>
1193
  <tr id='autoptimize_imgopt_ngimg' <?php if ( ! array_key_exists( 'autoptimize_imgopt_checkbox_field_1', $options ) || ( isset( $options['autoptimize_imgopt_checkbox_field_1'] ) && '1' !== $options['autoptimize_imgopt_checkbox_field_1'] ) ) { echo 'class="hidden"'; } ?>>
1194
+ <th scope="row"><?php _e( 'Load AVIF in supported browsers?', 'autoptimize' ); ?></th>
1195
  <td>
1196
+ <label><input type='checkbox' id='autoptimize_imgopt_ngimg_checkbox' name='autoptimize_imgopt_settings[autoptimize_imgopt_checkbox_field_4]' <?php if ( ! empty( $options['autoptimize_imgopt_checkbox_field_4'] ) && '1' === $options['autoptimize_imgopt_checkbox_field_3'] ) { echo 'checked="checked"'; } ?> value='1'><?php _e( 'Automatically serve AVIF image format to any browser that supports it.', 'autoptimize' ); ?></label>
1197
  </td>
1198
  </tr>
1199
  <tr>
1230
  jQuery("#autoptimize_imgopt_optimization_exclusions").hide("slow");
1231
  }
1232
  });
 
 
 
 
 
 
1233
  jQuery("#autoptimize_imgopt_lazyload_checkbox").change(function() {
1234
  if (this.checked) {
1235
  jQuery(".autoptimize_lazyload_child").show("slow");
1236
  } else {
1237
  jQuery(".autoptimize_lazyload_child").hide("slow");
 
1238
  }
1239
  });
1240
  });
classes/autoptimizeMain.php CHANGED
@@ -186,6 +186,9 @@ class autoptimizeMain
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
  } else {
191
  add_action( 'admin_notices', 'autoptimizeMain::notice_cache_unavailable' );
@@ -365,6 +368,11 @@ class autoptimizeMain
365
  if ( false === $ao_noptimize && array_key_exists( 'PageSpeed', $_GET ) && 'off' === $_GET['PageSpeed'] ) {
366
  $ao_noptimize = true;
367
  }
 
 
 
 
 
368
 
369
  // And finally allows blocking of autoptimization on your own terms regardless of above decisions.
370
  $ao_noptimize = (bool) apply_filters( 'autoptimize_filter_noptimize', $ao_noptimize );
@@ -488,6 +496,7 @@ class autoptimizeMain
488
  'autoptimizeScripts' => array(
489
  'aggregate' => $conf->get( 'autoptimize_js_aggregate' ),
490
  'defer_not_aggregate' => $conf->get( 'autoptimize_js_defer_not_aggregate' ),
 
491
  'justhead' => $conf->get( 'autoptimize_js_justhead' ),
492
  'forcehead' => $conf->get( 'autoptimize_js_forcehead' ),
493
  'trycatch' => $conf->get( 'autoptimize_js_trycatch' ),
@@ -564,9 +573,11 @@ class autoptimizeMain
564
  'autoptimize_html',
565
  'autoptimize_html_keepcomments',
566
  'autoptimize_enable_site_config',
 
567
  'autoptimize_js',
568
  'autoptimize_js_aggregate',
569
  'autoptimize_js_defer_not_aggregate',
 
570
  'autoptimize_js_exclude',
571
  'autoptimize_js_forcehead',
572
  'autoptimize_js_justhead',
@@ -689,7 +700,7 @@ class autoptimizeMain
689
  $_ao_imgopt_launch_ok = autoptimizeImages::launch_ok_wrapper();
690
  $_ao_imgopt_plug_dismissible = 'ao-img-opt-plug-123';
691
  $_ao_imgopt_active = autoptimizeImages::imgopt_active();
692
- $_is_ao_settings_page = ( str_replace( array( 'autoptimize', 'autoptimize_imgopt', 'ao_critcss', 'autoptimize_extra', 'ao_partners' ), '', $_SERVER['REQUEST_URI'] ) !== $_SERVER['REQUEST_URI'] ? true : false );
693
 
694
  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 ) ) {
695
  echo '<div class="notice notice-info is-dismissible" data-dismissible="' . $_ao_imgopt_plug_dismissible . '"><p>';
@@ -697,4 +708,27 @@ class autoptimizeMain
697
  echo '</p></div>';
698
  }
699
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
700
  }
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
  }
193
  } else {
194
  add_action( 'admin_notices', 'autoptimizeMain::notice_cache_unavailable' );
368
  if ( false === $ao_noptimize && array_key_exists( 'PageSpeed', $_GET ) && 'off' === $_GET['PageSpeed'] ) {
369
  $ao_noptimize = true;
370
  }
371
+
372
+ // If page/ post check post_meta to see if optimize is off.
373
+ if ( false === autoptimizeConfig::get_post_meta_ao_settings( 'ao_post_optimize' ) ) {
374
+ $ao_noptimize = true;
375
+ }
376
 
377
  // And finally allows blocking of autoptimization on your own terms regardless of above decisions.
378
  $ao_noptimize = (bool) apply_filters( 'autoptimize_filter_noptimize', $ao_noptimize );
496
  'autoptimizeScripts' => array(
497
  'aggregate' => $conf->get( 'autoptimize_js_aggregate' ),
498
  'defer_not_aggregate' => $conf->get( 'autoptimize_js_defer_not_aggregate' ),
499
+ 'defer_inline' => $conf->get( 'autoptimize_js_defer_inline' ),
500
  'justhead' => $conf->get( 'autoptimize_js_justhead' ),
501
  'forcehead' => $conf->get( 'autoptimize_js_forcehead' ),
502
  'trycatch' => $conf->get( 'autoptimize_js_trycatch' ),
573
  'autoptimize_html',
574
  'autoptimize_html_keepcomments',
575
  'autoptimize_enable_site_config',
576
+ 'autoptimize_enable_meta_ao_settings',
577
  'autoptimize_js',
578
  'autoptimize_js_aggregate',
579
  'autoptimize_js_defer_not_aggregate',
580
+ 'autoptimize_js_defer_inline',
581
  'autoptimize_js_exclude',
582
  'autoptimize_js_forcehead',
583
  'autoptimize_js_justhead',
700
  $_ao_imgopt_launch_ok = autoptimizeImages::launch_ok_wrapper();
701
  $_ao_imgopt_plug_dismissible = 'ao-img-opt-plug-123';
702
  $_ao_imgopt_active = autoptimizeImages::imgopt_active();
703
+ $_is_ao_settings_page = autoptimizeUtils::is_ao_settings();
704
 
705
  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 ) ) {
706
  echo '<div class="notice notice-info is-dismissible" data-dismissible="' . $_ao_imgopt_plug_dismissible . '"><p>';
708
  echo '</p></div>';
709
  }
710
  }
711
+
712
+ public static function notice_nopagecache()
713
+ {
714
+ /*
715
+ * 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.
716
+ *
717
+ * uses helper function in autoptimizeUtils.php
718
+ */
719
+ $_ao_nopagecache_notice = __( 'It looks like your site might not have <strong>page caching</strong> which is a <strong>must-have for performance</strong>, check with your host if they offer this or install a page caching plugin like for example', 'autoptimize' );
720
+ $_ao_pagecache_install_url = network_admin_url() . 'plugin-install.php?tab=search&type=term&s=';
721
+ $_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>, ...';
722
+ $_ao_nopagecache_dismissible = 'ao-nopagecache-forever'; // the notice is only shown once and will not re-appear when dismissed.
723
+ $_is_ao_settings_page = autoptimizeUtils::is_ao_settings();
724
+ $_found_pagecache = false;
725
+
726
+ if ( current_user_can( 'manage_options' ) && $_is_ao_settings_page && PAnD::is_admin_notice_active( $_ao_nopagecache_dismissible ) && true === apply_filters( 'autopitmize_filter_main_show_pagecache_notice', true ) ) {
727
+ if ( false === autoptimizeUtils::find_pagecache() ) {
728
+ echo '<div class="notice notice-info is-dismissible" data-dismissible="' . $_ao_nopagecache_dismissible . '"><p>';
729
+ echo $_ao_nopagecache_notice;
730
+ echo '</p></div>';
731
+ }
732
+ }
733
+ }
734
  }
classes/autoptimizeMetabox.php ADDED
@@ -0,0 +1,196 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Handles meta box to disable optimizations.
4
+ */
5
+
6
+ if ( ! defined( 'ABSPATH' ) ) {
7
+ exit;
8
+ }
9
+
10
+ class autoptimizeMetabox
11
+ {
12
+ public function __construct()
13
+ {
14
+ $this->run();
15
+ }
16
+
17
+ public function run()
18
+ {
19
+ add_action( 'add_meta_boxes', array( $this, 'ao_metabox_add_box' ) );
20
+ add_action( 'save_post', array( $this, 'ao_metabox_save' ) );
21
+ }
22
+
23
+ public function ao_metabox_add_box()
24
+ {
25
+ $screens = array(
26
+ 'post',
27
+ 'page',
28
+ // add extra types e.g. product or ... ?
29
+ );
30
+
31
+ foreach ( $screens as $screen ) {
32
+ add_meta_box(
33
+ 'ao_metabox',
34
+ __( 'Autoptimize this page', 'autoptimize' ),
35
+ array( $this, 'ao_metabox_content' ),
36
+ $screen,
37
+ 'side'
38
+ );
39
+ }
40
+ }
41
+
42
+ /**
43
+ * Prints the box content.
44
+ *
45
+ * @param WP_Post $post The object for the current post/page.
46
+ */
47
+ function ao_metabox_content( $post ) {
48
+ wp_nonce_field( 'ao_metabox', 'ao_metabox_nonce' );
49
+
50
+ $ao_opt_value = get_post_meta( $post->ID, 'ao_post_optimize', true );
51
+
52
+ if ( empty( $ao_opt_value ) ) {
53
+ $ao_opt_value = $this->get_metabox_default_values();
54
+ }
55
+
56
+ $_ao_meta_sub_opacity = '';
57
+ if ( 'on' !== $ao_opt_value['ao_post_optimize'] ) {
58
+ $_ao_meta_sub_opacity = 'opacity:.33;';
59
+ }
60
+ ?>
61
+ <p >
62
+ <input type="checkbox" id="autoptimize_post_optimize" class="ao_meta_main" name="ao_post_optimize" <?php echo 'on' !== $ao_opt_value['ao_post_optimize'] ? '' : 'checked="checked" '; ?> />
63
+ <label for="autoptimize_post_optimize">
64
+ <?php _e( 'Optimize this page?', 'autoptimize' ); ?>
65
+ </label>
66
+ </p>
67
+ <?php
68
+ $_ao_meta_js_style = '';
69
+ if ( 'on' !== get_option( 'autoptimize_js', false ) ) {
70
+ $_ao_meta_js_style = 'display:none;';
71
+ }
72
+ echo '<p class="ao_meta_sub" style="' . $_ao_meta_sub_opacity . $_ao_meta_js_style . '">';
73
+ ?>
74
+ <input type="checkbox" id="autoptimize_post_optimize_js" name="ao_post_js_optimize" <?php echo 'on' !== $ao_opt_value['ao_post_js_optimize'] ? '' : 'checked="checked" '; ?> />
75
+ <label for="autoptimize_post_optimize_js">
76
+ <?php _e( 'Optimize JS?', 'autoptimize' ); ?>
77
+ </label>
78
+ </p>
79
+ <?php
80
+ $_ao_meta_css_style = '';
81
+ if ( 'on' !== get_option( 'autoptimize_css', false ) ) {
82
+ $_ao_meta_css_style = 'display:none;';
83
+ }
84
+ echo '<p class="ao_meta_sub" style="' . $_ao_meta_sub_opacity . $_ao_meta_css_style . '">';
85
+ ?>
86
+ <input type="checkbox" id="autoptimize_post_optimize_css" name="ao_post_css_optimize" <?php echo 'on' !== $ao_opt_value['ao_post_css_optimize'] ? '' : 'checked="checked" '; ?> />
87
+ <label for="autoptimize_post_optimize_css">
88
+ <?php _e( 'Optimize CSS?', 'autoptimize' ); ?>
89
+ </label>
90
+ </p>
91
+ <?php
92
+ $_ao_meta_ccss_style = '';
93
+ if ( 'on' !== get_option( 'autoptimize_css_defer', false ) ) {
94
+ $_ao_meta_ccss_style = 'display:none;';
95
+ }
96
+ if ( 'on' !== $ao_opt_value['ao_post_css_optimize'] ) {
97
+ $_ao_meta_ccss_style .= 'opacity:.33;';
98
+ }
99
+ echo '<p class="ao_meta_sub ao_meta_sub_css" style="' . $_ao_meta_sub_opacity . $_ao_meta_ccss_style . '">';
100
+ ?>
101
+ <input type="checkbox" id="autoptimize_post_ccss" name="ao_post_ccss" <?php echo 'on' !== $ao_opt_value['ao_post_ccss'] ? '' : 'checked="checked" '; ?> />
102
+ <label for="autoptimize_post_ccss">
103
+ <?php _e( 'Inline critical CSS?', 'autoptimize' ); ?>
104
+ </label>
105
+ </p>
106
+ <?php
107
+ $_ao_meta_lazyload_style = '';
108
+ if ( false === autoptimizeImages::should_lazyload_wrapper() ) {
109
+ $_ao_meta_lazyload_style = 'display:none;';
110
+ }
111
+ echo '<p class="ao_meta_sub" style="' . $_ao_meta_sub_opacity . $_ao_meta_lazyload_style . '">';
112
+ ?>
113
+ <input type="checkbox" id="autoptimize_post_lazyload" name="ao_post_lazyload" <?php echo 'on' !== $ao_opt_value['ao_post_lazyload'] ? '' : 'checked="checked" '; ?> />
114
+ <label for="autoptimize_post_lazyload">
115
+ <?php _e( 'Lazyload images?', 'autoptimize' ); ?>
116
+ </label>
117
+ </p>
118
+ <script>
119
+ if ( typeof jQuery !== 'undefined' ) {
120
+ jQuery( "#autoptimize_post_optimize" ).change(function() {
121
+ if (this.checked) {
122
+ jQuery(".ao_meta_sub:visible").fadeTo("fast",1);
123
+ } else {
124
+ jQuery(".ao_meta_sub:visible").fadeTo("fast",.33);
125
+ }
126
+ });
127
+ jQuery( "#autoptimize_post_optimize_css" ).change(function() {
128
+ if (this.checked) {
129
+ jQuery(".ao_meta_sub_css:visible").fadeTo("fast",1);
130
+ } else {
131
+ jQuery(".ao_meta_sub_css:visible").fadeTo("fast",.33);
132
+ }
133
+ });
134
+ }
135
+ </script>
136
+ <?php
137
+ }
138
+
139
+ /**
140
+ * When the post is saved, saves our custom data.
141
+ *
142
+ * @param int $post_id The ID of the post being saved.
143
+ */
144
+ public function ao_metabox_save( $post_id ) {
145
+ // If this is an autosave, our form has not been submitted, so we don't want to do anything.
146
+ if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
147
+ return $post_id;
148
+ }
149
+
150
+ // check if from our own data.
151
+ if ( ! isset( $_POST['ao_metabox_nonce'] ) ) {
152
+ return $post_id;
153
+ }
154
+
155
+ // Check if our nonce is set and verify if valid.
156
+ $nonce = $_POST['ao_metabox_nonce'];
157
+ if ( ! wp_verify_nonce( $nonce, 'ao_metabox' ) ) {
158
+ return $post_id;
159
+ }
160
+
161
+ // Check the user's permissions.
162
+ if ( 'page' === $_POST['post_type'] ) {
163
+ if ( ! current_user_can( 'edit_page', $post_id ) ) {
164
+ return $post_id;
165
+ }
166
+ } else {
167
+ if ( ! current_user_can( 'edit_post', $post_id ) ) {
168
+ return $post_id;
169
+ }
170
+ }
171
+
172
+ // OK, we can have a look at the actual data now.
173
+ // Sanitize user input.
174
+ foreach ( array( 'ao_post_optimize', 'ao_post_js_optimize', 'ao_post_css_optimize', 'ao_post_ccss', 'ao_post_lazyload' ) as $opti_type ) {
175
+ if ( isset( $_POST[$opti_type] ) ) {
176
+ $ao_meta_result[$opti_type] = 'on';
177
+ } else {
178
+ $ao_meta_result[$opti_type] = '';
179
+ }
180
+ }
181
+
182
+ // Update the meta field in the database.
183
+ update_post_meta( $post_id, 'ao_post_optimize', $ao_meta_result );
184
+ }
185
+
186
+ public function get_metabox_default_values() {
187
+ $ao_metabox_defaults = array(
188
+ 'ao_post_optimize' => 'on',
189
+ 'ao_post_js_optimize' => 'on',
190
+ 'ao_post_css_optimize' => 'on',
191
+ 'ao_post_ccss' => 'on',
192
+ 'ao_post_lazyload' => 'on',
193
+ );
194
+ return $ao_metabox_defaults;
195
+ }
196
+ }
classes/autoptimizeScripts.php CHANGED
@@ -58,6 +58,8 @@ class autoptimizeScripts extends autoptimizeBase
58
  'nonce',
59
  'post_id',
60
  'data-noptimize',
 
 
61
  'logHuman',
62
  'amp-mobile-version-switcher',
63
  'data-rocketlazyloadscript',
@@ -117,6 +119,13 @@ class autoptimizeScripts extends autoptimizeBase
117
  * @var bool
118
  */
119
  private $defer_not_aggregate = false;
 
 
 
 
 
 
 
120
 
121
  /**
122
  * Setting; try/catch wrapping or not.
@@ -210,14 +219,23 @@ class autoptimizeScripts extends autoptimizeBase
210
  */
211
  public function read( $options )
212
  {
213
- $noptimize_js = apply_filters( 'autoptimize_filter_js_noptimize', false, $this->content );
 
 
 
 
 
 
 
 
 
 
214
  if ( $noptimize_js ) {
215
  return false;
216
  }
217
 
218
  // only optimize known good JS?
219
  $allowlist_js = apply_filters( 'autoptimize_filter_js_allowlist', '', $this->content );
220
- $allowlist_js = apply_filters( 'autoptimize_filter_js_whitelist', $allowlist_js, $this->content ); // fixme: to be removed in next version.
221
  if ( ! empty( $allowlist_js ) ) {
222
  $this->allowlist = array_filter( array_map( 'trim', explode( ',', $allowlist_js ) ) );
223
  }
@@ -245,9 +263,14 @@ class autoptimizeScripts extends autoptimizeBase
245
  }
246
 
247
  // Defer when not aggregating.
248
- if ( false === $this->aggregate && apply_filters( 'autoptimize_js_filter_defer_not_aggregate', $options['defer_not_aggregate'] ) ) {
249
  $this->defer_not_aggregate = true;
250
  }
 
 
 
 
 
251
 
252
  // include inline?
253
  if ( apply_filters( 'autoptimize_js_include_inline', $options['include_inline'] ) ) {
@@ -352,12 +375,8 @@ class autoptimizeScripts extends autoptimizeBase
352
  }
353
 
354
  // not aggregating but deferring?
355
- if ( $this->defer_not_aggregate && false === $this->aggregate && str_replace( $this->dontmove, '', $path ) === $path && strpos( $new_tag, ' defer' ) === false ) {
356
  $new_tag = str_replace( '<script ', '<script defer ', $new_tag );
357
- // and remove async as async+defer=async while we explicitly want defer.
358
- if ( strpos( $new_tag, ' async' ) !== false && apply_filters( 'autoptimize_filter_js_defer_remove_async', true ) ) {
359
- $new_tag = str_replace( array( ' async', ' async="async"', " async='async'" ), '', $new_tag );
360
- }
361
  }
362
 
363
  // Should we minify the non-aggregated script?
@@ -378,6 +397,11 @@ class autoptimizeScripts extends autoptimizeBase
378
  }
379
  }
380
 
 
 
 
 
 
381
  if ( $this->ismovable( $new_tag ) ) {
382
  // can be moved, flags and all.
383
  if ( $this->movetolast( $new_tag ) ) {
@@ -410,16 +434,25 @@ class autoptimizeScripts extends autoptimizeBase
410
  $code = preg_replace( '/(?:^\\s*<!--\\s*|\\s*(?:\\/\\/)?\\s*-->\\s*$)/', '', $code );
411
  $this->scripts[] = 'INLINE;' . $code;
412
  } else {
413
- // Can we move this?
414
- $autoptimize_js_moveable = apply_filters( 'autoptimize_js_moveable', '', $tag );
415
- if ( $this->ismovable( $tag ) || '' !== $autoptimize_js_moveable ) {
416
- if ( $this->movetolast( $tag ) || 'last' === $autoptimize_js_moveable ) {
417
- $this->move['last'][] = $tag;
 
 
 
 
418
  } else {
419
- $this->move['first'][] = $tag;
420
  }
 
 
 
 
 
 
421
  } else {
422
- // We shouldn't touch this.
423
  $tag = '';
424
  }
425
  }
58
  'nonce',
59
  'post_id',
60
  'data-noptimize',
61
+ 'data-cfasync',
62
+ 'data-pagespeed-no-defer',
63
  'logHuman',
64
  'amp-mobile-version-switcher',
65
  'data-rocketlazyloadscript',
119
  * @var bool
120
  */
121
  private $defer_not_aggregate = false;
122
+
123
+ /**
124
+ * Setting; defer inline JS?
125
+ *
126
+ * @var bool
127
+ */
128
+ private $defer_inline = false;
129
 
130
  /**
131
  * Setting; try/catch wrapping or not.
219
  */
220
  public function read( $options )
221
  {
222
+ $noptimize_js = false;
223
+
224
+ // If page/ post check post_meta to see if optimize is off.
225
+ if ( false === autoptimizeConfig::get_post_meta_ao_settings( 'ao_post_js_optimize' ) ) {
226
+ $noptimize_js = true;
227
+ }
228
+
229
+ // And a filter to enforce JS noptimize.
230
+ $noptimize_js = apply_filters( 'autoptimize_filter_js_noptimize', $noptimize_js, $this->content );
231
+
232
+ // And finally bail if noptimize_js is true.
233
  if ( $noptimize_js ) {
234
  return false;
235
  }
236
 
237
  // only optimize known good JS?
238
  $allowlist_js = apply_filters( 'autoptimize_filter_js_allowlist', '', $this->content );
 
239
  if ( ! empty( $allowlist_js ) ) {
240
  $this->allowlist = array_filter( array_map( 'trim', explode( ',', $allowlist_js ) ) );
241
  }
263
  }
264
 
265
  // Defer when not aggregating.
266
+ if ( false === $this->aggregate && apply_filters( 'autoptimize_filter_js_defer_not_aggregate', $options['defer_not_aggregate'] ) ) {
267
  $this->defer_not_aggregate = true;
268
  }
269
+
270
+ // Defer inline JS?
271
+ if ( true === $this->defer_not_aggregate && apply_filters( 'autoptimize_js_filter_defer_inline', $options['defer_inline'] ) ) {
272
+ $this->defer_inline = true;
273
+ }
274
 
275
  // include inline?
276
  if ( apply_filters( 'autoptimize_js_include_inline', $options['include_inline'] ) ) {
375
  }
376
 
377
  // not aggregating but deferring?
378
+ if ( $this->defer_not_aggregate && false === $this->aggregate && str_replace( $this->dontmove, '', $path ) === $path && strpos( $new_tag, ' defer' ) === false && strpos( $new_tag, ' async' ) === false ) {
379
  $new_tag = str_replace( '<script ', '<script defer ', $new_tag );
 
 
 
 
380
  }
381
 
382
  // Should we minify the non-aggregated script?
397
  }
398
  }
399
 
400
+ // Check if we still need to CDN (esp. for already minified resources).
401
+ if ( ! empty( $this->cdn_url ) || has_filter( 'autoptimize_filter_base_replace_cdn' ) ) {
402
+ $new_tag = str_replace( $url, $this->url_replace_cdn( $url ), $new_tag );
403
+ }
404
+
405
  if ( $this->ismovable( $new_tag ) ) {
406
  // can be moved, flags and all.
407
  if ( $this->movetolast( $new_tag ) ) {
434
  $code = preg_replace( '/(?:^\\s*<!--\\s*|\\s*(?:\\/\\/)?\\s*-->\\s*$)/', '', $code );
435
  $this->scripts[] = 'INLINE;' . $code;
436
  } else {
437
+ if ( false === $this->defer_inline ) {
438
+ // Can we move this?
439
+ $autoptimize_js_moveable = apply_filters( 'autoptimize_js_moveable', '', $tag );
440
+ if ( $this->ismovable( $tag ) || '' !== $autoptimize_js_moveable ) {
441
+ if ( $this->movetolast( $tag ) || 'last' === $autoptimize_js_moveable ) {
442
+ $this->move['last'][] = $tag;
443
+ } else {
444
+ $this->move['first'][] = $tag;
445
+ }
446
  } else {
447
+ $tag = '';
448
  }
449
+ } else if ( str_replace( $this->dontmove, '', $tag ) === $tag ) {
450
+ // defer inline JS by base64 encoding it.
451
+ preg_match( '#<script.*>(.*)</script>#Usmi', $tag, $match );
452
+ $new_tag = '<script defer src="data:text/javascript;base64,' . base64_encode( $match[1] ) . '"></script>';
453
+ $this->content = str_replace( $tag, $new_tag, $this->content );
454
+ $tag = '';
455
  } else {
 
456
  $tag = '';
457
  }
458
  }
classes/autoptimizeStyles.php CHANGED
@@ -164,12 +164,11 @@ class autoptimizeStyles extends autoptimizeBase
164
  public function read( $options )
165
  {
166
  $noptimize_css = apply_filters( 'autoptimize_filter_css_noptimize', false, $this->content );
167
- if ( $noptimize_css ) {
168
  return false;
169
  }
170
 
171
  $allowlist_css = apply_filters( 'autoptimize_filter_css_allowlist', '', $this->content );
172
- $allowlist_css = apply_filters( 'autoptimize_filter_css_whitelist', $allowlist_css, $this->content ); // fixme: to be removed in next version.
173
  if ( ! empty( $allowlist_css ) ) {
174
  $this->allowlist = array_filter( array_map( 'trim', explode( ',', $allowlist_css ) ) );
175
  }
@@ -221,6 +220,11 @@ class autoptimizeStyles extends autoptimizeBase
221
  $this->defer = $options['defer'];
222
  $this->defer = apply_filters( 'autoptimize_filter_css_defer', $this->defer, $this->content );
223
 
 
 
 
 
 
224
  // Should we inline while deferring?
225
  // value: inlined CSS.
226
  $this->defer_inline = apply_filters( 'autoptimize_filter_css_defer_inline', $this->sanitize_css( $options['defer_inline'] ), $this->content );
@@ -272,14 +276,18 @@ class autoptimizeStyles extends autoptimizeBase
272
  // Get the media.
273
  if ( false !== strpos( $tag, 'media=' ) ) {
274
  preg_match( '#media=(?:"|\')([^>]*)(?:"|\')#Ui', $tag, $medias );
275
- $medias = explode( ',', $medias[1] );
276
- $media = array();
277
- foreach ( $medias as $elem ) {
278
- if ( empty( $elem ) ) {
279
- $elem = 'all';
280
- }
 
281
 
282
- $media[] = $elem;
 
 
 
283
  }
284
  } else {
285
  // No media specified - applies to all.
@@ -355,6 +363,11 @@ class autoptimizeStyles extends autoptimizeBase
355
  if ( '' !== $new_tag ) {
356
  // Optionally defer (preload) non-aggregated CSS.
357
  $new_tag = $this->optionally_defer_excluded( $new_tag, $url );
 
 
 
 
 
358
  }
359
 
360
  // And replace!
164
  public function read( $options )
165
  {
166
  $noptimize_css = apply_filters( 'autoptimize_filter_css_noptimize', false, $this->content );
167
+ if ( $noptimize_css || false === autoptimizeConfig::get_post_meta_ao_settings( 'ao_post_css_optimize' )) {
168
  return false;
169
  }
170
 
171
  $allowlist_css = apply_filters( 'autoptimize_filter_css_allowlist', '', $this->content );
 
172
  if ( ! empty( $allowlist_css ) ) {
173
  $this->allowlist = array_filter( array_map( 'trim', explode( ',', $allowlist_css ) ) );
174
  }
220
  $this->defer = $options['defer'];
221
  $this->defer = apply_filters( 'autoptimize_filter_css_defer', $this->defer, $this->content );
222
 
223
+ // If page/ post check post_meta to see if optimize is off.
224
+ if ( $this->defer && false === autoptimizeConfig::get_post_meta_ao_settings( 'ao_post_ccss' ) ) {
225
+ $this->defer = false;
226
+ }
227
+
228
  // Should we inline while deferring?
229
  // value: inlined CSS.
230
  $this->defer_inline = apply_filters( 'autoptimize_filter_css_defer_inline', $this->sanitize_css( $options['defer_inline'] ), $this->content );
276
  // Get the media.
277
  if ( false !== strpos( $tag, 'media=' ) ) {
278
  preg_match( '#media=(?:"|\')([^>]*)(?:"|\')#Ui', $tag, $medias );
279
+ if ( !empty( $medias ) ) {
280
+ $medias = explode( ',', $medias[1] );
281
+ $media = array();
282
+ foreach ( $medias as $elem ) {
283
+ if ( empty( $elem ) ) {
284
+ $elem = 'all';
285
+ }
286
 
287
+ $media[] = $elem;
288
+ }
289
+ } else {
290
+ $media = array( 'all' );
291
  }
292
  } else {
293
  // No media specified - applies to all.
363
  if ( '' !== $new_tag ) {
364
  // Optionally defer (preload) non-aggregated CSS.
365
  $new_tag = $this->optionally_defer_excluded( $new_tag, $url );
366
+
367
+ // Check if we still need to CDN (esp. for already minified resources).
368
+ if ( ! empty( $this->cdn_url ) || has_filter( 'autoptimize_filter_base_replace_cdn' ) ) {
369
+ $new_tag = str_replace( $url, $this->url_replace_cdn( $url ), $new_tag );
370
+ }
371
  }
372
 
373
  // And replace!
classes/autoptimizeUtils.php CHANGED
@@ -394,4 +394,68 @@ class autoptimizeUtils
394
 
395
  return ( substr( $str, -$length, $length ) === $test );
396
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
397
  }
394
 
395
  return ( substr( $str, -$length, $length ) === $test );
396
  }
397
+
398
+ /**
399
+ * Returns true if a pagecache is found, false if not.
400
+ * Now used to show notice, might be used later on to (un)hide page caching in AO if no page cache found.
401
+ *
402
+ * @return bool
403
+ */
404
+ public static function find_pagecache() {
405
+ static $_found_pagecache = null;
406
+
407
+ if ( null === $_found_pagecache ) {
408
+ $_page_cache_constants = array( 'NGINX_HELPER_BASENAME', 'KINSTA_CACHE_ZONE', 'PL_INSTANCE_REF', 'WP_NINUKIS_WP_NAME', 'CACHE_ENABLER_VERSION', 'SBP_PLUGIN_NAME', 'SERVEBOLT_PLUGIN_FILE', 'SWCFPC_PLUGIN_PATH' );
409
+ $_page_cache_classes = array( 'Swift_Performance_Cache', 'WpFastestCache', 'c_ws_plugin__qcache_purging_routines', 'zencache', 'comet_cache', 'WpeCommon', 'FlywheelNginxCompat', 'PagelyCachePurge' );
410
+ $_page_cache_functions = array( 'wp_cache_clear_cache', 'cachify_flush_cache', 'w3tc_pgcache_flush', 'wp_fast_cache_bulk_delete_all', 'rapidcache_clear_cache', 'sg_cachepress_purge_cache', 'prune_super_cache', 'after_rocket_clean_domain', 'wpo_cache_flush', 'rt_nginx_helper_after_fastcgi_purge_all', 'hyper_cache_purged' );
411
+ $_ao_pagecache_transient = 'autoptimize_pagecache_check';
412
+ $_found_pagecache = get_transient( $_ao_pagecache_transient );
413
+
414
+ if ( current_user_can( 'manage_options' ) && false === $_found_pagecache ) {
415
+ // loop through known pagecache constants.
416
+ foreach ( $_page_cache_constants as $_constant ) {
417
+ if ( defined( $_constant ) ) {
418
+ $_found_pagecache = true;
419
+ break;
420
+ }
421
+ }
422
+ // and loop through known pagecache classes.
423
+ if ( false === $_found_pagecache ) {
424
+ foreach ( $_page_cache_classes as $_class ) {
425
+ if ( class_exists( $_class ) ) {
426
+ $_found_pagecache = true;
427
+ break;
428
+ }
429
+ }
430
+ }
431
+ // and loop through known pagecache functions.
432
+ if ( false === $_found_pagecache ) {
433
+ foreach ( $_page_cache_functions as $_function ) {
434
+ if ( function_exists( $_function ) ) {
435
+ $_found_pagecache = true;
436
+ break;
437
+ }
438
+ }
439
+ }
440
+
441
+ // store in transient for 1 week if pagecache found.
442
+ if ( true === $_found_pagecache ) {
443
+ set_transient( $_ao_pagecache_transient, true, WEEK_IN_SECONDS );
444
+ }
445
+ }
446
+ }
447
+
448
+ return $_found_pagecache;
449
+ }
450
+
451
+ /**
452
+ * Returns true if on one of the AO settings tabs, false if not.
453
+ * Used to limit notifications to AO settings pages.
454
+ *
455
+ * @return bool
456
+ */
457
+ public static function is_ao_settings() {
458
+ $_is_ao_settings = ( str_replace( array( 'autoptimize', 'autoptimize_imgopt', 'ao_critcss', 'autoptimize_extra', 'ao_partners' ), '', $_SERVER['REQUEST_URI'] ) !== $_SERVER['REQUEST_URI'] ? true : false );
459
+ return $_is_ao_settings;
460
+ }
461
  }
classes/critcss-inc/admin_settings_adv.php CHANGED
@@ -103,12 +103,13 @@ function ao_ccss_render_adv() {
103
  </tr>
104
  <tr>
105
  <th scope="row">
106
- <?php _e( 'Defer jQuery and other non-aggregated JS-files?', 'autoptimize' ); ?>
107
  </th>
108
  <td>
109
  <input type="checkbox" id="autoptimize_ccss_deferjquery" name="autoptimize_ccss_deferjquery" value="1" <?php checked( 1 == $ao_ccss_deferjquery ); ?>>
110
  <p class="notes">
111
  <?php _e( 'Defer all non-aggregated JS, including jQuery and inline JS to fix remaining render-blocking issues. Make sure to test your site thoroughly when activating this option!', 'autoptimize' ); ?>
 
112
  </p>
113
  </td>
114
  </tr>
103
  </tr>
104
  <tr>
105
  <th scope="row">
106
+ <?php _e( 'Defer jQuery and other non-aggregated JS-files? (deprecated)', 'autoptimize' ); ?>
107
  </th>
108
  <td>
109
  <input type="checkbox" id="autoptimize_ccss_deferjquery" name="autoptimize_ccss_deferjquery" value="1" <?php checked( 1 == $ao_ccss_deferjquery ); ?>>
110
  <p class="notes">
111
  <?php _e( 'Defer all non-aggregated JS, including jQuery and inline JS to fix remaining render-blocking issues. Make sure to test your site thoroughly when activating this option!', 'autoptimize' ); ?>
112
+ <?php _e( '<b>This functionality will be removed in a next major version of Autoptimize</b>, being replaced by the combination of the "do not aggregate but defer JS" + "defer inline JS" options on the main settings page.', 'autoptimize' ); ?>
113
  </p>
114
  </td>
115
  </tr>
classes/critcss-inc/admin_settings_queue.js.php CHANGED
@@ -39,6 +39,12 @@ if (queueOriginEl) {
39
  headers: {6: {sorter: false}}
40
  });
41
  }
 
 
 
 
 
 
42
  });
43
  }
44
 
@@ -207,6 +213,26 @@ function updateQueue(queue) {
207
  ?>
208
  }
209
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
210
  // Convert epoch to date for job times
211
  function EpochToDate(epoch) {
212
  if (epoch < 10000000000)
39
  headers: {6: {sorter: false}}
40
  });
41
  }
42
+
43
+ // unhide queuerunner button conditionally (we don't want people running the queue continuously) and attach event to it.
44
+ if (queueBodyEl > 4 || ( queueBodyEl > 0 && jQuery('#rules > tr').length < 1 ) ) {
45
+ jQuery('#queuerunner-container').show();
46
+ jQuery("#queuerunner").click(function(){queuerunner();});
47
+ }
48
  });
49
  }
50
 
213
  ?>
214
  }
215
 
216
+ // Run the queue manually (in case of cron issues/ impatient users).
217
+ function queuerunner() {
218
+ var data = {
219
+ 'action': 'ao_ccss_queuerunner',
220
+ 'ao_ccss_queuerunner_nonce': '<?php echo wp_create_nonce( 'ao_ccss_queuerunner_nonce' ); ?>',
221
+ };
222
+
223
+ jQuery.post(ajaxurl, data, function(response) {
224
+ response_array=JSON.parse(response);
225
+ if (response_array['code'] == 200) {
226
+ displayNotice( '<?php _e('Queue processed, reloading page.', 'autoptimize'); ?>', 'success' )
227
+ setTimeout(window.location.reload.bind(window.location), 1.5*1000);
228
+ } else if ( response_array['code'] == 302 ) {
229
+ displayNotice( '<?php _e('The queue is locked, retry in a couple of minutes. If this problem persists and the queue is not moving at all remove the <code>wp-content/uploads/ao_ccss/queue.lock</code> file.', 'autoptimize' ); ?>', 'warning' )
230
+ } else {
231
+ displayNotice( '<?php _e('Could not process queue.', 'autoptimize'); ?>', 'error' )
232
+ }
233
+ });
234
+ }
235
+
236
  // Convert epoch to date for job times
237
  function EpochToDate(epoch) {
238
  if (epoch < 10000000000)
classes/critcss-inc/admin_settings_queue.php CHANGED
@@ -63,7 +63,7 @@ function ao_ccss_render_queue() {
63
  <ol>
64
  <li><?php _e( 'The queue operates <strong>automatically, asynchronously and on regular intervals of 10 minutes.</strong> To view updated queue status, refresh this page.', 'autoptimize' ); ?></li>
65
  <li><?php _e( 'When the conditions to create a job are met (i.e. user not logged in, no matching <span class="badge manual">MANUAL</span> rule or CSS files has changed for an <span class="badge auto">AUTO</span> rule), a <span class="badge new">N</span> job is created in the queue.', 'autoptimize' ); ?></li>
66
- <li><?php _e( "Autoptimize CriticalCSS Power-Up constantly query the queue for <span class='badge new'>N</span> jobs. When it finds one, gears spins and jobs becomes <span class='badge pending'>P</span> while they are running and <a href='https://criticalcss.com/?aff=1' target='_blank'>criticalcss.com</a> doesn't return a result.", 'autoptimize' ); ?></li>
67
  <li><?php _e( 'As soon as <a href="https://criticalcss.com/?aff=1" target="_blank">criticalcss.com</a> returns a valid critical CSS file, the job is then finished and removed from the queue.', 'autoptimize' ); ?></li>
68
  <li><?php _e( 'When things go wrong, a job is marked as <span class="badge error">E</span>. You can retry faulty jobs, delete them or get in touch with <a href="https://criticalcss.com/?aff=1" target="_blank">criticalcss.com</a> for assistance.', 'autoptimize' ); ?></li>
69
  <li><?php _e( 'Sometimes an unknown condition can happen. In this case, the job status becomes <span class="badge unknown">U</span> and you may want to ask <a href="https://criticalcss.com/?aff=1" target="_blank">criticalcss.com</a> for help or just delete it.', 'autoptimize' ); ?></li>
@@ -80,6 +80,9 @@ function ao_ccss_render_queue() {
80
  </table>
81
  <input class="hidden" type="text" id="ao-ccss-queue" name="autoptimize_ccss_queue" value='<?php echo( $ao_ccss_queue ); ?>'>
82
  <div class="submit jobs-btn">
 
 
 
83
  <div class="alignright">
84
  <span id="removeAllJobs" class="button-secondary" style="color:red;"><?php _e( 'Remove all jobs', 'autoptimize' ); ?></span>
85
  </div>
63
  <ol>
64
  <li><?php _e( 'The queue operates <strong>automatically, asynchronously and on regular intervals of 10 minutes.</strong> To view updated queue status, refresh this page.', 'autoptimize' ); ?></li>
65
  <li><?php _e( 'When the conditions to create a job are met (i.e. user not logged in, no matching <span class="badge manual">MANUAL</span> rule or CSS files has changed for an <span class="badge auto">AUTO</span> rule), a <span class="badge new">N</span> job is created in the queue.', 'autoptimize' ); ?></li>
66
+ <li><?php _e( "Autoptimize CriticalCSS Power-Up constantly queries the queue for <span class='badge new'>N</span> jobs. When it finds one, gears spins and jobs becomes <span class='badge pending'>P</span> while they are running and <a href='https://criticalcss.com/?aff=1' target='_blank'>criticalcss.com</a> doesn't return a result.", 'autoptimize' ); ?></li>
67
  <li><?php _e( 'As soon as <a href="https://criticalcss.com/?aff=1" target="_blank">criticalcss.com</a> returns a valid critical CSS file, the job is then finished and removed from the queue.', 'autoptimize' ); ?></li>
68
  <li><?php _e( 'When things go wrong, a job is marked as <span class="badge error">E</span>. You can retry faulty jobs, delete them or get in touch with <a href="https://criticalcss.com/?aff=1" target="_blank">criticalcss.com</a> for assistance.', 'autoptimize' ); ?></li>
69
  <li><?php _e( 'Sometimes an unknown condition can happen. In this case, the job status becomes <span class="badge unknown">U</span> and you may want to ask <a href="https://criticalcss.com/?aff=1" target="_blank">criticalcss.com</a> for help or just delete it.', 'autoptimize' ); ?></li>
80
  </table>
81
  <input class="hidden" type="text" id="ao-ccss-queue" name="autoptimize_ccss_queue" value='<?php echo( $ao_ccss_queue ); ?>'>
82
  <div class="submit jobs-btn">
83
+ <div id="queuerunner-container" class="alignleft hidden">
84
+ <span id="queuerunner" class="button-secondary"><?php _e( 'Manually processs the job queue', 'autoptimize' ); ?></span>
85
+ </div>
86
  <div class="alignright">
87
  <span id="removeAllJobs" class="button-secondary" style="color:red;"><?php _e( 'Remove all jobs', 'autoptimize' ); ?></span>
88
  </div>
classes/critcss-inc/admin_settings_rules.js.php CHANGED
@@ -362,8 +362,10 @@ function updateAfterChange() {
362
  document.getElementById('ao_title_and_button').scrollIntoView();
363
  }
364
 
365
- function displayNotice(textIn) {
366
- jQuery('<div class="error notice is-dismissable"><p>'+textIn+'</p></div>').insertBefore("#unSavedWarning");
 
 
367
  }
368
 
369
  function resetForm() {
362
  document.getElementById('ao_title_and_button').scrollIntoView();
363
  }
364
 
365
+ function displayNotice(textIn, level) {
366
+ if ( '' == level ) { level = 'error'; }
367
+ jQuery('<div class="notice-' + level + ' notice is-dismissable"><p>'+textIn+'</p></div>').insertBefore("#unSavedWarning");
368
+ document.getElementById('ao_title_and_button').scrollIntoView();
369
  }
370
 
371
  function resetForm() {
readme.txt CHANGED
@@ -3,9 +3,9 @@ Contributors: futtta, optimizingmatters, zytzagoo, turl
3
  Tags: optimize, minify, performance, images, core web vitals, lazy-load, pagespeed, google fonts
4
  Donate link: http://blog.futtta.be/2013/10/21/do-not-donate-to-me/
5
  Requires at least: 4.9
6
- Tested up to: 5.7
7
  Requires PHP: 5.6
8
- Stable tag: 2.8.4
9
 
10
  Autoptimize speeds up your website by optimizing JS, CSS, images (incl. lazy-load), HTML and Google Fonts, asyncing JS, removing emoji cruft and more.
11
 
@@ -287,6 +287,15 @@ location ~* /wp-content/cache/autoptimize/.*\.(js|css)$ {
287
  try_files $uri $uri/ /wp-content/autoptimize_404_handler.php;
288
  }`
289
 
 
 
 
 
 
 
 
 
 
290
  = What open source software/ projects are used in Autoptimize? =
291
 
292
  The following great open source projects are used in Autoptimize in some form or another:
@@ -319,11 +328,20 @@ Just [fork Autoptimize on Github](https://github.com/futtta/autoptimize) and cod
319
 
320
  == Changelog ==
321
 
 
 
 
 
 
 
 
 
 
322
  = 2.8.4 =
323
  * fix for an authenticated XSS vulnerability
324
 
325
  = 2.8.3 =
326
- * fix for missing ao-minify-html.php file
327
 
328
  = 2.8.2 =
329
  * Images: only show "did you know shortpixel" notice on Autoptimize settings pages (no more littering all over the backend)
3
  Tags: optimize, minify, performance, images, core web vitals, lazy-load, pagespeed, google fonts
4
  Donate link: http://blog.futtta.be/2013/10/21/do-not-donate-to-me/
5
  Requires at least: 4.9
6
+ Tested up to: 5.8
7
  Requires PHP: 5.6
8
+ Stable tag: 2.9.0
9
 
10
  Autoptimize speeds up your website by optimizing JS, CSS, images (incl. lazy-load), HTML and Google Fonts, asyncing JS, removing emoji cruft and more.
11
 
287
  try_files $uri $uri/ /wp-content/autoptimize_404_handler.php;
288
  }`
289
 
290
+ And this a nice alternative approach (provided by fboylovesyou);
291
+
292
+ `location ~* /wp-content/cache/autoptimize/.*\.(css)$ {
293
+ try_files $uri $uri/ /wp-content/cache/autoptimize/css/autoptimize_fallback.css;
294
+ }
295
+ location ~* /wp-content/cache/autoptimize/.*\.(js)$ {
296
+ try_files $uri $uri/ /wp-content/cache/autoptimize/js/autoptimize_fallback.js;
297
+ }`
298
+
299
  = What open source software/ projects are used in Autoptimize? =
300
 
301
  The following great open source projects are used in Autoptimize in some form or another:
328
 
329
  == Changelog ==
330
 
331
+ = 2.9.0 =
332
+ * New: per page/ post Autoptimize settings so one can disable specific optimizations (needs to be enabled on the main settings page under "Misc Options").
333
+ * New: "defer inline JS" as sub-option of "do not aggregate but defer" allowing to defer (almost) all JS.
334
+ * Improvement: Image optimization now automatically switches between AVIF & WebP & Jpeg even if lazyload is not active (AVIF has to be explicitly enabled).
335
+ * Improvement: re-ordering of "JavaScript optimization" settings
336
+ * Misc. other minor fixes, see the [GitHub commit log](https://github.com/futtta/autoptimize/commits/beta)
337
+
338
+ This release coincides with my father's 76th birthday, who continues to be a big inspritation to me. He's a mechanical engineer who after retirement focused his technical insights, experience and never-ending inquisitiveness on fountain pen design and prototyping, inventing a new bulkfiller mechanism in the process. Search the web for `Fountainbel` to find out more about him (or read [this older blogpost I wrote in Dutch](https://blog.futtta.be/2008/04/09/mijn-vader-is-een-tovenaar/)). Love you pops!
339
+
340
  = 2.8.4 =
341
  * fix for an authenticated XSS vulnerability
342
 
343
  = 2.8.3 =
344
+ * fix for missing ao-minify-html.php
345
 
346
  = 2.8.2 =
347
  * Images: only show "did you know shortpixel" notice on Autoptimize settings pages (no more littering all over the backend)