Autoptimize - Version 2.8.0

Version Description

  • JavaScript: new option "defer but don't aggregate"
  • JavaScript: ensure Autoptimize also acts on jQuery in WordPress 5.6 which is renamed to jquery.min.js from jquery.js before.
  • Images: add field to exclude images from being optimized.
  • Images: new filter (autoptimize_filter_imgopt_lazyload_from_nth) to tell AO not to lazyload the first X images (to improve LCP/ CLS).
  • Critical CSS: major improvements of the job processing mechanism, reducing time spent from up to 1 minute to just a couple of seconds.
  • Critical CSS: under "advanced options" replace "request limit" with "queue processing time limit" (default 30s).
  • Extra | Google Fonts: better parsing of version 2 Google Font URL's (/css2/).
  • Misc. other minor fixes, see the GitHub commit log.
Download this release

Release Info

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

Code changes from version 2.7.8 to 2.8.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.7.8
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.7.8' );
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.8.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.8.0' );
25
 
26
  // plugin_dir_path() returns the trailing slash!
27
  define( 'AUTOPTIMIZE_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
classes/autoptimizeCache.php CHANGED
@@ -632,7 +632,7 @@ class autoptimizeCache
632
  $_fallback_php = trailingslashit( WP_CONTENT_DIR ) . $_fallback_filename;
633
  $_fallback_status = true;
634
 
635
- if ( ! file_exists( $_fallback_php ) ) {
636
  $_fallback_php_contents = file_get_contents( AUTOPTIMIZE_PLUGIN_DIR . 'config/' . $_fallback_filename );
637
  $_fallback_php_contents = str_replace( '<?php exit;', '<?php', $_fallback_php_contents );
638
  $_fallback_php_contents = str_replace( '<!--ao-cache-dir-->', AUTOPTIMIZE_CACHE_DIR, $_fallback_php_contents );
632
  $_fallback_php = trailingslashit( WP_CONTENT_DIR ) . $_fallback_filename;
633
  $_fallback_status = true;
634
 
635
+ if ( ! file_exists( $_fallback_php ) && is_writable( WP_CONTENT_DIR ) ) {
636
  $_fallback_php_contents = file_get_contents( AUTOPTIMIZE_PLUGIN_DIR . 'config/' . $_fallback_filename );
637
  $_fallback_php_contents = str_replace( '<?php exit;', '<?php', $_fallback_php_contents );
638
  $_fallback_php_contents = str_replace( '<!--ao-cache-dir-->', AUTOPTIMIZE_CACHE_DIR, $_fallback_php_contents );
classes/autoptimizeConfig.php CHANGED
@@ -115,6 +115,8 @@ class autoptimizeConfig
115
 
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
 
119
  /* rss block */
120
  #futtta_feed ul{list-style:outside;}
@@ -222,11 +224,16 @@ if ( is_network_admin() && autoptimizeOptionWrapper::is_ao_active_for_network()
222
  <th scope="row"><?php _e( 'Optimize JavaScript Code?', 'autoptimize' ); ?></th>
223
  <td><input type="checkbox" id="autoptimize_js" name="autoptimize_js" <?php echo autoptimizeOptionWrapper::get_option( 'autoptimize_js' ) ? 'checked="checked" ' : ''; ?>/></td>
224
  </tr>
225
- <tr valign="top" class="js_sub">
226
  <th scope="row"><?php _e( 'Aggregate JS-files?', 'autoptimize' ); ?></th>
227
  <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" ' : ''; ?>/>
228
  <?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>
229
  </tr>
 
 
 
 
 
230
  <tr valign="top" class="js_sub js_aggregate">
231
  <th scope="row"><?php _e( 'Also aggregate inline JS?', 'autoptimize' ); ?></th>
232
  <td><label class="cb_label"><input type="checkbox" name="autoptimize_js_include_inline" <?php echo autoptimizeOptionWrapper::get_option( 'autoptimize_js_include_inline' ) ? 'checked="checked" ' : ''; ?>/>
@@ -251,7 +258,7 @@ if ( is_network_admin() && autoptimizeOptionWrapper::is_ao_active_for_network()
251
  <?php } ?>
252
  <tr valign="top" class="js_sub">
253
  <th scope="row"><?php _e( 'Exclude scripts from Autoptimize:', 'autoptimize' ); ?></th>
254
- <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' ) ); ?>"/><br />
255
  <?php
256
  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' );
257
  ?>
@@ -521,15 +528,30 @@ echo __( 'A comma-separated list of CSS you want to exclude from being optimized
521
 
522
  jQuery( "#autoptimize_js_aggregate" ).change(function() {
523
  if (this.checked && jQuery("#autoptimize_js").prop('checked')) {
524
- jQuery(".js_aggregate:visible").fadeTo("fast",1);
 
 
 
525
  jQuery( "#min_excl_row" ).show();
526
  } else {
527
- jQuery(".js_aggregate:visible").fadeTo("fast",.33);
528
- if ( jQuery( "#autoptimize_css_aggregate" ).prop('checked') == false ) {
 
529
  jQuery( "#min_excl_row" ).hide();
530
  }
531
  }
532
  });
 
 
 
 
 
 
 
 
 
 
 
533
 
534
  jQuery( "#autoptimize_css" ).change(function() {
535
  if (this.checked) {
@@ -611,6 +633,8 @@ echo __( 'A comma-separated list of CSS you want to exclude from being optimized
611
  }
612
  if (!jQuery("#autoptimize_js_aggregate").prop('checked')) {
613
  jQuery(".js_aggregate:visible").fadeTo('fast',.33);
 
 
614
  }
615
  if (jQuery("#autoptimize_enable_site_config").prop('checked')) {
616
  jQuery("li.itemDetail:not(.multiSite)").fadeTo('fast',.33);
@@ -664,6 +688,7 @@ echo __( 'A comma-separated list of CSS you want to exclude from being optimized
664
  register_setting( 'autoptimize', 'autoptimize_enable_site_config' );
665
  register_setting( 'autoptimize', 'autoptimize_js' );
666
  register_setting( 'autoptimize', 'autoptimize_js_aggregate' );
 
667
  register_setting( 'autoptimize', 'autoptimize_js_exclude' );
668
  register_setting( 'autoptimize', 'autoptimize_js_trycatch' );
669
  register_setting( 'autoptimize', 'autoptimize_js_justhead' );
@@ -720,31 +745,32 @@ echo __( 'A comma-separated list of CSS you want to exclude from being optimized
720
  public static function get_defaults()
721
  {
722
  static $config = array(
723
- 'autoptimize_html' => 0,
724
- 'autoptimize_html_keepcomments' => 0,
725
- 'autoptimize_enable_site_config' => 1,
726
- 'autoptimize_js' => 0,
727
- 'autoptimize_js_aggregate' => 1,
728
- 'autoptimize_js_exclude' => 'wp-includes/js/dist/, wp-includes/js/tinymce/, js/jquery/jquery.js',
729
- 'autoptimize_js_trycatch' => 0,
730
- 'autoptimize_js_justhead' => 0,
731
- 'autoptimize_js_include_inline' => 0,
732
- 'autoptimize_js_forcehead' => 0,
733
- 'autoptimize_css' => 0,
734
- 'autoptimize_css_aggregate' => 1,
735
- 'autoptimize_css_exclude' => 'admin-bar.min.css, dashicons.min.css, wp-content/cache/, wp-content/uploads/',
736
- 'autoptimize_css_justhead' => 0,
737
- 'autoptimize_css_include_inline' => 1,
738
- 'autoptimize_css_defer' => 0,
739
- 'autoptimize_css_defer_inline' => '',
740
- 'autoptimize_css_inline' => 0,
741
- 'autoptimize_css_datauris' => 0,
742
- 'autoptimize_cdn_url' => '',
743
- 'autoptimize_cache_nogzip' => 1,
744
- 'autoptimize_optimize_logged' => 1,
745
- 'autoptimize_optimize_checkout' => 0,
746
- 'autoptimize_minify_excluded' => 1,
747
- 'autoptimize_cache_fallback' => 1,
 
748
  );
749
 
750
  return $config;
115
 
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;}
224
  <th scope="row"><?php _e( 'Optimize JavaScript Code?', 'autoptimize' ); ?></th>
225
  <td><input type="checkbox" id="autoptimize_js" name="autoptimize_js" <?php echo autoptimizeOptionWrapper::get_option( 'autoptimize_js' ) ? 'checked="checked" ' : ''; ?>/></td>
226
  </tr>
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" ' : ''; ?>/>
258
  <?php } ?>
259
  <tr valign="top" class="js_sub">
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
  ?>
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
  }
543
  });
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
 
556
  jQuery( "#autoptimize_css" ).change(function() {
557
  if (this.checked) {
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);
688
  register_setting( 'autoptimize', 'autoptimize_enable_site_config' );
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' );
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;
classes/autoptimizeCriticalCSSBase.php CHANGED
@@ -105,7 +105,7 @@ class autoptimizeCriticalCSSBase {
105
  $autoptimize_ccss_options['ao_ccss_queue_raw'] = get_option( 'autoptimize_ccss_queue', false );
106
  $autoptimize_ccss_options['ao_ccss_viewport'] = get_option( 'autoptimize_ccss_viewport', false );
107
  $autoptimize_ccss_options['ao_ccss_finclude'] = get_option( 'autoptimize_ccss_finclude', false );
108
- $autoptimize_ccss_options['ao_ccss_rlimit'] = get_option( 'autoptimize_ccss_rlimit', '5' );
109
  $autoptimize_ccss_options['ao_ccss_noptimize'] = get_option( 'autoptimize_ccss_noptimize', false );
110
  $autoptimize_ccss_options['ao_ccss_debug'] = get_option( 'autoptimize_ccss_debug', false );
111
  $autoptimize_ccss_options['ao_ccss_key'] = get_option( 'autoptimize_ccss_key' );
105
  $autoptimize_ccss_options['ao_ccss_queue_raw'] = get_option( 'autoptimize_ccss_queue', false );
106
  $autoptimize_ccss_options['ao_ccss_viewport'] = get_option( 'autoptimize_ccss_viewport', false );
107
  $autoptimize_ccss_options['ao_ccss_finclude'] = get_option( 'autoptimize_ccss_finclude', false );
108
+ $autoptimize_ccss_options['ao_ccss_rtimelimit'] = get_option( 'autoptimize_ccss_rtimelimit', '30' );
109
  $autoptimize_ccss_options['ao_ccss_noptimize'] = get_option( 'autoptimize_ccss_noptimize', false );
110
  $autoptimize_ccss_options['ao_ccss_debug'] = get_option( 'autoptimize_ccss_debug', false );
111
  $autoptimize_ccss_options['ao_ccss_key'] = get_option( 'autoptimize_ccss_key' );
classes/autoptimizeCriticalCSSCron.php CHANGED
@@ -83,12 +83,17 @@ class autoptimizeCriticalCSSCron {
83
 
84
  // Attach required variables.
85
  global $ao_ccss_queue;
86
- global $ao_ccss_rlimit;
87
 
88
- // Initialize job counters.
89
- $jc = 1;
90
- $jr = 1;
91
- $jt = count( $ao_ccss_queue );
 
 
 
 
 
92
 
93
  // Sort queue by ascending job status (e.g. ERROR, JOB_ONGOING, JOB_QUEUED, NEW...).
94
  array_multisort( array_column( $ao_ccss_queue, 'jqstat' ), $ao_ccss_queue ); // @codingStandardsIgnoreLine
@@ -116,15 +121,16 @@ class autoptimizeCriticalCSSCron {
116
 
117
  // If job hash is new or different of a previous one.
118
  if ( $hash ) {
 
 
 
 
 
 
 
119
  // Set job hash.
120
  $jprops['hash'] = $hash;
121
 
122
- // If this is not the first job, wait 10 seconds before process next job due criticalcss.com API limits.
123
- if ( $jr > 1 ) {
124
- autoptimizeCriticalCSSCore::ao_ccss_log( 'Waiting ' . AO_CCSS_SLEEP . ' seconds due to criticalcss.com API limits', 3 );
125
- sleep( AO_CCSS_SLEEP );
126
- }
127
-
128
  // Dispatch the job generate request and increment request count.
129
  $apireq = $this->ao_ccss_api_generate( $path, $queue_debug, $qdobj['htcode'] );
130
  $jr++;
@@ -191,15 +197,8 @@ class autoptimizeCriticalCSSCron {
191
  // Log the pending job.
192
  autoptimizeCriticalCSSCore::ao_ccss_log( 'Found PENDING job with local ID <' . $jprops['ljid'] . '>, continuing its queue processing', 3 );
193
 
194
- // If this is not the first job, wait before process next job due criticalcss.com API limits.
195
- if ( $jr > 1 ) {
196
- autoptimizeCriticalCSSCore::ao_ccss_log( 'Waiting ' . AO_CCSS_SLEEP . ' seconds due to criticalcss.com API limits', 3 );
197
- sleep( AO_CCSS_SLEEP );
198
- }
199
-
200
  // Dispatch the job result request and increment request count.
201
  $apireq = $this->ao_ccss_api_results( $jprops['jid'], $queue_debug, $qdobj['htcode'] );
202
- $jr++;
203
 
204
  // NOTE: All the following condigitons maps to the ones in admin_settings_queue.js.php
205
  // Replace API response values if queue debugging is enabled and some value is set.
@@ -241,13 +240,17 @@ class autoptimizeCriticalCSSCron {
241
  } elseif ( 'GOOD' == $apireq['resultStatus'] && ( 'WARN' == $apireq['validationStatus'] || 'BAD' == $apireq['validationStatus'] || 'SCREENSHOT_WARN_BLANK' == $apireq['validationStatus'] ) ) {
242
  // SUCCESS: GOOD job with WARN or BAD validation
243
  // Update job properties.
244
- $jprops['file'] = $this->ao_ccss_save_file( $apireq['css'], $trule, true );
245
  $jprops['jqstat'] = $apireq['status'];
246
  $jprops['jrstat'] = $apireq['resultStatus'];
247
  $jprops['jvstat'] = $apireq['validationStatus'];
248
  $jprops['jftime'] = microtime( true );
249
- $rule_update = true;
250
- autoptimizeCriticalCSSCore::ao_ccss_log( 'Job id <' . $jprops['ljid'] . '> result request successful, remote id <' . $jprops['jid'] . '>, status <' . $jprops['jqstat'] . ', file saved <' . $jprops['file'] . '> but requires REVIEW', 3 );
 
 
 
 
 
251
  } elseif ( 'GOOD' != $apireq['resultStatus'] && ( 'GOOD' != $apireq['validationStatus'] || 'WARN' != $apireq['validationStatus'] || 'BAD' != $apireq['validationStatus'] || 'SCREENSHOT_WARN_BLANK' != $apireq['validationStatus'] ) ) {
252
  // ERROR: no GOOD, WARN or BAD results
253
  // Update job properties.
@@ -343,9 +346,9 @@ class autoptimizeCriticalCSSCron {
343
  autoptimizeCriticalCSSCore::ao_ccss_log( 'Nothing to do on this job', 3 );
344
  }
345
 
346
- // Break the loop if request limit is set and was reached.
347
- if ( $ao_ccss_rlimit && $ao_ccss_rlimit == $jr ) {
348
- autoptimizeCriticalCSSCore::ao_ccss_log( 'The limit of ' . $ao_ccss_rlimit . ' request(s) to criticalcss.com was reached, queue control must finish now', 3 );
349
  break;
350
  }
351
 
83
 
84
  // Attach required variables.
85
  global $ao_ccss_queue;
86
+ global $ao_ccss_rtimelimit;
87
 
88
+ // Initialize counters.
89
+ if ( $ao_ccss_rtimelimit == 0 ) {
90
+ // no time limit set, let's go with 1000 seconds.
91
+ $ao_ccss_rtimelimit = 1000;
92
+ }
93
+ $mt = time() + $ao_ccss_rtimelimit; // maxtime queue processing can run.
94
+ $jc = 1; // job count number.
95
+ $jr = 1; // jobs requests number.
96
+ $jt = count( $ao_ccss_queue ); // number of jobs in queue.
97
 
98
  // Sort queue by ascending job status (e.g. ERROR, JOB_ONGOING, JOB_QUEUED, NEW...).
99
  array_multisort( array_column( $ao_ccss_queue, 'jqstat' ), $ao_ccss_queue ); // @codingStandardsIgnoreLine
121
 
122
  // If job hash is new or different of a previous one.
123
  if ( $hash ) {
124
+ if ( $jr > 2 ) {
125
+ // we already posted 2 jobs to criticalcss.com, don't post more this run
126
+ // but we can keep on processing the queue to keep it tidy.
127
+ autoptimizeCriticalCSSCore::ao_ccss_log( 'Holding off on generating request for job with local ID <' . $jprops['ljid'] . '>, maximum number of POSTS reached.', 3 );
128
+ continue;
129
+ }
130
+
131
  // Set job hash.
132
  $jprops['hash'] = $hash;
133
 
 
 
 
 
 
 
134
  // Dispatch the job generate request and increment request count.
135
  $apireq = $this->ao_ccss_api_generate( $path, $queue_debug, $qdobj['htcode'] );
136
  $jr++;
197
  // Log the pending job.
198
  autoptimizeCriticalCSSCore::ao_ccss_log( 'Found PENDING job with local ID <' . $jprops['ljid'] . '>, continuing its queue processing', 3 );
199
 
 
 
 
 
 
 
200
  // Dispatch the job result request and increment request count.
201
  $apireq = $this->ao_ccss_api_results( $jprops['jid'], $queue_debug, $qdobj['htcode'] );
 
202
 
203
  // NOTE: All the following condigitons maps to the ones in admin_settings_queue.js.php
204
  // Replace API response values if queue debugging is enabled and some value is set.
240
  } elseif ( 'GOOD' == $apireq['resultStatus'] && ( 'WARN' == $apireq['validationStatus'] || 'BAD' == $apireq['validationStatus'] || 'SCREENSHOT_WARN_BLANK' == $apireq['validationStatus'] ) ) {
241
  // SUCCESS: GOOD job with WARN or BAD validation
242
  // Update job properties.
 
243
  $jprops['jqstat'] = $apireq['status'];
244
  $jprops['jrstat'] = $apireq['resultStatus'];
245
  $jprops['jvstat'] = $apireq['validationStatus'];
246
  $jprops['jftime'] = microtime( true );
247
+ if ( apply_filters( 'autoptimize_filter_ccss_save_review_rules', true ) ) {
248
+ $jprops['file'] = $this->ao_ccss_save_file( $apireq['css'], $trule, true );
249
+ $rule_update = true;
250
+ autoptimizeCriticalCSSCore::ao_ccss_log( 'Job id <' . $jprops['ljid'] . '> result request successful, remote id <' . $jprops['jid'] . '>, status <' . $jprops['jqstat'] . ', file saved <' . $jprops['file'] . '> but requires REVIEW', 3 );
251
+ } else {
252
+ autoptimizeCriticalCSSCore::ao_ccss_log( 'Job id <' . $jprops['ljid'] . '> result request successful, remote id <' . $jprops['jid'] . '>, status <' . $jprops['jqstat'] . ', file saved <' . $jprops['file'] . '> but required REVIEW so not saved.', 3 );
253
+ }
254
  } elseif ( 'GOOD' != $apireq['resultStatus'] && ( 'GOOD' != $apireq['validationStatus'] || 'WARN' != $apireq['validationStatus'] || 'BAD' != $apireq['validationStatus'] || 'SCREENSHOT_WARN_BLANK' != $apireq['validationStatus'] ) ) {
255
  // ERROR: no GOOD, WARN or BAD results
256
  // Update job properties.
346
  autoptimizeCriticalCSSCore::ao_ccss_log( 'Nothing to do on this job', 3 );
347
  }
348
 
349
+ // Break the loop if request time limit is (almost exceeded).
350
+ if ( time() > $mt ) {
351
+ autoptimizeCriticalCSSCore::ao_ccss_log( 'The time limit of ' . $ao_ccss_rtimelimit . ' seconds was exceeded, queue control must finish now', 3 );
352
  break;
353
  }
354
 
classes/autoptimizeCriticalCSSEnqueue.php CHANGED
@@ -216,8 +216,8 @@ class autoptimizeCriticalCSSEnqueue {
216
  // but remove prefix to be able to check if the function exists & returns true.
217
  $_type = str_replace( array( 'woo_', 'bp_', 'bbp_', 'edd_' ), '', $type );
218
  if ( function_exists( $_type ) && call_user_func( $_type ) ) {
219
- // Make sure we only return is_front_page (and is_home) for one page, not for the "paged frontpage" (/page/2 ..).
220
- if ( ( 'is_front_page' !== $_type && 'is_home' !== $_type ) || ! is_paged() ) {
221
  $page_type = $type;
222
  break;
223
  }
216
  // but remove prefix to be able to check if the function exists & returns true.
217
  $_type = str_replace( array( 'woo_', 'bp_', 'bbp_', 'edd_' ), '', $type );
218
  if ( function_exists( $_type ) && call_user_func( $_type ) ) {
219
+ // Make sure we only return for one page, not for the "paged pages" (/page/2 ..).
220
+ if ( ! is_page() || ! is_paged() ) {
221
  $page_type = $type;
222
  break;
223
  }
classes/autoptimizeCriticalCSSSettings.php CHANGED
@@ -58,7 +58,7 @@ class autoptimizeCriticalCSSSettings {
58
  register_setting( 'ao_ccss_options_group', 'autoptimize_ccss_queue' );
59
  register_setting( 'ao_ccss_options_group', 'autoptimize_ccss_viewport' );
60
  register_setting( 'ao_ccss_options_group', 'autoptimize_ccss_finclude' );
61
- register_setting( 'ao_ccss_options_group', 'autoptimize_ccss_rlimit' );
62
  register_setting( 'ao_ccss_options_group', 'autoptimize_ccss_noptimize' );
63
  register_setting( 'ao_ccss_options_group', 'autoptimize_ccss_debug' );
64
  register_setting( 'ao_ccss_options_group', 'autoptimize_ccss_key' );
@@ -143,16 +143,28 @@ class autoptimizeCriticalCSSSettings {
143
  <?php
144
  }
145
 
146
- // Check for Autoptimize.
147
  if ( ! empty( $ao_ccss_key ) && ! $ao_css_defer ) {
148
- ?>
149
- <div class="notice-error notice"><p>
150
- <?php
151
- _e( "Oops! Please <strong>activate the \"Inline and Defer CSS\" option</strong> on Autoptimize's main settings page to use this power-up.", 'autoptimize' );
152
- ?>
153
- </p></div>
154
- <?php
155
- return;
 
 
 
 
 
 
 
 
 
 
 
 
156
  }
157
 
158
  // check if WordPress cron is disabled and warn if so.
@@ -222,6 +234,8 @@ class autoptimizeCriticalCSSSettings {
222
  <div class="notice-success notice"><p>
223
  <?php
224
  _e( 'Great, Autoptimize will now automatically start creating new critical CSS rules, you should see those appearing below in the next couple of hours.', 'autoptimize' );
 
 
225
  ?>
226
  </p></div>
227
  <?php
@@ -238,6 +252,19 @@ class autoptimizeCriticalCSSSettings {
238
  <?php
239
  }
240
 
 
 
 
 
 
 
 
 
 
 
 
 
 
241
  // Settings Form.
242
  ?>
243
  <form id="settings" method="post" action="options.php">
@@ -281,7 +308,7 @@ class autoptimizeCriticalCSSSettings {
281
  echo '<input class="hidden" name="autoptimize_ccss_viewport[w]" value="' . $viewport['w'] . '">';
282
  echo '<input class="hidden" name="autoptimize_ccss_viewport[h]" value="' . $viewport['h'] . '">';
283
  echo '<input class="hidden" name="autoptimize_ccss_finclude" value="' . $ao_ccss_finclude . '">';
284
- echo '<input class="hidden" name="autoptimize_ccss_rlimit" value="' . $ao_ccss_rlimit . '">';
285
  echo '<input class="hidden" name="autoptimize_ccss_debug" value="' . $ao_ccss_debug . '">';
286
  echo '<input class="hidden" name="autoptimize_ccss_noptimize" value="' . $ao_ccss_noptimize . '">';
287
  echo '<input class="hidden" name="autoptimize_css_defer_inline" value="' . esc_attr( $ao_css_defer_inline ) . '">';
58
  register_setting( 'ao_ccss_options_group', 'autoptimize_ccss_queue' );
59
  register_setting( 'ao_ccss_options_group', 'autoptimize_ccss_viewport' );
60
  register_setting( 'ao_ccss_options_group', 'autoptimize_ccss_finclude' );
61
+ register_setting( 'ao_ccss_options_group', 'autoptimize_ccss_rtimelimit' );
62
  register_setting( 'ao_ccss_options_group', 'autoptimize_ccss_noptimize' );
63
  register_setting( 'ao_ccss_options_group', 'autoptimize_ccss_debug' );
64
  register_setting( 'ao_ccss_options_group', 'autoptimize_ccss_key' );
143
  <?php
144
  }
145
 
146
+ // Check for "inline & defer CSS" being active in Autoptimize.
147
  if ( ! empty( $ao_ccss_key ) && ! $ao_css_defer ) {
148
+ if ( empty( $ao_ccss_keyst ) ) {
149
+ // no keystate so likely in activation-process of CCSS, let's enable "inline & defer CSS" immediately to make things easier!
150
+ autoptimizeOptionWrapper::update_option( 'autoptimize_css_defer', 'on' );
151
+ ?>
152
+ <div class="notice-info notice"><p>
153
+ <?php
154
+ _e( "The \"Inline and Defer CSS\" option was activated to allow critical CSS to be used.", 'autoptimize' );
155
+ ?>
156
+ </p></div>
157
+ <?php
158
+ } else {
159
+ // we have keystate, so "inline & defer CSS" was probably disable for troubleshooting, warn but let users continue.
160
+ ?>
161
+ <div class="notice-warning notice"><p>
162
+ <?php
163
+ _e( "Oops! Please <strong>activate the \"Inline and Defer CSS\" option</strong> on Autoptimize's main settings page ensure critical CSS is used on the front-end.", 'autoptimize' );
164
+ ?>
165
+ </p></div>
166
+ <?php
167
+ }
168
  }
169
 
170
  // check if WordPress cron is disabled and warn if so.
234
  <div class="notice-success notice"><p>
235
  <?php
236
  _e( 'Great, Autoptimize will now automatically start creating new critical CSS rules, you should see those appearing below in the next couple of hours.', 'autoptimize' );
237
+ echo ' ';
238
+ _e( 'In the meantime you might want to <strong>edit default rule CSS now</strong>, to avoid all CSS being inlined when no (applicable) rules are found.', 'autoptimize' );
239
  ?>
240
  </p></div>
241
  <?php
252
  <?php
253
  }
254
 
255
+ // warn if too many rules (based on length of ao_ccss_rules option) as that might cause issues at e.g. wpengine
256
+ // see https://wpengine.com/support/database-optimization-best-practices/#Autoloaded_Data
257
+ $_raw_rules_length = strlen( get_option( 'autoptimize_ccss_rules', '') );
258
+ if ( $_raw_rules_length > apply_filters( 'autoptimize_ccss_rules_length_warning', 500000 ) ) {
259
+ ?>
260
+ <div class="notice-warning notice"><p>
261
+ <?php
262
+ _e( 'It looks like the amount of Critical CSS rules is very high, it is recommended to reconfigure Autoptimize (e.g. by manually creating broader rules) to ensure less rules are created.', 'autoptimize' );
263
+ ?>
264
+ </p></div>
265
+ <?php
266
+ }
267
+
268
  // Settings Form.
269
  ?>
270
  <form id="settings" method="post" action="options.php">
308
  echo '<input class="hidden" name="autoptimize_ccss_viewport[w]" value="' . $viewport['w'] . '">';
309
  echo '<input class="hidden" name="autoptimize_ccss_viewport[h]" value="' . $viewport['h'] . '">';
310
  echo '<input class="hidden" name="autoptimize_ccss_finclude" value="' . $ao_ccss_finclude . '">';
311
+ echo '<input class="hidden" name="autoptimize_ccss_rtimelimit" value="' . $ao_ccss_rtimelimit . '">';
312
  echo '<input class="hidden" name="autoptimize_ccss_debug" value="' . $ao_ccss_debug . '">';
313
  echo '<input class="hidden" name="autoptimize_ccss_noptimize" value="' . $ao_ccss_noptimize . '">';
314
  echo '<input class="hidden" name="autoptimize_css_defer_inline" value="' . esc_attr( $ao_css_defer_inline ) . '">';
classes/autoptimizeCriticalCSSSettingsAjax.php CHANGED
@@ -218,7 +218,7 @@ class autoptimizeCriticalCSSSettingsAjax {
218
  $settings['additional'] = get_option( 'autoptimize_ccss_additional' );
219
  $settings['viewport'] = get_option( 'autoptimize_ccss_viewport' );
220
  $settings['finclude'] = get_option( 'autoptimize_ccss_finclude' );
221
- $settings['rlimit'] = get_option( 'autoptimize_ccss_rlimit' );
222
  $settings['noptimize'] = get_option( 'autoptimize_ccss_noptimize' );
223
  $settings['debug'] = get_option( 'autoptimize_ccss_debug' );
224
  $settings['key'] = get_option( 'autoptimize_ccss_key' );
@@ -323,7 +323,7 @@ class autoptimizeCriticalCSSSettingsAjax {
323
  update_option( 'autoptimize_ccss_additional', $settings['additional'] );
324
  update_option( 'autoptimize_ccss_viewport', $settings['viewport'] );
325
  update_option( 'autoptimize_ccss_finclude', $settings['finclude'] );
326
- update_option( 'autoptimize_ccss_rlimit', $settings['rlimit'] );
327
  update_option( 'autoptimize_ccss_noptimize', $settings['noptimize'] );
328
  update_option( 'autoptimize_ccss_debug', $settings['debug'] );
329
  update_option( 'autoptimize_ccss_key', $settings['key'] );
218
  $settings['additional'] = get_option( 'autoptimize_ccss_additional' );
219
  $settings['viewport'] = get_option( 'autoptimize_ccss_viewport' );
220
  $settings['finclude'] = get_option( 'autoptimize_ccss_finclude' );
221
+ $settings['rtimelimit'] = get_option( 'autoptimize_ccss_rtimelimit' );
222
  $settings['noptimize'] = get_option( 'autoptimize_ccss_noptimize' );
223
  $settings['debug'] = get_option( 'autoptimize_ccss_debug' );
224
  $settings['key'] = get_option( 'autoptimize_ccss_key' );
323
  update_option( 'autoptimize_ccss_additional', $settings['additional'] );
324
  update_option( 'autoptimize_ccss_viewport', $settings['viewport'] );
325
  update_option( 'autoptimize_ccss_finclude', $settings['finclude'] );
326
+ update_option( 'autoptimize_ccss_rtimelimit', $settings['rtimelimit'] );
327
  update_option( 'autoptimize_ccss_noptimize', $settings['noptimize'] );
328
  update_option( 'autoptimize_ccss_debug', $settings['debug'] );
329
  update_option( 'autoptimize_ccss_key', $settings['key'] );
classes/autoptimizeExtra.php CHANGED
@@ -237,7 +237,9 @@ class autoptimizeExtra
237
  $font = str_replace( array( '%7C', '%7c' ), '|', $font );
238
  if ( strpos( $font, 'fonts.googleapis.com/css2' ) !== false ) {
239
  // (Somewhat) change Google Fonts APIv2 syntax back to v1.
240
- $font = str_replace( array( 'wght@', 'wght%40', ';', '%3B' ), array( '', '', ',', ',' ), $font );
 
 
241
  }
242
  $font = explode( 'family=', $font );
243
  $font = ( isset( $font[1] ) ) ? explode( '&', $font[1] ) : array();
@@ -419,7 +421,7 @@ class autoptimizeExtra
419
  $preload_as = 'style';
420
  } elseif ( autoptimizeUtils::str_ends_in( $_preload, '.js' ) ) {
421
  $preload_as = 'script';
422
- } elseif ( autoptimizeUtils::str_ends_in( $_preload, '.woff' ) || autoptimizeUtils::str_ends_in( $_preload, '.woff2' ) || autoptimizeUtils::str_ends_in( $_preload, '.ttf' ) || autoptimizeUtils::str_ends_in( $_preload, '.eot' ) ) {
423
  $preload_as = 'font';
424
  $crossorigin = ' crossorigin';
425
  $mime_type = ' type="font/' . pathinfo( $_preload, PATHINFO_EXTENSION ) . '"';
237
  $font = str_replace( array( '%7C', '%7c' ), '|', $font );
238
  if ( strpos( $font, 'fonts.googleapis.com/css2' ) !== false ) {
239
  // (Somewhat) change Google Fonts APIv2 syntax back to v1.
240
+ // todo: support for 100..900
241
+ $font = rawurldecode( $font );
242
+ $font = str_replace( array( 'css2?', 'ital,wght@', 'wght@', 'ital@', '0,', '1,', ':1', ';', '&family=' ), array( 'css?', '', '', '', '', 'italic', ':italic', ',', '%7C' ), $font );
243
  }
244
  $font = explode( 'family=', $font );
245
  $font = ( isset( $font[1] ) ) ? explode( '&', $font[1] ) : array();
421
  $preload_as = 'style';
422
  } elseif ( autoptimizeUtils::str_ends_in( $_preload, '.js' ) ) {
423
  $preload_as = 'script';
424
+ } elseif ( autoptimizeUtils::str_ends_in( $_preload, '.woff' ) || autoptimizeUtils::str_ends_in( $_preload, '.woff2' ) || autoptimizeUtils::str_ends_in( $_preload, '.ttf' ) || autoptimizeUtils::str_ends_in( $_preload, '.eot' ) || autoptimizeUtils::str_ends_in( $_preload, '.otf' ) ) {
425
  $preload_as = 'font';
426
  $crossorigin = ' crossorigin';
427
  $mime_type = ' type="font/' . pathinfo( $_preload, PATHINFO_EXTENSION ) . '"';
classes/autoptimizeImages.php CHANGED
@@ -31,6 +31,7 @@ class autoptimizeImages
31
  }
32
 
33
  $this->set_options( $options );
 
34
  }
35
 
36
  public function set_options( array $options )
@@ -411,7 +412,10 @@ class autoptimizeImages
411
  }
412
 
413
  if ( null === $nopti_images ) {
414
- $nopti_images = apply_filters( 'autoptimize_filter_imgopt_noptimize', '' );
 
 
 
415
  }
416
 
417
  $site_host = AUTOPTIMIZE_SITE_DOMAIN;
@@ -504,7 +508,13 @@ class autoptimizeImages
504
  $width = 180;
505
  $height = 180;
506
  }
507
- return $this->replace_img_callback( $matches, $width, $height );
 
 
 
 
 
 
508
  }
509
 
510
  public function filter_optimize_images( $in )
@@ -759,7 +769,8 @@ class autoptimizeImages
759
 
760
  public function add_lazyload( $tag, $placeholder = '' ) {
761
  // adds actual lazyload-attributes to an image node.
762
- if ( str_ireplace( $this->get_lazyload_exclusions(), '', $tag ) === $tag ) {
 
763
  $tag = $this->maybe_fix_missing_quotes( $tag );
764
 
765
  // store original tag for use in noscript version.
@@ -889,7 +900,7 @@ class autoptimizeImages
889
  if ( strpos( $tag, 'class=' ) !== false ) {
890
  $tag = preg_replace( '/(\sclass\s?=\s?("|\'))/', '$1' . $target_class, $tag );
891
  } else {
892
- $tag = preg_replace( '/(<img)\s/', '$1 class="' . trim( $target_class ) . '" ', $tag );
893
  }
894
 
895
  return $tag;
@@ -1108,6 +1119,12 @@ class autoptimizeImages
1108
  ?>
1109
  </td>
1110
  </tr>
 
 
 
 
 
 
1111
  <tr id='autoptimize_imgopt_quality' <?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"'; } ?>>
1112
  <th scope="row"><?php _e( 'Image Optimization quality', 'autoptimize' ); ?></th>
1113
  <td>
@@ -1163,9 +1180,11 @@ class autoptimizeImages
1163
  if (this.checked) {
1164
  jQuery("#autoptimize_imgopt_quality").show("slow");
1165
  jQuery("#autoptimize_imgopt_ngimg").show("slow");
 
1166
  } else {
1167
  jQuery("#autoptimize_imgopt_quality").hide("slow");
1168
  jQuery("#autoptimize_imgopt_ngimg").hide("slow");
 
1169
  }
1170
  });
1171
  jQuery("#autoptimize_imgopt_ngimg_checkbox").change(function() {
31
  }
32
 
33
  $this->set_options( $options );
34
+ $this->lazyload_counter = 0;
35
  }
36
 
37
  public function set_options( array $options )
412
  }
413
 
414
  if ( null === $nopti_images ) {
415
+ if ( is_array( $this->options ) && array_key_exists( 'autoptimize_imgopt_text_field_6', $this->options ) ) {
416
+ $nopti_images = $this->options['autoptimize_imgopt_text_field_6'];
417
+ }
418
+ $nopti_images = apply_filters( 'autoptimize_filter_imgopt_noptimize', $nopti_images );
419
  }
420
 
421
  $site_host = AUTOPTIMIZE_SITE_DOMAIN;
508
  $width = 180;
509
  $height = 180;
510
  }
511
+
512
+ // make sure we're not trying to optimize a *.ico file
513
+ if ( strpos( $matches[1], '.ico' ) === false ) {
514
+ return $this->replace_img_callback( $matches, $width, $height );
515
+ } else {
516
+ return $matches;
517
+ }
518
  }
519
 
520
  public function filter_optimize_images( $in )
769
 
770
  public function add_lazyload( $tag, $placeholder = '' ) {
771
  // adds actual lazyload-attributes to an image node.
772
+ $this->lazyload_counter++;
773
+ if ( str_ireplace( $this->get_lazyload_exclusions(), '', $tag ) === $tag && $this->lazyload_counter >= apply_filters( 'autoptimize_filter_imgopt_lazyload_from_nth', 0 ) ) {
774
  $tag = $this->maybe_fix_missing_quotes( $tag );
775
 
776
  // store original tag for use in noscript version.
900
  if ( strpos( $tag, 'class=' ) !== false ) {
901
  $tag = preg_replace( '/(\sclass\s?=\s?("|\'))/', '$1' . $target_class, $tag );
902
  } else {
903
+ $tag = preg_replace( '/(<[a-zA-Z]*)\s/', '$1 class="' . trim( $target_class ) . '" ', $tag );
904
  }
905
 
906
  return $tag;
1119
  ?>
1120
  </td>
1121
  </tr>
1122
+ <tr id='autoptimize_imgopt_optimization_exclusions' <?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"'; } ?>>
1123
+ <th scope="row"><?php _e( 'Optimization exclusions', 'autoptimize' ); ?></th>
1124
+ <td>
1125
+ <label><input type='text' style='width:80%' id='autoptimize_imgopt_optimization_exclusions' name='autoptimize_imgopt_settings[autoptimize_imgopt_text_field_6]' value='<?php if ( ! empty( $options['autoptimize_imgopt_text_field_6'] ) ) { echo esc_attr( $options['autoptimize_imgopt_text_field_6'] ); } ?>'><br /><?php _e( 'Comma-separated list of image classes or filenames that should not be optimized.', 'autoptimize' ); ?></label>
1126
+ </td>
1127
+ </tr>
1128
  <tr id='autoptimize_imgopt_quality' <?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"'; } ?>>
1129
  <th scope="row"><?php _e( 'Image Optimization quality', 'autoptimize' ); ?></th>
1130
  <td>
1180
  if (this.checked) {
1181
  jQuery("#autoptimize_imgopt_quality").show("slow");
1182
  jQuery("#autoptimize_imgopt_ngimg").show("slow");
1183
+ jQuery("#autoptimize_imgopt_optimization_exclusions").show("slow");
1184
  } else {
1185
  jQuery("#autoptimize_imgopt_quality").hide("slow");
1186
  jQuery("#autoptimize_imgopt_ngimg").hide("slow");
1187
+ jQuery("#autoptimize_imgopt_optimization_exclusions").hide("slow");
1188
  }
1189
  });
1190
  jQuery("#autoptimize_imgopt_ngimg_checkbox").change(function() {
classes/autoptimizeMain.php CHANGED
@@ -486,14 +486,15 @@ class autoptimizeMain
486
 
487
  $classoptions = array(
488
  'autoptimizeScripts' => array(
489
- 'aggregate' => $conf->get( 'autoptimize_js_aggregate' ),
490
- 'justhead' => $conf->get( 'autoptimize_js_justhead' ),
491
- 'forcehead' => $conf->get( 'autoptimize_js_forcehead' ),
492
- 'trycatch' => $conf->get( 'autoptimize_js_trycatch' ),
493
- 'js_exclude' => $conf->get( 'autoptimize_js_exclude' ),
494
- 'cdn_url' => $conf->get( 'autoptimize_cdn_url' ),
495
- 'include_inline' => $conf->get( 'autoptimize_js_include_inline' ),
496
- 'minify_excluded' => $conf->get( 'autoptimize_minify_excluded' ),
 
497
  ),
498
  'autoptimizeStyles' => array(
499
  'aggregate' => $conf->get( 'autoptimize_css_aggregate' ),
@@ -565,6 +566,7 @@ class autoptimizeMain
565
  'autoptimize_enable_site_config',
566
  'autoptimize_js',
567
  'autoptimize_js_aggregate',
 
568
  'autoptimize_js_exclude',
569
  'autoptimize_js_forcehead',
570
  'autoptimize_js_justhead',
@@ -590,6 +592,7 @@ class autoptimizeMain
590
  'autoptimize_ccss_viewport',
591
  'autoptimize_ccss_finclude',
592
  'autoptimize_ccss_rlimit',
 
593
  'autoptimize_ccss_noptimize',
594
  'autoptimize_ccss_debug',
595
  'autoptimize_ccss_key',
486
 
487
  $classoptions = array(
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' ),
494
+ 'js_exclude' => $conf->get( 'autoptimize_js_exclude' ),
495
+ 'cdn_url' => $conf->get( 'autoptimize_cdn_url' ),
496
+ 'include_inline' => $conf->get( 'autoptimize_js_include_inline' ),
497
+ 'minify_excluded' => $conf->get( 'autoptimize_minify_excluded' ),
498
  ),
499
  'autoptimizeStyles' => array(
500
  'aggregate' => $conf->get( 'autoptimize_css_aggregate' ),
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',
592
  'autoptimize_ccss_viewport',
593
  'autoptimize_ccss_finclude',
594
  'autoptimize_ccss_rlimit',
595
+ 'autoptimize_ccss_rtimelimit',
596
  'autoptimize_ccss_noptimize',
597
  'autoptimize_ccss_debug',
598
  'autoptimize_ccss_key',
classes/autoptimizeScripts.php CHANGED
@@ -109,6 +109,13 @@ class autoptimizeScripts extends autoptimizeBase
109
  */
110
  private $aggregate = true;
111
 
 
 
 
 
 
 
 
112
  /**
113
  * Setting; try/catch wrapping or not.
114
  *
@@ -234,6 +241,11 @@ class autoptimizeScripts extends autoptimizeBase
234
  if ( $this->aggregate && apply_filters( 'autoptimize_filter_js_dontaggregate', false ) ) {
235
  $this->aggregate = false;
236
  }
 
 
 
 
 
237
 
238
  // include inline?
239
  if ( apply_filters( 'autoptimize_js_include_inline', $options['include_inline'] ) ) {
@@ -336,6 +348,15 @@ class autoptimizeScripts extends autoptimizeBase
336
  }
337
  }
338
  }
 
 
 
 
 
 
 
 
 
339
 
340
  // Should we minify the non-aggregated script?
341
  // -> if aggregate is on and exclude minify is on
109
  */
110
  private $aggregate = true;
111
 
112
+ /**
113
+ * Setting; if not aggregated, should we defer?
114
+ *
115
+ * @var bool
116
+ */
117
+ private $defer_not_aggregate = false;
118
+
119
  /**
120
  * Setting; try/catch wrapping or not.
121
  *
241
  if ( $this->aggregate && apply_filters( 'autoptimize_filter_js_dontaggregate', false ) ) {
242
  $this->aggregate = false;
243
  }
244
+
245
+ // Defer when not aggregating.
246
+ if ( false === $this->aggregate && apply_filters( 'autoptimize_js_filter_defer_not_aggregate', $options['defer_not_aggregate'] ) ) {
247
+ $this->defer_not_aggregate = true;
248
+ }
249
 
250
  // include inline?
251
  if ( apply_filters( 'autoptimize_js_include_inline', $options['include_inline'] ) ) {
348
  }
349
  }
350
  }
351
+
352
+ // not aggregating but deferring?
353
+ if ( $this->defer_not_aggregate && false === $this->aggregate && str_replace( $this->dontmove, '', $path ) === $path && strpos( $new_tag, ' defer' ) === false ) {
354
+ $new_tag = str_replace( '<script ', '<script defer ', $new_tag );
355
+ // and remove async as async+defer=async while we explicitly want defer.
356
+ if ( strpos( $new_tag, ' async' ) !== false && apply_filters( 'autoptimize_filter_js_defer_remove_async', true ) ) {
357
+ $new_tag = str_replace( array( ' async', ' async="async"', " async='async'" ), '', $new_tag );
358
+ }
359
+ }
360
 
361
  // Should we minify the non-aggregated script?
362
  // -> if aggregate is on and exclude minify is on
classes/autoptimizeVersionUpdatesHandler.php CHANGED
@@ -53,6 +53,10 @@ class autoptimizeVersionUpdatesHandler
53
  $this->upgrade_from_2_4();
54
  $major_update = false;
55
  // No break, intentionally, so all upgrades are ran during a single request...
 
 
 
 
56
  }
57
 
58
  if ( true === $major_update ) {
@@ -249,4 +253,16 @@ class autoptimizeVersionUpdatesHandler
249
  autoptimizeOptionWrapper::update_option( 'autoptimize_imgopt_settings', $imgopt_settings );
250
  }
251
  }
 
 
 
 
 
 
 
 
 
 
 
 
252
  }
53
  $this->upgrade_from_2_4();
54
  $major_update = false;
55
  // No break, intentionally, so all upgrades are ran during a single request...
56
+ case '2.7':
57
+ $this->upgrade_from_2_7();
58
+ $major_update = true;
59
+ // No break, intentionally, so all upgrades are ran during a single request...
60
  }
61
 
62
  if ( true === $major_update ) {
253
  autoptimizeOptionWrapper::update_option( 'autoptimize_imgopt_settings', $imgopt_settings );
254
  }
255
  }
256
+
257
+ /**
258
+ * remove CCSS request limit option + update jquery exclusion to include WordPress 5.6 jquery.min.js.
259
+ */
260
+ private function upgrade_from_2_7() {
261
+ delete_option( 'autoptimize_ccss_rlimit' );
262
+ $js_exclusions = get_option( 'autoptimize_js_exclude', '' );
263
+ if ( strpos( $js_exclusions, 'js/jquery/jquery.js' ) !== false && strpos( $js_exclusions, 'js/jquery/jquery.min.js' ) === false ) {
264
+ $js_exclusions .= ', js/jquery/jquery.min.js';
265
+ update_option( 'autoptimize_js_exclude', $js_exclusions );
266
+ }
267
+ }
268
  }
classes/critcss-inc/admin_settings_adv.php CHANGED
@@ -10,7 +10,7 @@ function ao_ccss_render_adv() {
10
  // Attach required globals.
11
  global $ao_ccss_debug;
12
  global $ao_ccss_finclude;
13
- global $ao_ccss_rlimit;
14
  global $ao_ccss_noptimize;
15
  global $ao_ccss_loggedin;
16
  global $ao_ccss_forcepath;
@@ -59,12 +59,12 @@ function ao_ccss_render_adv() {
59
  </tr>
60
  <tr>
61
  <th scope="row">
62
- <?php _e( 'Request Limit', 'autoptimize' ); ?>
63
  </th>
64
  <td>
65
- <input type="number" id="autoptimize_ccss_rlimit" name="autoptimize_ccss_rlimit" min="1" max="240" placeholder="0" value="<?php echo $ao_ccss_rlimit; ?>" />
66
  <p class="notes">
67
- <?php _e( 'Certain hosting services impose hard limitations to background processes on either execution time, requests made from your server to any third party services, or both. This could lead to a faulty operation of the queue background process triggered by WP-Cron. If automated rules are not being created, you may be facing this limitation from your hosting provider. In that case, set the request limit to a reasonable number between 1 and 240. The queue fire a request to <a href="https://criticalcss.com/account/api-keys?aff=1" target="_blank">criticalcss.com</a> on every 15 seconds (due to service limitations). If your hosting provider allows a 60 seconds time span to background processes runtime, set this value to 3 or 4 so the queue can operate within the boundaries. The maximum value of 240 allows enough requests for one hour long. To disable this limit and to let requests be made at will, just delete any values in this setting (a grey 0 will show).', 'autoptimize' ); ?>
68
  </p>
69
  </td>
70
  </tr>
10
  // Attach required globals.
11
  global $ao_ccss_debug;
12
  global $ao_ccss_finclude;
13
+ global $ao_ccss_rtimelimit;
14
  global $ao_ccss_noptimize;
15
  global $ao_ccss_loggedin;
16
  global $ao_ccss_forcepath;
59
  </tr>
60
  <tr>
61
  <th scope="row">
62
+ <?php _e( 'Queue processing time limit', 'autoptimize' ); ?>
63
  </th>
64
  <td>
65
+ <input type="number" id="autoptimize_ccss_rtimelimit" name="autoptimize_ccss_rtimelimit" min="0" max="240" placeholder="0" value="<?php echo $ao_ccss_rtimelimit; ?>" />
66
  <p class="notes">
67
+ <?php _e( 'The cronned queue processing is an asynchronous process triggerd by (WordPress) cron. To avoid this process from running too long and potentially getting killed, you can set the number of seconds here, 0 means no limit.', 'autoptimize' ); ?>
68
  </p>
69
  </td>
70
  </tr>
classes/external/js/lazysizes.min.js CHANGED
@@ -1,3 +1,3 @@
1
  /*! lazysizes + ls unveilhooks - v5.2.2 (incl. ls-uvh data-link fix) */
2
  !function(e){var t=function(u,D,f){"use strict";var k,H;if(function(){var e;var t={lazyClass:"lazyload",loadedClass:"lazyloaded",loadingClass:"lazyloading",preloadClass:"lazypreload",errorClass:"lazyerror",autosizesClass:"lazyautosizes",srcAttr:"data-src",srcsetAttr:"data-srcset",sizesAttr:"data-sizes",minSize:40,customMedia:{},init:true,expFactor:1.5,hFac:.8,loadMode:2,loadHidden:true,ricTimeout:0,throttleDelay:125};H=u.lazySizesConfig||u.lazysizesConfig||{};for(e in t){if(!(e in H)){H[e]=t[e]}}}(),!D||!D.getElementsByClassName){return{init:function(){},cfg:H,noSupport:true}}var O=D.documentElement,a=u.HTMLPictureElement,P="addEventListener",$="getAttribute",q=u[P].bind(u),I=u.setTimeout,U=u.requestAnimationFrame||I,l=u.requestIdleCallback,j=/^picture$/i,r=["load","error","lazyincluded","_lazyloaded"],i={},G=Array.prototype.forEach,J=function(e,t){if(!i[t]){i[t]=new RegExp("(\\s|^)"+t+"(\\s|$)")}return i[t].test(e[$]("class")||"")&&i[t]},K=function(e,t){if(!J(e,t)){e.setAttribute("class",(e[$]("class")||"").trim()+" "+t)}},Q=function(e,t){var i;if(i=J(e,t)){e.setAttribute("class",(e[$]("class")||"").replace(i," "))}},V=function(t,i,e){var a=e?P:"removeEventListener";if(e){V(t,i)}r.forEach(function(e){t[a](e,i)})},X=function(e,t,i,a,r){var n=D.createEvent("Event");if(!i){i={}}i.instance=k;n.initEvent(t,!a,!r);n.detail=i;e.dispatchEvent(n);return n},Y=function(e,t){var i;if(!a&&(i=u.picturefill||H.pf)){if(t&&t.src&&!e[$]("srcset")){e.setAttribute("srcset",t.src)}i({reevaluate:true,elements:[e]})}else if(t&&t.src){e.src=t.src}},Z=function(e,t){return(getComputedStyle(e,null)||{})[t]},s=function(e,t,i){i=i||e.offsetWidth;while(i<H.minSize&&t&&!e._lazysizesWidth){i=t.offsetWidth;t=t.parentNode}return i},ee=function(){var i,a;var t=[];var r=[];var n=t;var s=function(){var e=n;n=t.length?r:t;i=true;a=false;while(e.length){e.shift()()}i=false};var e=function(e,t){if(i&&!t){e.apply(this,arguments)}else{n.push(e);if(!a){a=true;(D.hidden?I:U)(s)}}};e._lsFlush=s;return e}(),te=function(i,e){return e?function(){ee(i)}:function(){var e=this;var t=arguments;ee(function(){i.apply(e,t)})}},ie=function(e){var i;var a=0;var r=H.throttleDelay;var n=H.ricTimeout;var t=function(){i=false;a=f.now();e()};var s=l&&n>49?function(){l(t,{timeout:n});if(n!==H.ricTimeout){n=H.ricTimeout}}:te(function(){I(t)},true);return function(e){var t;if(e=e===true){n=33}if(i){return}i=true;t=r-(f.now()-a);if(t<0){t=0}if(e||t<9){s()}else{I(s,t)}}},ae=function(e){var t,i;var a=99;var r=function(){t=null;e()};var n=function(){var e=f.now()-i;if(e<a){I(n,a-e)}else{(l||r)(r)}};return function(){i=f.now();if(!t){t=I(n,a)}}},e=function(){var v,m,c,h,e;var y,z,g,p,C,b,A;var n=/^img$/i;var d=/^iframe$/i;var E="onscroll"in u&&!/(gle|ing)bot/.test(navigator.userAgent);var _=0;var w=0;var N=0;var M=-1;var x=function(e){N--;if(!e||N<0||!e.target){N=0}};var W=function(e){if(A==null){A=Z(D.body,"visibility")=="hidden"}return A||!(Z(e.parentNode,"visibility")=="hidden"&&Z(e,"visibility")=="hidden")};var S=function(e,t){var i;var a=e;var r=W(e);g-=t;b+=t;p-=t;C+=t;while(r&&(a=a.offsetParent)&&a!=D.body&&a!=O){r=(Z(a,"opacity")||1)>0;if(r&&Z(a,"overflow")!="visible"){i=a.getBoundingClientRect();r=C>i.left&&p<i.right&&b>i.top-1&&g<i.bottom+1}}return r};var t=function(){var e,t,i,a,r,n,s,l,o,u,f,c;var d=k.elements;if((h=H.loadMode)&&N<8&&(e=d.length)){t=0;M++;for(;t<e;t++){if(!d[t]||d[t]._lazyRace){continue}if(!E||k.prematureUnveil&&k.prematureUnveil(d[t])){R(d[t]);continue}if(!(l=d[t][$]("data-expand"))||!(n=l*1)){n=w}if(!u){u=!H.expand||H.expand<1?O.clientHeight>500&&O.clientWidth>500?500:370:H.expand;k._defEx=u;f=u*H.expFactor;c=H.hFac;A=null;if(w<f&&N<1&&M>2&&h>2&&!D.hidden){w=f;M=0}else if(h>1&&M>1&&N<6){w=u}else{w=_}}if(o!==n){y=innerWidth+n*c;z=innerHeight+n;s=n*-1;o=n}i=d[t].getBoundingClientRect();if((b=i.bottom)>=s&&(g=i.top)<=z&&(C=i.right)>=s*c&&(p=i.left)<=y&&(b||C||p||g)&&(H.loadHidden||W(d[t]))&&(m&&N<3&&!l&&(h<3||M<4)||S(d[t],n))){R(d[t]);r=true;if(N>9){break}}else if(!r&&m&&!a&&N<4&&M<4&&h>2&&(v[0]||H.preloadAfterLoad)&&(v[0]||!l&&(b||C||p||g||d[t][$](H.sizesAttr)!="auto"))){a=v[0]||d[t]}}if(a&&!r){R(a)}}};var i=ie(t);var B=function(e){var t=e.target;if(t._lazyCache){delete t._lazyCache;return}x(e);K(t,H.loadedClass);Q(t,H.loadingClass);V(t,L);X(t,"lazyloaded")};var a=te(B);var L=function(e){a({target:e.target})};var T=function(t,i){try{t.contentWindow.location.replace(i)}catch(e){t.src=i}};var F=function(e){var t;var i=e[$](H.srcsetAttr);if(t=H.customMedia[e[$]("data-media")||e[$]("media")]){e.setAttribute("media",t)}if(i){e.setAttribute("srcset",i)}};var s=te(function(t,e,i,a,r){var n,s,l,o,u,f;if(!(u=X(t,"lazybeforeunveil",e)).defaultPrevented){if(a){if(i){K(t,H.autosizesClass)}else{t.setAttribute("sizes",a)}}s=t[$](H.srcsetAttr);n=t[$](H.srcAttr);if(r){l=t.parentNode;o=l&&j.test(l.nodeName||"")}f=e.firesLoad||"src"in t&&(s||n||o);u={target:t};K(t,H.loadingClass);if(f){clearTimeout(c);c=I(x,2500);V(t,L,true)}if(o){G.call(l.getElementsByTagName("source"),F)}if(s){t.setAttribute("srcset",s)}else if(n&&!o){if(d.test(t.nodeName)){T(t,n)}else{t.src=n}}if(r&&(s||o)){Y(t,{src:n})}}if(t._lazyRace){delete t._lazyRace}Q(t,H.lazyClass);ee(function(){var e=t.complete&&t.naturalWidth>1;if(!f||e){if(e){K(t,"ls-is-cached")}B(u);t._lazyCache=true;I(function(){if("_lazyCache"in t){delete t._lazyCache}},9)}if(t.loading=="lazy"){N--}},true)});var R=function(e){if(e._lazyRace){return}var t;var i=n.test(e.nodeName);var a=i&&(e[$](H.sizesAttr)||e[$]("sizes"));var r=a=="auto";if((r||!m)&&i&&(e[$]("src")||e.srcset)&&!e.complete&&!J(e,H.errorClass)&&J(e,H.lazyClass)){return}t=X(e,"lazyunveilread").detail;if(r){re.updateElem(e,true,e.offsetWidth)}e._lazyRace=true;N++;s(e,t,r,a,i)};var r=ae(function(){H.loadMode=3;i()});var l=function(){if(H.loadMode==3){H.loadMode=2}r()};var o=function(){if(m){return}if(f.now()-e<999){I(o,999);return}m=true;H.loadMode=3;i();q("scroll",l,true)};return{_:function(){e=f.now();k.elements=D.getElementsByClassName(H.lazyClass);v=D.getElementsByClassName(H.lazyClass+" "+H.preloadClass);q("scroll",i,true);q("resize",i,true);q("pageshow",function(e){if(e.persisted){var t=D.querySelectorAll("."+H.loadingClass);if(t.length&&t.forEach){U(function(){t.forEach(function(e){if(e.complete){R(e)}})})}}});if(u.MutationObserver){new MutationObserver(i).observe(O,{childList:true,subtree:true,attributes:true})}else{O[P]("DOMNodeInserted",i,true);O[P]("DOMAttrModified",i,true);setInterval(i,999)}q("hashchange",i,true);["focus","mouseover","click","load","transitionend","animationend"].forEach(function(e){D[P](e,i,true)});if(/d$|^c/.test(D.readyState)){o()}else{q("load",o);D[P]("DOMContentLoaded",i);I(o,2e4)}if(k.elements.length){t();ee._lsFlush()}else{i()}},checkElems:i,unveil:R,_aLSL:l}}(),re=function(){var i;var n=te(function(e,t,i,a){var r,n,s;e._lazysizesWidth=a;a+="px";e.setAttribute("sizes",a);if(j.test(t.nodeName||"")){r=t.getElementsByTagName("source");for(n=0,s=r.length;n<s;n++){r[n].setAttribute("sizes",a)}}if(!i.detail.dataAttr){Y(e,i.detail)}});var a=function(e,t,i){var a;var r=e.parentNode;if(r){i=s(e,r,i);a=X(e,"lazybeforesizes",{width:i,dataAttr:!!t});if(!a.defaultPrevented){i=a.detail.width;if(i&&i!==e._lazysizesWidth){n(e,r,a,i)}}}};var e=function(){var e;var t=i.length;if(t){e=0;for(;e<t;e++){a(i[e])}}};var t=ae(e);return{_:function(){i=D.getElementsByClassName(H.autosizesClass);q("resize",t)},checkElems:t,updateElem:a}}(),t=function(){if(!t.i&&D.getElementsByClassName){t.i=true;re._();e._()}};return I(function(){H.init&&t()}),k={cfg:H,autoSizer:re,loader:e,init:t,uP:Y,aC:K,rC:Q,hC:J,fire:X,gW:s,rAF:ee}}(e,e.document,Date);e.lazySizes=t,"object"==typeof module&&module.exports&&(module.exports=t)}("undefined"!=typeof window?window:{});
3
- !function(e,t){var a=function(){t(e.lazySizes),e.removeEventListener("lazyunveilread",a,!0)};t=t.bind(null,e,e.document),"object"==typeof module&&module.exports?t(require("lazysizes")):"function"==typeof define&&define.amd?define(["lazysizes"],t):e.lazySizes?a():e.addEventListener("lazyunveilread",a,!0)}(window,function(e,n,i){"use strict";var l,o,d={};function u(e,t){var a,r;d[e]||(a=n.createElement(t?"link":"script"),r=n.getElementsByTagName("script")[0],t?(a.rel="stylesheet",a.href=e):a.src=e,d[e]=!0,d[a.src||a.href]=!0,r.parentNode.insertBefore(a,r))}n.addEventListener&&(l=function(e,t){var a=n.createElement("img");a.onload=function(){a.onload=null,a.onerror=null,a=null,t()},a.onerror=a.onload,a.src=e,a&&a.complete&&a.onload&&a.onload()},addEventListener("lazybeforeunveil",function(e){var t,a,r;if(e.detail.instance==i&&!e.defaultPrevented){var n=e.target;if("none"==n.preload&&(n.preload=n.getAttribute("data-preload")||"auto"),null!=n.getAttribute("data-autoplay"))if(n.getAttribute("data-expand")&&!n.autoplay)try{n.play()}catch(e){}else requestAnimationFrame(function(){n.setAttribute("data-expand","-10"),i.aC(n,i.cfg.lazyClass)});(t=n.getAttribute("data-link")),t&&"img"!=n.tagName.toLowerCase&&u(t,!0),(t=n.getAttribute("data-script"))&&u(t),(t=n.getAttribute("data-require"))&&(i.cfg.requireJs?i.cfg.requireJs([t]):u(t)),(a=n.getAttribute("data-bg"))&&(e.detail.firesLoad=!0,l(a,function(){n.style.backgroundImage="url("+(o.test(a)?JSON.stringify(a):a)+")",e.detail.firesLoad=!1,i.fire(n,"_lazyloaded",{},!0,!0)})),(r=n.getAttribute("data-poster"))&&(e.detail.firesLoad=!0,l(r,function(){n.poster=r,e.detail.firesLoad=!1,i.fire(n,"_lazyloaded",{},!0,!0)}))}},!(o=/\(|\)|\s|'/)))});
1
  /*! lazysizes + ls unveilhooks - v5.2.2 (incl. ls-uvh data-link fix) */
2
  !function(e){var t=function(u,D,f){"use strict";var k,H;if(function(){var e;var t={lazyClass:"lazyload",loadedClass:"lazyloaded",loadingClass:"lazyloading",preloadClass:"lazypreload",errorClass:"lazyerror",autosizesClass:"lazyautosizes",srcAttr:"data-src",srcsetAttr:"data-srcset",sizesAttr:"data-sizes",minSize:40,customMedia:{},init:true,expFactor:1.5,hFac:.8,loadMode:2,loadHidden:true,ricTimeout:0,throttleDelay:125};H=u.lazySizesConfig||u.lazysizesConfig||{};for(e in t){if(!(e in H)){H[e]=t[e]}}}(),!D||!D.getElementsByClassName){return{init:function(){},cfg:H,noSupport:true}}var O=D.documentElement,a=u.HTMLPictureElement,P="addEventListener",$="getAttribute",q=u[P].bind(u),I=u.setTimeout,U=u.requestAnimationFrame||I,l=u.requestIdleCallback,j=/^picture$/i,r=["load","error","lazyincluded","_lazyloaded"],i={},G=Array.prototype.forEach,J=function(e,t){if(!i[t]){i[t]=new RegExp("(\\s|^)"+t+"(\\s|$)")}return i[t].test(e[$]("class")||"")&&i[t]},K=function(e,t){if(!J(e,t)){e.setAttribute("class",(e[$]("class")||"").trim()+" "+t)}},Q=function(e,t){var i;if(i=J(e,t)){e.setAttribute("class",(e[$]("class")||"").replace(i," "))}},V=function(t,i,e){var a=e?P:"removeEventListener";if(e){V(t,i)}r.forEach(function(e){t[a](e,i)})},X=function(e,t,i,a,r){var n=D.createEvent("Event");if(!i){i={}}i.instance=k;n.initEvent(t,!a,!r);n.detail=i;e.dispatchEvent(n);return n},Y=function(e,t){var i;if(!a&&(i=u.picturefill||H.pf)){if(t&&t.src&&!e[$]("srcset")){e.setAttribute("srcset",t.src)}i({reevaluate:true,elements:[e]})}else if(t&&t.src){e.src=t.src}},Z=function(e,t){return(getComputedStyle(e,null)||{})[t]},s=function(e,t,i){i=i||e.offsetWidth;while(i<H.minSize&&t&&!e._lazysizesWidth){i=t.offsetWidth;t=t.parentNode}return i},ee=function(){var i,a;var t=[];var r=[];var n=t;var s=function(){var e=n;n=t.length?r:t;i=true;a=false;while(e.length){e.shift()()}i=false};var e=function(e,t){if(i&&!t){e.apply(this,arguments)}else{n.push(e);if(!a){a=true;(D.hidden?I:U)(s)}}};e._lsFlush=s;return e}(),te=function(i,e){return e?function(){ee(i)}:function(){var e=this;var t=arguments;ee(function(){i.apply(e,t)})}},ie=function(e){var i;var a=0;var r=H.throttleDelay;var n=H.ricTimeout;var t=function(){i=false;a=f.now();e()};var s=l&&n>49?function(){l(t,{timeout:n});if(n!==H.ricTimeout){n=H.ricTimeout}}:te(function(){I(t)},true);return function(e){var t;if(e=e===true){n=33}if(i){return}i=true;t=r-(f.now()-a);if(t<0){t=0}if(e||t<9){s()}else{I(s,t)}}},ae=function(e){var t,i;var a=99;var r=function(){t=null;e()};var n=function(){var e=f.now()-i;if(e<a){I(n,a-e)}else{(l||r)(r)}};return function(){i=f.now();if(!t){t=I(n,a)}}},e=function(){var v,m,c,h,e;var y,z,g,p,C,b,A;var n=/^img$/i;var d=/^iframe$/i;var E="onscroll"in u&&!/(gle|ing)bot/.test(navigator.userAgent);var _=0;var w=0;var N=0;var M=-1;var x=function(e){N--;if(!e||N<0||!e.target){N=0}};var W=function(e){if(A==null){A=Z(D.body,"visibility")=="hidden"}return A||!(Z(e.parentNode,"visibility")=="hidden"&&Z(e,"visibility")=="hidden")};var S=function(e,t){var i;var a=e;var r=W(e);g-=t;b+=t;p-=t;C+=t;while(r&&(a=a.offsetParent)&&a!=D.body&&a!=O){r=(Z(a,"opacity")||1)>0;if(r&&Z(a,"overflow")!="visible"){i=a.getBoundingClientRect();r=C>i.left&&p<i.right&&b>i.top-1&&g<i.bottom+1}}return r};var t=function(){var e,t,i,a,r,n,s,l,o,u,f,c;var d=k.elements;if((h=H.loadMode)&&N<8&&(e=d.length)){t=0;M++;for(;t<e;t++){if(!d[t]||d[t]._lazyRace){continue}if(!E||k.prematureUnveil&&k.prematureUnveil(d[t])){R(d[t]);continue}if(!(l=d[t][$]("data-expand"))||!(n=l*1)){n=w}if(!u){u=!H.expand||H.expand<1?O.clientHeight>500&&O.clientWidth>500?500:370:H.expand;k._defEx=u;f=u*H.expFactor;c=H.hFac;A=null;if(w<f&&N<1&&M>2&&h>2&&!D.hidden){w=f;M=0}else if(h>1&&M>1&&N<6){w=u}else{w=_}}if(o!==n){y=innerWidth+n*c;z=innerHeight+n;s=n*-1;o=n}i=d[t].getBoundingClientRect();if((b=i.bottom)>=s&&(g=i.top)<=z&&(C=i.right)>=s*c&&(p=i.left)<=y&&(b||C||p||g)&&(H.loadHidden||W(d[t]))&&(m&&N<3&&!l&&(h<3||M<4)||S(d[t],n))){R(d[t]);r=true;if(N>9){break}}else if(!r&&m&&!a&&N<4&&M<4&&h>2&&(v[0]||H.preloadAfterLoad)&&(v[0]||!l&&(b||C||p||g||d[t][$](H.sizesAttr)!="auto"))){a=v[0]||d[t]}}if(a&&!r){R(a)}}};var i=ie(t);var B=function(e){var t=e.target;if(t._lazyCache){delete t._lazyCache;return}x(e);K(t,H.loadedClass);Q(t,H.loadingClass);V(t,L);X(t,"lazyloaded")};var a=te(B);var L=function(e){a({target:e.target})};var T=function(t,i){try{t.contentWindow.location.replace(i)}catch(e){t.src=i}};var F=function(e){var t;var i=e[$](H.srcsetAttr);if(t=H.customMedia[e[$]("data-media")||e[$]("media")]){e.setAttribute("media",t)}if(i){e.setAttribute("srcset",i)}};var s=te(function(t,e,i,a,r){var n,s,l,o,u,f;if(!(u=X(t,"lazybeforeunveil",e)).defaultPrevented){if(a){if(i){K(t,H.autosizesClass)}else{t.setAttribute("sizes",a)}}s=t[$](H.srcsetAttr);n=t[$](H.srcAttr);if(r){l=t.parentNode;o=l&&j.test(l.nodeName||"")}f=e.firesLoad||"src"in t&&(s||n||o);u={target:t};K(t,H.loadingClass);if(f){clearTimeout(c);c=I(x,2500);V(t,L,true)}if(o){G.call(l.getElementsByTagName("source"),F)}if(s){t.setAttribute("srcset",s)}else if(n&&!o){if(d.test(t.nodeName)){T(t,n)}else{t.src=n}}if(r&&(s||o)){Y(t,{src:n})}}if(t._lazyRace){delete t._lazyRace}Q(t,H.lazyClass);ee(function(){var e=t.complete&&t.naturalWidth>1;if(!f||e){if(e){K(t,"ls-is-cached")}B(u);t._lazyCache=true;I(function(){if("_lazyCache"in t){delete t._lazyCache}},9)}if(t.loading=="lazy"){N--}},true)});var R=function(e){if(e._lazyRace){return}var t;var i=n.test(e.nodeName);var a=i&&(e[$](H.sizesAttr)||e[$]("sizes"));var r=a=="auto";if((r||!m)&&i&&(e[$]("src")||e.srcset)&&!e.complete&&!J(e,H.errorClass)&&J(e,H.lazyClass)){return}t=X(e,"lazyunveilread").detail;if(r){re.updateElem(e,true,e.offsetWidth)}e._lazyRace=true;N++;s(e,t,r,a,i)};var r=ae(function(){H.loadMode=3;i()});var l=function(){if(H.loadMode==3){H.loadMode=2}r()};var o=function(){if(m){return}if(f.now()-e<999){I(o,999);return}m=true;H.loadMode=3;i();q("scroll",l,true)};return{_:function(){e=f.now();k.elements=D.getElementsByClassName(H.lazyClass);v=D.getElementsByClassName(H.lazyClass+" "+H.preloadClass);q("scroll",i,true);q("resize",i,true);q("pageshow",function(e){if(e.persisted){var t=D.querySelectorAll("."+H.loadingClass);if(t.length&&t.forEach){U(function(){t.forEach(function(e){if(e.complete){R(e)}})})}}});if(u.MutationObserver){new MutationObserver(i).observe(O,{childList:true,subtree:true,attributes:true})}else{O[P]("DOMNodeInserted",i,true);O[P]("DOMAttrModified",i,true);setInterval(i,999)}q("hashchange",i,true);["focus","mouseover","click","load","transitionend","animationend"].forEach(function(e){D[P](e,i,true)});if(/d$|^c/.test(D.readyState)){o()}else{q("load",o);D[P]("DOMContentLoaded",i);I(o,2e4)}if(k.elements.length){t();ee._lsFlush()}else{i()}},checkElems:i,unveil:R,_aLSL:l}}(),re=function(){var i;var n=te(function(e,t,i,a){var r,n,s;e._lazysizesWidth=a;a+="px";e.setAttribute("sizes",a);if(j.test(t.nodeName||"")){r=t.getElementsByTagName("source");for(n=0,s=r.length;n<s;n++){r[n].setAttribute("sizes",a)}}if(!i.detail.dataAttr){Y(e,i.detail)}});var a=function(e,t,i){var a;var r=e.parentNode;if(r){i=s(e,r,i);a=X(e,"lazybeforesizes",{width:i,dataAttr:!!t});if(!a.defaultPrevented){i=a.detail.width;if(i&&i!==e._lazysizesWidth){n(e,r,a,i)}}}};var e=function(){var e;var t=i.length;if(t){e=0;for(;e<t;e++){a(i[e])}}};var t=ae(e);return{_:function(){i=D.getElementsByClassName(H.autosizesClass);q("resize",t)},checkElems:t,updateElem:a}}(),t=function(){if(!t.i&&D.getElementsByClassName){t.i=true;re._();e._()}};return I(function(){H.init&&t()}),k={cfg:H,autoSizer:re,loader:e,init:t,uP:Y,aC:K,rC:Q,hC:J,fire:X,gW:s,rAF:ee}}(e,e.document,Date);e.lazySizes=t,"object"==typeof module&&module.exports&&(module.exports=t)}("undefined"!=typeof window?window:{});
3
+ !function(e,t){var a=function(){t(e.lazySizes),e.removeEventListener("lazyunveilread",a,!0)};t=t.bind(null,e,e.document),"object"==typeof module&&module.exports?t(require("lazysizes")):"function"==typeof define&&define.amd?define(["lazysizes"],t):e.lazySizes?a():e.addEventListener("lazyunveilread",a,!0)}(window,function(e,n,i){"use strict";var l,o,d={};function u(e,t){var a,r;d[e]||(a=n.createElement(t?"link":"script"),r=n.getElementsByTagName("script")[0],t?(a.rel="stylesheet",a.href=e):a.src=e,d[e]=!0,d[a.src||a.href]=!0,r.parentNode.insertBefore(a,r))}n.addEventListener&&(l=function(e,t){var a=n.createElement("img");a.onload=function(){a.onload=null,a.onerror=null,a=null,t()},a.onerror=a.onload,a.src=e,a&&a.complete&&a.onload&&a.onload()},addEventListener("lazybeforeunveil",function(e){var t,a,r;if(e.detail.instance==i&&!e.defaultPrevented){var n=e.target;if("none"==n.preload&&(n.preload=n.getAttribute("data-preload")||"auto"),null!=n.getAttribute("data-autoplay"))if(n.getAttribute("data-expand")&&!n.autoplay)try{n.play()}catch(e){}else requestAnimationFrame(function(){n.setAttribute("data-expand","-10"),i.aC(n,i.cfg.lazyClass)});(t=n.getAttribute("data-link"))&&"img"!=n.tagName.toLowerCase()&&u(t,!0),(t=n.getAttribute("data-script"))&&u(t),(t=n.getAttribute("data-require"))&&(i.cfg.requireJs?i.cfg.requireJs([t]):u(t)),(a=n.getAttribute("data-bg"))&&(e.detail.firesLoad=!0,l(a,function(){n.style.backgroundImage="url("+(o.test(a)?JSON.stringify(a):a)+")",e.detail.firesLoad=!1,i.fire(n,"_lazyloaded",{},!0,!0)})),(r=n.getAttribute("data-poster"))&&(e.detail.firesLoad=!0,l(r,function(){n.poster=r,e.detail.firesLoad=!1,i.fire(n,"_lazyloaded",{},!0,!0)}))}},!(o=/\(|\)|\s|'/)))});
readme.txt CHANGED
@@ -3,9 +3,9 @@ Contributors: futtta, optimizingmatters, zytzagoo, turl
3
  Tags: optimize, minify, performance, pagespeed, images, lazy-load, 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.5
7
  Requires PHP: 5.6
8
- Stable tag: 2.7.8
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
 
@@ -114,7 +114,7 @@ If you want your uploaded images to be on the CDN as well, you can change the up
114
 
115
  Autoptimize supports this, but it is not enabled by default because [non-local fonts might require some extra configuration](http://davidwalsh.name/cdn-fonts). But if you have your cross-origin request policy in order, you can tell Autoptimize to put your fonts on the CDN by hooking into the API, setting `autoptimize_filter_css_fonts_cdn` to `true` this way;
116
 
117
- `add_filter('autoptimize_filter_css_fonts_cdn',__return_true);`
118
 
119
  = I'm using Cloudflare, what should I enter as CDN root directory =
120
 
@@ -319,6 +319,16 @@ Just [fork Autoptimize on Github](https://github.com/futtta/autoptimize) and cod
319
 
320
  == Changelog ==
321
 
 
 
 
 
 
 
 
 
 
 
322
  = 2.7.8 =
323
  * Image optimization: add support for AVIF image format for browsers that support it (enabled with the existing WebP-option, also requires lazy-load to be active)
324
  * Critical CSS: further security improvements of critical CSS import settings upload, based on the input of [Marcin Weglowski of afine.com](https://afine.com)
@@ -379,41 +389,5 @@ Just [fork Autoptimize on Github](https://github.com/futtta/autoptimize) and cod
379
  * New option to ensure missing autoptimized files are served with fallback JS/ CSS.
380
  * Batch of misc. smaller improvements & fixes, more info in the [GitHub commit log](https://github.com/futtta/autoptimize/commits/beta).
381
 
382
- = 2.6.2 =
383
- * auto-exclude images from lazyload when they have `loading="eager"` attribute.
384
- * bugfix: don't take querystring into account when deciding as-value for preloaded resources.
385
- * bugfix; ensure lqip images (used when both image optimization and lazyload are active) always work by normalizing the URL before sending it to shortpixel.
386
- * minimum WordPress version bumped to 4.4.
387
-
388
- = 2.6.1 =
389
- * bugfixes for multiple lazyload bugs causing images not to load or load incorrectly
390
- * bugfixes for multiple multisite bugs causing settings-screen to be unavailable
391
- * bugfix re-added 3rd parameter to `autoptimize_filter_js_minify_excluded`-filter to ensure backwards-compatibility and thus avoid breaking Smart Cookie Kit which expected that 3rd parameter.
392
-
393
- = 2.6.0 =
394
- * New: Autoptimize can be configured at network level or at individual site-level when on multisite.
395
- * Extra: new option to specify what resources need to be preloaded.
396
- * Extra: add `display=swap` to Autoptimized (CSS-based) Google Fonts.
397
- * Images: support for lazyloading of background-images when set in the inline style attribute of a div.
398
- * Images: updated to lazysizes 5.2.
399
- * CSS/ JS: no longer add type attributes to Autoptimized resources.
400
- * Improvement: cache clearing now also integrates with Kinsta, WP-Optimize & Nginx helper.
401
- * Added "Critical CSS" tab to highlight the criticalcss.com integration, which will be fully included in Autoptimize 2.7.
402
- * Batch of misc. smaller improvements & fixes, more info in the [GitHub commit log](https://github.com/futtta/autoptimize/commits/beta).
403
-
404
- = 2.5.1 =
405
- * Images: Also optimize & lazyload &lt;picture>&lt;source>
406
- * Images: Misc. improvements to lazyload
407
- * Images: Updated to LazySizes 5.0.0
408
- * CSS: improvements to the deferring logic for non-aggregated CSS resources.
409
- * Settings-page: Show "JS, CSS & HTML" advanced options by default (many people did not see the button)
410
-
411
- = 2.5.0 =
412
- * moved image optimization to a separate tab and move all code to a separate file.
413
- * added lazyloading (using lazysizes)
414
- * added webp support (requires image optimization and lazyloading to be active)
415
- * added option to enable/ disable the minification of excluded JS/ CSS files (on by default)
416
- * misc. bugfixes and smaller improvements
417
-
418
  = older =
419
  * see [https://plugins.svn.wordpress.org/autoptimize/tags/2.7.2/readme.txt](https://plugins.svn.wordpress.org/autoptimize/tags/2.7.2/readme.txt)
3
  Tags: optimize, minify, performance, pagespeed, images, lazy-load, 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.6
7
  Requires PHP: 5.6
8
+ Stable tag: 2.8.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
 
114
 
115
  Autoptimize supports this, but it is not enabled by default because [non-local fonts might require some extra configuration](http://davidwalsh.name/cdn-fonts). But if you have your cross-origin request policy in order, you can tell Autoptimize to put your fonts on the CDN by hooking into the API, setting `autoptimize_filter_css_fonts_cdn` to `true` this way;
116
 
117
+ `add_filter( 'autoptimize_filter_css_fonts_cdn', '__return_true' );`
118
 
119
  = I'm using Cloudflare, what should I enter as CDN root directory =
120
 
319
 
320
  == Changelog ==
321
 
322
+ = 2.8.0 =
323
+ * JavaScript: new option "defer but don't aggregate"
324
+ * JavaScript: ensure Autoptimize also acts on jQuery in WordPress 5.6 which is renamed to jquery.min.js from jquery.js before.
325
+ * Images: add field to exclude images from being optimized.
326
+ * Images: new filter (`autoptimize_filter_imgopt_lazyload_from_nth`) to tell AO not to lazyload the first X images (to improve LCP/ CLS).
327
+ * Critical CSS: major improvements of the job processing mechanism, reducing time spent from up to 1 minute to just a couple of seconds.
328
+ * Critical CSS: under "advanced options" replace "request limit" with "queue processing time limit" (default 30s).
329
+ * Extra | Google Fonts: better parsing of version 2 Google Font URL's (/css2/).
330
+ * Misc. other minor fixes, see the [GitHub commit log](https://github.com/futtta/autoptimize/commits/beta).
331
+
332
  = 2.7.8 =
333
  * Image optimization: add support for AVIF image format for browsers that support it (enabled with the existing WebP-option, also requires lazy-load to be active)
334
  * Critical CSS: further security improvements of critical CSS import settings upload, based on the input of [Marcin Weglowski of afine.com](https://afine.com)
389
  * New option to ensure missing autoptimized files are served with fallback JS/ CSS.
390
  * Batch of misc. smaller improvements & fixes, more info in the [GitHub commit log](https://github.com/futtta/autoptimize/commits/beta).
391
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
392
  = older =
393
  * see [https://plugins.svn.wordpress.org/autoptimize/tags/2.7.2/readme.txt](https://plugins.svn.wordpress.org/autoptimize/tags/2.7.2/readme.txt)