Autoptimize - Version 3.1.3

Version Description

  • Multiple fixes for metabox LCP image preloads (thanks Kishorchand for notifying & providing a staging environment to debug on).
  • Fix in revslider compatibility (hat tip Waqar Ahmed for reporting & helping out ).
  • No image optimization or criticalcss attempts on localhost installations any more + notification of that fact if localhost detected.
  • Some other minor changes/ improvements/ filters, see the GitHub commit log.
Download this release

Release Info

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

Code changes from version 3.1.2 to 3.1.3

autoptimize.php CHANGED
@@ -1,11 +1,11 @@
1
  <?php
2
  /**
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: 3.1.2
7
  * Author: Frank Goossens (futtta)
8
- * Author URI: https://autoptimize.com/
9
  * Text Domain: autoptimize
10
  * License: GPLv2
11
  * Released under the GNU General Public License (GPL)
@@ -21,7 +21,7 @@ if ( ! defined( 'ABSPATH' ) ) {
21
  exit;
22
  }
23
 
24
- define( 'AUTOPTIMIZE_PLUGIN_VERSION', '3.1.2' );
25
 
26
  // plugin_dir_path() returns the trailing slash!
27
  define( 'AUTOPTIMIZE_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
1
  <?php
2
  /**
3
  * Plugin Name: Autoptimize
4
+ * Plugin URI: https://autoptimize.com/pro/
5
  * Description: Makes your site faster by optimizing CSS, JS, Images, Google fonts and more.
6
+ * Version: 3.1.3
7
  * Author: Frank Goossens (futtta)
8
+ * Author URI: https://autoptimize.com/pro/
9
  * Text Domain: autoptimize
10
  * License: GPLv2
11
  * Released under the GNU General Public License (GPL)
21
  exit;
22
  }
23
 
24
+ define( 'AUTOPTIMIZE_PLUGIN_VERSION', '3.1.3' );
25
 
26
  // plugin_dir_path() returns the trailing slash!
27
  define( 'AUTOPTIMIZE_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
classes/autoptimizeCompatibility.php CHANGED
@@ -36,7 +36,7 @@ class autoptimizeCompatibility
36
  'autoptimize_filter_js_exclude',
37
  function( $js_excl = '', $html = '' ) {
38
  $revslider_excl = 'revslider, setREVStartSize, window.RSIW, window.RS_MODULES, jquery.min.js';
39
- if ( ! empty( $html ) && false !== strpos( $html, '<rs-slides>' ) ) {
40
  if ( is_array( $js_excl ) ) {
41
  $js_excl = implode( ',', $js_excl );
42
  }
@@ -55,7 +55,7 @@ class autoptimizeCompatibility
55
  add_filter(
56
  'autoptimize_filter_js_removables',
57
  function( $to_remove = '', $html = '' ) {
58
- if ( ! empty( $html ) && false === strpos( $html, '<rs-slides>' ) ) {
59
  $to_remove .= 'plugins/revslider, setREVStartSize, window.RSIW, window.RS_MODULES';
60
  }
61
 
36
  'autoptimize_filter_js_exclude',
37
  function( $js_excl = '', $html = '' ) {
38
  $revslider_excl = 'revslider, setREVStartSize, window.RSIW, window.RS_MODULES, jquery.min.js';
39
+ if ( ! empty( $html ) && false !== strpos( $html, '<rs-slides' ) ) {
40
  if ( is_array( $js_excl ) ) {
41
  $js_excl = implode( ',', $js_excl );
42
  }
55
  add_filter(
56
  'autoptimize_filter_js_removables',
57
  function( $to_remove = '', $html = '' ) {
58
+ if ( ! empty( $html ) && false === strpos( $html, '<rs-slides' ) ) {
59
  $to_remove .= 'plugins/revslider, setREVStartSize, window.RSIW, window.RS_MODULES';
60
  }
61
 
classes/autoptimizeCriticalCSSCore.php CHANGED
@@ -456,91 +456,97 @@ class autoptimizeCriticalCSSCore {
456
 
457
  // Avoid AO optimizations if required by config or avoid lazyload if lazyload is active in AO.
458
  if ( ! empty( $noptimize ) ) {
459
- $src_url .= '?ao_noptirocket=1';
460
  } elseif ( class_exists( 'autoptimizeImages', false ) && autoptimizeImages::should_lazyload_wrapper() ) {
461
- $src_url .= '?ao_nolazy=1';
462
  }
463
 
464
  $src_url = apply_filters( 'autoptimize_filter_ccss_cron_srcurl', $src_url );
465
 
466
- // Prepare the request.
467
- $url = esc_url_raw( AO_CCSS_API . 'generate' );
468
- $args = array(
469
- 'headers' => apply_filters(
470
- 'autoptimize_ccss_cron_api_generate_headers',
471
- array(
472
- 'User-Agent' => 'Autoptimize v' . AO_CCSS_VER,
473
- 'Content-type' => 'application/json; charset=utf-8',
474
- 'Authorization' => 'JWT ' . $key,
475
- 'Connection' => 'close',
476
- )
477
- ),
478
- // Body must be JSON.
479
- 'body' => json_encode(
480
- apply_filters(
481
- 'autoptimize_ccss_cron_api_generate_body',
482
  array(
483
- 'url' => $src_url,
484
- 'aff' => 1,
485
- 'aocssv' => AO_CCSS_VER,
 
486
  )
487
- )
488
- ),
489
- );
 
 
 
 
 
 
 
 
 
 
 
490
 
491
- // Dispatch the request and store its response code.
492
- $req = wp_safe_remote_post( $url, $args );
493
- $code = wp_remote_retrieve_response_code( $req );
494
- $body = json_decode( wp_remote_retrieve_body( $req ), true );
495
-
496
- if ( 200 == $code ) {
497
- // Response is OK.
498
- // Set key status as valid and log key check.
499
- update_option( 'autoptimize_ccss_keyst', 2 );
500
- $this->ao_ccss_log( 'criticalcss.com: API key is valid, updating key status', 3 );
501
-
502
- // extract job-id from $body and put it in the queue as a P job
503
- // but only if no jobs and no rules!
504
- $queue = $this->criticalcss->get_option( 'queue' );
505
- $rules = $this->criticalcss->get_option( 'rules' );
506
-
507
- if ( 0 == count( $queue ) && 0 == count( $rules['types'] ) && 0 == count( $rules['paths'] ) ) {
508
- if ( 'JOB_QUEUED' == $body['job']['status'] || 'JOB_ONGOING' == $body['job']['status'] ) {
509
- $jprops['ljid'] = 'firstrun';
510
- $jprops['rtarget'] = 'types|is_front_page';
511
- $jprops['ptype'] = 'is_front_page';
512
- $jprops['hashes'][] = 'dummyhash';
513
- $jprops['hash'] = 'dummyhash';
514
- $jprops['file'] = null;
515
- $jprops['jid'] = $body['job']['id'];
516
- $jprops['jqstat'] = $body['job']['status'];
517
- $jprops['jrstat'] = null;
518
- $jprops['jvstat'] = null;
519
- $jprops['jctime'] = microtime( true );
520
- $jprops['jftime'] = null;
521
- $queue['/'] = $jprops;
522
- $queue_raw = json_encode( $queue );
523
- update_option( 'autoptimize_ccss_queue', $queue_raw, false );
524
- $this->ao_ccss_log( 'Created P job for is_front_page based on API key check response.', 3 );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
525
  }
 
526
  }
527
- return true;
528
- } elseif ( 401 == $code ) {
529
- // Response is unauthorized
530
- // Set key status as invalid and log key check.
531
- update_option( 'autoptimize_ccss_keyst', 1 );
532
- $this->ao_ccss_log( 'criticalcss.com: API key is invalid, updating key status', 3 );
533
- return false;
534
  } else {
535
- // Response unkown
536
- // Log key check attempt.
537
- $this->ao_ccss_log( 'criticalcss.com: could not check API key status, this is a service error, body follows if any...', 2 );
538
- if ( ! empty( $body ) ) {
539
- $this->ao_ccss_log( print_r( $body, true ), 2 );
540
- }
541
- if ( is_wp_error( $req ) ) {
542
- $this->ao_ccss_log( $req->get_error_message(), 2 );
543
- }
544
  return false;
545
  }
546
  }
456
 
457
  // Avoid AO optimizations if required by config or avoid lazyload if lazyload is active in AO.
458
  if ( ! empty( $noptimize ) ) {
459
+ $src_url .= '/?ao_noptirocket=1';
460
  } elseif ( class_exists( 'autoptimizeImages', false ) && autoptimizeImages::should_lazyload_wrapper() ) {
461
+ $src_url .= '/?ao_nolazy=1';
462
  }
463
 
464
  $src_url = apply_filters( 'autoptimize_filter_ccss_cron_srcurl', $src_url );
465
 
466
+ if ( true !== autoptimizeUtils::is_local_server( parse_url( $src_url, PHP_URL_HOST ) ) ) {
467
+ // Prepare the request.
468
+ $url = esc_url_raw( AO_CCSS_API . 'generate' );
469
+ $args = array(
470
+ 'headers' => apply_filters(
471
+ 'autoptimize_ccss_cron_api_generate_headers',
 
 
 
 
 
 
 
 
 
 
472
  array(
473
+ 'User-Agent' => 'Autoptimize v' . AO_CCSS_VER,
474
+ 'Content-type' => 'application/json; charset=utf-8',
475
+ 'Authorization' => 'JWT ' . $key,
476
+ 'Connection' => 'close',
477
  )
478
+ ),
479
+ // Body must be JSON.
480
+ 'body' => json_encode(
481
+ apply_filters(
482
+ 'autoptimize_ccss_cron_api_generate_body',
483
+ array(
484
+ 'url' => $src_url,
485
+ 'aff' => 1,
486
+ 'aocssv' => AO_CCSS_VER,
487
+ )
488
+ ),
489
+ JSON_UNESCAPED_SLASHES
490
+ ),
491
+ );
492
 
493
+ // Dispatch the request and store its response code.
494
+ $req = wp_safe_remote_post( $url, $args );
495
+ $code = wp_remote_retrieve_response_code( $req );
496
+ $body = json_decode( wp_remote_retrieve_body( $req ), true );
497
+
498
+ if ( 200 == $code ) {
499
+ // Response is OK.
500
+ // Set key status as valid and log key check.
501
+ update_option( 'autoptimize_ccss_keyst', 2 );
502
+ $this->ao_ccss_log( 'criticalcss.com: API key is valid, updating key status', 3 );
503
+
504
+ // extract job-id from $body and put it in the queue as a P job
505
+ // but only if no jobs and no rules!
506
+ $queue = $this->criticalcss->get_option( 'queue' );
507
+ $rules = $this->criticalcss->get_option( 'rules' );
508
+
509
+ if ( 0 == count( $queue ) && 0 == count( $rules['types'] ) && 0 == count( $rules['paths'] ) ) {
510
+ if ( 'JOB_QUEUED' == $body['job']['status'] || 'JOB_ONGOING' == $body['job']['status'] ) {
511
+ $jprops['ljid'] = 'firstrun';
512
+ $jprops['rtarget'] = 'types|is_front_page';
513
+ $jprops['ptype'] = 'is_front_page';
514
+ $jprops['hashes'][] = 'dummyhash';
515
+ $jprops['hash'] = 'dummyhash';
516
+ $jprops['file'] = null;
517
+ $jprops['jid'] = $body['job']['id'];
518
+ $jprops['jqstat'] = $body['job']['status'];
519
+ $jprops['jrstat'] = null;
520
+ $jprops['jvstat'] = null;
521
+ $jprops['jctime'] = microtime( true );
522
+ $jprops['jftime'] = null;
523
+ $queue['/'] = $jprops;
524
+ $queue_raw = json_encode( $queue );
525
+ update_option( 'autoptimize_ccss_queue', $queue_raw, false );
526
+ $this->ao_ccss_log( 'Created P job for is_front_page based on API key check response.', 3 );
527
+ }
528
+ }
529
+ return true;
530
+ } elseif ( 401 == $code ) {
531
+ // Response is unauthorized
532
+ // Set key status as invalid and log key check.
533
+ update_option( 'autoptimize_ccss_keyst', 1 );
534
+ $this->ao_ccss_log( 'criticalcss.com: API key is invalid, updating key status', 3 );
535
+ return false;
536
+ } else {
537
+ // Response unkown
538
+ // Log key check attempt.
539
+ $this->ao_ccss_log( 'criticalcss.com: could not check API key status, this is a service error, body follows if any...', 2 );
540
+ if ( ! empty( $body ) ) {
541
+ $this->ao_ccss_log( print_r( $body, true ), 2 );
542
+ }
543
+ if ( is_wp_error( $req ) ) {
544
+ $this->ao_ccss_log( $req->get_error_message(), 2 );
545
  }
546
+ return false;
547
  }
 
 
 
 
 
 
 
548
  } else {
549
+ // localhost/ private network server, no API check possible.
 
 
 
 
 
 
 
 
550
  return false;
551
  }
552
  }
classes/autoptimizeCriticalCSSCron.php CHANGED
@@ -477,103 +477,109 @@ class autoptimizeCriticalCSSCron {
477
 
478
  $src_url = apply_filters( 'autoptimize_filter_ccss_cron_srcurl', $src_url );
479
 
480
- // Initialize request body.
481
- $body = array();
482
- $body['url'] = $src_url;
483
- $body['aff'] = 1;
484
- $body['aocssv'] = AO_CCSS_VER;
485
-
486
- // Prepare and add viewport size to the body if available.
487
- $viewport = $this->criticalcss->viewport();
488
- if ( ! empty( $viewport['w'] ) && ! empty( $viewport['h'] ) ) {
489
- $body['width'] = $viewport['w'];
490
- $body['height'] = $viewport['h'];
491
- }
492
-
493
- // Prepare and add forceInclude to the body if available.
494
- $finclude = $this->criticalcss->get_option( 'finclude' );
495
- $finclude = $this->ao_ccss_finclude( $finclude );
496
- if ( ! empty( $finclude ) ) {
497
- $body['forceInclude'] = $finclude;
498
- }
499
-
500
- // Add filter to allow the body array to be altered (e.g. to add customPageHeaders).
501
- $body = apply_filters( 'autoptimize_ccss_cron_api_generate_body', $body );
502
-
503
- // Body must be json and log it.
504
- $body = json_encode( $body );
505
- $this->criticalcss->log( 'criticalcss.com: POST generate request body is ' . $body, 3 );
506
-
507
- // Prepare the request.
508
- $url = esc_url_raw( AO_CCSS_API . 'generate?aover=' . AO_CCSS_VER );
509
- $args = array(
510
- 'headers' => apply_filters(
511
- 'autoptimize_ccss_cron_api_generate_headers',
512
- array(
513
- 'User-Agent' => 'Autoptimize v' . AO_CCSS_VER,
514
- 'Content-type' => 'application/json; charset=utf-8',
515
- 'Authorization' => 'JWT ' . $key,
516
- 'Connection' => 'close',
517
- )
518
- ),
519
- 'body' => $body,
520
- );
521
 
522
- // Dispatch the request and store its response code.
523
- $req = wp_safe_remote_post( $url, $args );
524
- $code = wp_remote_retrieve_response_code( $req );
525
- $body = json_decode( wp_remote_retrieve_body( $req ), true );
 
 
526
 
527
- if ( $debug && $dcode ) {
528
- // If queue debug is active, change response code.
529
- $code = $dcode;
530
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
531
 
532
- if ( 200 == $code ) {
533
- // Response code is OK.
534
- // Workaround criticalcss.com non-RESTful reponses.
535
- if ( 'JOB_QUEUED' == $body['job']['status'] || 'JOB_ONGOING' == $body['job']['status'] || 'STATUS_JOB_BAD' == $body['job']['status'] ) {
536
- // Log successful and return encoded request body.
537
- $this->criticalcss->log( 'criticalcss.com: POST generate request for path <' . $src_url . '> replied successfully', 3 );
 
 
 
 
 
 
538
 
539
- // This code also means the key is valid, so cache key status for 24h if not already cached.
540
- if ( ( ! $key_status || 2 != $key_status ) && $key ) {
541
- update_option( 'autoptimize_ccss_keyst', 2 );
542
- $this->criticalcss->log( 'criticalcss.com: API key is valid, updating key status', 3 );
 
 
 
543
  }
544
-
545
- // Return the request body.
546
- return $body;
547
  } else {
548
- // Log successful requests with invalid reponses.
549
- $this->criticalcss->log( 'criticalcss.com: POST generate request for path <' . $src_url . '> replied with code <' . $code . '> and an UNKNOWN error condition, body follows...', 2 );
550
- $this->criticalcss->log( print_r( $body, true ), 2 );
551
- return $body;
552
- }
553
- } else {
554
- // Response code is anything else.
555
- // Log failed request with a valid response code and return body.
556
- if ( $code ) {
557
- $this->criticalcss->log( 'criticalcss.com: POST generate request for path <' . $src_url . '> replied with error code <' . $code . '>, body follows...', 2 );
558
- $this->criticalcss->log( print_r( $body, true ), 2 );
559
 
560
- if ( 401 == $code ) {
561
- // If request is unauthorized, also clear key status.
562
- update_option( 'autoptimize_ccss_keyst', 1 );
563
- $this->criticalcss->log( 'criticalcss.com: API key is invalid, updating key status', 3 );
564
- }
 
 
 
565
 
566
- // Return the request body.
567
- return $body;
568
- } else {
569
- // Log failed request with no response and return false.
570
- $this->criticalcss->log( 'criticalcss.com: POST generate request for path <' . $src_url . '> has no response, this could be a service timeout', 2 );
571
- if ( is_wp_error( $req ) ) {
572
- $this->criticalcss->log( $req->get_error_message(), 2 );
573
  }
574
-
575
- return false;
576
  }
 
 
 
 
577
  }
578
  }
579
 
477
 
478
  $src_url = apply_filters( 'autoptimize_filter_ccss_cron_srcurl', $src_url );
479
 
480
+ if ( true !== autoptimizeUtils::is_local_server( parse_url( $src_url, PHP_URL_HOST ) ) ) {
481
+ // Initialize request body.
482
+ $body = array();
483
+ $body['url'] = $src_url;
484
+ $body['aff'] = 1;
485
+ $body['aocssv'] = AO_CCSS_VER;
486
+
487
+ // Prepare and add viewport size to the body if available.
488
+ $viewport = $this->criticalcss->viewport();
489
+ if ( ! empty( $viewport['w'] ) && ! empty( $viewport['h'] ) ) {
490
+ $body['width'] = $viewport['w'];
491
+ $body['height'] = $viewport['h'];
492
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
493
 
494
+ // Prepare and add forceInclude to the body if available.
495
+ $finclude = $this->criticalcss->get_option( 'finclude' );
496
+ $finclude = $this->ao_ccss_finclude( $finclude );
497
+ if ( ! empty( $finclude ) ) {
498
+ $body['forceInclude'] = $finclude;
499
+ }
500
 
501
+ // Add filter to allow the body array to be altered (e.g. to add customPageHeaders).
502
+ $body = apply_filters( 'autoptimize_ccss_cron_api_generate_body', $body );
503
+
504
+ // Body must be json and log it.
505
+ $body = json_encode( $body, JSON_UNESCAPED_SLASHES );
506
+ $this->criticalcss->log( 'criticalcss.com: POST generate request body is ' . $body, 3 );
507
+
508
+ // Prepare the request.
509
+ $url = esc_url_raw( AO_CCSS_API . 'generate?aover=' . AO_CCSS_VER );
510
+ $args = array(
511
+ 'headers' => apply_filters(
512
+ 'autoptimize_ccss_cron_api_generate_headers',
513
+ array(
514
+ 'User-Agent' => 'Autoptimize v' . AO_CCSS_VER,
515
+ 'Content-type' => 'application/json; charset=utf-8',
516
+ 'Authorization' => 'JWT ' . $key,
517
+ 'Connection' => 'close',
518
+ )
519
+ ),
520
+ 'body' => $body,
521
+ );
522
+
523
+ // Dispatch the request and store its response code.
524
+ $req = wp_safe_remote_post( $url, $args );
525
+ $code = wp_remote_retrieve_response_code( $req );
526
+ $body = json_decode( wp_remote_retrieve_body( $req ), true );
527
+
528
+ if ( $debug && $dcode ) {
529
+ // If queue debug is active, change response code.
530
+ $code = $dcode;
531
+ }
532
 
533
+ if ( 200 == $code ) {
534
+ // Response code is OK.
535
+ // Workaround criticalcss.com non-RESTful reponses.
536
+ if ( 'JOB_QUEUED' == $body['job']['status'] || 'JOB_ONGOING' == $body['job']['status'] || 'STATUS_JOB_BAD' == $body['job']['status'] ) {
537
+ // Log successful and return encoded request body.
538
+ $this->criticalcss->log( 'criticalcss.com: POST generate request for path <' . $src_url . '> replied successfully', 3 );
539
+
540
+ // This code also means the key is valid, so cache key status for 24h if not already cached.
541
+ if ( ( ! $key_status || 2 != $key_status ) && $key ) {
542
+ update_option( 'autoptimize_ccss_keyst', 2 );
543
+ $this->criticalcss->log( 'criticalcss.com: API key is valid, updating key status', 3 );
544
+ }
545
 
546
+ // Return the request body.
547
+ return $body;
548
+ } else {
549
+ // Log successful requests with invalid reponses.
550
+ $this->criticalcss->log( 'criticalcss.com: POST generate request for path <' . $src_url . '> replied with code <' . $code . '> and an UNKNOWN error condition, body follows...', 2 );
551
+ $this->criticalcss->log( print_r( $body, true ), 2 );
552
+ return $body;
553
  }
 
 
 
554
  } else {
555
+ // Response code is anything else.
556
+ // Log failed request with a valid response code and return body.
557
+ if ( $code ) {
558
+ $this->criticalcss->log( 'criticalcss.com: POST generate request for path <' . $src_url . '> replied with error code <' . $code . '>, body follows...', 2 );
559
+ $this->criticalcss->log( print_r( $body, true ), 2 );
560
+
561
+ if ( 401 == $code ) {
562
+ // If request is unauthorized, also clear key status.
563
+ update_option( 'autoptimize_ccss_keyst', 1 );
564
+ $this->criticalcss->log( 'criticalcss.com: API key is invalid, updating key status', 3 );
565
+ }
566
 
567
+ // Return the request body.
568
+ return $body;
569
+ } else {
570
+ // Log failed request with no response and return false.
571
+ $this->criticalcss->log( 'criticalcss.com: POST generate request for path <' . $src_url . '> has no response, this could be a service timeout', 2 );
572
+ if ( is_wp_error( $req ) ) {
573
+ $this->criticalcss->log( $req->get_error_message(), 2 );
574
+ }
575
 
576
+ return false;
 
 
 
 
 
 
577
  }
 
 
578
  }
579
+ } else {
580
+ // localhost/ private network server, no CCSS possible.
581
+ $this->criticalcss->log( 'ccss cron: job not created at ccss.com as for local server', 3 );
582
+ return false;
583
  }
584
  }
585
 
classes/autoptimizeCriticalCSSEnqueue.php CHANGED
@@ -20,7 +20,10 @@ class autoptimizeCriticalCSSEnqueue {
20
  $enqueue = true;
21
 
22
  // ... which are not the ones below.
23
- if ( 'nokey' == $key['status'] || 'invalid' == $key['status'] ) {
 
 
 
24
  $enqueue = false;
25
  $this->criticalcss->log( 'Job queuing is not available: no valid API key found.', 3 );
26
  } elseif ( ! empty( $hash ) && ( is_user_logged_in() || is_feed() || is_404() || ( defined( 'DOING_AJAX' ) && DOING_AJAX ) || $this->ao_ccss_ua() || false === apply_filters( 'autoptimize_filter_ccss_enqueue_should_enqueue', true ) ) ) {
20
  $enqueue = true;
21
 
22
  // ... which are not the ones below.
23
+ if ( true === autoptimizeUtils::is_local_server() ) {
24
+ $enqueue = false;
25
+ $this->criticalcss->log('cant enqueue as local/ private', 3 );
26
+ } elseif ( 'nokey' == $key['status'] || 'invalid' == $key['status'] ) {
27
  $enqueue = false;
28
  $this->criticalcss->log( 'Job queuing is not available: no valid API key found.', 3 );
29
  } elseif ( ! empty( $hash ) && ( is_user_logged_in() || is_feed() || is_404() || ( defined( 'DOING_AJAX' ) && DOING_AJAX ) || $this->ao_ccss_ua() || false === apply_filters( 'autoptimize_filter_ccss_enqueue_should_enqueue', true ) ) ) {
classes/autoptimizeCriticalCSSSettings.php CHANGED
@@ -132,6 +132,14 @@ class autoptimizeCriticalCSSSettings {
132
  // Print AO settings tabs.
133
  echo autoptimizeConfig::ao_admin_tabs();
134
 
 
 
 
 
 
 
 
 
135
  $mkdirresult = $this->criticalcss->create_ao_ccss_dir();
136
 
137
  // Warn if we could not create those files.
132
  // Print AO settings tabs.
133
  echo autoptimizeConfig::ao_admin_tabs();
134
 
135
+ if ( autoptimizeUtils::is_local_server() && isset( $ao_ccss_key ) ) { ?>
136
+ <div class="notice-warning notice"><p>
137
+ <?php
138
+ echo __( 'The Critical CSS service does not work on locally hosted sites or when the server is on a private network.', 'autoptimize' );
139
+ ?>
140
+ </p></div>
141
+ <?php }
142
+
143
  $mkdirresult = $this->criticalcss->create_ao_ccss_dir();
144
 
145
  // Warn if we could not create those files.
classes/autoptimizeImages.php CHANGED
@@ -469,6 +469,8 @@ class autoptimizeImages
469
 
470
  if ( array_key_exists( 'host', $url_parsed ) && $url_parsed['host'] !== $site_host && empty( $cdn_url ) ) {
471
  return false;
 
 
472
  } elseif ( ! empty( $cdn_url ) && strpos( $url, $cdn_url ) === false && array_key_exists( 'host', $url_parsed ) && $url_parsed['host'] !== $site_host ) {
473
  return false;
474
  } elseif ( strpos( $url, '.php' ) !== false ) {
@@ -588,8 +590,9 @@ class autoptimizeImages
588
  );
589
  }
590
 
591
- // get img preloads as set in post metabox.
592
- $metabox_preloads = array_filter( array_map( 'trim', explode( ',', wp_strip_all_tags( autoptimizeConfig::get_post_meta_ao_settings( 'ao_post_preload' ) ) ) ) );
 
593
 
594
  // extract img tags.
595
  if ( preg_match_all( '#<img[^>]*src[^>]*>#Usmi', $in, $matches ) ) {
@@ -639,6 +642,11 @@ class autoptimizeImages
639
  }
640
  }
641
 
 
 
 
 
 
642
  // do lazyload stuff.
643
  if ( $this->should_lazyload( $in ) && ! empty( $url ) ) {
644
  // first do lpiq placeholder logic.
@@ -679,11 +687,6 @@ class autoptimizeImages
679
  if ( $tag !== $orig_tag ) {
680
  $to_replace[ $orig_tag ] = $tag;
681
  }
682
-
683
- // and check if image needs to be prelaoded.
684
- if ( ! empty( $metabox_preloads ) && is_array( $metabox_preloads ) && str_replace( $metabox_preloads, '', $tag ) !== $tag ) {
685
- $to_preload .= $this->create_img_preload_tag( $tag );
686
- }
687
  }
688
  }
689
 
@@ -842,14 +845,15 @@ class autoptimizeImages
842
  // extract img tags and add lazyload attribs/ add preloads.
843
  if ( preg_match_all( '#<img[^>]*src[^>]*>#Usmi', $out, $matches ) ) {
844
  foreach ( $matches[0] as $tag ) {
845
- if ( $this->should_lazyload( $out ) ) {
846
- $to_replace[ $tag ] = $this->add_lazyload( $tag );
847
- }
848
-
849
- // and check if image needs to be prelaoded.
850
  if ( ! empty( $metabox_preloads ) && is_array( $metabox_preloads ) && str_replace( $metabox_preloads, '', $tag ) !== $tag ) {
851
  $to_preload .= $this->create_img_preload_tag( $tag );
852
  }
 
 
 
 
 
853
  }
854
  $out = str_replace( array_keys( $to_replace ), array_values( $to_replace ), $out );
855
  }
@@ -977,6 +981,11 @@ class autoptimizeImages
977
 
978
  // clean up; remove tabs/ linebreaks/ spaces.
979
  $tag = preg_replace( '/\s+/', ' ', $tag );
 
 
 
 
 
980
 
981
  // rewrite img tag to link preload img.
982
  $_from = array( '<img ', ' src=', ' sizes=', ' srcset=' );
@@ -984,10 +993,10 @@ class autoptimizeImages
984
  $tag = str_replace( $_from, $_to, $tag );
985
 
986
  // and remove title, alt, class and id.
987
- $tag = preg_replace( '/ ((?:title|alt|class|id|loading)=".*")/Um', '', $tag );
988
- if ( str_replace( array( ' title=', ' class=', ' alt=', ' id=' ), '', $tag ) !== $tag ) {
989
  // 2nd regex pass if still title/ class/ alt in case single quotes were used iso doubles.
990
- $tag = preg_replace( '/ ((?:title|alt|class|id|loading)=\'.*\')/Um', '', $tag );
991
  }
992
 
993
  return $tag;
@@ -1194,6 +1203,13 @@ class autoptimizeImages
1194
  <div class="wrap">
1195
  <h1><?php apply_filters( 'autoptimize_filter_settings_is_pro', false ) ? _e( 'Autoptimize Pro Settings', 'autoptimize' ) : _e( 'Autoptimize Settings', 'autoptimize' ); ?></h1>
1196
  <?php echo autoptimizeConfig::ao_admin_tabs(); ?>
 
 
 
 
 
 
 
1197
  <?php if ( 'down' === $options['availabilities']['extra_imgopt']['status'] ) { ?>
1198
  <div class="notice-warning notice"><p>
1199
  <?php
@@ -1220,7 +1236,7 @@ class autoptimizeImages
1220
  <form id='ao_settings_form' action='<?php echo admin_url( 'options.php' ); ?>' method='post'>
1221
  <?php settings_fields( 'autoptimize_imgopt_settings' ); ?>
1222
  <h2><?php _e( 'Image optimization', 'autoptimize' ); ?></h2>
1223
- <span id='autoptimize_imgopt_descr'><?php echo apply_filters( 'autoptimize_filter_imgopt_intro_copy', __( 'Make your site significantly faster by just ticking a couple of checkboxes to optimize and lazy load your images, modern image format support included!', 'autoptimize' ) ); ?></span>
1224
  <table class="form-table">
1225
  <tr>
1226
  <th scope="row"><?php _e( 'Optimize Images', 'autoptimize' ); ?></th>
469
 
470
  if ( array_key_exists( 'host', $url_parsed ) && $url_parsed['host'] !== $site_host && empty( $cdn_url ) ) {
471
  return false;
472
+ } elseif ( autoptimizeUtils::is_local_server() ) {
473
+ return false;
474
  } elseif ( ! empty( $cdn_url ) && strpos( $url, $cdn_url ) === false && array_key_exists( 'host', $url_parsed ) && $url_parsed['host'] !== $site_host ) {
475
  return false;
476
  } elseif ( strpos( $url, '.php' ) !== false ) {
590
  );
591
  }
592
 
593
+ // get img preloads as set in post metabox, exploding ", " instead of "," because LCP preload
594
+ // could be a shortpixel URL, which has comma's and results in way too many preloads.
595
+ $metabox_preloads = array_filter( array_map( 'trim', explode( ', ', wp_strip_all_tags( autoptimizeConfig::get_post_meta_ao_settings( 'ao_post_preload' ) ) ) ) );
596
 
597
  // extract img tags.
598
  if ( preg_match_all( '#<img[^>]*src[^>]*>#Usmi', $in, $matches ) ) {
642
  }
643
  }
644
 
645
+ // check if the image needs to be prelaoded.
646
+ if ( ! empty( $metabox_preloads ) && is_array( $metabox_preloads ) && str_replace( $metabox_preloads, '', $tag ) !== $tag ) {
647
+ $to_preload .= $this->create_img_preload_tag( $tag );
648
+ }
649
+
650
  // do lazyload stuff.
651
  if ( $this->should_lazyload( $in ) && ! empty( $url ) ) {
652
  // first do lpiq placeholder logic.
687
  if ( $tag !== $orig_tag ) {
688
  $to_replace[ $orig_tag ] = $tag;
689
  }
 
 
 
 
 
690
  }
691
  }
692
 
845
  // extract img tags and add lazyload attribs/ add preloads.
846
  if ( preg_match_all( '#<img[^>]*src[^>]*>#Usmi', $out, $matches ) ) {
847
  foreach ( $matches[0] as $tag ) {
848
+ // check if image needs to be preloaded.
 
 
 
 
849
  if ( ! empty( $metabox_preloads ) && is_array( $metabox_preloads ) && str_replace( $metabox_preloads, '', $tag ) !== $tag ) {
850
  $to_preload .= $this->create_img_preload_tag( $tag );
851
  }
852
+
853
+ // and lazyloaded.
854
+ if ( $this->should_lazyload( $out ) ) {
855
+ $to_replace[ $tag ] = $this->add_lazyload( $tag );
856
+ }
857
  }
858
  $out = str_replace( array_keys( $to_replace ), array_values( $to_replace ), $out );
859
  }
981
 
982
  // clean up; remove tabs/ linebreaks/ spaces.
983
  $tag = preg_replace( '/\s+/', ' ', $tag );
984
+
985
+ // remove noscript.
986
+ if ( false !== strpos( $tag, '<noscript' ) ) {
987
+ $tag = preg_replace( '/<noscript.*<\/noscript>/mU', '', $tag );
988
+ }
989
 
990
  // rewrite img tag to link preload img.
991
  $_from = array( '<img ', ' src=', ' sizes=', ' srcset=' );
993
  $tag = str_replace( $_from, $_to, $tag );
994
 
995
  // and remove title, alt, class and id.
996
+ $tag = preg_replace( '/ ((?:title|alt|class|id|loading|fetchpriority|decoding|data-no-lazy)=".*")/Um', '', $tag );
997
+ if ( str_replace( array( ' title=', ' class=', ' alt=', ' id=', ' fetchpriority=', ' decoding=', ' data-no-lazy=' ), '', $tag ) !== $tag ) {
998
  // 2nd regex pass if still title/ class/ alt in case single quotes were used iso doubles.
999
+ $tag = preg_replace( '/ ((?:title|alt|class|id|loading|fetchpriority|decoding|data-no-lazy)=\'.*\')/Um', '', $tag );
1000
  }
1001
 
1002
  return $tag;
1203
  <div class="wrap">
1204
  <h1><?php apply_filters( 'autoptimize_filter_settings_is_pro', false ) ? _e( 'Autoptimize Pro Settings', 'autoptimize' ) : _e( 'Autoptimize Settings', 'autoptimize' ); ?></h1>
1205
  <?php echo autoptimizeConfig::ao_admin_tabs(); ?>
1206
+ <?php if ( autoptimizeUtils::is_local_server() ) { ?>
1207
+ <div class="notice-warning notice"><p>
1208
+ <?php
1209
+ echo __( 'The image optimization service does not work on locally hosted sites or when the server is on a private network.', 'autoptimize' );
1210
+ ?>
1211
+ </p></div>
1212
+ <?php } ?>
1213
  <?php if ( 'down' === $options['availabilities']['extra_imgopt']['status'] ) { ?>
1214
  <div class="notice-warning notice"><p>
1215
  <?php
1236
  <form id='ao_settings_form' action='<?php echo admin_url( 'options.php' ); ?>' method='post'>
1237
  <?php settings_fields( 'autoptimize_imgopt_settings' ); ?>
1238
  <h2><?php _e( 'Image optimization', 'autoptimize' ); ?></h2>
1239
+ <span id='autoptimize_imgopt_descr'><?php echo apply_filters( 'autoptimize_filter_imgopt_intro_copy', __( 'Make your site significantly faster by just ticking a couple of checkboxes to optimize and lazy load your images, modern image format support included! No additional plugins or services needed.', 'autoptimize' ) ); ?></span>
1240
  <table class="form-table">
1241
  <tr>
1242
  <th scope="row"><?php _e( 'Optimize Images', 'autoptimize' ); ?></th>
classes/autoptimizeMetabox.php CHANGED
@@ -117,7 +117,14 @@ class autoptimizeMetabox
117
  <?php _e( 'Lazyload images?', 'autoptimize' ); ?>
118
  </label>
119
  </p>
120
- <p class="ao_meta_sub" style="<?php echo $_ao_meta_sub_opacity; ?>">
 
 
 
 
 
 
 
121
  <label for="autoptimize_post_preload">
122
  <?php _e( 'LCP Image to preload', 'autoptimize' ); ?>
123
  </label>
@@ -179,6 +186,19 @@ class autoptimizeMetabox
179
  jQuery("#generateccss:visible").fadeTo("fast",.33);
180
  }
181
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
182
  jQuery("#generateccss").click(function(e){
183
  e.preventDefault();
184
  // disable button to avoid it being clicked several times.
117
  <?php _e( 'Lazyload images?', 'autoptimize' ); ?>
118
  </label>
119
  </p>
120
+ <?php
121
+ $_ao_meta_preload_style = '';
122
+ if ( false === autoptimizeImages::should_lazyload_wrapper() && false === autoptimizeImages::imgopt_active() ) {
123
+ // img preload requires imgopt and/ or lazyload to be active.
124
+ $_ao_meta_preload_style = 'opacity:.33;';
125
+ }
126
+ ?>
127
+ <p class="ao_meta_sub ao_meta_preload" style="<?php echo $_ao_meta_sub_opacity . $_ao_meta_preload_style; ?>">
128
  <label for="autoptimize_post_preload">
129
  <?php _e( 'LCP Image to preload', 'autoptimize' ); ?>
130
  </label>
186
  jQuery("#generateccss:visible").fadeTo("fast",.33);
187
  }
188
  });
189
+ <?php
190
+ if ( true === autoptimizeImages::should_lazyload_wrapper() && false === autoptimizeImages::imgopt_active() ) {
191
+ ?>
192
+ jQuery( "#autoptimize_post_lazyload" ).change(function() {
193
+ if (this.checked) {
194
+ jQuery(".ao_meta_preload:visible").fadeTo("fast",1);
195
+ } else {
196
+ jQuery(".ao_meta_preload:visible").fadeTo("fast",.33);
197
+ }
198
+ });
199
+ <?php
200
+ }
201
+ ?>
202
  jQuery("#generateccss").click(function(e){
203
  e.preventDefault();
204
  // disable button to avoid it being clicked several times.
classes/autoptimizeUtils.php CHANGED
@@ -490,7 +490,7 @@ class autoptimizeUtils
490
  * @return bool
491
  */
