Autoptimize - Version 3.1.1

Version Description

  • images: when optimizing images and lazyloading is on, then by default do not set an LQIP (low quality image placeholder) any more (reason: it might look nice but it comes with a small-ish perf. penalty). This can be re-enabled by returning true to the autoptimize_filter_imgopt_lazyload_dolqip filter.
  • security: further improvements to critical CSS settings page (again with the great assistance of WPScan Security).
  • 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.1
Comparing to
See all releases

Code changes from version 3.1.0 to 3.1.1

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: 3.1.0
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', '3.1.0' );
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: 3.1.1
7
  * Author: Frank Goossens (futtta)
8
  * Author URI: https://autoptimize.com/
9
  * Text Domain: autoptimize
21
  exit;
22
  }
23
 
24
+ define( 'AUTOPTIMIZE_PLUGIN_VERSION', '3.1.1' );
25
 
26
  // plugin_dir_path() returns the trailing slash!
27
  define( 'AUTOPTIMIZE_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
classes/autoptimizeCache.php CHANGED
@@ -91,7 +91,7 @@ class autoptimizeCache
91
  * @param string $data Data to cache.
92
  * @param string $mime Mimetype.
93
  *
94
- * @return void
95
  */
96
  public function cache( $data, $mime )
97
  {
@@ -386,7 +386,7 @@ class autoptimizeCache
386
  // see https://blog.futtta.be/2018/11/17/warning-divi-purging-autoptimizes-cache/ .
387
  $dbt = debug_backtrace( DEBUG_BACKTRACE_IGNORE_ARGS, 2 );
388
  $caller = isset( $dbt[1]['function'] ) ? $dbt[1]['function'] : null;
389
- if ( $caller === 'et_core_clear_wp_cache' ) {
390
  _doing_it_wrong( 'autoptimizeCache::clearall', 'Divi devs: please don\'t clear Autoptimize\'s cache, it is unneeded and can break sites. You can contact me at futtta@gmail.com to discuss.', 'Autoptimize 2.9.6' );
391
  return false;
392
  }
@@ -695,7 +695,7 @@ class autoptimizeCache
695
 
696
  // prepare for Shakeeb's Unused CSS files to be 404-handled as well.
697
  if ( strpos( $original_request, 'uucss/uucss-' ) !== false ) {
698
- $original_request = preg_replace( '/uucss\/uucss-[a-z0-9]{32}-/', 'css/', $original_request );
699
  }
700
 
701
  // set fallback URL.
91
  * @param string $data Data to cache.
92
  * @param string $mime Mimetype.
93
  *
94
+ * @return void|bool
95
  */
96
  public function cache( $data, $mime )
97
  {
386
  // see https://blog.futtta.be/2018/11/17/warning-divi-purging-autoptimizes-cache/ .
387
  $dbt = debug_backtrace( DEBUG_BACKTRACE_IGNORE_ARGS, 2 );
388
  $caller = isset( $dbt[1]['function'] ) ? $dbt[1]['function'] : null;
389
+ if ( 'et_core_clear_wp_cache' === $caller ) {
390
  _doing_it_wrong( 'autoptimizeCache::clearall', 'Divi devs: please don\'t clear Autoptimize\'s cache, it is unneeded and can break sites. You can contact me at futtta@gmail.com to discuss.', 'Autoptimize 2.9.6' );
391
  return false;
392
  }
695
 
696
  // prepare for Shakeeb's Unused CSS files to be 404-handled as well.
697
  if ( strpos( $original_request, 'uucss/uucss-' ) !== false ) {
698
+ $original_request = preg_replace( '/uucss\/uucss-[a-z0-9]{32}-/', 'css/', $original_request );
699
  }
700
 
701
  // set fallback URL.
classes/autoptimizeCompatibility.php CHANGED
@@ -1,7 +1,6 @@
1
  <?php
2
  /**
3
  * Multiple compatibility snippets to ensure important/ stubborn plugins work out of the box.
4
- *
5
  */
6
 
7
  if ( ! defined( 'ABSPATH' ) ) {
@@ -12,7 +11,6 @@ class autoptimizeCompatibility
12
  {
13
  /**
14
  * Constructor.
15
- *
16
  */
17
  public function __construct()
18
  {
@@ -24,7 +22,6 @@ class autoptimizeCompatibility
24
 
25
  /**
26
  * Runs multiple compatibility snippets to ensure important plugins work out of the box.
27
- *
28
  */
29
  public function run()
30
  {
@@ -35,69 +32,89 @@ class autoptimizeCompatibility
35
 
36
  // Revslider; jQuery should not be deferred + exclude all revslider JS.
37
  if ( defined( 'RS_REVISION' ) && $this->conf->get( 'autoptimize_js' ) && true == $this->inline_js_config_checker() && apply_filters( 'autoptimize_filter_compatibility_revslider_active', true ) ) {
38
- add_filter( 'autoptimize_filter_js_exclude', function( $js_excl = '', $html = '' ) {
39
- $revslider_excl = 'revslider, setREVStartSize, window.RSIW, window.RS_MODULES, jquery.min.js';
40
- if ( ! empty( $html ) && false !== strpos( $html, '<rs-slides>' ) ) {
41
- if ( is_array( $js_excl ) ) {
42
- $js_excl = implode( ',', $js_excl );
 
 
 
 
 
43
  }
44
-
45
- $js_excl .= ',' . $revslider_excl;
46
- }
47
- return $js_excl;
48
- }, 11, 2 );
49
  }
50
 
51
  // Revslider; remove revslider JS if no slides in HTML for non-logged in users.
52
  if ( defined( 'RS_REVISION' ) && $this->conf->get( 'autoptimize_js' ) && false === is_user_logged_in() && apply_filters( 'autoptimize_filter_compatibility_revslider_remover_active', true ) ) {
53
- add_filter( 'autoptimize_filter_js_removables', function( $to_remove = '', $html = '' ) {
54
- if ( ! empty( $html ) && false === strpos( $html, '<rs-slides>') ) {
55
- $to_remove .= 'plugins/revslider, setREVStartSize, window.RSIW, window.RS_MODULES';
56
- }
 
 
57
 
58
- return $to_remove;
59
- }, 11, 2 );
 
 
 
60
  }
61
 
62
  // Exclude jQuery if inline JS is found that requires jQuery.
63
  if ( $this->inline_js_config_checker() && false === strpos( $this->conf->get( 'autoptimize_js_exclude' ), 'jquery.min.js' ) && apply_filters( 'autoptimize_filter_compatibility_inline_jquery', true ) ) {
64
- add_filter( 'autoptimize_filter_js_exclude', function( $js_excl = '', $html = '' ) {
65
- if ( ! empty( $html ) && preg_match( '/<script[^>]*>[^<]*(jQuery|\$)\([^<]*<\/script>/Usm', $html ) ) {
66
- if ( is_array( $js_excl ) ) {
67
- $js_excl = implode( ',', $js_excl );
68
- }
69
-
70
- if ( false === strpos( $js_excl, 'jquery.min.js' ) ) {
71
- $js_excl .= ', jquery.min.js';
72
- }
73
-
74
- // also exclude jquery.js if for whatever reason that is still used.
75
- if ( false === strpos( $js_excl, 'jquery.js' ) ) {
76
- $js_excl .= ', jquery.js';
 
 
 
77
  }
78
- }
79
- return $js_excl;
80
- }, 12, 2 );
 
 
81
  }
82
 
83
  // Make JS-based Gutenberg blocks work OOTB.
84
  if ( $this->inline_js_config_checker() && apply_filters( 'autoptimize_filter_compatibility_gutenberg_js', true ) ) {
85
- add_filter( 'autoptimize_filter_js_exclude', function( $js_excl = '', $html = '' ) {
86
- if ( ! empty( $html ) && false !== strpos( $html, 'wp.i18n' ) || false !== strpos( $html, 'wp.apiFetch' ) || false !== strpos( $html, 'window.lodash' ) ) {
87
- if ( is_array( $js_excl ) ) {
88
- $js_excl = implode( ',', $js_excl );
89
- }
90
-
91
- if ( false === strpos( $js_excl, 'jquery.min.js' ) ) {
92
- $js_excl .= ', jquery.min.js';
93
- }
94
-
95
- if ( false === strpos( $js_excl, 'wp-includes/js/dist' ) ) {
96
- $js_excl .= ', wp-includes/js/dist';
 
 
 
97
  }
98
- }
99
- return $js_excl;
100
- }, 13, 2 );
 
 
101
  }
102
  }
103
 
1
  <?php
2
  /**
3
  * Multiple compatibility snippets to ensure important/ stubborn plugins work out of the box.
 
4
  */
5
 
6
  if ( ! defined( 'ABSPATH' ) ) {
11
  {
12
  /**
13
  * Constructor.
 
14
  */
15
  public function __construct()
16
  {
22
 
23
  /**
24
  * Runs multiple compatibility snippets to ensure important plugins work out of the box.
 
25
  */
26
  public function run()
27
  {
32
 
33
  // Revslider; jQuery should not be deferred + exclude all revslider JS.
34
  if ( defined( 'RS_REVISION' ) && $this->conf->get( 'autoptimize_js' ) && true == $this->inline_js_config_checker() && apply_filters( 'autoptimize_filter_compatibility_revslider_active', true ) ) {
35
+ add_filter(
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
+ }
43
+
44
+ $js_excl .= ',' . $revslider_excl;
45
  }
46
+ return $js_excl;
47
+ },
48
+ 11,
49
+ 2
50
+ );
51
  }
52
 
53
  // Revslider; remove revslider JS if no slides in HTML for non-logged in users.
54
  if ( defined( 'RS_REVISION' ) && $this->conf->get( 'autoptimize_js' ) && false === is_user_logged_in() && apply_filters( 'autoptimize_filter_compatibility_revslider_remover_active', true ) ) {
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
 
62
+ return $to_remove;
63
+ },
64
+ 11,
65
+ 2
66
+ );
67
  }
68
 
69
  // Exclude jQuery if inline JS is found that requires jQuery.
70
  if ( $this->inline_js_config_checker() && false === strpos( $this->conf->get( 'autoptimize_js_exclude' ), 'jquery.min.js' ) && apply_filters( 'autoptimize_filter_compatibility_inline_jquery', true ) ) {
71
+ add_filter(
72
+ 'autoptimize_filter_js_exclude',
73
+ function( $js_excl = '', $html = '' ) {
74
+ if ( ! empty( $html ) && preg_match( '/<script[^>]*>[^<]*(jQuery|\$)\([^<]*<\/script>/Usm', $html ) ) {
75
+ if ( is_array( $js_excl ) ) {
76
+ $js_excl = implode( ',', $js_excl );
77
+ }
78
+
79
+ if ( false === strpos( $js_excl, 'jquery.min.js' ) ) {
80
+ $js_excl .= ', jquery.min.js';
81
+ }
82
+
83
+ // also exclude jquery.js if for whatever reason that is still used.
84
+ if ( false === strpos( $js_excl, 'jquery.js' ) ) {
85
+ $js_excl .= ', jquery.js';
86
+ }
87
  }
88
+ return $js_excl;
89
+ },
90
+ 12,
91
+ 2
92
+ );
93
  }
94
 
95
  // Make JS-based Gutenberg blocks work OOTB.
96
  if ( $this->inline_js_config_checker() && apply_filters( 'autoptimize_filter_compatibility_gutenberg_js', true ) ) {
97
+ add_filter(
98
+ 'autoptimize_filter_js_exclude',
99
+ function( $js_excl = '', $html = '' ) {
100
+ if ( ! empty( $html ) && false !== strpos( $html, 'wp.i18n' ) || false !== strpos( $html, 'wp.apiFetch' ) || false !== strpos( $html, 'window.lodash' ) ) {
101
+ if ( is_array( $js_excl ) ) {
102
+ $js_excl = implode( ',', $js_excl );
103
+ }
104
+
105
+ if ( false === strpos( $js_excl, 'jquery.min.js' ) ) {
106
+ $js_excl .= ', jquery.min.js';
107
+ }
108
+
109
+ if ( false === strpos( $js_excl, 'wp-includes/js/dist' ) ) {
110
+ $js_excl .= ', wp-includes/js/dist';
111
+ }
112
  }
113
+ return $js_excl;
114
+ },
115
+ 13,
116
+ 2
117
+ );
118
  }
119
  }
120
 
classes/autoptimizeConfig.php CHANGED
@@ -64,7 +64,7 @@ class autoptimizeConfig
64
  $this->settings_screen_do_remote_http = apply_filters( 'autoptimize_settingsscreen_remotehttp', $this->settings_screen_do_remote_http );
65
 
66
  if ( $this->is_ao_meta_settings_active() ) {
67
- $metaBox = new autoptimizeMetabox();
68
  }
69
  }
70
 
@@ -100,6 +100,8 @@ class autoptimizeConfig
100
 
101
  public function show_config()
102
  {
 
 
103
  $conf = self::instance();
104
  ?>
105
  <style>
@@ -427,7 +429,7 @@ if ( true === autoptimizeImages::imgopt_active() && true === apply_filters( 'aut
427
  $details = ', ~' . $ao_cache_size . ' total';
428
  }
429
  // translators: Kilobytes + timestamp shown.
430
- printf( __( '%1$s files, totalling %2$s (calculated at %3$s)', 'autoptimize' ), $ao_stat_arr[0], $ao_cache_size, date( 'H:i e', $ao_stat_arr[2] ) );
431
  }
432
  ?>
433
  </td>
@@ -440,7 +442,7 @@ if ( true === autoptimizeImages::imgopt_active() && true === apply_filters( 'aut
440
  <table class="form-table">
441
  <tr valign="top">
442
  <th scope="row"><?php _e( 'Save aggregated script/css as static files?', 'autoptimize' ); ?></th>
443
- <td><label class="cb_label"><input type="checkbox" name="autoptimize_cache_nogzip" <?php echo $conf->get( 'autoptimize_cache_nogzip') ? 'checked="checked" ' : ''; ?>/>
444
  <?php _e( 'By default files saved are static css/js, uncheck this option if your webserver doesn\'t properly handle the compression and expiry.', 'autoptimize' ); ?></label></td>
445
  </tr>
446
  <?php
@@ -814,14 +816,14 @@ if ( true === autoptimizeImages::imgopt_active() && true === apply_filters( 'aut
814
  'autoptimize_js_aggregate' => 0,
815
  'autoptimize_js_defer_not_aggregate' => 1,
816
  'autoptimize_js_defer_inline' => 1,
817
- 'autoptimize_js_exclude' => '', // 'wp-includes/js/dist/, wp-includes/js/tinymce/, js/jquery/jquery.min.js',
818
  'autoptimize_js_trycatch' => 0,
819
  'autoptimize_js_justhead' => 0,
820
  'autoptimize_js_include_inline' => 0,
821
  'autoptimize_js_forcehead' => 0,
822
  'autoptimize_css' => 0,
823
  'autoptimize_css_aggregate' => 0,
824
- 'autoptimize_css_exclude' => '', // admin-bar.min.css, dashicons.min.css, wp-content/cache/, wp-content/uploads/',
825
  'autoptimize_css_justhead' => 0,
826
  'autoptimize_css_include_inline' => 0,
827
  'autoptimize_css_defer' => 0,
@@ -1016,6 +1018,8 @@ if ( true === autoptimizeImages::imgopt_active() && true === apply_filters( 'aut
1016
  /**
1017
  * Returns the post meta AO settings for reuse in different optimizers.
1018
  *
 
 
1019
  * @return bool
1020
  */
1021
  public static function get_post_meta_ao_settings( $optim ) {
@@ -1050,16 +1054,16 @@ if ( true === autoptimizeImages::imgopt_active() && true === apply_filters( 'aut
1050
  } else if ( array_key_exists( 'ao_post_optimize', $_meta_value ) && 'on' !== $_meta_value['ao_post_optimize'] ) {
1051
  // ao entirely off for this page.
1052
  return false;
1053
- } else if ( array_key_exists( $optim, $_meta_value ) && empty( $_meta_value[$optim] ) ) {
1054
  // sub-optimization off for this page.
1055
  return false;
1056
- } else if ( array_key_exists( $optim, $_meta_value ) && 'on' === $_meta_value[$optim] ) {
1057
  // sub-optimization is explictly on.
1058
  return true;
1059
- } else if ( array_key_exists( $optim, $_meta_value ) && in_array( $optim, array( 'ao_post_preload' ) ) && ! empty( $_meta_value[$optim] ) ) {
1060
  // a non-bool metabox optimization (currently only preload field), return value instead of bool.
1061
- return $_meta_value[$optim];
1062
- } else if ( in_array( $optim, array( 'ao_post_preload' ) ) && ( ! array_key_exists( $optim, $_meta_value ) || empty( $_meta_value[$optim] ) ) ) {
1063
  // a non-bool metabox optimization not found or empty, so returning false.
1064
  return false;
1065
  } else {
64
  $this->settings_screen_do_remote_http = apply_filters( 'autoptimize_settingsscreen_remotehttp', $this->settings_screen_do_remote_http );
65
 
66
  if ( $this->is_ao_meta_settings_active() ) {
67
+ $meta_box = new autoptimizeMetabox();
68
  }
69
  }
70
 
100
 
101
  public function show_config()
102
  {
103
+ // phpcs:disable Generic.WhiteSpace.ScopeIndent.IncorrectExact
104
+ // phpcs:disable Generic.WhiteSpace.ScopeIndent.Incorrect
105
  $conf = self::instance();
106
  ?>
107
  <style>
429
  $details = ', ~' . $ao_cache_size . ' total';
430
  }
431
  // translators: Kilobytes + timestamp shown.
432
+ printf( __( '%1$s files, totalling %2$s (calculated at %3$s)', 'autoptimize' ), $ao_stat_arr[0], $ao_cache_size, date( 'H:i e', $ao_stat_arr[2] ) ); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
433
  }
434
  ?>
435
  </td>
442
  <table class="form-table">
443
  <tr valign="top">
444
  <th scope="row"><?php _e( 'Save aggregated script/css as static files?', 'autoptimize' ); ?></th>
445
+ <td><label class="cb_label"><input type="checkbox" name="autoptimize_cache_nogzip" <?php echo $conf->get( 'autoptimize_cache_nogzip' ) ? 'checked="checked" ' : ''; ?>/>
446
  <?php _e( 'By default files saved are static css/js, uncheck this option if your webserver doesn\'t properly handle the compression and expiry.', 'autoptimize' ); ?></label></td>
447
  </tr>
448
  <?php
816
  'autoptimize_js_aggregate' => 0,
817
  'autoptimize_js_defer_not_aggregate' => 1,
818
  'autoptimize_js_defer_inline' => 1,
819
+ 'autoptimize_js_exclude' => '',
820
  'autoptimize_js_trycatch' => 0,
821
  'autoptimize_js_justhead' => 0,
822
  'autoptimize_js_include_inline' => 0,
823
  'autoptimize_js_forcehead' => 0,
824
  'autoptimize_css' => 0,
825
  'autoptimize_css_aggregate' => 0,
826
+ 'autoptimize_css_exclude' => '',
827
  'autoptimize_css_justhead' => 0,
828
  'autoptimize_css_include_inline' => 0,
829
  'autoptimize_css_defer' => 0,
1018
  /**
1019
  * Returns the post meta AO settings for reuse in different optimizers.
1020
  *
1021
+ * @param string $optim What optimization we need meta setting for.
1022
+ *
1023
  * @return bool
1024
  */
1025
  public static function get_post_meta_ao_settings( $optim ) {
1054
  } else if ( array_key_exists( 'ao_post_optimize', $_meta_value ) && 'on' !== $_meta_value['ao_post_optimize'] ) {
1055
  // ao entirely off for this page.
1056
  return false;
1057
+ } else if ( array_key_exists( $optim, $_meta_value ) && empty( $_meta_value[ $optim ] ) ) {
1058
  // sub-optimization off for this page.
1059
  return false;
1060
+ } else if ( array_key_exists( $optim, $_meta_value ) && 'on' === $_meta_value[ $optim ] ) {
1061
  // sub-optimization is explictly on.
1062
  return true;
1063
+ } else if ( array_key_exists( $optim, $_meta_value ) && in_array( $optim, array( 'ao_post_preload' ) ) && ! empty( $_meta_value[ $optim ] ) ) {
1064
  // a non-bool metabox optimization (currently only preload field), return value instead of bool.
1065
+ return $_meta_value[ $optim ];
1066
+ } else if ( in_array( $optim, array( 'ao_post_preload' ) ) && ( ! array_key_exists( $optim, $_meta_value ) || empty( $_meta_value[ $optim ] ) ) ) {
1067
  // a non-bool metabox optimization not found or empty, so returning false.
1068
  return false;
1069
  } else {
classes/autoptimizeCriticalCSSBase.php CHANGED
@@ -159,10 +159,10 @@ class autoptimizeCriticalCSSBase {
159
  /**
160
  * Log a message via CCSS Core object
161
  *
162
- * @param string $msg
163
- * @param int $lvl
164
  *
165
- * @return void
166
  */
167
  public function log( $msg, $lvl ) {
168
  return $this->_core->ao_ccss_log( $msg, $lvl );
@@ -180,7 +180,7 @@ class autoptimizeCriticalCSSBase {
180
  /**
181
  * Check CCSS contents from Core object
182
  *
183
- * @param string $ccss
184
  *
185
  * @return bool
186
  */
@@ -191,7 +191,7 @@ class autoptimizeCriticalCSSBase {
191
  /**
192
  * Get key status from Core object
193
  *
194
- * @param bool $render
195
  *
196
  * @return array
197
  */
@@ -210,6 +210,10 @@ class autoptimizeCriticalCSSBase {
210
 
211
  /**
212
  * Run enqueue in CCSS Enqueue object
 
 
 
 
213
  */
214
  public function enqueue( $hash = '', $path = '', $type = 'is_page' ) {
215
  // Enqueue is sometimes required on wp-admin requests, load it just-in-time.
@@ -230,7 +234,7 @@ class autoptimizeCriticalCSSBase {
230
  /**
231
  * Get a Critical CSS option
232
  *
233
- * @param string $name The option name
234
  *
235
  * @return mixed
236
  */
@@ -355,7 +359,7 @@ class autoptimizeCriticalCSSBase {
355
  // Attach interval to schedule.
356
  $schedules['ao_ccss'] = array(
357
  'interval' => $intsec,
358
- 'display' => __( 'Every ' . $inttxt . ' (Autoptimize Crit. CSS)' ),
359
  );
360
  return $schedules;
361
  }
@@ -363,7 +367,7 @@ class autoptimizeCriticalCSSBase {
363
  public function create_ao_ccss_dir() {
364
  // Make sure dir to write ao_ccss exists and is writable.
365
  if ( ! is_dir( AO_CCSS_DIR ) ) {
366
- // TODO: use wp_mkdir_p()
367
  $mkdirresp = @mkdir( AO_CCSS_DIR, 0775, true ); // @codingStandardsIgnoreLine
368
  } else {
369
  $mkdirresp = true;
@@ -403,7 +407,7 @@ class autoptimizeCriticalCSSBase {
403
  /**
404
  * Helper function to determine if a rule is MANUAL.
405
  *
406
- * @param array $rule
407
  *
408
  * @return bool
409
  */
@@ -418,12 +422,11 @@ class autoptimizeCriticalCSSBase {
418
  /**
419
  * Scheduled action to check an inactive key. Not part of autoptimizeCriticalCSSCron.php
420
  * to allow us to only load the main cron logic if we have an active key to begin with.
421
- *
422
  */
423
  public function ao_ccss_check_key() {
424
  $ao_ccss_key = $this->get_option( 'key' );
425
  $_result = $this->_core->ao_ccss_key_validation( $ao_ccss_key );
426
- $_resmsg = ( true === $_result) ? 'ok' : 'nok';
427
  $this->log( 'Inactive key checked, result was ' . $_resmsg, 3 );
428
  }
429
  }
159
  /**
160
  * Log a message via CCSS Core object
161
  *
162
+ * @param string $msg Message to log.
163
+ * @param int $lvl Loglevel.
164
  *
165
+ * @return empty
166
  */
167
  public function log( $msg, $lvl ) {
168
  return $this->_core->ao_ccss_log( $msg, $lvl );
180
  /**
181
  * Check CCSS contents from Core object
182
  *
183
+ * @param string $ccss Critical CSS to be checked.
184
  *
185
  * @return bool
186
  */
191
  /**
192
  * Get key status from Core object
193
  *
194
+ * @param bool $render Indicates if key status is to be rendered.
195
  *
196
  * @return array
197
  */
210
 
211
  /**
212
  * Run enqueue in CCSS Enqueue object
213
+ *
214
+ * @param string $hash Hash (default empty).
215
+ * @param string $path Path (default empty).
216
+ * @param string $type (default is_page).
217
  */
218
  public function enqueue( $hash = '', $path = '', $type = 'is_page' ) {
219
  // Enqueue is sometimes required on wp-admin requests, load it just-in-time.
234
  /**
235
  * Get a Critical CSS option
236
  *
237
+ * @param string $name The option name.
238
  *
239
  * @return mixed
240
  */
359
  // Attach interval to schedule.
360
  $schedules['ao_ccss'] = array(
361
  'interval' => $intsec,
362
+ 'display' => sprintf( __( 'Every %s (Autoptimize Crit. CSS)', 'autoptimize' ), $inttxt ),
363
  );
364
  return $schedules;
365
  }
367
  public function create_ao_ccss_dir() {
368
  // Make sure dir to write ao_ccss exists and is writable.
369
  if ( ! is_dir( AO_CCSS_DIR ) ) {
370
+ // TODO: use wp_mkdir_p() ?
371
  $mkdirresp = @mkdir( AO_CCSS_DIR, 0775, true ); // @codingStandardsIgnoreLine
372
  } else {
373
  $mkdirresp = true;
407
  /**
408
  * Helper function to determine if a rule is MANUAL.
409
  *
410
+ * @param array $rule Rule to check.
411
  *
412
  * @return bool
413
  */
422
  /**
423
  * Scheduled action to check an inactive key. Not part of autoptimizeCriticalCSSCron.php
424
  * to allow us to only load the main cron logic if we have an active key to begin with.
 
425
  */
426
  public function ao_ccss_check_key() {
427
  $ao_ccss_key = $this->get_option( 'key' );
428
  $_result = $this->_core->ao_ccss_key_validation( $ao_ccss_key );
429
+ $_resmsg = ( true === $_result ) ? 'ok' : 'nok';
430
  $this->log( 'Inactive key checked, result was ' . $_resmsg, 3 );
431
  }
432
  }
classes/autoptimizeCriticalCSSCore.php CHANGED
@@ -9,6 +9,11 @@ if ( ! defined( 'ABSPATH' ) ) {
9
  }
10
 
11
  class autoptimizeCriticalCSSCore {
 
 
 
 
 
12
  protected $_types = null;
13
 
14
  public function __construct() {
@@ -277,7 +282,8 @@ class autoptimizeCriticalCSSCore {
277
  'bbp_is_topics_created',
278
  'bbp_is_user_home',
279
  'bbp_is_user_home_edit',
280
- ), $this->_types
 
281
  );
282
  }
283
 
@@ -319,7 +325,8 @@ class autoptimizeCriticalCSSCore {
319
  'bp_is_user',
320
  'bp_is_user_profile',
321
  'bp_is_wire',
322
- ), $this->_types
 
323
  );
324
  }
325
 
@@ -331,7 +338,8 @@ class autoptimizeCriticalCSSCore {
331
  'edd_is_failed_transaction_page',
332
  'edd_is_purchase_history_page',
333
  'edd_is_success_page',
334
- ), $this->_types
 
335
  );
336
  }
337
 
@@ -348,7 +356,8 @@ class autoptimizeCriticalCSSCore {
348
  'woo_is_shop',
349
  'woo_is_wc_endpoint_url',
350
  'woo_is_woocommerce',
351
- ), $this->_types
 
352
  );
353
  }
354
  }
@@ -457,15 +466,19 @@ class autoptimizeCriticalCSSCore {
457
  // Prepare the request.
458
  $url = esc_url_raw( AO_CCSS_API . 'generate' );
459
  $args = array(
460
- 'headers' => apply_filters( 'autoptimize_ccss_cron_api_generate_headers', array(
461
- 'User-Agent' => 'Autoptimize v' . AO_CCSS_VER,
462
- 'Content-type' => 'application/json; charset=utf-8',
463
- 'Authorization' => 'JWT ' . $key,
464
- 'Connection' => 'close',
465
- ) ),
 
 
 
466
  // Body must be JSON.
467
  'body' => json_encode(
468
- apply_filters( 'autoptimize_ccss_cron_api_generate_body',
 
469
  array(
470
  'url' => $src_url,
471
  'aff' => 1,
@@ -600,7 +613,7 @@ class autoptimizeCriticalCSSCore {
600
  if ( $level ) {
601
 
602
  // Prepare message.
603
- $message = date( 'c' ) . ' - [' . $level . '] ' . htmlentities( $msg ) . '<br>';
604
 
605
  // Write message to log file.
606
  error_log( $message, 3, AO_CCSS_LOG );
9
  }
10
 
11
  class autoptimizeCriticalCSSCore {
12
+ /**
13
+ * Critical CSS page types.
14
+ *
15
+ * @var array
16
+ */
17
  protected $_types = null;
18
 
19
  public function __construct() {
282
  'bbp_is_topics_created',
283
  'bbp_is_user_home',
284
  'bbp_is_user_home_edit',
285
+ ),
286
+ $this->_types
287
  );
288
  }
289
 
325
  'bp_is_user',
326
  'bp_is_user_profile',
327
  'bp_is_wire',
328
+ ),
329
+ $this->_types
330
  );
331
  }
332
 
338
  'edd_is_failed_transaction_page',
339
  'edd_is_purchase_history_page',
340
  'edd_is_success_page',
341
+ ),
342
+ $this->_types
343
  );
344
  }
345
 
356
  'woo_is_shop',
357
  'woo_is_wc_endpoint_url',
358
  'woo_is_woocommerce',
359
+ ),
360
+ $this->_types
361
  );
362
  }
363
  }
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,
613
  if ( $level ) {
614
 
615
  // Prepare message.
616
+ $message = date( 'c' ) . ' - [' . $level . '] ' . htmlentities( $msg ) . '<br>'; // @codingStandardsIgnoreLine
617
 
618
  // Write message to log file.
619
  error_log( $message, 3, AO_CCSS_LOG );
classes/autoptimizeCriticalCSSCron.php CHANGED
@@ -81,7 +81,7 @@ class autoptimizeCriticalCSSCron {
81
  $rtimelimit = $this->criticalcss->get_option( 'rtimelimit' );
82
 
83
  // Initialize counters.
84
- if ( $rtimelimit == 0 ) {
85
  // no time limit set, let's go with 1000 seconds.
86
  $rtimelimit = 1000;
87
  }
@@ -507,12 +507,15 @@ class autoptimizeCriticalCSSCron {
507
  // Prepare the request.
508
  $url = esc_url_raw( AO_CCSS_API . 'generate?aover=' . AO_CCSS_VER );
509
  $args = array(
510
- 'headers' => apply_filters( 'autoptimize_ccss_cron_api_generate_headers', array(
511
- 'User-Agent' => 'Autoptimize v' . AO_CCSS_VER,
512
- 'Content-type' => 'application/json; charset=utf-8',
513
- 'Authorization' => 'JWT ' . $key,
514
- 'Connection' => 'close',
515
- ) ),
 
 
 
516
  'body' => $body,
517
  );
518
 
@@ -582,11 +585,14 @@ class autoptimizeCriticalCSSCron {
582
  // Prepare the request.
583
  $url = AO_CCSS_API . 'results?resultId=' . $jobid;
584
  $args = array(
585
- 'headers' => apply_filters( 'autoptimize_ccss_cron_api_generate_headers', array(
586
- 'User-Agent' => 'Autoptimize CriticalCSS Power-Up v' . AO_CCSS_VER,
587
- 'Authorization' => 'JWT ' . $key,
588
- 'Connection' => 'close',
589
- ) ),
 
 
 
590
  );
591
 
592
  // Dispatch the request and store its response code.
@@ -701,7 +707,7 @@ class autoptimizeCriticalCSSCron {
701
 
702
  // Prepare rule variables.
703
  $trule = explode( '|', $srule );
704
- if ( array_key_exists( $trule[1], $rules[$trule[0]] ) ) {
705
  $rule = $rules[ $trule[0] ][ $trule[1] ];
706
  } else {
707
  $rule = array();
@@ -720,7 +726,7 @@ class autoptimizeCriticalCSSCron {
720
  $rule['file'] = $file;
721
  $action = 'UPDATED';
722
  $rtype = 'AUTO';
723
- } elseif ( is_array( $rule ) && 0 !== $rule['hash'] && ctype_alnum( $rule['hash'] ) ) {
724
  // If this is an genuine AUTO rule, update its hash and filename
725
  // Set rule hash, file and action flag.
726
  $rule['hash'] = $hash;
81
  $rtimelimit = $this->criticalcss->get_option( 'rtimelimit' );
82
 
83
  // Initialize counters.
84
+ if ( 0 == $rtimelimit ) {
85
  // no time limit set, let's go with 1000 seconds.
86
  $rtimelimit = 1000;
87
  }
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
 
585
  // Prepare the request.
586
  $url = AO_CCSS_API . 'results?resultId=' . $jobid;
587
  $args = array(
588
+ 'headers' => apply_filters(
589
+ 'autoptimize_ccss_cron_api_generate_headers',
590
+ array(
591
+ 'User-Agent' => 'Autoptimize CriticalCSS Power-Up v' . AO_CCSS_VER,
592
+ 'Authorization' => 'JWT ' . $key,
593
+ 'Connection' => 'close',
594
+ )
595
+ ),
596
  );
597
 
598
  // Dispatch the request and store its response code.
707
 
708
  // Prepare rule variables.
709
  $trule = explode( '|', $srule );
710
+ if ( array_key_exists( $trule[1], $rules[ $trule[0] ] ) ) {
711
  $rule = $rules[ $trule[0] ][ $trule[1] ];
712
  } else {
713
  $rule = array();
726
  $rule['file'] = $file;
727
  $action = 'UPDATED';
728
  $rtype = 'AUTO';
729
+ } elseif ( is_array( $rule ) && 0 !== $rule['hash'] && ctype_alnum( $rule['hash'] ) ) {
730
  // If this is an genuine AUTO rule, update its hash and filename
731
  // Set rule hash, file and action flag.
732
  $rule['hash'] = $hash;
classes/autoptimizeCriticalCSSEnqueue.php CHANGED
@@ -22,13 +22,13 @@ class autoptimizeCriticalCSSEnqueue {
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 ) ) ) {
27
  $enqueue = false;
28
- $this->criticalcss->log( "Job queuing is not available for WordPress's logged in users, feeds, error pages, ajax calls or calls from criticalcss.com itself.", 3 );
29
  } elseif ( empty( $hash ) && empty( $path ) || ( ( 'is_single' !== $type ) && ( 'is_page' !== $type ) ) ) {
30
  $enqueue = false;
31
- $this->criticalcss->log( "Forced job queuing failed, no path or not right type", 3 );
32
  }
33
 
34
  if ( ! $enqueue ) {
@@ -48,7 +48,7 @@ class autoptimizeCriticalCSSEnqueue {
48
  $req_type = $this->ao_ccss_get_type();
49
  } elseif ( ! empty( $path ) ) {
50
  $req_orig = $path;
51
- if ( $path === '/' ) {
52
  $req_type = 'is_front_page';
53
  } else {
54
  $req_type = $type;
@@ -63,7 +63,7 @@ class autoptimizeCriticalCSSEnqueue {
63
  if ( apply_filters( 'autoptimize_filter_ccss_coreenqueue_honor_lang', false ) && strpos( $req_orig, 'lang=' ) !== false ) {
64
  $req_params = strtok( '?' );
65
  parse_str( $req_params, $req_params_arr );
66
- if ( array_key_exists( 'lang', $req_params_arr ) && !empty( $req_params_arr['lang'] ) ) {
67
  $req_path .= '?lang=' . $req_params_arr['lang'];
68
  }
69
  }
@@ -128,7 +128,7 @@ class autoptimizeCriticalCSSEnqueue {
128
  // Should we switch to path-base AUTO-rules? Conditions:
129
  // 1. forcepath option has to be enabled (off by default)
130
  // 2. request type should be (by default, but filterable) one of is_page (removed for now: woo_is_product or woo_is_product_category).
131
- if ( ( $forcepath && in_array( $req_type, apply_filters( 'autoptimize_filter_ccss_coreenqueue_forcepathfortype', array( 'is_page' ) ) ) ) || apply_filters( 'autoptimize_filter_ccss_coreenqueue_ignorealltypes', false ) || empty( $hash )) {
132
  if ( '/' !== $req_path ) {
133
  $target_rule = 'paths|' . $req_path;
134
  } else {
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 ) ) ) {
27
  $enqueue = false;
28
+ $this->criticalcss->log( 'Job queuing is not available for WordPress\'s logged in users, feeds, error pages, ajax calls or calls from criticalcss.com itself.', 3 );
29
  } elseif ( empty( $hash ) && empty( $path ) || ( ( 'is_single' !== $type ) && ( 'is_page' !== $type ) ) ) {
30
  $enqueue = false;
31
+ $this->criticalcss->log( 'Forced job queuing failed, no path or not right type', 3 );
32
  }
33
 
34
  if ( ! $enqueue ) {
48
  $req_type = $this->ao_ccss_get_type();
49
  } elseif ( ! empty( $path ) ) {
50
  $req_orig = $path;
51
+ if ( '/' === $path ) {
52
  $req_type = 'is_front_page';
53
  } else {
54
  $req_type = $type;
63
  if ( apply_filters( 'autoptimize_filter_ccss_coreenqueue_honor_lang', false ) && strpos( $req_orig, 'lang=' ) !== false ) {
64
  $req_params = strtok( '?' );
65
  parse_str( $req_params, $req_params_arr );
66
+ if ( array_key_exists( 'lang', $req_params_arr ) && ! empty( $req_params_arr['lang'] ) ) {
67
  $req_path .= '?lang=' . $req_params_arr['lang'];
68
  }
69
  }
128
  // Should we switch to path-base AUTO-rules? Conditions:
129
  // 1. forcepath option has to be enabled (off by default)
130
  // 2. request type should be (by default, but filterable) one of is_page (removed for now: woo_is_product or woo_is_product_category).
131
+ if ( ( $forcepath && in_array( $req_type, apply_filters( 'autoptimize_filter_ccss_coreenqueue_forcepathfortype', array( 'is_page' ) ) ) ) || apply_filters( 'autoptimize_filter_ccss_coreenqueue_ignorealltypes', false ) || empty( $hash ) ) {
132
  if ( '/' !== $req_path ) {
133
  $target_rule = 'paths|' . $req_path;
134
  } else {
classes/autoptimizeCriticalCSSSettings.php CHANGED
@@ -160,10 +160,10 @@ class autoptimizeCriticalCSSSettings {
160
  if ( ! empty( $ao_ccss_key ) && ! $ao_css_defer && empty( $ao_ccss_keyst ) ) {
161
  // no keystate so likely in activation-process of CCSS, let's enable "inline & defer CSS" immediately to make things easier!
162
  autoptimizeOptionWrapper::update_option( 'autoptimize_css_defer', 'on' );
163
- ?>
164
  <div class="notice-info notice"><p>
165
  <?php
166
- _e( "The \"Eliminate render-blocking CSS\" option was activated to allow critical CSS to be used.", 'autoptimize' );
167
  ?>
168
  </p></div>
169
  <?php
@@ -266,8 +266,8 @@ class autoptimizeCriticalCSSSettings {
266
  }
267
 
268
  // warn if too many rules (based on length of ao_ccss_rules option) as that might cause issues at e.g. wpengine
269
- // see https://wpengine.com/support/database-optimization-best-practices/#Autoloaded_Data
270
- $_raw_rules_length = strlen( get_option( 'autoptimize_ccss_rules', '') );
271
  if ( $_raw_rules_length > apply_filters( 'autoptimize_ccss_rules_length_warning', 500000 ) ) {
272
  ?>
273
  <div class="notice-warning notice"><p>
@@ -331,7 +331,7 @@ class autoptimizeCriticalCSSSettings {
331
  echo '<input class="hidden" name="autoptimize_ccss_debug" value="' . esc_attr( $ao_ccss_debug ) . '">';
332
  echo '<input class="hidden" name="autoptimize_ccss_noptimize" value="' . esc_attr( $ao_ccss_noptimize ) . '">';
333
  echo '<input class="hidden" name="autoptimize_css_defer_inline" value="' . esc_attr( $ao_css_defer_inline ) . '">';
334
- echo '<input class="hidden" name="autoptimize_ccss_loggedin" value="' . esc_attr( $ao_ccss_loggedin ). '">';
335
  echo '<input class="hidden" name="autoptimize_ccss_forcepath" value="' . esc_attr( $ao_ccss_forcepath ) . '">';
336
  echo '<input class="hidden" name="autoptimize_ccss_domain" id="autoptimize_ccss_domain" value="' . esc_attr( $ao_ccss_domain ) . '">';
337
  }
@@ -357,7 +357,7 @@ class autoptimizeCriticalCSSSettings {
357
  });
358
  }
359
  </script>
360
- <form id="importSettingsForm"<?php if ( $this->is_multisite_network_admin() ) { echo ' class="hidden"'; } ?>>
361
  <span id="exportSettings" class="button-secondary"><?php _e( 'Export Settings', 'autoptimize' ); ?></span>
362
  <input class="button-secondary" id="importSettings" type="button" value="<?php _e( 'Import Settings', 'autoptimize' ); ?>" onclick="upload();return false;" />
363
  <input class="button-secondary" id="settingsfile" name="settingsfile" type="file" />
@@ -369,14 +369,14 @@ class autoptimizeCriticalCSSSettings {
369
  if ( ! $this->is_multisite_network_admin() ) {
370
  // Include debug panel if debug mode is enable.
371
  if ( $ao_ccss_debug ) {
372
- ?>
373
  <div id="debug">
374
  <?php
375
  // Include debug panel.
376
  include( 'critcss-inc/admin_settings_debug.php' );
377
  ?>
378
  </div><!-- /#debug -->
379
- <?php
380
  }
381
  echo '<script>';
382
  include( 'critcss-inc/admin_settings_rules.js.php' );
160
  if ( ! empty( $ao_ccss_key ) && ! $ao_css_defer && empty( $ao_ccss_keyst ) ) {
161
  // no keystate so likely in activation-process of CCSS, let's enable "inline & defer CSS" immediately to make things easier!
162
  autoptimizeOptionWrapper::update_option( 'autoptimize_css_defer', 'on' );
163
+ ?>
164
  <div class="notice-info notice"><p>
165
  <?php
166
+ _e( 'The "Eliminate render-blocking CSS" option was activated to allow critical CSS to be used.', 'autoptimize' );
167
  ?>
168
  </p></div>
169
  <?php
266
  }
267
 
268
  // warn if too many rules (based on length of ao_ccss_rules option) as that might cause issues at e.g. wpengine
269
+ // see https://wpengine.com/support/database-optimization-best-practices/#Autoloaded_Data .
270
+ $_raw_rules_length = strlen( get_option( 'autoptimize_ccss_rules', '' ) );
271
  if ( $_raw_rules_length > apply_filters( 'autoptimize_ccss_rules_length_warning', 500000 ) ) {
272
  ?>
273
  <div class="notice-warning notice"><p>
331
  echo '<input class="hidden" name="autoptimize_ccss_debug" value="' . esc_attr( $ao_ccss_debug ) . '">';
332
  echo '<input class="hidden" name="autoptimize_ccss_noptimize" value="' . esc_attr( $ao_ccss_noptimize ) . '">';
333
  echo '<input class="hidden" name="autoptimize_css_defer_inline" value="' . esc_attr( $ao_css_defer_inline ) . '">';
334
+ echo '<input class="hidden" name="autoptimize_ccss_loggedin" value="' . esc_attr( $ao_ccss_loggedin ) . '">';
335
  echo '<input class="hidden" name="autoptimize_ccss_forcepath" value="' . esc_attr( $ao_ccss_forcepath ) . '">';
336
  echo '<input class="hidden" name="autoptimize_ccss_domain" id="autoptimize_ccss_domain" value="' . esc_attr( $ao_ccss_domain ) . '">';
337
  }
357
  });
358
  }
359
  </script>
360
+ <form id="importSettingsForm"<?php if ( $this->is_multisite_network_admin() ) { echo ' class="hidden"'; } // @codingStandardsIgnoreLine ?>>
361
  <span id="exportSettings" class="button-secondary"><?php _e( 'Export Settings', 'autoptimize' ); ?></span>
362
  <input class="button-secondary" id="importSettings" type="button" value="<?php _e( 'Import Settings', 'autoptimize' ); ?>" onclick="upload();return false;" />
363
  <input class="button-secondary" id="settingsfile" name="settingsfile" type="file" />
369
  if ( ! $this->is_multisite_network_admin() ) {
370
  // Include debug panel if debug mode is enable.
371
  if ( $ao_ccss_debug ) {
372
+ ?>
373
  <div id="debug">
374
  <?php
375
  // Include debug panel.
376
  include( 'critcss-inc/admin_settings_debug.php' );
377
  ?>
378
  </div><!-- /#debug -->
379
+ <?php
380
  }
381
  echo '<script>';
382
  include( 'critcss-inc/admin_settings_rules.js.php' );
classes/autoptimizeCriticalCSSSettingsAjax.php CHANGED
@@ -88,11 +88,13 @@ class autoptimizeCriticalCSSSettingsAjax {
88
  $status = file_put_contents( $critcssfile, $critcsscontents, LOCK_EX );
89
  // Or set as error.
90
  } else {
91
- $error = true;
 
92
  }
93
  // Or just set an error.
94
  } else {
95
- $error = true;
 
96
  }
97
 
98
  // Prepare response.
@@ -104,7 +106,7 @@ class autoptimizeCriticalCSSSettingsAjax {
104
  if ( $critcssfile ) {
105
  $response['string'] = 'File ' . $critcssfile . ' saved.';
106
  } else {
107
- $response['string'] = 'Empty content do not need to be saved.';
108
  }
109
  }
110
 
@@ -235,7 +237,7 @@ class autoptimizeCriticalCSSSettingsAjax {
235
  $settings['js']['forcehead'] = get_option( 'autoptimize_js_forcehead' );
236
  $settings['js']['justhead'] = get_option( 'autoptimize_js_justhead' );
237
  $settings['js']['trycatch'] = get_option( 'autoptimize_js_trycatch' );
238
- $settings['js']['include_inline'] = get_option( 'autoptimize_js_include_inline');
239
 
240
  // CSS settings.
241
  $settings['css']['root'] = get_option( 'autoptimize_css' );
@@ -280,7 +282,7 @@ class autoptimizeCriticalCSSSettingsAjax {
280
  }
281
 
282
  // Prepare archive.
283
- $zipfile = AO_CCSS_DIR . str_replace( array('.', '/'), '_', parse_url( AUTOPTIMIZE_WP_SITE_URL, PHP_URL_HOST ) ) . '_' . date( 'Ymd-H\hi' ) . '_ao_ccss_settings.zip';
284
  $file = pathinfo( $zipfile, PATHINFO_BASENAME );
285
  $zip = new ZipArchive();
286
  $ret = $zip->open( $zipfile, ZipArchive::CREATE );
@@ -298,7 +300,7 @@ class autoptimizeCriticalCSSSettingsAjax {
298
  $zip->addGlob( AO_CCSS_DIR . '*.css', 0, $options );
299
  $zip->close();
300
  }
301
-
302
  // settings.json has been added to zipfile, so can be removed now.
303
  if ( file_exists( $exportfile ) ) {
304
  unlink( $exportfile );
@@ -344,9 +346,9 @@ class autoptimizeCriticalCSSSettingsAjax {
344
  $zip = new ZipArchive;
345
  if ( $zip->open( $zipfile ) === true ) {
346
  // loop through all files in the zipfile.
347
- for ($i = 0; $i < $zip->numFiles; $i++) {
348
  // but only extract known good files.
349
- if ( preg_match('/^settings\.json$|^\.\/ccss_[a-z0-9]{32}\.css$/', $zip->getNameIndex( $i ) ) > 0 ) {
350
  $zip->extractTo( AO_CCSS_DIR, $zip->getNameIndex( $i ) );
351
  }
352
  }
@@ -373,7 +375,7 @@ class autoptimizeCriticalCSSSettingsAjax {
373
  if ( false === array_key_exists( 'ccss', $settings ) || false === array_key_exists( $ccss_setting, $settings['ccss'] ) ) {
374
  continue;
375
  } else {
376
- update_option( 'autoptimize_ccss_' . $ccss_setting, $settings['ccss'][$ccss_setting] );
377
  }
378
  }
379
 
@@ -384,7 +386,7 @@ class autoptimizeCriticalCSSSettingsAjax {
384
  } else if ( 'root' === $js_setting ) {
385
  update_option( 'autoptimize_js', $settings['js']['root'] );
386
  } else {
387
- update_option( 'autoptimize_js_' . $js_setting, $settings['js'][$js_setting] );
388
  }
389
  }
390
 
@@ -395,7 +397,7 @@ class autoptimizeCriticalCSSSettingsAjax {
395
  } else if ( 'root' === $css_setting ) {
396
  update_option( 'autoptimize_css', $settings['css']['root'] );
397
  } else {
398
- update_option( 'autoptimize_css_' . $css_setting, $settings['css'][$css_setting] );
399
  }
400
  }
401
 
@@ -404,7 +406,7 @@ class autoptimizeCriticalCSSSettingsAjax {
404
  if ( false === array_key_exists( 'other', $settings ) || false === array_key_exists( $other_setting, $settings['other'] ) ) {
405
  continue;
406
  } else {
407
- update_option( $other_setting, $settings['other'][$other_setting] );
408
  }
409
  }
410
 
@@ -413,7 +415,7 @@ class autoptimizeCriticalCSSSettingsAjax {
413
  update_option( 'autoptimize_pro_boosters', $settings['pro']['boosters'] );
414
  update_option( 'autoptimize_pro_pagecache', $settings['pro']['pagecache'] );
415
  }
416
-
417
  // settings.json has been imported, so can be removed now.
418
  if ( file_exists( $importfile ) ) {
419
  unlink( $importfile );
@@ -475,7 +477,7 @@ class autoptimizeCriticalCSSSettingsAjax {
475
  // save rules over AJAX, too many users forget to press "save changes".
476
  if ( current_user_can( 'manage_options' ) ) {
477
  if ( array_key_exists( 'critcssrules', $_POST ) ) {
478
- $rules = stripslashes( $_POST['critcssrules'] ); // ugly, but seems correct as per https://developer.wordpress.org/reference/functions/stripslashes_deep/#comment-1045
479
  if ( ! empty( $rules ) ) {
480
  $_unsafe_rules_array = json_decode( wp_strip_all_tags( $rules ), true );
481
  if ( ! empty( $_unsafe_rules_array ) && is_array( $_unsafe_rules_array ) ) {
@@ -536,7 +538,7 @@ class autoptimizeCriticalCSSSettingsAjax {
536
  public function rrmdir( $path ) {
537
  // recursively remove a directory as found on
538
  // https://andy-carter.com/blog/recursively-remove-a-directory-in-php.
539
- $files = glob($path . '/*');
540
  foreach ( $files as $file ) {
541
  is_dir( $file ) ? $this->rrmdir( $file ) : unlink( $file );
542
  }
88
  $status = file_put_contents( $critcssfile, $critcsscontents, LOCK_EX );
89
  // Or set as error.
90
  } else {
91
+ $error = true;
92
+ $critcssfile = 'CCSS content not acceptable.';
93
  }
94
  // Or just set an error.
95
  } else {
96
+ $error = true;
97
+ $critcssfile = 'Not allowed or problem with CCSS filename.';
98
  }
99
 
100
  // Prepare response.
106
  if ( $critcssfile ) {
107
  $response['string'] = 'File ' . $critcssfile . ' saved.';
108
  } else {
109
+ $response['string'] = 'Empty content does not need to be saved.';
110
  }
111
  }
112
 
237
  $settings['js']['forcehead'] = get_option( 'autoptimize_js_forcehead' );
238
  $settings['js']['justhead'] = get_option( 'autoptimize_js_justhead' );
239
  $settings['js']['trycatch'] = get_option( 'autoptimize_js_trycatch' );
240
+ $settings['js']['include_inline'] = get_option( 'autoptimize_js_include_inline' );
241
 
242
  // CSS settings.
243
  $settings['css']['root'] = get_option( 'autoptimize_css' );
282
  }
283
 
284
  // Prepare archive.
285
+ $zipfile = AO_CCSS_DIR . str_replace( array( '.', '/' ), '_', parse_url( AUTOPTIMIZE_WP_SITE_URL, PHP_URL_HOST ) ) . '_' . date( 'Ymd-H\hi' ) . '_ao_ccss_settings.zip'; // @codingStandardsIgnoreLine
286
  $file = pathinfo( $zipfile, PATHINFO_BASENAME );
287
  $zip = new ZipArchive();
288
  $ret = $zip->open( $zipfile, ZipArchive::CREATE );
300
  $zip->addGlob( AO_CCSS_DIR . '*.css', 0, $options );
301
  $zip->close();
302
  }
303
+
304
  // settings.json has been added to zipfile, so can be removed now.
305
  if ( file_exists( $exportfile ) ) {
306
  unlink( $exportfile );
346
  $zip = new ZipArchive;
347
  if ( $zip->open( $zipfile ) === true ) {
348
  // loop through all files in the zipfile.
349
+ for ( $i = 0; $i < $zip->numFiles; $i++ ) { // @codingStandardsIgnoreLine
350
  // but only extract known good files.
351
+ if ( preg_match( '/^settings\.json$|^\.\/ccss_[a-z0-9]{32}\.css$/', $zip->getNameIndex( $i ) ) > 0 ) {
352
  $zip->extractTo( AO_CCSS_DIR, $zip->getNameIndex( $i ) );
353
  }
354
  }
375
  if ( false === array_key_exists( 'ccss', $settings ) || false === array_key_exists( $ccss_setting, $settings['ccss'] ) ) {
376
  continue;
377
  } else {
378
+ update_option( 'autoptimize_ccss_' . $ccss_setting, $settings['ccss'][ $ccss_setting ] );
379
  }
380
  }
381
 
386
  } else if ( 'root' === $js_setting ) {
387
  update_option( 'autoptimize_js', $settings['js']['root'] );
388
  } else {
389
+ update_option( 'autoptimize_js_' . $js_setting, $settings['js'][ $js_setting ] );
390
  }
391
  }
392
 
397
  } else if ( 'root' === $css_setting ) {
398
  update_option( 'autoptimize_css', $settings['css']['root'] );
399
  } else {
400
+ update_option( 'autoptimize_css_' . $css_setting, $settings['css'][ $css_setting ] );
401
  }
402
  }
403
 
406
  if ( false === array_key_exists( 'other', $settings ) || false === array_key_exists( $other_setting, $settings['other'] ) ) {
407
  continue;
408
  } else {
409
+ update_option( $other_setting, $settings['other'][ $other_setting ] );
410
  }
411
  }
412
 
415
  update_option( 'autoptimize_pro_boosters', $settings['pro']['boosters'] );
416
  update_option( 'autoptimize_pro_pagecache', $settings['pro']['pagecache'] );
417
  }
418
+
419
  // settings.json has been imported, so can be removed now.
420
  if ( file_exists( $importfile ) ) {
421
  unlink( $importfile );
477
  // save rules over AJAX, too many users forget to press "save changes".
478
  if ( current_user_can( 'manage_options' ) ) {
479
  if ( array_key_exists( 'critcssrules', $_POST ) ) {
480
+ $rules = stripslashes( $_POST['critcssrules'] ); // ugly, but seems correct as per https://developer.wordpress.org/reference/functions/stripslashes_deep/#comment-1045 .
481
  if ( ! empty( $rules ) ) {
482
  $_unsafe_rules_array = json_decode( wp_strip_all_tags( $rules ), true );
483
  if ( ! empty( $_unsafe_rules_array ) && is_array( $_unsafe_rules_array ) ) {
538
  public function rrmdir( $path ) {
539
  // recursively remove a directory as found on
540
  // https://andy-carter.com/blog/recursively-remove-a-directory-in-php.
541
+ $files = glob( $path . '/*' );
542
  foreach ( $files as $file ) {
543
  is_dir( $file ) ? $this->rrmdir( $file ) : unlink( $file );
544
  }
classes/autoptimizeExitSurvey.php CHANGED
@@ -12,7 +12,7 @@ class autoptimizeExitSurvey
12
  function __construct() {
13
  global $pagenow;
14
 
15
- if ( $pagenow != 'plugins.php' ) {
16
  return;
17
  }
18
 
@@ -21,10 +21,7 @@ class autoptimizeExitSurvey
21
  }
22
 
23
  function enqueue_survey_scripts() {
24
- wp_enqueue_script( 'ao_exit_survey', plugins_url( '/static/exit-survey/exit-survey.js', __FILE__ ), array(
25
- 'jquery'
26
- ), AUTOPTIMIZE_PLUGIN_VERSION );
27
-
28
  wp_enqueue_style( 'ao_exit_survey', plugins_url( '/static/exit-survey/exit-survey.css', __FILE__ ), null, AUTOPTIMIZE_PLUGIN_VERSION );
29
  }
30
 
@@ -32,12 +29,12 @@ class autoptimizeExitSurvey
32
  global $wp_version;
33
 
34
  $data = array(
35
- "home" => home_url(),
36
- "dest" => 'aHR0cHM6Ly9taXNjLm9wdGltaXppbmdtYXR0ZXJzLmNvbS9hb19leGl0X3N1cnZleS9pbmRleC5waHA='
37
  );
38
  ?>
39
 
40
- <div class="ao-plugin-uninstall-feedback-popup ao-feedback" id="ao_uninstall_feedback_popup" data-modal="<?php echo base64_encode( json_encode( $data ) ) ?>">
41
  <div class="popup--header">
42
  <h5><?php _e( 'Sorry to see you go!', 'autoptimize' ); ?></h5>
43
  </div><!--/.popup--header-->
@@ -86,12 +83,11 @@ class autoptimizeExitSurvey
86
  <div class="popup--footer">
87
  <div class="actions">
88
  <a href="#" class="info-disclosure-link"><?php _e( 'What info do we collect?', 'autoptimize' ); ?></a>
89
- <div class="info-disclosure-content"><p><?php _e( 'Below is a detailed view of all data that Optimizing Matters will receive if
90
- you fill in this survey. Your email address is only shared if you explicitly fill it in, your IP addres is never sent.', 'autoptimize' ); ?></p>
91
  <ul>
92
- <li><strong><?php _e( 'Plugin version', 'autoptimize' ); ?> </strong> <code id="ao_plugin_version"> <?php echo AUTOPTIMIZE_PLUGIN_VERSION ?> </code></li>
93
- <li><strong><?php _e( 'WordPress version', 'autoptimize' ); ?> </strong> <code id="core_version"> <?php echo $wp_version ?> </code></li>
94
- <li><strong><?php _e( 'Current website:', 'autoptimize' ); ?></strong> <code> <?php echo trailingslashit(get_site_url()) ?> </code></li>
95
  <li><strong><?php _e( 'Uninstall reason', 'autoptimize' ); ?> </strong> <i> <?php _e( 'Selected reason from the above survey', 'autoptimize' ); ?> </i></li>
96
  </ul>
97
  </div>
@@ -117,5 +113,6 @@ class autoptimizeExitSurvey
117
  </div><!--/.actions-->
118
  </div><!--/.popup--footer-->
119
  </div>
120
- <?php }
 
121
  }
12
  function __construct() {
13
  global $pagenow;
14
 
15
+ if ( 'plugins.php' != $pagenow ) {
16
  return;
17
  }
18
 
21
  }
22
 
23
  function enqueue_survey_scripts() {
24
+ wp_enqueue_script( 'ao_exit_survey', plugins_url( '/static/exit-survey/exit-survey.js', __FILE__ ), array( 'jquery' ), AUTOPTIMIZE_PLUGIN_VERSION );
 
 
 
25
  wp_enqueue_style( 'ao_exit_survey', plugins_url( '/static/exit-survey/exit-survey.css', __FILE__ ), null, AUTOPTIMIZE_PLUGIN_VERSION );
26
  }
27
 
29
  global $wp_version;
30
 
31
  $data = array(
32
+ 'home' => home_url(),
33
+ 'dest' => 'aHR0cHM6Ly9taXNjLm9wdGltaXppbmdtYXR0ZXJzLmNvbS9hb19leGl0X3N1cnZleS9pbmRleC5waHA=',
34
  );
35
  ?>
36
 
37
+ <div class="ao-plugin-uninstall-feedback-popup ao-feedback" id="ao_uninstall_feedback_popup" data-modal="<?php echo base64_encode( json_encode( $data ) ); ?>">
38
  <div class="popup--header">
39
  <h5><?php _e( 'Sorry to see you go!', 'autoptimize' ); ?></h5>
40
  </div><!--/.popup--header-->
83
  <div class="popup--footer">
84
  <div class="actions">
85
  <a href="#" class="info-disclosure-link"><?php _e( 'What info do we collect?', 'autoptimize' ); ?></a>
86
+ <div class="info-disclosure-content"><p><?php _e( 'Below is a detailed view of all data that Optimizing Matters will receive if you fill in this survey. Your email address is only shared if you explicitly fill it in, your IP addres is never sent.', 'autoptimize' ); ?></p>
 
87
  <ul>
88
+ <li><strong><?php _e( 'Plugin version', 'autoptimize' ); ?> </strong> <code id="ao_plugin_version"> <?php echo AUTOPTIMIZE_PLUGIN_VERSION; ?> </code></li>
89
+ <li><strong><?php _e( 'WordPress version', 'autoptimize' ); ?> </strong> <code id="core_version"> <?php echo $wp_version; ?> </code></li>
90
+ <li><strong><?php _e( 'Current website:', 'autoptimize' ); ?></strong> <code> <?php echo trailingslashit( get_site_url() ); ?> </code></li>
91
  <li><strong><?php _e( 'Uninstall reason', 'autoptimize' ); ?> </strong> <i> <?php _e( 'Selected reason from the above survey', 'autoptimize' ); ?> </i></li>
92
  </ul>
93
  </div>
113
  </div><!--/.actions-->
114
  </div><!--/.popup--footer-->
115
  </div>
116
+ <?php
117
+ }
118
  }
classes/autoptimizeExtra.php CHANGED
@@ -428,7 +428,7 @@ class autoptimizeExtra
428
  // iterate through array and add preload link to tmp string.
429
  $preload_output = '';
430
  foreach ( $preloads as $preload ) {
431
- if ( $preload !== filter_var( $preload, FILTER_VALIDATE_URL ) ) {
432
  continue;
433
  }
434
  $preload = esc_url_raw( $preload );
@@ -476,10 +476,13 @@ class autoptimizeExtra
476
  remove_action( 'wp_body_open', 'wp_global_styles_render_svg_filters' );
477
 
478
  if ( true === apply_filters( 'autoptimize_filter_extra_global_styles_and_block_css', true ) ) {
479
- add_action( 'wp_enqueue_scripts', function(){
480
- wp_dequeue_style( 'wp-block-library' );
481
- wp_dequeue_style( 'wp-block-library-theme' );
482
- });
 
 
 
483
  }
484
  }
485
 
@@ -510,6 +513,8 @@ class autoptimizeExtra
510
 
511
  public function options_page()
512
  {
 
 
513
  // Working with actual option values from the database here.
514
  // That way any saves are still processed as expected, but we can still
515
  // override behavior by using `new autoptimizeExtra($custom_options)` and not have that custom
428
  // iterate through array and add preload link to tmp string.
429
  $preload_output = '';
430
  foreach ( $preloads as $preload ) {
431
+ if ( filter_var( $preload, FILTER_VALIDATE_URL ) !== $preload ) {
432
  continue;
433
  }
434
  $preload = esc_url_raw( $preload );
476
  remove_action( 'wp_body_open', 'wp_global_styles_render_svg_filters' );
477
 
478
  if ( true === apply_filters( 'autoptimize_filter_extra_global_styles_and_block_css', true ) ) {
479
+ add_action(
480
+ 'wp_enqueue_scripts',
481
+ function() {
482
+ wp_dequeue_style( 'wp-block-library' );
483
+ wp_dequeue_style( 'wp-block-library-theme' );
484
+ }
485
+ );
486
  }
487
  }
488
 
513
 
514
  public function options_page()
515
  {
516
+ // phpcs:disable Squiz.ControlStructures.ControlSignature.NewlineAfterOpenBrace
517
+
518
  // Working with actual option values from the database here.
519
  // That way any saves are still processed as expected, but we can still
520
  // override behavior by using `new autoptimizeExtra($custom_options)` and not have that custom
classes/autoptimizeImages.php CHANGED
@@ -61,7 +61,17 @@ class autoptimizeImages
61
 
62
  if ( null === $value['availabilities'] ) {
63
  // We can't seem to check service availability, use mock result with imgopt status UP.
64
- $_mock_settings = array( 'extra_imgopt' => array( 'status' => 'up', 'hosts' => array( '1' => 'https://sp-ao.shortpixel.ai/' ) ), 'critcss' => array( 'status' => 'up' ) );
 
 
 
 
 
 
 
 
 
 
65
  $value['availabilities'] = $_mock_settings;
66
  }
67
  }
@@ -194,6 +204,10 @@ class autoptimizeImages
194
  /**
195
  * Disables core's native lazyload for images, not for iframes.
196
  *
 
 
 
 
197
  * @return bool
198
  */
199
  public function should_disable_core_lazyload( $flag = true, $tag = '', $context = '' ) {
@@ -546,7 +560,7 @@ class autoptimizeImages
546
  $height = 180;
547
  }
548
 
549
- // make sure we're not trying to optimize a *.ico file
550
  if ( strpos( $matches[1], '.ico' ) === false ) {
551
  return $this->replace_img_callback( $matches, $width, $height );
552
  } else {
@@ -580,7 +594,7 @@ class autoptimizeImages
580
  // extract img tags.
581
  if ( preg_match_all( '#<img[^>]*src[^>]*>#Usmi', $in, $matches ) ) {
582
  foreach ( $matches[0] as $tag ) {
583
- $tag = apply_filters( 'autoptimize_filter_imgopt_tag_preopt' , $tag );
584
 
585
  $orig_tag = $tag;
586
  $imgopt_w = '';
@@ -639,7 +653,7 @@ class autoptimizeImages
639
  $_url = $this->normalize_img_url( $_url );
640
 
641
  $placeholder = '';
642
- if ( $this->can_optimize_image( $_url, $tag ) && apply_filters( 'autoptimize_filter_imgopt_lazyload_dolqip', true, $_url ) && false === apply_filters( 'autoptimize_filter_imgopt_do_spai', false ) ) {
643
  $lqip_w = '';
644
  $lqip_h = '';
645
  if ( isset( $imgopt_w ) && ! empty( $imgopt_w ) ) {
@@ -659,7 +673,7 @@ class autoptimizeImages
659
  $tag = str_replace( '<img ', '<img decoding="async" ', $tag );
660
  }
661
 
662
- $tag = apply_filters( 'autoptimize_filter_imgopt_tag_postopt' , $tag );
663
 
664
  // and add tag to array for later replacement.
665
  if ( $tag !== $orig_tag ) {
@@ -721,8 +735,8 @@ class autoptimizeImages
721
 
722
  if ( ! empty( $metabox_preloads ) && is_array( $metabox_preloads ) && empty( $to_preload ) && false !== apply_filters( 'autoptimize_filter_imgopt_dopreloads', true ) ) {
723
  // the preload was not in an img tag, so adding a non-responsive preload instead.
724
- foreach( $metabox_preloads as $img_preload ) {
725
- $to_preload .= '<link rel="preload" href="' . $img_preload . '" as="image">' ;
726
  }
727
  }
728
 
@@ -854,8 +868,8 @@ class autoptimizeImages
854
 
855
  if ( ! empty( $metabox_preloads ) && is_array( $metabox_preloads ) && empty( $to_preload ) && false !== apply_filters( 'autoptimize_filter_imgopt_dopreloads', true ) ) {
856
  // the preload was not in an img tag, so adding a non-responsive preload instead.
857
- foreach( $metabox_preloads as $img_preload ) {
858
- $to_preload .= '<link rel="preload" href="' . $img_preload . '" as="image">' ;
859
  }
860
  }
861
 
@@ -921,7 +935,7 @@ class autoptimizeImages
921
  }
922
 
923
  public function add_lazyload_js_footer() {
924
- if ( false === autoptimizeMain::should_buffer() || autoptimizeMain::is_amp_markup('') ) {
925
  return;
926
  }
927
 
@@ -933,7 +947,7 @@ class autoptimizeImages
933
 
934
  $_extra = autoptimizeOptionWrapper::get_option( 'autoptimize_extra_settings', '' );
935
  if ( is_array( $_extra ) && array_key_exists( 'autoptimize_extra_checkbox_field_0', $_extra ) && ! empty( $_extra['autoptimize_extra_checkbox_field_0'] ) ) {
936
- // if "remove query strings" is active in "extra", then let's be consistant and not add one ourselves? :)
937
  $lazysizes_js = plugins_url( 'external/js/lazysizes.min.js', __FILE__ );
938
  } else {
939
  $lazysizes_js = plugins_url( 'external/js/lazysizes.min.js?ao_version=' . AUTOPTIMIZE_PLUGIN_VERSION, __FILE__ );
@@ -971,7 +985,7 @@ class autoptimizeImages
971
 
972
  // and remove title, alt, class and id.
973
  $tag = preg_replace( '/ ((?:title|alt|class|id|loading)=".*")/Um', '', $tag );
974
- if ( $tag !== str_replace( array(' title=', ' class=', ' alt=', ' id=' ), '', $tag ) ) {
975
  // 2nd regex pass if still title/ class/ alt in case single quotes were used iso doubles.
976
  $tag = preg_replace( '/ ((?:title|alt|class|id|loading)=\'.*\')/Um', '', $tag );
977
  }
@@ -1160,6 +1174,9 @@ class autoptimizeImages
1160
 
1161
  public function imgopt_options_page()
1162
  {
 
 
 
1163
  // Check querystring for "refreshCacheChecker" and call cachechecker if so.
1164
  if ( array_key_exists( 'refreshImgProvStats', $_GET ) && 1 == $_GET['refreshImgProvStats'] ) {
1165
  $this->query_img_provider_stats( true );
@@ -1203,12 +1220,12 @@ class autoptimizeImages
1203
  <form id='ao_settings_form' action='<?php echo admin_url( 'options.php' ); ?>' method='post'>
1204
  <?php settings_fields( 'autoptimize_imgopt_settings' ); ?>
1205
  <h2><?php _e( 'Image optimization', 'autoptimize' ); ?></h2>
1206
- <span id='autoptimize_imgopt_descr'><?php _e( 'Make your site significantly faster by just ticking a couple of checkboxes to optimize and lazy load your images, WebP and AVIF support included!', 'autoptimize' ); ?></span>
1207
  <table class="form-table">
1208
  <tr>
1209
  <th scope="row"><?php _e( 'Optimize Images', 'autoptimize' ); ?></th>
1210
  <td>
1211
- <label><input id='autoptimize_imgopt_checkbox' type='checkbox' name='autoptimize_imgopt_settings[autoptimize_imgopt_checkbox_field_1]' <?php if ( ! empty( $options['autoptimize_imgopt_checkbox_field_1'] ) && '1' === $options['autoptimize_imgopt_checkbox_field_1'] ) { echo 'checked="checked"'; } ?> value='1'><?php _e( 'Optimize images on the fly and serve them from Shortpixel\'s global CDN.', 'autoptimize' ); ?></label>
1212
  <?php
1213
  // show shortpixel status.
1214
  $_notice = autoptimizeImages::instance()->get_imgopt_status_notice();
@@ -1238,14 +1255,14 @@ class autoptimizeImages
1238
  // translators: link points to shortpixel.
1239
  $upsell_msg_2 = sprintf( __( '%1$sSign-up now%2$s to receive x2 more CDN traffic or image optimization credits for free! This offer also applies to any future plan that you\'ll choose to purchase.', 'autoptimize' ), '<a href="https://shortpixel.com/aospai' . $sp_url_suffix . '" target="_blank">', '</a>' );
1240
  }
1241
- echo apply_filters( 'autoptimize_imgopt_imgopt_settings_copy', $upsell_msg_1 . ' ' . $upsell_msg_2 . '</p>' );
1242
  }
1243
  // translators: link points to shortpixel FAQ.
1244
  $faqcopy = sprintf( __( '<strong>Questions</strong>? Have a look at the %1$sAutoptimize + ShortPixel FAQ%2$s!', 'autoptimize' ), '<strong><a href="https://help.shortpixel.com/category/405-autoptimize" target="_blank">', '</strong></a>' );
1245
  $faqcopy = $faqcopy . ' ' . __( 'Only works for websites and images that are publicly available.', 'autoptimize' );
1246
  // translators: links points to shortpixel TOS & Privacy Policy.
1247
  $toscopy = sprintf( __( 'Usage of this feature is subject to Shortpixel\'s %1$sTerms of Use%2$s and %3$sPrivacy policy%4$s.', 'autoptimize' ), '<a href="https://shortpixel.com/tos' . $sp_url_suffix . '" target="_blank">', '</a>', '<a href="https://shortpixel.com/pp' . $sp_url_suffix . '" target="_blank">', '</a>' );
1248
- echo apply_filters( 'autoptimize_imgopt_imgopt_settings_tos', '<p>' . $faqcopy . ' ' . $toscopy . '</p>' );
1249
  ?>
1250
  </td>
1251
  </tr>
@@ -1278,17 +1295,27 @@ class autoptimizeImages
1278
  <p>
1279
  <?php
1280
  // translators: link points to shortpixel image test page.
1281
- echo apply_filters( 'autoptimize_imgopt_imgopt_quality_copy', sprintf( __( 'You can %1$stest compression levels here%2$s.', 'autoptimize' ), '<a href="https://shortpixel.com/oic' . $sp_url_suffix . '" target="_blank">', '</a>' ) );
1282
  ?>
1283
  </p>
1284
  </td>
1285
  </tr>
1286
- <tr id='autoptimize_imgopt_ngimg' <?php if ( ! array_key_exists( 'autoptimize_imgopt_checkbox_field_1', $options ) || ( isset( $options['autoptimize_imgopt_checkbox_field_1'] ) && '1' !== $options['autoptimize_imgopt_checkbox_field_1'] ) ) { echo 'class="hidden"'; } ?>>
1287
- <th scope="row"><?php _e( 'Load AVIF in supported browsers?', 'autoptimize' ); ?></th>
1288
- <td>
1289
- <label><input type='checkbox' id='autoptimize_imgopt_ngimg_checkbox' name='autoptimize_imgopt_settings[autoptimize_imgopt_checkbox_field_4]' <?php if ( ! empty( $options['autoptimize_imgopt_checkbox_field_4'] ) && '1' === $options['autoptimize_imgopt_checkbox_field_4'] ) { echo 'checked="checked"'; } ?> value='1'><?php _e( 'Automatically serve AVIF image format to any browser that supports it.', 'autoptimize' ); ?></label>
1290
- </td>
1291
- </tr>
 
 
 
 
 
 
 
 
 
 
1292
  <tr>
1293
  <th scope="row"><?php _e( 'Lazy-load images?', 'autoptimize' ); ?></th>
1294
  <td>
@@ -1339,7 +1366,7 @@ class autoptimizeImages
1339
  * Ïmg opt status as used on dashboard.
1340
  */
1341
  public function get_imgopt_status_notice() {
1342
- if ( $this->imgopt_active() ) {
1343
  $_imgopt_notice = '';
1344
  $_stat = autoptimizeOptionWrapper::get_option( 'autoptimize_imgopt_provider_stat', '' );
1345
  $_site_host = AUTOPTIMIZE_SITE_DOMAIN;
@@ -1367,10 +1394,13 @@ class autoptimizeImages
1367
 
1368
  // add info on freshness + refresh link if status is not 2 (good shape).
1369
  if ( 2 != $_stat['Status'] ) {
1370
- $_imgopt_stats_refresh_url = add_query_arg( array(
1371
- 'page' => 'autoptimize_imgopt',
1372
- 'refreshImgProvStats' => '1',
1373
- ), admin_url( 'options-general.php' ) );
 
 
 
1374
  if ( $_stat && array_key_exists( 'timestamp', $_stat ) && ! empty( $_stat['timestamp'] ) ) {
1375
  $_imgopt_stats_last_run = __( 'based on status at ', 'autoptimize' ) . date_i18n( autoptimizeOptionWrapper::get_option( 'time_format' ), $_stat['timestamp'] );
1376
  } else {
@@ -1401,9 +1431,11 @@ class autoptimizeImages
1401
 
1402
  /**
1403
  * Get img provider stats (used to display notice).
 
 
1404
  */
1405
  public function query_img_provider_stats( $_refresh = false ) {
1406
- if ( ! empty( $this->options['autoptimize_imgopt_checkbox_field_1'] ) ) {
1407
  $url = '';
1408
  $stat_dom = 'https://no-cdn.shortpixel.ai/';
1409
  $endpoint = $stat_dom . 'read-domain/';
61
 
62
  if ( null === $value['availabilities'] ) {
63
  // We can't seem to check service availability, use mock result with imgopt status UP.
64
+ $_mock_settings = array(
65
+ 'extra_imgopt' => array(
66
+ 'status' => 'up',
67
+ 'hosts' => array(
68
+ '1' => 'https://sp-ao.shortpixel.ai/',
69
+ ),
70
+ ),
71
+ 'critcss' => array(
72
+ 'status' => 'up',
73
+ ),
74
+ );
75
  $value['availabilities'] = $_mock_settings;
76
  }
77
  }
204
  /**
205
  * Disables core's native lazyload for images, not for iframes.
206
  *
207
+ * @param bool $flag Incoming flag (mostly true).
208
+ * @param string $tag Tag (img or iframe).
209
+ * @param string $context Full context.
210
+ *
211
  * @return bool
212
  */
213
  public function should_disable_core_lazyload( $flag = true, $tag = '', $context = '' ) {
560
  $height = 180;
561
  }
562
 
563
+ // make sure we're not trying to optimize a *.ico file.
564
  if ( strpos( $matches[1], '.ico' ) === false ) {
565
  return $this->replace_img_callback( $matches, $width, $height );
566
  } else {
594
  // extract img tags.
595
  if ( preg_match_all( '#<img[^>]*src[^>]*>#Usmi', $in, $matches ) ) {
596
  foreach ( $matches[0] as $tag ) {
597
+ $tag = apply_filters( 'autoptimize_filter_imgopt_tag_preopt', $tag );
598
 
599
  $orig_tag = $tag;
600
  $imgopt_w = '';
653
  $_url = $this->normalize_img_url( $_url );
654
 
655
  $placeholder = '';
656
+ if ( $this->can_optimize_image( $_url, $tag ) && apply_filters( 'autoptimize_filter_imgopt_lazyload_dolqip', false, $_url ) && false === apply_filters( 'autoptimize_filter_imgopt_do_spai', false ) ) {
657
  $lqip_w = '';
658
  $lqip_h = '';
659
  if ( isset( $imgopt_w ) && ! empty( $imgopt_w ) ) {
673
  $tag = str_replace( '<img ', '<img decoding="async" ', $tag );
674
  }
675
 
676
+ $tag = apply_filters( 'autoptimize_filter_imgopt_tag_postopt', $tag );
677
 
678
  // and add tag to array for later replacement.
679
  if ( $tag !== $orig_tag ) {
735
 
736
  if ( ! empty( $metabox_preloads ) && is_array( $metabox_preloads ) && empty( $to_preload ) && false !== apply_filters( 'autoptimize_filter_imgopt_dopreloads', true ) ) {
737
  // the preload was not in an img tag, so adding a non-responsive preload instead.
738
+ foreach ( $metabox_preloads as $img_preload ) {
739
+ $to_preload .= '<link rel="preload" href="' . $img_preload . '" as="image">';
740
  }
741
  }
742
 
868
 
869
  if ( ! empty( $metabox_preloads ) && is_array( $metabox_preloads ) && empty( $to_preload ) && false !== apply_filters( 'autoptimize_filter_imgopt_dopreloads', true ) ) {
870
  // the preload was not in an img tag, so adding a non-responsive preload instead.
871
+ foreach ( $metabox_preloads as $img_preload ) {
872
+ $to_preload .= '<link rel="preload" href="' . $img_preload . '" as="image">';
873
  }
874
  }
875
 
935
  }
936
 
937
  public function add_lazyload_js_footer() {
938
+ if ( false === autoptimizeMain::should_buffer() || autoptimizeMain::is_amp_markup( '' ) ) {
939
  return;
940
  }
941
 
947
 
948
  $_extra = autoptimizeOptionWrapper::get_option( 'autoptimize_extra_settings', '' );
949
  if ( is_array( $_extra ) && array_key_exists( 'autoptimize_extra_checkbox_field_0', $_extra ) && ! empty( $_extra['autoptimize_extra_checkbox_field_0'] ) ) {
950
+ // if "remove query strings" is active in "extra", then let's be consistant and not add one ourselves :-) ?
951
  $lazysizes_js = plugins_url( 'external/js/lazysizes.min.js', __FILE__ );
952
  } else {
953
  $lazysizes_js = plugins_url( 'external/js/lazysizes.min.js?ao_version=' . AUTOPTIMIZE_PLUGIN_VERSION, __FILE__ );
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
  }
1174
 
1175
  public function imgopt_options_page()
1176
  {
1177
+ // phpcs:disable Squiz.ControlStructures.ControlSignature.NewlineAfterOpenBrace
1178
+ // phpcs:disable Generic.Formatting.DisallowMultipleStatements.SameLine
1179
+
1180
  // Check querystring for "refreshCacheChecker" and call cachechecker if so.
1181
  if ( array_key_exists( 'refreshImgProvStats', $_GET ) && 1 == $_GET['refreshImgProvStats'] ) {
1182
  $this->query_img_provider_stats( true );
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>
1227
  <td>
1228
+ <label><input id='autoptimize_imgopt_checkbox' type='checkbox' name='autoptimize_imgopt_settings[autoptimize_imgopt_checkbox_field_1]' <?php if ( ! empty( $options['autoptimize_imgopt_checkbox_field_1'] ) && '1' === $options['autoptimize_imgopt_checkbox_field_1'] ) { echo 'checked="checked"'; } ?> value='1'><?php echo apply_filters( 'autoptimize_filter_imgopt_main_setting_copy', __( 'Optimize images on the fly and serve them from Shortpixel\'s global CDN.', 'autoptimize' ) ); ?></label>
1229
  <?php
1230
  // show shortpixel status.
1231
  $_notice = autoptimizeImages::instance()->get_imgopt_status_notice();
1255
  // translators: link points to shortpixel.
1256
  $upsell_msg_2 = sprintf( __( '%1$sSign-up now%2$s to receive x2 more CDN traffic or image optimization credits for free! This offer also applies to any future plan that you\'ll choose to purchase.', 'autoptimize' ), '<a href="https://shortpixel.com/aospai' . $sp_url_suffix . '" target="_blank">', '</a>' );
1257
  }
1258
+ echo apply_filters( 'autoptimize_filter_imgopt_settings_copy', $upsell_msg_1 . ' ' . $upsell_msg_2 . '</p>' );
1259
  }
1260
  // translators: link points to shortpixel FAQ.
1261
  $faqcopy = sprintf( __( '<strong>Questions</strong>? Have a look at the %1$sAutoptimize + ShortPixel FAQ%2$s!', 'autoptimize' ), '<strong><a href="https://help.shortpixel.com/category/405-autoptimize" target="_blank">', '</strong></a>' );
1262
  $faqcopy = $faqcopy . ' ' . __( 'Only works for websites and images that are publicly available.', 'autoptimize' );
1263
  // translators: links points to shortpixel TOS & Privacy Policy.
1264
  $toscopy = sprintf( __( 'Usage of this feature is subject to Shortpixel\'s %1$sTerms of Use%2$s and %3$sPrivacy policy%4$s.', 'autoptimize' ), '<a href="https://shortpixel.com/tos' . $sp_url_suffix . '" target="_blank">', '</a>', '<a href="https://shortpixel.com/pp' . $sp_url_suffix . '" target="_blank">', '</a>' );
1265
+ echo apply_filters( 'autoptimize_filter_imgopt_settings_tos', '<p>' . $faqcopy . ' ' . $toscopy . '</p>' );
1266
  ?>
1267
  </td>
1268
  </tr>
1295
  <p>
1296
  <?php
1297
  // translators: link points to shortpixel image test page.
1298
+ echo apply_filters( 'autoptimize_filter_imgopt_quality_copy', sprintf( __( 'You can %1$stest compression levels here%2$s.', 'autoptimize' ), '<a href="https://shortpixel.com/oic' . $sp_url_suffix . '" target="_blank">', '</a>' ) );
1299
  ?>
1300
  </p>
1301
  </td>
1302
  </tr>
1303
+ <?php
1304
+ if ( apply_filters( 'autoptimize_filter_imgopt_settings_show_avif', true ) ) {
1305
+ ?>
1306
+ <tr id='autoptimize_imgopt_ngimg' <?php if ( ! array_key_exists( 'autoptimize_imgopt_checkbox_field_1', $options ) || ( isset( $options['autoptimize_imgopt_checkbox_field_1'] ) && '1' !== $options['autoptimize_imgopt_checkbox_field_1'] ) ) { echo 'class="hidden"'; } ?>>
1307
+ <th scope="row"><?php _e( 'Load AVIF in supported browsers?', 'autoptimize' ); ?></th>
1308
+ <td>
1309
+ <label><input type='checkbox' id='autoptimize_imgopt_ngimg_checkbox' name='autoptimize_imgopt_settings[autoptimize_imgopt_checkbox_field_4]' <?php if ( ! empty( $options['autoptimize_imgopt_checkbox_field_4'] ) && '1' === $options['autoptimize_imgopt_checkbox_field_4'] ) { echo 'checked="checked"'; } ?> value='1'><?php _e( 'Automatically serve AVIF image format to any browser that supports it.', 'autoptimize' ); ?></label>
1310
+ </td>
1311
+ </tr>
1312
+ <?php
1313
+ } else {
1314
+ ?>
1315
+ <input type='hidden' id='autoptimize_imgopt_ngimg_checkbox' name='autoptimize_imgopt_settings[autoptimize_imgopt_checkbox_field_4]' value='0'>
1316
+ <?php
1317
+ }
1318
+ ?>
1319
  <tr>
1320
  <th scope="row"><?php _e( 'Lazy-load images?', 'autoptimize' ); ?></th>
1321
  <td>
1366
  * Ïmg opt status as used on dashboard.
1367
  */
1368
  public function get_imgopt_status_notice() {
1369
+ if ( $this->imgopt_active() && apply_filters( 'autoptimize_filter_imgopt_status_shortpixel', true ) ) {
1370
  $_imgopt_notice = '';
1371
  $_stat = autoptimizeOptionWrapper::get_option( 'autoptimize_imgopt_provider_stat', '' );
1372
  $_site_host = AUTOPTIMIZE_SITE_DOMAIN;
1394
 
1395
  // add info on freshness + refresh link if status is not 2 (good shape).
1396
  if ( 2 != $_stat['Status'] ) {
1397
+ $_imgopt_stats_refresh_url = add_query_arg(
1398
+ array(
1399
+ 'page' => 'autoptimize_imgopt',
1400
+ 'refreshImgProvStats' => '1',
1401
+ ),
1402
+ admin_url( 'options-general.php' )
1403
+ );
1404
  if ( $_stat && array_key_exists( 'timestamp', $_stat ) && ! empty( $_stat['timestamp'] ) ) {
1405
  $_imgopt_stats_last_run = __( 'based on status at ', 'autoptimize' ) . date_i18n( autoptimizeOptionWrapper::get_option( 'time_format' ), $_stat['timestamp'] );
1406
  } else {
1431
 
1432
  /**
1433
  * Get img provider stats (used to display notice).
1434
+ *
1435
+ * @param bool $_refresh Should the stats be forcefully refreshed or not.
1436
  */
1437
  public function query_img_provider_stats( $_refresh = false ) {
1438
+ if ( ! empty( $this->options['autoptimize_imgopt_checkbox_field_1'] ) && apply_filters( 'autoptimize_filter_imgopt_status_shortpixel', true ) ) {
1439
  $url = '';
1440
  $stat_dom = 'https://no-cdn.shortpixel.ai/';
1441
  $endpoint = $stat_dom . 'read-domain/';
classes/autoptimizeMain.php CHANGED
@@ -391,11 +391,11 @@ class autoptimizeMain
391
  }
392
 
393
  // Misc. querystring paramaters that will stop AO from doing optimizations (pagebuilders +
394
- // 2 generic parameters that could/ should become standard between optimization plugins?)
395
  if ( false === $ao_noptimize ) {
396
  $_qs_showstoppers = array( 'no_cache', 'no_optimize', 'tve', 'elementor-preview', 'fl_builder', 'vc_action', 'et_fb', 'bt-beaverbuildertheme', 'ct_builder', 'fb-edit', 'siteorigin_panels_live_editor', 'preview' );
397
 
398
- // doing Jonathan a quick favor to allow correct unused CSS generation ;-)
399
  if ( apply_filters( 'autoptimize_filter_main_showstoppers_do_wp_rocket_a_favor', true ) ) {
400
  $_qs_showstoppers[] = 'nowprocket';
401
  }
@@ -742,7 +742,7 @@ class autoptimizeMain
742
  public static function notice_installed()
743
  {
744
  echo '<div class="updated"><p>';
745
- printf( __( 'Thank you for installing and activating Autoptimize. Please configure it under %sSettings -> Autoptimize%s to start improving your site\'s performance.', 'autoptimize' ), '<a href="options-general.php?page=autoptimize">', '</a>' );
746
  echo '</p></div>';
747
  }
748
 
391
  }
392
 
393
  // Misc. querystring paramaters that will stop AO from doing optimizations (pagebuilders +
394
+ // 2 generic parameters that could/ should become standard between optimization plugins?).
395
  if ( false === $ao_noptimize ) {
396
  $_qs_showstoppers = array( 'no_cache', 'no_optimize', 'tve', 'elementor-preview', 'fl_builder', 'vc_action', 'et_fb', 'bt-beaverbuildertheme', 'ct_builder', 'fb-edit', 'siteorigin_panels_live_editor', 'preview' );
397
 
398
+ // doing Jonathan a quick favor to allow correct unused CSS generation ;-) .
399
  if ( apply_filters( 'autoptimize_filter_main_showstoppers_do_wp_rocket_a_favor', true ) ) {
400
  $_qs_showstoppers[] = 'nowprocket';
401
  }
742
  public static function notice_installed()
743
  {
744
  echo '<div class="updated"><p>';
745
+ printf( __( 'Thank you for installing and activating Autoptimize. Please configure it under %1$sSettings -> Autoptimize%2$s to start improving your site\'s performance.', 'autoptimize' ), '<a href="options-general.php?page=autoptimize">', '</a>' );
746
  echo '</p></div>';
747
  }
748
 
classes/autoptimizeMetabox.php CHANGED
@@ -49,6 +49,8 @@ class autoptimizeMetabox
49
  */
50
  function ao_metabox_content( $post )
51
  {
 
 
52
  wp_nonce_field( 'ao_metabox', 'ao_metabox_nonce' );
53
 
54
  $ao_opt_value = $this->check_ao_opt_sanity( get_post_meta( $post->ID, 'ao_post_optimize', true ) );
@@ -115,18 +117,18 @@ class autoptimizeMetabox
115
  <?php _e( 'Lazyload images?', 'autoptimize' ); ?>
116
  </label>
117
  </p>
118
- <p class="ao_meta_sub" style="<?php echo $_ao_meta_sub_opacity ?>">
119
  <label for="autoptimize_post_preload">
120
  <?php _e( 'LCP Image to preload', 'autoptimize' ); ?>
121
  </label>
122
  <?php
123
- if ( is_array( $ao_opt_value ) && array_key_exists( 'ao_post_preload', $ao_opt_value ) ) {
124
- $_preload_img = esc_attr( $ao_opt_value['ao_post_preload'] );
125
- } else {
126
- $_preload_img = '';
127
- }
128
  ?>
129
- <input type="text" id="autoptimize_post_preload" name="ao_post_preload" value="<?php echo $_preload_img ?>">
130
  </p>
131
  <p>&nbsp;</p>
132
  <p>
@@ -191,12 +193,12 @@ class autoptimizeMetabox
191
  jQuery.post(ajaxurl, data, function(response) {
192
  response_array=JSON.parse(response);
193
  if (response_array['code'] == 200) {
194
- setCritCSSbutton("<?php _e('Added to CCSS job queue.', 'autoptimize' ); ?>", "green");
195
  } else {
196
- setCritCSSbutton("<?php _e('Could not add to CCSS job queue.', 'autoptimize' ); ?>", "orange");
197
  }
198
  }).fail(function() {
199
- setCritCSSbutton("<?php _e('Sorry, something went wrong.', 'autoptimize' ); ?>", "orange");
200
  });
201
  });
202
  });
@@ -243,20 +245,20 @@ class autoptimizeMetabox
243
  }
244
  }
245
 
246
- // OK, we can have a look at the actual data now.
247
- // Sanitize user input.
248
- foreach ( array( 'ao_post_optimize', 'ao_post_js_optimize', 'ao_post_css_optimize', 'ao_post_ccss', 'ao_post_lazyload', 'ao_post_preload' ) as $opti_type ) {
249
- if ( ! isset( $_POST[$opti_type] ) ) {
250
- $ao_meta_result[$opti_type] = '';
251
- } else if ( 'on' === $_POST[$opti_type] ) {
252
- $ao_meta_result[$opti_type] = 'on';
253
- } else if ( in_array( $opti_type, array( 'ao_post_preload' ) ) ) {
254
- $ao_meta_result[$opti_type] = $_POST[$opti_type];
255
- }
256
- }
257
 
258
- // Update the meta field in the database.
259
- update_post_meta( $post_id, 'ao_post_optimize', $ao_meta_result );
260
  }
261
 
262
  public function ao_metabox_generateccss_callback()
@@ -312,7 +314,7 @@ class autoptimizeMetabox
312
  } else {
313
  foreach ( array( 'ao_post_optimize', 'ao_post_js_optimize', 'ao_post_css_optimize', 'ao_post_ccss', 'ao_post_lazyload' ) as $key ) {
314
  if ( ! array_key_exists( $key, $ao_opt_val ) ) {
315
- $ao_opt_val[$key] = 'off';
316
  }
317
  }
318
  }
49
  */
50
  function ao_metabox_content( $post )
51
  {
52
+ // phpcs:disable Squiz.ControlStructures.ControlSignature.NewlineAfterOpenBrace
53
+
54
  wp_nonce_field( 'ao_metabox', 'ao_metabox_nonce' );
55
 
56
  $ao_opt_value = $this->check_ao_opt_sanity( get_post_meta( $post->ID, 'ao_post_optimize', true ) );
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>
124
  <?php
125
+ if ( is_array( $ao_opt_value ) && array_key_exists( 'ao_post_preload', $ao_opt_value ) ) {
126
+ $_preload_img = esc_attr( $ao_opt_value['ao_post_preload'] );
127
+ } else {
128
+ $_preload_img = '';
129
+ }
130
  ?>
131
+ <input type="text" id="autoptimize_post_preload" name="ao_post_preload" value="<?php echo $_preload_img; ?>">
132
  </p>
133
  <p>&nbsp;</p>
134
  <p>
193
  jQuery.post(ajaxurl, data, function(response) {
194
  response_array=JSON.parse(response);
195
  if (response_array['code'] == 200) {
196
+ setCritCSSbutton("<?php _e( 'Added to CCSS job queue.', 'autoptimize' ); ?>", "green");
197
  } else {
198
+ setCritCSSbutton("<?php _e( 'Could not add to CCSS job queue.', 'autoptimize' ); ?>", "orange");
199
  }
200
  }).fail(function() {
201
+ setCritCSSbutton("<?php _e( 'Sorry, something went wrong.', 'autoptimize' ); ?>", "orange");
202
  });
203
  });
204
  });
245
  }
246
  }
247
 
248
+ // OK, we can have a look at the actual data now.
249
+ // Sanitize user input.
250
+ foreach ( array( 'ao_post_optimize', 'ao_post_js_optimize', 'ao_post_css_optimize', 'ao_post_ccss', 'ao_post_lazyload', 'ao_post_preload' ) as $opti_type ) {
251
+ if ( ! isset( $_POST[ $opti_type ] ) ) {
252
+ $ao_meta_result[ $opti_type ] = '';
253
+ } else if ( 'on' === $_POST[ $opti_type ] ) {
254
+ $ao_meta_result[ $opti_type ] = 'on';
255
+ } else if ( in_array( $opti_type, array( 'ao_post_preload' ) ) ) {
256
+ $ao_meta_result[ $opti_type ] = $_POST[ $opti_type ];
257
+ }
258
+ }
259
 
260
+ // Update the meta field in the database.
261
+ update_post_meta( $post_id, 'ao_post_optimize', $ao_meta_result );
262
  }
263
 
264
  public function ao_metabox_generateccss_callback()
314
  } else {
315
  foreach ( array( 'ao_post_optimize', 'ao_post_js_optimize', 'ao_post_css_optimize', 'ao_post_ccss', 'ao_post_lazyload' ) as $key ) {
316
  if ( ! array_key_exists( $key, $ao_opt_val ) ) {
317
+ $ao_opt_val[ $key ] = 'off';
318
  }
319
  }
320
  }
classes/autoptimizePartners.php CHANGED
@@ -34,9 +34,12 @@ class autoptimizePartners
34
 
35
  public function add_partner_tabs( $in )
36
  {
37
- $in = array_merge( $in, array(
38
- 'ao_partners' => __( 'Optimize More!', 'autoptimize' ),
39
- ) );
 
 
 
40
 
41
  return $in;
42
  }
@@ -92,7 +95,7 @@ class autoptimizePartners
92
 
93
  public function ao_partners_page()
94
  {
95
- ?>
96
  <style>
97
  .itemDetail {
98
  background: #fff;
@@ -145,6 +148,6 @@ class autoptimizePartners
145
  <?php echo $this->get_ao_partner_feed_markup(); ?>
146
  </div>
147
  </div>
148
- <?php
149
  }
150
  }
34
 
35
  public function add_partner_tabs( $in )
36
  {
37
+ $in = array_merge(
38
+ $in,
39
+ array(
40
+ 'ao_partners' => __( 'Optimize More!', 'autoptimize' ),
41
+ )
42
+ );
43
 
44
  return $in;
45
  }
95
 
96
  public function ao_partners_page()
97
  {
98
+ ?>
99
  <style>
100
  .itemDetail {
101
  background: #fff;
148
  <?php echo $this->get_ao_partner_feed_markup(); ?>
149
  </div>
150
  </div>
151
+ <?php
152
  }
153
  }
classes/autoptimizeStyles.php CHANGED
@@ -164,7 +164,7 @@ class autoptimizeStyles extends autoptimizeBase
164
  public function read( $options )
165
  {
166
  $noptimize_css = apply_filters( 'autoptimize_filter_css_noptimize', false, $this->content );
167
- if ( $noptimize_css || false === autoptimizeConfig::get_post_meta_ao_settings( 'ao_post_css_optimize' )) {
168
  return false;
169
  }
170
 
@@ -281,7 +281,7 @@ class autoptimizeStyles extends autoptimizeBase
281
  // Get the media.
282
  if ( false !== strpos( $tag, 'media=' ) ) {
283
  preg_match( '#media=(?:"|\')([^>]*)(?:"|\')#Ui', $tag, $medias );
284
- if ( !empty( $medias ) ) {
285
  $medias = explode( ',', $medias[1] );
286
  $media = array();
287
  foreach ( $medias as $elem ) {
@@ -639,7 +639,9 @@ class autoptimizeStyles extends autoptimizeBase
639
  $replacement_url = $this->url_replace_cdn( $url );
640
  // Prepare replacements array.
641
  $replacements[ $url_src_matches[1][ $count ] ] = str_replace(
642
- $original_url, $replacement_url, $url_src_matches[1][ $count ]
 
 
643
  );
644
  }
645
  }
@@ -765,7 +767,9 @@ class autoptimizeStyles extends autoptimizeBase
765
  // Just do the "simple" CDN replacement.
766
  $replacement_url = $this->url_replace_cdn( $url );
767
  $imgreplace[ $url_src_matches[1][ $count ] ] = str_replace(
768
- $original_url, $replacement_url, $url_src_matches[1][ $count ]
 
 
769
  );
770
  }
771
  }
@@ -1230,8 +1234,8 @@ class autoptimizeStyles extends autoptimizeBase
1230
  // must make sure the autoptimize_action_css_hash action still fires for CCSS's sake.
1231
  $ao_ccss_key = get_option( 'autoptimize_ccss_key', '' );
1232
  if ( false === $this->aggregate && isset( $ao_ccss_key ) && ! empty( $ao_ccss_key ) ) {
1233
- $hash = 'single_' . md5( file_get_contents( $filepath ) );
1234
- do_action( 'autoptimize_action_css_hash', $hash );
1235
  }
1236
  return false;
1237
  }
@@ -1309,7 +1313,7 @@ class autoptimizeStyles extends autoptimizeBase
1309
  * https://github.com/twigphp/Twig/blob/3.x/src/Extension/EscaperExtension.php#L300-L319
1310
  * https://github.com/laminas/laminas-escaper/blob/2.8.x/src/Escaper.php#L205-L221
1311
  *
1312
- * @param string $css the to be sanitized CSS
1313
  * @return string sanitized CSS.
1314
  */
1315
  public static function sanitize_css( $css )
164
  public function read( $options )
165
  {
166
  $noptimize_css = apply_filters( 'autoptimize_filter_css_noptimize', false, $this->content );
167
+ if ( $noptimize_css || false === autoptimizeConfig::get_post_meta_ao_settings( 'ao_post_css_optimize' ) ) {
168
  return false;
169
  }
170
 
281
  // Get the media.
282
  if ( false !== strpos( $tag, 'media=' ) ) {
283
  preg_match( '#media=(?:"|\')([^>]*)(?:"|\')#Ui', $tag, $medias );
284
+ if ( ! empty( $medias ) ) {
285
  $medias = explode( ',', $medias[1] );
286
  $media = array();
287
  foreach ( $medias as $elem ) {
639
  $replacement_url = $this->url_replace_cdn( $url );
640
  // Prepare replacements array.
641
  $replacements[ $url_src_matches[1][ $count ] ] = str_replace(
642
+ $original_url,
643
+ $replacement_url,
644
+ $url_src_matches[1][ $count ]
645
  );
646
  }
647
  }
767
  // Just do the "simple" CDN replacement.
768
  $replacement_url = $this->url_replace_cdn( $url );
769
  $imgreplace[ $url_src_matches[1][ $count ] ] = str_replace(
770
+ $original_url,
771
+ $replacement_url,
772
+ $url_src_matches[1][ $count ]
773
  );
774
  }
775
  }
1234
  // must make sure the autoptimize_action_css_hash action still fires for CCSS's sake.
1235
  $ao_ccss_key = get_option( 'autoptimize_ccss_key', '' );
1236
  if ( false === $this->aggregate && isset( $ao_ccss_key ) && ! empty( $ao_ccss_key ) ) {
1237
+ $hash = 'single_' . md5( file_get_contents( $filepath ) );
1238
+ do_action( 'autoptimize_action_css_hash', $hash );
1239
  }
1240
  return false;
1241
  }
1313
  * https://github.com/twigphp/Twig/blob/3.x/src/Extension/EscaperExtension.php#L300-L319
1314
  * https://github.com/laminas/laminas-escaper/blob/2.8.x/src/Escaper.php#L205-L221
1315
  *
1316
+ * @param string $css the to be sanitized CSS.
1317
  * @return string sanitized CSS.
1318
  */
1319
  public static function sanitize_css( $css )
classes/autoptimizeToolbar.php CHANGED
@@ -28,7 +28,7 @@ class autoptimizeToolbar
28
  public function load_toolbar()
29
  {
30
  // Check permissions and that toolbar is not hidden via filter.
31
- if ( current_user_can( 'manage_options' ) && apply_filters( 'autoptimize_filter_toolbar_show', true ) && ! autoptimizeMain::is_amp_markup('') ) {
32
 
33
  // Create a handler for the AJAX toolbar requests.
34
  add_action( 'wp_ajax_autoptimize_delete_cache', array( $this, 'delete_cache' ) );
@@ -80,38 +80,44 @@ class autoptimizeToolbar
80
  // Create or add new items into the Admin Toolbar.
81
  // Main "Autoptimize" node.
82
  $_my_name = apply_filters( 'autoptimize_filter_settings_is_pro', false ) ? __( 'Autoptimize Pro', 'autoptimize' ) : __( 'Autoptimize', 'autoptimize' );
83
- $wp_admin_bar->add_node( array(
84
- 'id' => 'autoptimize',
85
- 'title' => '<span class="ab-icon"></span><span class="ab-label">' . $_my_name . '</span>',
86
- 'href' => admin_url( 'options-general.php?page=autoptimize' ),
87
- 'meta' => array( 'class' => 'bullet-' . $color ),
88
- ));
 
 
89
 
90
  // "Cache Info" node.
91
- $wp_admin_bar->add_node( array(
92
- 'id' => 'autoptimize-cache-info',
93
- 'title' => '<p>' . __( 'CSS/ JS Cache Info', 'autoptimize' ) . '</p>' .
94
- '<div class="autoptimize-radial-bar" percentage="' . $percentage . '">' .
95
- '<div class="autoptimize-circle">' .
96
- '<div class="mask full"><div class="fill bg-' . $color . '"></div></div>' .
97
- '<div class="mask half"><div class="fill bg-' . $color . '"></div></div>' .
98
- '<div class="shadow"></div>' .
99
- '</div>' .
100
- '<div class="inset"><div class="percentage"><div class="numbers ' . $color . '">' . $percentage . '%</div></div></div>' .
101
- '</div>' .
102
- '<table>' .
103
- '<tr><td>' . __( 'Size', 'autoptimize' ) . ':</td><td class="size ' . $color . '">' . $size . '</td></tr>' .
104
- '<tr><td>' . __( 'Files', 'autoptimize' ) . ':</td><td class="files white">' . $files . '</td></tr>' .
105
- '</table>',
106
- 'parent' => 'autoptimize',
107
- ));
 
 
108
 
109
  // "Delete Cache" node.
110
- $wp_admin_bar->add_node( array(
111
- 'id' => 'autoptimize-delete-cache',
112
- 'title' => __( 'Clear CSS/ JS Cache', 'autoptimize' ),
113
- 'parent' => 'autoptimize',
114
- ));
 
 
115
  }
116
 
117
  public function delete_cache()
@@ -137,13 +143,17 @@ class autoptimizeToolbar
137
 
138
  // Localizes a registered script with data for a JavaScript variable.
139
  // Needed for the AJAX to work properly on the frontend.
140
- wp_localize_script( 'autoptimize-toolbar', 'autoptimize_ajax_object', array(
141
- 'ajaxurl' => admin_url( 'admin-ajax.php' ),
142
- // translators: links to the Autoptimize settings page.
143
- 'error_msg' => sprintf( __( 'Your Autoptimize cache might not have been purged successfully, please check on the <a href=%s>Autoptimize settings page</a>.', 'autoptimize' ), admin_url( 'options-general.php?page=autoptimize' ) . ' style="white-space:nowrap;"' ),
144
- 'dismiss_msg' => __( 'Dismiss this notice.' ),
145
- 'nonce' => wp_create_nonce( 'ao_delcache_nonce' ),
146
- ) );
 
 
 
 
147
  }
148
 
149
  public function format_filesize( $bytes, $decimals = 2 )
28
  public function load_toolbar()
29
  {
30
  // Check permissions and that toolbar is not hidden via filter.
31
+ if ( current_user_can( 'manage_options' ) && apply_filters( 'autoptimize_filter_toolbar_show', true ) && ! autoptimizeMain::is_amp_markup( '' ) ) {
32
 
33
  // Create a handler for the AJAX toolbar requests.
34
  add_action( 'wp_ajax_autoptimize_delete_cache', array( $this, 'delete_cache' ) );
80
  // Create or add new items into the Admin Toolbar.
81
  // Main "Autoptimize" node.
82
  $_my_name = apply_filters( 'autoptimize_filter_settings_is_pro', false ) ? __( 'Autoptimize Pro', 'autoptimize' ) : __( 'Autoptimize', 'autoptimize' );
83
+ $wp_admin_bar->add_node(
84
+ array(
85
+ 'id' => 'autoptimize',
86
+ 'title' => '<span class="ab-icon"></span><span class="ab-label">' . $_my_name . '</span>',
87
+ 'href' => admin_url( 'options-general.php?page=autoptimize' ),
88
+ 'meta' => array( 'class' => 'bullet-' . $color ),
89
+ )
90
+ );
91
 
92
  // "Cache Info" node.
93
+ $wp_admin_bar->add_node(
94
+ array(
95
+ 'id' => 'autoptimize-cache-info',
96
+ 'title' => '<p>' . __( 'CSS/ JS Cache Info', 'autoptimize' ) . '</p>' .
97
+ '<div class="autoptimize-radial-bar" percentage="' . $percentage . '">' .
98
+ '<div class="autoptimize-circle">' .
99
+ '<div class="mask full"><div class="fill bg-' . $color . '"></div></div>' .
100
+ '<div class="mask half"><div class="fill bg-' . $color . '"></div></div>' .
101
+ '<div class="shadow"></div>' .
102
+ '</div>' .
103
+ '<div class="inset"><div class="percentage"><div class="numbers ' . $color . '">' . $percentage . '%</div></div></div>' .
104
+ '</div>' .
105
+ '<table>' .
106
+ '<tr><td>' . __( 'Size', 'autoptimize' ) . ':</td><td class="size ' . $color . '">' . $size . '</td></tr>' .
107
+ '<tr><td>' . __( 'Files', 'autoptimize' ) . ':</td><td class="files white">' . $files . '</td></tr>' .
108
+ '</table>',
109
+ 'parent' => 'autoptimize',
110
+ )
111
+ );
112
 
113
  // "Delete Cache" node.
114
+ $wp_admin_bar->add_node(
115
+ array(
116
+ 'id' => 'autoptimize-delete-cache',
117
+ 'title' => __( 'Clear CSS/ JS Cache', 'autoptimize' ),
118
+ 'parent' => 'autoptimize',
119
+ )
120
+ );
121
  }
122
 
123
  public function delete_cache()
143
 
144
  // Localizes a registered script with data for a JavaScript variable.
145
  // Needed for the AJAX to work properly on the frontend.
146
+ wp_localize_script(
147
+ 'autoptimize-toolbar',
148
+ 'autoptimize_ajax_object',
149
+ array(
150
+ 'ajaxurl' => admin_url( 'admin-ajax.php' ),
151
+ // translators: links to the Autoptimize settings page.
152
+ 'error_msg' => sprintf( __( 'Your Autoptimize cache might not have been purged successfully, please check on the <a href=%s>Autoptimize settings page</a>.', 'autoptimize' ), admin_url( 'options-general.php?page=autoptimize' ) . ' style="white-space:nowrap;"' ),
153
+ 'dismiss_msg' => __( 'Dismiss this notice.' ),
154
+ 'nonce' => wp_create_nonce( 'ao_delcache_nonce' ),
155
+ )
156
+ );
157
  }
158
 
159
  public function format_filesize( $bytes, $decimals = 2 )
classes/autoptimizeUtils.php CHANGED
@@ -399,15 +399,46 @@ class autoptimizeUtils
399
  * Returns true if a pagecache is found, false if not.
400
  * Now used to show notice, might be used later on to (un)hide page caching in AO if no page cache found.
401
  *
 
 
402
  * @return bool
403
  */
404
  public static function find_pagecache( $disregard_transient = false ) {
405
  static $_found_pagecache = null;
406
 
407
  if ( null === $_found_pagecache ) {
408
- $_page_cache_constants = array( 'NgInx' => 'NGINX_HELPER_BASENAME', 'Kinsta' => 'KINSTA_CACHE_ZONE', 'Presslabs' => 'PL_INSTANCE_REF', '' => 'Pressidium', 'Cache Enabler' => 'CACHE_ENABLER_VERSION', 'Speed Booster Pack' => 'SBP_PLUGIN_NAME', 'Servebolt' => 'SERVEBOLT_PLUGIN_FILE', 'WP CloudFlare Super Page Cache' => 'SWCFPC_PLUGIN_PATH', 'Cachify' => 'CACHIFY_CACHE_DIR', 'WP Rocket' => 'WP_ROCKET_CACHE_PATH', 'WP Optimize' => 'WPO_VERSION', 'Autoptimize Pro' => 'AO_PRO_PAGECACHE_CACHE_DIR' );
409
- $_page_cache_classes = array( 'Swift Performance' => 'Swift_Performance_Cache', 'WP Fastest Cache' => 'WpFastestCache', 'Quick Cache' => 'c_ws_plugin__qcache_purging_routines', 'ZenCache' => 'zencache', 'Comet Cache' => 'comet_cache', 'WP Engine' => 'WpeCommon', 'Flywheel' => 'FlywheelNginxCompat', 'Pagely' => 'PagelyCachePurge' );
410
- $_page_cache_functions = array( 'WP Super Cache' => 'wp_cache_clear_cache', 'W3 Total Cache' => 'w3tc_pgcache_flush', 'WP Fast Cache' => 'wp_fast_cache_bulk_delete_all', 'Rapidcache' => 'rapidcache_clear_cache', 'Siteground' => 'sg_cachepress_purge_cache', 'WP Super Cache' => 'prune_super_cache' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
411
 
412
  $_found_pagecache = false;
413
  if ( true !== $disregard_transient ) {
@@ -470,36 +501,36 @@ class autoptimizeUtils
470
  */
471
  public static function find_potential_conflicts() {
472
  if ( defined( 'WPFC_WP_CONTENT_BASENAME' ) ) {
473
- $_wpfc_options = json_decode( get_option( 'WpFastestCache' ) );
474
- foreach ( array( 'wpFastestCacheMinifyCss', 'wpFastestCacheCombineCss','wpFastestCacheCombineJs' ) as $_wpfc_conflicting ) {
475
- if ( isset( $_wpfc_options->$_wpfc_conflicting ) && $_wpfc_options->$_wpfc_conflicting === 'on' ) {
476
  return 'WP Fastest Cache';
477
  }
478
  }
479
  } elseif ( defined( 'W3TC_VERSION' ) ) {
480
- $w3tcConfig = file_get_contents( WP_CONTENT_DIR . '/w3tc-config/master.php' );
481
- $w3tc_minify_on = strpos( $w3tcConfig, '"minify.enabled": true' );
482
  if ( $w3tc_minify_on ) {
483
  return 'W3 Total Cache';
484
  }
485
- } elseif ( defined('SiteGround_Optimizer\VERSION') ) {
486
- if ( get_option('siteground_optimizer_optimize_css') == 1 || get_option('siteground_optimizer_optimize_javascript') == 1 || get_option('siteground_optimizer_combine_javascript') == 1 || get_option('siteground_optimizer_combine_css') == 1 ) {
487
  return 'Siteground Optimizer';
488
  }
489
  } elseif ( defined( 'WPO_VERSION' ) ) {
490
  $_wpo_options = get_site_option( 'wpo_minify_config' );
491
- if ( is_array( $_wpo_options ) && $_wpo_options['enabled'] == 1 && ( $_wpo_options['enable_css'] == 1 || $_wpo_options['enable_js'] == 1 ) ) {
492
  return 'WP Optimize';
493
  }
494
  } elseif ( defined( 'WPACU_PLUGIN_VERSION' ) || defined( 'WPACU_PRO_PLUGIN_VERSION' ) ) {
495
- $wpacuSettingsClass = new \WpAssetCleanUp\Settings();
496
- $wpacuSettings = $wpacuSettingsClass->getAll();
497
 
498
- if ( $wpacuSettings['minify_loaded_css'] || $wpacuSettings['minify_loaded_js'] || $wpacuSettings['combine_loaded_js'] || $wpacuSettings['combine_loaded_css'] ) {
499
  return 'Asset Cleanup';
500
  }
501
  } elseif ( defined( 'WP_ROCKET_VERSION' ) && function_exists( 'get_rocket_option' ) ) {
502
- if ( get_rocket_option( 'minify_js' ) || get_rocket_option( 'minify_concatenate_js' ) || get_rocket_option( 'minify_css' ) || get_rocket_option( 'minify_concatenate_css' ) || get_rocket_option('async_css' ) ) {
503
  return 'WP Rocket';
504
  }
505
  } elseif ( function_exists( 'fvm_get_settings' ) ) {
399
  * Returns true if a pagecache is found, false if not.
400
  * Now used to show notice, might be used later on to (un)hide page caching in AO if no page cache found.
401
  *
402
+ * @param bool $disregard_transient False by default, but can be used to ignore the transient and retest.
403
+ *
404
  * @return bool
405
  */
406
  public static function find_pagecache( $disregard_transient = false ) {
407
  static $_found_pagecache = null;
408
 
409
  if ( null === $_found_pagecache ) {
410
+ $_page_cache_constants = array(
411
+ 'NgInx' => 'NGINX_HELPER_BASENAME',
412
+ 'Kinsta' => 'KINSTA_CACHE_ZONE',
413
+ 'Presslabs' => 'PL_INSTANCE_REF',
414
+ 'Cache Enabler' => 'CACHE_ENABLER_VERSION',
415
+ 'Speed Booster Pack' => 'SBP_PLUGIN_NAME',
416
+ 'Servebolt' => 'SERVEBOLT_PLUGIN_FILE',
417
+ 'WP CloudFlare Super Page Cache' => 'SWCFPC_PLUGIN_PATH',
418
+ 'Cachify' => 'CACHIFY_CACHE_DIR',
419
+ 'WP Rocket' => 'WP_ROCKET_CACHE_PATH',
420
+ 'WP Optimize' => 'WPO_VERSION',
421
+ 'Autoptimize Pro' => 'AO_PRO_PAGECACHE_CACHE_DIR',
422
+ );
423
+ $_page_cache_classes = array(
424
+ 'Pressidium' => 'Ninukis_Plugin',
425
+ 'Swift Performance' => 'Swift_Performance_Cache',
426
+ 'WP Fastest Cache' => 'WpFastestCache',
427
+ 'Quick Cache' => 'c_ws_plugin__qcache_purging_routines',
428
+ 'ZenCache' => 'zencache',
429
+ 'Comet Cache' => 'comet_cache',
430
+ 'WP Engine' => 'WpeCommon',
431
+ 'Flywheel' => 'FlywheelNginxCompat',
432
+ 'Pagely' => 'PagelyCachePurge',
433
+ );
434
+ $_page_cache_functions = array(
435
+ 'WP Super Cache' => 'wp_cache_clear_cache',
436
+ 'W3 Total Cache' => 'w3tc_pgcache_flush',
437
+ 'WP Fast Cache' => 'wp_fast_cache_bulk_delete_all',
438
+ 'Rapidcache' => 'rapidcache_clear_cache',
439
+ 'Siteground' => 'sg_cachepress_purge_cache',
440
+ 'WP Super Cache' => 'prune_super_cache',
441
+ );
442
 
443
  $_found_pagecache = false;
444
  if ( true !== $disregard_transient ) {
501
  */
502
  public static function find_potential_conflicts() {
503
  if ( defined( 'WPFC_WP_CONTENT_BASENAME' ) ) {
504
+ $_wpfc_options = json_decode( get_option( 'WpFastestCache' ) );
505
+ foreach ( array( 'wpFastestCacheMinifyCss', 'wpFastestCacheCombineCss', 'wpFastestCacheCombineJs' ) as $_wpfc_conflicting ) {
506
+ if ( isset( $_wpfc_options->$_wpfc_conflicting ) && 'on' === $_wpfc_options->$_wpfc_conflicting ) {
507
  return 'WP Fastest Cache';
508
  }
509
  }
510
  } elseif ( defined( 'W3TC_VERSION' ) ) {
511
+ $w3tc_config = file_get_contents( WP_CONTENT_DIR . '/w3tc-config/master.php' );
512
+ $w3tc_minify_on = strpos( $w3tc_config, '"minify.enabled": true' );
513
  if ( $w3tc_minify_on ) {
514
  return 'W3 Total Cache';
515
  }
516
+ } elseif ( defined( 'SiteGround_Optimizer\VERSION' ) ) {
517
+ if ( get_option( 'siteground_optimizer_optimize_css' ) == 1 || get_option( 'siteground_optimizer_optimize_javascript' ) == 1 || get_option( 'siteground_optimizer_combine_javascript' ) == 1 || get_option( 'siteground_optimizer_combine_css' ) == 1 ) {
518
  return 'Siteground Optimizer';
519
  }
520
  } elseif ( defined( 'WPO_VERSION' ) ) {
521
  $_wpo_options = get_site_option( 'wpo_minify_config' );
522
+ if ( is_array( $_wpo_options ) && 1 == $_wpo_options['enabled'] && ( 1 == $_wpo_options['enable_css'] || 1 == $_wpo_options['enable_js'] ) ) {
523
  return 'WP Optimize';
524
  }
525
  } elseif ( defined( 'WPACU_PLUGIN_VERSION' ) || defined( 'WPACU_PRO_PLUGIN_VERSION' ) ) {
526
+ $wpacu_settings_class = new \WpAssetCleanUp\Settings();
527
+ $wpacu_settings = $wpacu_settings_class->getAll();
528
 
529
+ if ( $wpacu_settings['minify_loaded_css'] || $wpacu_settings['minify_loaded_js'] || $wpacu_settings['combine_loaded_js'] || $wpacu_settings['combine_loaded_css'] ) {
530
  return 'Asset Cleanup';
531
  }
532
  } elseif ( defined( 'WP_ROCKET_VERSION' ) && function_exists( 'get_rocket_option' ) ) {
533
+ if ( get_rocket_option( 'minify_js' ) || get_rocket_option( 'minify_concatenate_js' ) || get_rocket_option( 'minify_css' ) || get_rocket_option( 'minify_concatenate_css' ) || get_rocket_option( 'async_css' ) ) {
534
  return 'WP Rocket';
535
  }
536
  } elseif ( function_exists( 'fvm_get_settings' ) ) {
classes/autoptimizeVersionUpdatesHandler.php CHANGED
@@ -58,7 +58,7 @@ class autoptimizeVersionUpdatesHandler
58
  $major_update = true;
59
  // No break, intentionally, so all upgrades are ran during a single request...
60
  case '2.8':
61
- // nothing
62
  case '2.9':
63
  if ( version_compare( autoptimizeOptionWrapper::get_option( 'autoptimize_version', 'none' ), '2.9.999', 'lt' ) ) {
64
  $this->upgrade_from_2_9_before_compatibility();
@@ -262,7 +262,7 @@ class autoptimizeVersionUpdatesHandler
262
  }
263
 
264
  /**
265
- * remove CCSS request limit option + update jquery exclusion to include WordPress 5.6 jquery.min.js.
266
  */
267
  private function upgrade_from_2_7() {
268
  delete_option( 'autoptimize_ccss_rlimit' );
@@ -274,7 +274,7 @@ class autoptimizeVersionUpdatesHandler
274
  }
275
 
276
  /**
277
- * set an option to indicate the AO installation predates the compatibility logic, this way we
278
  * can avoid adding compatibility code that is likely not needed and maybe not wanted as it
279
  * can introduce performance regressions.
280
  */
58
  $major_update = true;
59
  // No break, intentionally, so all upgrades are ran during a single request...
60
  case '2.8':
61
+ // nothing.
62
  case '2.9':
63
  if ( version_compare( autoptimizeOptionWrapper::get_option( 'autoptimize_version', 'none' ), '2.9.999', 'lt' ) ) {
64
  $this->upgrade_from_2_9_before_compatibility();
262
  }
263
 
264
  /**
265
+ * Remove CCSS request limit option + update jquery exclusion to include WordPress 5.6 jquery.min.js.
266
  */
267
  private function upgrade_from_2_7() {
268
  delete_option( 'autoptimize_ccss_rlimit' );
274
  }
275
 
276
  /**
277
+ * Set an option to indicate the AO installation predates the compatibility logic, this way we
278
  * can avoid adding compatibility code that is likely not needed and maybe not wanted as it
279
  * can introduce performance regressions.
280
  */
classes/critcss-inc/admin_settings_adv.php CHANGED
@@ -26,7 +26,7 @@ function ao_ccss_render_adv() {
26
 
27
  // Get viewport size.
28
  $viewport = $criticalcss->viewport();
29
- ?>
30
  <ul id="adv-panel">
31
  <li class="itemDetail">
32
  <h2 class="itemTitle fleft"><?php _e( 'Advanced Settings', 'autoptimize' ); ?></h2>
26
 
27
  // Get viewport size.
28
  $viewport = $criticalcss->viewport();
29
+ ?>
30
  <ul id="adv-panel">
31
  <li class="itemDetail">
32
  <h2 class="itemTitle fleft"><?php _e( 'Advanced Settings', 'autoptimize' ); ?></h2>
classes/critcss-inc/admin_settings_debug.php CHANGED
@@ -7,26 +7,32 @@
7
  global $wpdb;
8
 
9
  // Query AO's options.
10
- $ao_options = $wpdb->get_results('
11
- SELECT option_name AS name,
12
- option_value AS value
13
- FROM ' . $wpdb->options . '
14
- WHERE option_name LIKE "autoptimize_%%"
15
- ORDER BY name
16
- ', ARRAY_A);
 
 
 
17
 
18
  // Query AO's transients.
19
- $ao_trans = $wpdb->get_results('
20
- SELECT option_name AS name,
21
- option_value AS value
22
- FROM ' . $wpdb->options . '
23
- WHERE option_name LIKE "_transient_autoptimize_%%"
24
- OR option_name LIKE "_transient_timeout_autoptimize_%%"
25
- ', ARRAY_A);
 
 
 
26
 
27
  // Render debug panel if there's something to show.
28
  if ( $ao_options || $ao_trans ) {
29
- ?>
30
  <!-- BEGIN: Settings Debug -->
31
  <ul>
32
  <li class="itemDetail">
@@ -35,12 +41,12 @@ if ( $ao_options || $ao_trans ) {
35
  <?php
36
  // Render options.
37
  if ( $ao_options ) {
38
- ?>
39
  <h4><?php _e( 'Options', 'autoptimize' ); ?>:</h4>
40
  <table class="form-table debug">
41
  <?php
42
  foreach ( $ao_options as $option ) {
43
- ?>
44
  <tr>
45
  <th scope="row">
46
  <?php echo $option['name']; ?>
@@ -60,7 +66,7 @@ if ( $ao_options || $ao_trans ) {
60
  ?>
61
  </td>
62
  </tr>
63
- <?php
64
  }
65
  ?>
66
  </table>
@@ -77,5 +83,5 @@ if ( $ao_options || $ao_trans ) {
77
  </li>
78
  </ul>
79
  <!-- END: Settings Debug -->
80
- <?php
81
  }
7
  global $wpdb;
8
 
9
  // Query AO's options.
10
+ $ao_options = $wpdb->get_results(
11
+ '
12
+ SELECT option_name AS name,
13
+ option_value AS value
14
+ FROM ' . $wpdb->options . '
15
+ WHERE option_name LIKE "autoptimize_%%"
16
+ ORDER BY name
17
+ ',
18
+ ARRAY_A
19
+ );
20
 
21
  // Query AO's transients.
22
+ $ao_trans = $wpdb->get_results(
23
+ '
24
+ SELECT option_name AS name,
25
+ option_value AS value
26
+ FROM ' . $wpdb->options . '
27
+ WHERE option_name LIKE "_transient_autoptimize_%%"
28
+ OR option_name LIKE "_transient_timeout_autoptimize_%%"
29
+ ',
30
+ ARRAY_A
31
+ );
32
 
33
  // Render debug panel if there's something to show.
34
  if ( $ao_options || $ao_trans ) {
35
+ ?>
36
  <!-- BEGIN: Settings Debug -->
37
  <ul>
38
  <li class="itemDetail">
41
  <?php
42
  // Render options.
43
  if ( $ao_options ) {
44
+ ?>
45
  <h4><?php _e( 'Options', 'autoptimize' ); ?>:</h4>
46
  <table class="form-table debug">
47
  <?php
48
  foreach ( $ao_options as $option ) {
49
+ ?>
50
  <tr>
51
  <th scope="row">
52
  <?php echo $option['name']; ?>
66
  ?>
67
  </td>
68
  </tr>
69
+ <?php
70
  }
71
  ?>
72
  </table>
83
  </li>
84
  </ul>
85
  <!-- END: Settings Debug -->
86
+ <?php
87
  }
classes/critcss-inc/admin_settings_key.php CHANGED
@@ -59,5 +59,5 @@ function ao_ccss_render_key( $key, $status, $status_msg, $message, $color ) {
59
  </div>
60
  </li>
61
  </ul>
62
- <?php
63
  }
59
  </div>
60
  </li>
61
  </ul>
62
+ <?php
63
  }
classes/critcss-inc/admin_settings_queue.js.php CHANGED
@@ -228,12 +228,12 @@ function queuerunner() {
228
  jQuery.post(ajaxurl, data, function(response) {
229
  response_array=JSON.parse(response);
230
  if (response_array['code'] == 200) {
231
- displayNotice( '<?php _e('Queue processed, reloading page.', 'autoptimize'); ?>', 'success' )
232
  setTimeout(window.location.reload.bind(window.location), 1.5*1000);
233
  } else if ( response_array['code'] == 302 ) {
234
- displayNotice( '<?php _e('The queue is locked, retry in a couple of minutes. If this problem persists and the queue is not moving at all remove the <code>wp-content/uploads/ao_ccss/queue.lock</code> file.', 'autoptimize' ); ?>', 'warning' )
235
  } else {
236
- displayNotice( '<?php _e('Could not process queue.', 'autoptimize'); ?>', 'error' )
237
  }
238
  });
239
  }
228
  jQuery.post(ajaxurl, data, function(response) {
229
  response_array=JSON.parse(response);
230
  if (response_array['code'] == 200) {
231
+ displayNotice( '<?php _e( 'Queue processed, reloading page.', 'autoptimize' ); ?>', 'success' )
232
  setTimeout(window.location.reload.bind(window.location), 1.5*1000);
233
  } else if ( response_array['code'] == 302 ) {
234
+ displayNotice( '<?php _e( 'The queue is locked, retry in a couple of minutes. If this problem persists and the queue is not moving at all remove the <code>wp-content/uploads/ao_ccss/queue.lock</code> file.', 'autoptimize' ); ?>', 'warning' )
235
  } else {
236
+ displayNotice( '<?php _e( 'Could not process queue.', 'autoptimize' ); ?>', 'error' )
237
  }
238
  });
239
  }
classes/critcss-inc/admin_settings_queue.php CHANGED
@@ -17,7 +17,7 @@ function ao_ccss_render_queue() {
17
  } else {
18
  $ao_ccss_queue = json_encode( $ao_ccss_queue );
19
  }
20
- ?>
21
 
22
  <ul id="queue-panel">
23
  <li class="itemDetail">
@@ -92,5 +92,5 @@ function ao_ccss_render_queue() {
92
  <!-- END Queue UI -->
93
  </li>
94
  </ul>
95
- <?php
96
  }
17
  } else {
18
  $ao_ccss_queue = json_encode( $ao_ccss_queue );
19
  }
20
+ ?>
21
 
22
  <ul id="queue-panel">
23
  <li class="itemDetail">
92
  <!-- END Queue UI -->
93
  </li>
94
  </ul>
95
+ <?php
96
  }
classes/critcss-inc/admin_settings_rules.js.php CHANGED
@@ -57,12 +57,12 @@ function drawTable(critCssArray) {
57
  filest=nv.file;
58
  auto_style = '';
59
  <?php
60
- $criticalcss = new autoptimizeCriticalCSSBase();
61
- if ( $criticalcss->is_api_active() ){
62
- ?>api_active = 1;<?php
63
- } else {
64
- ?>api_active = 0;<?php
65
- }
66
  ?>
67
  if (file == 0) {
68
  file='<?php _e( 'To be fetched from criticalcss.com in the next queue run...', 'autoptimize' ); ?>';
@@ -84,7 +84,17 @@ function drawTable(critCssArray) {
84
  }
85
  }
86
  if ( k == "paths" ) {
87
- target = '<a href="<?php echo AUTOPTIMIZE_WP_SITE_URL; ?>' + i + '" target="_blank">' + i + '</a>';
 
 
 
 
 
 
 
 
 
 
88
  } else {
89
  target = i.replace(/(woo_|template_|custom_post_|edd_|bp_|bbp_)/,'');
90
  }
@@ -100,22 +110,22 @@ function drawTable(critCssArray) {
100
  // R rules were found, show a notice!
101
  // and add some JS magic to ensure the notice works as a notice, but is shown inline
102
  // in the rules panel instead of in the notice area where it would be too prominent.
103
- <?php
104
  $_ao_ccss_review_notice_id = 'autoptimize-ccss-review-rules-notice-30';
105
  // Translators: before the 1st word a number + a space will be displayed, as in e.g. "2 of above rules".
106
- $_ao_ccss_review_notice_copy = __('of the above rules got flagged by criticalcss.com as to be reviewed. This is often due to font-related issues which can be safely ignored, but you can log in to your account at https://criticalcss.com and compare screenshots for rules by clicking the red exclamation mark to confirm if all is OK.', 'autoptimize');
107
  if ( PAnD::is_admin_notice_active( $_ao_ccss_review_notice_id ) ) {
108
- ?>
109
  jQuery("#rules-notices").append( "&nbsp;<div class='rnotice notice notice-info is-dismissible hidden' data-dismissible='<?php echo $_ao_ccss_review_notice_id; ?>'><p>" + rnotice + " <?php echo $_ao_ccss_review_notice_copy; ?>" + "</p></div>");
110
  jQuery( document ).ready(function() {
111
  jQuery("div.rnotice").detach().appendTo('#rules-notices');
112
  jQuery("div.rnotice").show();
113
  });
114
- <?php
115
  } else if ( $ao_ccss_debug ) {
116
- ?>
117
  console.log( "Autoptimize: " + rnotice + " <?php echo $_ao_ccss_review_notice_copy; ?>" );
118
- <?php
119
  }
120
  ?>
121
  }
@@ -403,7 +413,7 @@ function updateAfterChange() {
403
  <?php
404
  // autosave rules is on by default, but can be disabled with a filter.
405
  if ( apply_filters( 'autoptimize_filter_ccss_settings_rules_autosave', true ) ) {
406
- ?>
407
  var data = {
408
  'action': 'ao_ccss_saverules',
409
  'ao_ccss_saverules_nonce': '<?php echo wp_create_nonce( 'ao_ccss_saverules_nonce' ); ?>',
57
  filest=nv.file;
58
  auto_style = '';
59
  <?php
60
+ $criticalcss = new autoptimizeCriticalCSSBase();
61
+ if ( $criticalcss->is_api_active() ) {
62
+ echo 'api_active = 1;' . "\n";
63
+ } else {
64
+ echo 'api_active = 0;' . "\n";
65
+ }
66
  ?>
67
  if (file == 0) {
68
  file='<?php _e( 'To be fetched from criticalcss.com in the next queue run...', 'autoptimize' ); ?>';
84
  }
85
  }
86
  if ( k == "paths" ) {
87
+ <?php
88
+ if ( apply_filters( 'autoptimize_filter_ccss_paths_clickable', true ) ) {
89
+ ?>
90
+ target = '<a href="<?php echo AUTOPTIMIZE_WP_SITE_URL; ?>' + i + '" target="_blank">' + i + '</a>';
91
+ <?php
92
+ } else {
93
+ ?>
94
+ target = i;
95
+ <?php
96
+ }
97
+ ?>
98
  } else {
99
  target = i.replace(/(woo_|template_|custom_post_|edd_|bp_|bbp_)/,'');
100
  }
110
  // R rules were found, show a notice!
111
  // and add some JS magic to ensure the notice works as a notice, but is shown inline
112
  // in the rules panel instead of in the notice area where it would be too prominent.
113
+ <?php
114
  $_ao_ccss_review_notice_id = 'autoptimize-ccss-review-rules-notice-30';
115
  // Translators: before the 1st word a number + a space will be displayed, as in e.g. "2 of above rules".
116
+ $_ao_ccss_review_notice_copy = __( 'of the above rules got flagged by criticalcss.com as to be reviewed. This is often due to font-related issues which can be safely ignored, but you can log in to your account at https://criticalcss.com and compare screenshots for rules by clicking the red exclamation mark to confirm if all is OK.', 'autoptimize' );
117
  if ( PAnD::is_admin_notice_active( $_ao_ccss_review_notice_id ) ) {
118
+ ?>
119
  jQuery("#rules-notices").append( "&nbsp;<div class='rnotice notice notice-info is-dismissible hidden' data-dismissible='<?php echo $_ao_ccss_review_notice_id; ?>'><p>" + rnotice + " <?php echo $_ao_ccss_review_notice_copy; ?>" + "</p></div>");
120
  jQuery( document ).ready(function() {
121
  jQuery("div.rnotice").detach().appendTo('#rules-notices');
122
  jQuery("div.rnotice").show();
123
  });
124
+ <?php
125
  } else if ( $ao_ccss_debug ) {
126
+ ?>
127
  console.log( "Autoptimize: " + rnotice + " <?php echo $_ao_ccss_review_notice_copy; ?>" );
128
+ <?php
129
  }
130
  ?>
131
  }
413
  <?php
414
  // autosave rules is on by default, but can be disabled with a filter.
415
  if ( apply_filters( 'autoptimize_filter_ccss_settings_rules_autosave', true ) ) {
416
+ ?>
417
  var data = {
418
  'action': 'ao_ccss_saverules',
419
  'ao_ccss_saverules_nonce': '<?php echo wp_create_nonce( 'ao_ccss_saverules_nonce' ); ?>',
classes/critcss-inc/admin_settings_rules.php CHANGED
@@ -9,13 +9,13 @@
9
  function ao_ccss_render_rules() {
10
  // Attach required arrays.
11
  $criticalcss = autoptimize()->criticalcss();
12
- $ao_ccss_rules = $criticalcss->get_option( 'rules' );
13
  $ao_ccss_types = $criticalcss->get_types();
14
-
15
  if ( empty( $ao_ccss_types ) || ! is_array( $ao_ccss_types ) ) {
16
  $ao_ccss_types = array( 'No conditionals, check CSS optimization settings.' );
17
  }
18
- ?>
19
  <ul id="rules-panel">
20
  <li class="itemDetail">
21
  <h2 class="itemTitle"><?php _e( 'Rules', 'autoptimize' ); ?></h2>
@@ -204,6 +204,26 @@ function ao_ccss_render_rules() {
204
  <!-- END Rules UI -->
205
  </li>
206
  </ul>
207
- <?php
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
208
  }
209
  ?>
9
  function ao_ccss_render_rules() {
10
  // Attach required arrays.
11
  $criticalcss = autoptimize()->criticalcss();
12
+ $ao_ccss_rules = sanitize_rules( $criticalcss->get_option( 'rules' ) );
13
  $ao_ccss_types = $criticalcss->get_types();
14
+
15
  if ( empty( $ao_ccss_types ) || ! is_array( $ao_ccss_types ) ) {
16
  $ao_ccss_types = array( 'No conditionals, check CSS optimization settings.' );
17
  }
18
+ ?>
19
  <ul id="rules-panel">
20
  <li class="itemDetail">
21
  <h2 class="itemTitle"><?php _e( 'Rules', 'autoptimize' ); ?></h2>
204
  <!-- END Rules UI -->
205
  </li>
206
  </ul>
207
+ <?php
208
+ }
209
+
210
+ /**
211
+ * Sanitize rules before rendering.
212
+ *
213
+ * @param array $rules Array with rules to be sanitized.
214
+ */
215
+ function sanitize_rules( $rules ) {
216
+ if ( apply_filters( 'autoptimize_filter_ccss_paths_clickable', true ) ) {
217
+ if ( array_key_exists( 'paths', $rules ) ) {
218
+ foreach ( $rules['paths'] as $key => $value ) {
219
+ $newkey = esc_url( $key );
220
+ if ( $newkey !== $key ) {
221
+ unset( $rules['paths'][ $key ] );
222
+ $rules['paths'][ $newkey ] = $value;
223
+ }
224
+ }
225
+ }
226
+ }
227
+ return $rules;
228
  }
229
  ?>
readme.txt CHANGED
@@ -5,7 +5,7 @@ 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.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
 
@@ -315,9 +315,14 @@ Just [fork Autoptimize on Github](https://github.com/futtta/autoptimize) and cod
315
 
316
  == Changelog ==
317
 
 
 
 
 
 
318
  = 3.1.0 =
319
- * new: HTML sub-option: "minify inline CSS/ JS" (off by default).
320
- * new: Misc option: permanently allow the "do not run compatibility logic" flag to be removed (which was set for users upgrading from AO 2.9.* to AO 3.0.* as the assumption was things were working anyway).
321
  * security: improvements to the critical CSS settings page to fix authenticated cross site scripting issues as reported by WPScan Security.
322
  * bugfix: "defer inline JS" of very large chunks of inline JS could cause server errors (PCRE crash actually) so not deferring if string is more then 200000 characters (filter available).
323
  * some other minor changes/ improvements/ hooks, see the [GitHub commit log](https://github.com/futtta/autoptimize/commits/beta)
5
  Requires at least: 4.9
6
  Tested up to: 6.0
7
  Requires PHP: 5.6
8
+ Stable tag: 3.1.1
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
 
315
 
316
  == Changelog ==
317
 
318
+ = 3.1.1 =
319
+ * images: when optimizing images and lazyloading is on, then by default do not set an LQIP (low quality image placeholder) any more (reason: it might *look* nice but it comes with a small-ish perf. penalty). This can be re-enabled by returning true to the `autoptimize_filter_imgopt_lazyload_dolqip` filter.
320
+ * security: further improvements to critical CSS settings page (again with the great assistance of WPScan Security).
321
+ * some other minor changes/ improvements/ filters, see the [GitHub commit log](https://github.com/futtta/autoptimize/commits/beta).
322
+
323
  = 3.1.0 =
324
+ * new HTML sub-option: "minify inline CSS/ JS" (off by default).
325
+ * new Misc option: permanently allow the "do not run compatibility logic" flag to be removed (which was set for users upgrading from AO 2.9.* to AO 3.0.* as the assumption was things were working anyway).
326
  * security: improvements to the critical CSS settings page to fix authenticated cross site scripting issues as reported by WPScan Security.
327
  * bugfix: "defer inline JS" of very large chunks of inline JS could cause server errors (PCRE crash actually) so not deferring if string is more then 200000 characters (filter available).
328
  * some other minor changes/ improvements/ hooks, see the [GitHub commit log](https://github.com/futtta/autoptimize/commits/beta)