492
  public static function is_ao_settings() {
493
- $_is_ao_settings = ( str_replace( array( 'autoptimize', 'autoptimize_imgopt', 'ao_critcss', 'autoptimize_extra', 'ao_partners' ), '', $_SERVER['REQUEST_URI'] ) !== $_SERVER['REQUEST_URI'] ? true : false );
494
  return $_is_ao_settings;
495
  }
496
 
@@ -539,4 +539,36 @@ class autoptimizeUtils
539
 
540
  return false;
541
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
542
  }
490
  * @return bool
491
  */
492
  public static function is_ao_settings() {
493
+ $_is_ao_settings = ( str_replace( array( 'autoptimize', 'autoptimize_imgopt', 'ao_critcss', 'autoptimize_extra', 'ao_partners', 'ao_pro_boosters' ), '', $_SERVER['REQUEST_URI'] ) !== $_SERVER['REQUEST_URI'] ? true : false );
494
  return $_is_ao_settings;
495
  }
496
 
539
 
540
  return false;
541
  }
542
+
543
+ /**
544
+ * Returns true if false if on a local dev environment, true if not.
545
+ * Used to disallow image opt/ critcss for local dev environments.
546
+ *
547
+ * @return bool
548
+ */
549
+ public static function is_local_server( $_domain = AUTOPTIMIZE_SITE_DOMAIN ) {
550
+ static $_is_local_server = null;
551
+
552
+ if ( null === $_is_local_server ) {
553
+ if ( false === strpos( $_domain, '.' ) && false === strpos( $_domain, ':' ) ) {
554
+ // no dots in domain or colon (ipv6 address), so impossible to reach, this also matches 'localhost' or any other single-word domain.
555
+ $_is_local_server = true;
556
+ } elseif ( in_array( $_domain, array( '127.0.0.1', '0000:0000:0000:0000:0000:0000:0000:0001', '0:0:0:0:0:0:0:1', '::1' ) ) ) {
557
+ // localhost IPv4/ IPv6.
558
+ $_is_local_server = true;
559
+ } elseif ( 0 === strpos( $_domain, '127.' ) || 0 === strpos( $_domain, '192.168.' ) || 0 === strpos( $_domain, 'fd' ) ) {
560
+ // private ranges so unreachable for imgopt/ CCSS.
561
+ $_is_local_server = true;
562
+ } elseif ( autoptimizeUtils::str_ends_in( $_domain, '.local') ) {
563
+ // matches 'whatever.local'.
564
+ $_is_local_server = true;
565
+ } else {
566
+ // likely OK.
567
+ $_is_local_server = false;
568
+ }
569
+ }
570
+
571
+ // filter to override result for testing purposes.
572
+ return apply_filters( 'autoptimize_filter_utils_is_local_server', $_is_local_server );
573
+ }
574
  }
classes/static/exit-survey/exit-survey.js CHANGED
@@ -1,6 +1,6 @@
1
  (function ($) {
2
  $(document).ready(function () {
3
- var targetElement = 'tr[data-slug="autoptimize"] span.deactivate a';
4
  var redirectUrl = $(targetElement).attr('href');
5
  if ($('.ao-feedback-overlay').length === 0) {
6
  $('body').prepend('<div class="ao-feedback-overlay"></div>');
@@ -8,9 +8,7 @@
8
  $('#ao_uninstall_feedback_popup').appendTo($(targetElement).parent());
9
 
10
  $(targetElement).on('click', function (e) {
11
- if ( false == e.target.href.includes('https://wordpress.org/') && false == e.target.href.includes('https://blog.futtta.be/') ) {
12
- e.preventDefault();
13
- }
14
  $('#ao_uninstall_feedback_popup ').addClass('active');
15
  $('body').addClass('ao-feedback-open');
16
  $('.ao-feedback-overlay').on('click', function () {
1
  (function ($) {
2
  $(document).ready(function () {
3
+ var targetElement = 'tr[data-plugin="autoptimize/autoptimize.php"] span.deactivate a';
4
  var redirectUrl = $(targetElement).attr('href');
5
  if ($('.ao-feedback-overlay').length === 0) {
6
  $('body').prepend('<div class="ao-feedback-overlay"></div>');
8
  $('#ao_uninstall_feedback_popup').appendTo($(targetElement).parent());
9
 
10
  $(targetElement).on('click', function (e) {
11
+ e.preventDefault();
 
 
12
  $('#ao_uninstall_feedback_popup ').addClass('active');
13
  $('body').addClass('ao-feedback-open');
14
  $('.ao-feedback-overlay').on('click', function () {
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: 6.0
7
  Requires PHP: 5.6
8
- Stable tag: 3.1.2
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
 
@@ -14,8 +14,11 @@ Autoptimize speeds up your website by optimizing JS, CSS, images (incl. lazy-loa
14
  Autoptimize makes optimizing your site really easy. It can aggregate, minify and cache scripts and styles, injects CSS in the page head by default but can also inline critical CSS and defer the aggregated full CSS, moves and defers scripts to the footer and minifies HTML. You can optimize and lazy-load images (with support for WebP and AVIF formats), optimize Google Fonts, async non-aggregated JavaScript, remove WordPress core emoji cruft and more. As such it can improve your site's performance even when already on HTTP/2! There is extensive API available to enable you to tailor Autoptimize to each and every site's specific needs.
15
  If you consider performance important, you really should use one of the many caching plugins to do page caching. Some good candidates to complement Autoptimize that way are e.g. [Speed Booster pack](https://wordpress.org/plugins/speed-booster-pack/), [KeyCDN's Cache Enabler](https://wordpress.org/plugins/cache-enabler), [WP Super Cache](http://wordpress.org/plugins/wp-super-cache/) or if you use Cloudflare [WP Cloudflare Super Page Cache](https://wordpress.org/plugins/wp-cloudflare-page-cache/).
16
 
 
 
 
17
  > <strong>Premium Support</strong><br>
18
- > We provide great [Autoptimize Pro Support and Web Performance Optimization services](https://misc.optimizingmatters.com/partners/?from=partnertab&partner=autoptimizepro), check out our offering on [https://accelera.autoptimize.com/](https://misc.optimizingmatters.com/partners/?from=partnertab&partner=autoptimizepro)!
19
 
20
  (Speed-surfing image under creative commons [by LL Twistiti](https://www.flickr.com/photos/twistiti/818552808/))
21
 
@@ -316,6 +319,12 @@ Just [fork Autoptimize on Github](https://github.com/futtta/autoptimize) and cod
316
 
317
  == Changelog ==
318
 
 
 
 
 
 
 
319
  = 3.1.2 =
320
  * Google Fonts: some more removal logic
321
  * fix for 404 fallback bug (hat tip to Asif for finding & reporting)
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: 6.1
7
  Requires PHP: 5.6
8
+ Stable tag: 3.1.3
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
 
14
  Autoptimize makes optimizing your site really easy. It can aggregate, minify and cache scripts and styles, injects CSS in the page head by default but can also inline critical CSS and defer the aggregated full CSS, moves and defers scripts to the footer and minifies HTML. You can optimize and lazy-load images (with support for WebP and AVIF formats), optimize Google Fonts, async non-aggregated JavaScript, remove WordPress core emoji cruft and more. As such it can improve your site's performance even when already on HTTP/2! There is extensive API available to enable you to tailor Autoptimize to each and every site's specific needs.
15
  If you consider performance important, you really should use one of the many caching plugins to do page caching. Some good candidates to complement Autoptimize that way are e.g. [Speed Booster pack](https://wordpress.org/plugins/speed-booster-pack/), [KeyCDN's Cache Enabler](https://wordpress.org/plugins/cache-enabler), [WP Super Cache](http://wordpress.org/plugins/wp-super-cache/) or if you use Cloudflare [WP Cloudflare Super Page Cache](https://wordpress.org/plugins/wp-cloudflare-page-cache/).
16
 
17
+ > <strong>Autoptimize Pro</strong><br>
18
+ > [Autoptimize Pro is a premium Power-Up](https://misc.optimizingmatters.com/partners/?from=partnertab&partner=aopro), adding image optimization, CDN, automatic critical CSS rules and extra “booster” options, all in one handy subscription to [make your site even faster!](https://misc.optimizingmatters.com/partners/?from=partnertab&partner=aopro)!
19
+
20
  > <strong>Premium Support</strong><br>
21
+ > We provide great [Premium Support and Web Performance Optimization services](https://misc.optimizingmatters.com/partners/?from=partnertab&partner=autoptimizepro), check out our offering on [https://accelera.autoptimize.com/](https://misc.optimizingmatters.com/partners/?from=partnertab&partner=autoptimizepro)!
22
 
23
  (Speed-surfing image under creative commons [by LL Twistiti](https://www.flickr.com/photos/twistiti/818552808/))
24
 
319
 
320
  == Changelog ==
321
 
322
+ = 3.1.3 =
323
+ * Multiple fixes for metabox LCP image preloads (thanks [Kishorchand](https://foxscribbler.com/) for notifying & providing a staging environment to debug on).
324
+ * Fix in revslider compatibility (hat tip [Waqar Ahmed for reporting & helping out](https://wordpress.org/support/topic/issue-with-latest-version-of-slider-revolution/) ).
325
+ * No image optimization or criticalcss attempts on localhost installations any more + notification of that fact if localhost detected.
326
+ * Some other minor changes/ improvements/ filters, see the [GitHub commit log](https://github.com/futtta/autoptimize/commits/beta).
327
+
328
  = 3.1.2 =
329
  * Google Fonts: some more removal logic
330
  * fix for 404 fallback bug (hat tip to Asif for finding & reporting)