Autoptimize - Version 2.9.1

Version Description

  • New: logic to detect possibly conflicting plugins, with notification if found.
  • Improvement: to be reviewed critical css rules UI change.
  • Improvement: automatically save critical CSS rules when changed.
  • Fix for no CCSS jobs being created when "aggregate CSS" is off and all files are minified.
  • Fix for some page caches not being detected correctly leading to notification being shown when it should not (thanks @optimocha for warning me!)
  • Fix for a (rare) lazyload-regression in 2.9.0.
  • Fix for a (rare) image optimization issue when the same image is referenced multiple times as background-image in optimized CSS.
Download this release

Release Info

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

Code changes from version 2.9.0 to 2.9.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: 2.9.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', '2.9.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: 2.9.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', '2.9.1' );
25
 
26
  // plugin_dir_path() returns the trailing slash!
27
  define( 'AUTOPTIMIZE_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
classes/autoptimizeConfig.php CHANGED
@@ -461,7 +461,7 @@ $_rapidload_link = 'https://misc.optimizingmatters.com/partners/?from=csssetting
461
  ?>
462
  <tr valign="top">
463
  <th scope="row"><?php _e( 'Enable configuration per post/ page?', 'autoptimize' ); ?></th>
464
- <td><label class="cb_label"><input type="checkbox" name="autoptimize_enable_meta_ao_settings" <?php echo autoptimizeOptionWrapper::get_option( 'autoptimize_enable_meta_ao_settings', '0' ) ? 'checked="checked" ' : ''; ?>/>
465
  <?php _e( 'Add a "metabox" to the post/ page edit screen allowing different optimizations to be turned off on a per post/ page level?', 'autoptimize' ); ?></label></td>
466
  </tr>
467
  <?php } ?>
@@ -811,7 +811,7 @@ $_rapidload_link = 'https://misc.optimizingmatters.com/partners/?from=csssetting
811
  'autoptimize_optimize_checkout' => 0,
812
  'autoptimize_minify_excluded' => 1,
813
  'autoptimize_cache_fallback' => 1,
814
- 'autoptimize_enable_meta_ao_settings' => 0,
815
  );
816
 
817
  return $config;
@@ -1024,7 +1024,7 @@ $_rapidload_link = 'https://misc.optimizingmatters.com/partners/?from=csssetting
1024
  static $_meta_settings_active = null;
1025
 
1026
  if ( null === $_meta_settings_active ) {
1027
- $_meta_settings_active = apply_filters( 'autoptimize_filter_enable_meta_ao_settings', autoptimizeOptionWrapper::get_option( 'autoptimize_enable_meta_ao_settings', '0' ) );
1028
  }
1029
 
1030
  return $_meta_settings_active;
461
  ?>
462
  <tr valign="top">
463
  <th scope="row"><?php _e( 'Enable configuration per post/ page?', 'autoptimize' ); ?></th>
464
+ <td><label class="cb_label"><input type="checkbox" name="autoptimize_enable_meta_ao_settings" <?php echo autoptimizeOptionWrapper::get_option( 'autoptimize_enable_meta_ao_settings', '1' ) ? 'checked="checked" ' : ''; ?>/>
465
  <?php _e( 'Add a "metabox" to the post/ page edit screen allowing different optimizations to be turned off on a per post/ page level?', 'autoptimize' ); ?></label></td>
466
  </tr>
467
  <?php } ?>
811
  'autoptimize_optimize_checkout' => 0,
812
  'autoptimize_minify_excluded' => 1,
813
  'autoptimize_cache_fallback' => 1,
814
+ 'autoptimize_enable_meta_ao_settings' => 1,
815
  );
816
 
817
  return $config;
1024
  static $_meta_settings_active = null;
1025
 
1026
  if ( null === $_meta_settings_active ) {
1027
+ $_meta_settings_active = apply_filters( 'autoptimize_filter_enable_meta_ao_settings', autoptimizeOptionWrapper::get_option( 'autoptimize_enable_meta_ao_settings', '1' ) );
1028
  }
1029
 
1030
  return $_meta_settings_active;
classes/autoptimizeCriticalCSSSettingsAjax.php CHANGED
@@ -28,6 +28,7 @@ class autoptimizeCriticalCSSSettingsAjax {
28
  add_action( 'wp_ajax_ao_ccss_export', array( $this, 'ao_ccss_export_callback' ) );
29
  add_action( 'wp_ajax_ao_ccss_import', array( $this, 'ao_ccss_import_callback' ) );
30
  add_action( 'wp_ajax_ao_ccss_queuerunner', array( $this, 'ao_ccss_queuerunner_callback' ) );
 
31
  }
32
 
33
  public function critcss_fetch_callback() {
@@ -379,6 +380,56 @@ class autoptimizeCriticalCSSSettingsAjax {
379
  wp_die();
380
  }
381
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
382
  public function critcss_check_filename( $filename ) {
383
  // Try to avoid directory traversal when reading/writing/deleting critical CSS files.
384
  if ( strpos( $filename, 'ccss_' ) !== 0 ) {
28
  add_action( 'wp_ajax_ao_ccss_export', array( $this, 'ao_ccss_export_callback' ) );
29
  add_action( 'wp_ajax_ao_ccss_import', array( $this, 'ao_ccss_import_callback' ) );
30
  add_action( 'wp_ajax_ao_ccss_queuerunner', array( $this, 'ao_ccss_queuerunner_callback' ) );
31
+ add_action( 'wp_ajax_ao_ccss_saverules', array( $this, 'ao_ccss_saverules_callback' ) );
32
  }
33
 
34
  public function critcss_fetch_callback() {
380
  wp_die();
381
  }
382
 
383
+ public function ao_ccss_saverules_callback() {
384
+ check_ajax_referer( 'ao_ccss_saverules_nonce', 'ao_ccss_saverules_nonce' );
385
+
386
+ // save rules over AJAX, too many users forget to press "save changes".
387
+ if ( current_user_can( 'manage_options' ) ) {
388
+ if ( array_key_exists( 'critcssrules', $_POST ) ) {
389
+ $rules = stripslashes( $_POST['critcssrules'] ); // ugly, but seems correct as per https://developer.wordpress.org/reference/functions/stripslashes_deep/#comment-1045
390
+ if ( ! empty( $rules ) ) {
391
+ $_unsafe_rules_array = json_decode( wp_strip_all_tags( $rules ), true );
392
+ if ( ! empty( $_unsafe_rules_array ) && is_array( $_unsafe_rules_array ) ) {
393
+ $_safe_rules_array = array();
394
+ if ( array_key_exists( 'paths', $_unsafe_rules_array ) ) {
395
+ $_safe_rules_array['paths'] = $_unsafe_rules_array['paths'];
396
+ }
397
+ if ( array_key_exists( 'types', $_unsafe_rules_array ) ) {
398
+ $_safe_rules_array['types'] = $_unsafe_rules_array['types'];
399
+ }
400
+ $_safe_rules = json_encode( $_safe_rules_array, JSON_FORCE_OBJECT );
401
+ if ( ! empty( $_safe_rules ) ) {
402
+ update_option( 'autoptimize_ccss_rules', $_safe_rules );
403
+ $response['code'] = '200';
404
+ $response['msg'] = 'Rules saved';
405
+ } else {
406
+ $_error = 'Could not auto-save rules (safe rules empty)';
407
+ }
408
+ } else {
409
+ $_error = 'Could not auto-save rules (rules could not be json_decoded)';
410
+ }
411
+ } else {
412
+ $_error = 'Could not auto-save rules (rules empty)';
413
+ }
414
+ } else {
415
+ $_error = 'Could not auto-save rules (rules not in $_POST)';
416
+ }
417
+ } else {
418
+ $_error = 'Not allowed';
419
+ }
420
+
421
+ if ( ! isset( $response ) && $_error ) {
422
+ $response['code'] = '500';
423
+ $response['msg'] = $_error;
424
+ }
425
+
426
+ // Dispatch respose.
427
+ echo json_encode( $response );
428
+
429
+ // Close ajax request.
430
+ wp_die();
431
+ }
432
+
433
  public function critcss_check_filename( $filename ) {
434
  // Try to avoid directory traversal when reading/writing/deleting critical CSS files.
435
  if ( strpos( $filename, 'ccss_' ) !== 0 ) {
classes/autoptimizeImages.php CHANGED
@@ -186,7 +186,7 @@ class autoptimizeImages
186
  *
187
  * @return bool
188
  */
189
- public function should_disable_core_lazyload( $flag, $tag, $context ) {
190
  if ( 'img' === $tag ) {
191
  return false;
192
  }
@@ -391,7 +391,7 @@ class autoptimizeImages
391
  {
392
  $in = $this->normalize_img_url( $in );
393
 
394
- if ( $this->can_optimize_image( $in ) ) {
395
  return $this->build_imgopt_url( $in, '', '' );
396
  } else {
397
  return $in;
186
  *
187
  * @return bool
188
  */
189
+ public function should_disable_core_lazyload( $flag = true, $tag = '', $context = '' ) {
190
  if ( 'img' === $tag ) {
191
  return false;
192
  }
391
  {
392
  $in = $this->normalize_img_url( $in );
393
 
394
+ if ( $this->can_optimize_image( $in ) && false === strpos( $in, $this->get_imgopt_host() ) ) {
395
  return $this->build_imgopt_url( $in, '', '' );
396
  } else {
397
  return $in;
classes/autoptimizeMain.php CHANGED
@@ -189,6 +189,7 @@ class autoptimizeMain
189
 
190
  // Add "no cache found" notice.
191
  add_action( 'admin_notices', 'autoptimizeMain::notice_nopagecache', 99 );
 
192
  }
193
  } else {
194
  add_action( 'admin_notices', 'autoptimizeMain::notice_cache_unavailable' );
@@ -716,7 +717,7 @@ class autoptimizeMain
716
  *
717
  * uses helper function in autoptimizeUtils.php
718
  */
719
- $_ao_nopagecache_notice = __( 'It looks like your site might not have <strong>page caching</strong> which is a <strong>must-have for performance</strong>, check with your host if they offer this or install a page caching plugin like for example', 'autoptimize' );
720
  $_ao_pagecache_install_url = network_admin_url() . 'plugin-install.php?tab=search&type=term&s=';
721
  $_ao_nopagecache_notice .= ' <a href="' . $_ao_pagecache_install_url . 'wp+super+cache' . '">WP Super Cache</a>, <a href="' . $_ao_pagecache_install_url . 'keycdn+cache+enabler' . '">KeyCDN Cache Enabler</a>, ...';
722
  $_ao_nopagecache_dismissible = 'ao-nopagecache-forever'; // the notice is only shown once and will not re-appear when dismissed.
@@ -731,4 +732,25 @@ class autoptimizeMain
731
  }
732
  }
733
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
734
  }
189
 
190
  // Add "no cache found" notice.
191
  add_action( 'admin_notices', 'autoptimizeMain::notice_nopagecache', 99 );
192
+ add_action( 'admin_notices', 'autoptimizeMain::notice_potential_conflict', 99 );
193
  }
194
  } else {
195
  add_action( 'admin_notices', 'autoptimizeMain::notice_cache_unavailable' );
717
  *
718
  * uses helper function in autoptimizeUtils.php
719
  */
720
+ $_ao_nopagecache_notice = __( 'It looks like your site might not have <strong>page caching</strong> which is a <strong>must-have for performance</strong>. If you are sure you have a page cache, you can close this notice, but when in doubt check with your host if they offer this or install a page caching plugin like for example', 'autoptimize' );
721
  $_ao_pagecache_install_url = network_admin_url() . 'plugin-install.php?tab=search&type=term&s=';
722
  $_ao_nopagecache_notice .= ' <a href="' . $_ao_pagecache_install_url . 'wp+super+cache' . '">WP Super Cache</a>, <a href="' . $_ao_pagecache_install_url . 'keycdn+cache+enabler' . '">KeyCDN Cache Enabler</a>, ...';
723
  $_ao_nopagecache_dismissible = 'ao-nopagecache-forever'; // the notice is only shown once and will not re-appear when dismissed.
732
  }
733
  }
734
  }
735
+
736
+ public static function notice_potential_conflict()
737
+ {
738
+ /*
739
+ * Using other plugins to do CSS/ JS optimization can cause unexpected and hard to troubleshoot issues, warn users who seem to be in that situation.
740
+ */
741
+ // Translators: the sentence will be finished with the name of the offending plugin and a final stop.
742
+ $_ao_potential_conflict_notice = __( 'It looks like you have <strong>another plugin also doing CSS and/ or JS optimization</strong>, which can result in hard to troubleshoot <strong>conflicts</strong>. For this reason it is recommended to disable this functionality in', 'autoptimize' ) . ' ';
743
+ $_ao_potential_conflict_dismissible = 'ao-potential-conflict-forever'; // the notice is only shown once and will not re-appear when dismissed.
744
+ $_is_ao_settings_page = autoptimizeUtils::is_ao_settings();
745
+
746
+ if ( current_user_can( 'manage_options' ) && $_is_ao_settings_page && PAnD::is_admin_notice_active( $_ao_potential_conflict_dismissible ) && true === apply_filters( 'autopitmize_filter_main_show_potential_conclict_notice', true ) ) {
747
+ $_potential_conflicts = autoptimizeUtils::find_potential_conflicts();
748
+ if ( false !== $_potential_conflicts ) {
749
+ $_ao_potential_conflict_notice .= '<strong>' . $_potential_conflicts . '</strong>.';
750
+ echo '<div class="notice notice-info is-dismissible" data-dismissible="' . $_ao_potential_conflict_dismissible . '"><p>';
751
+ echo $_ao_potential_conflict_notice;
752
+ echo '</p></div>';
753
+ }
754
+ }
755
+ }
756
  }
classes/autoptimizeStyles.php CHANGED
@@ -1221,6 +1221,13 @@ class autoptimizeStyles extends autoptimizeBase
1221
  $contents = $this->prepare_minify_single( $filepath );
1222
 
1223
  if ( empty( $contents ) ) {
 
 
 
 
 
 
 
1224
  return false;
1225
  }
1226
 
1221
  $contents = $this->prepare_minify_single( $filepath );
1222
 
1223
  if ( empty( $contents ) ) {
1224
+ // if aggregate is off and CCSS is used but all files are minified already, then we
1225
+ // must make sure the autoptimize_action_css_hash action still fires for CCSS's sake.
1226
+ $ao_ccss_key = get_option( 'autoptimize_ccss_key', '' );
1227
+ if ( false === $this->aggregate && isset( $ao_ccss_key ) && ! empty( $ao_ccss_key ) ) {
1228
+ $hash = 'single_' . md5( file_get_contents( $filepath ) );
1229
+ do_action( 'autoptimize_action_css_hash', $hash );
1230
+ }
1231
  return false;
1232
  }
1233
 
classes/autoptimizeUtils.php CHANGED
@@ -405,9 +405,9 @@ class autoptimizeUtils
405
  static $_found_pagecache = null;
406
 
407
  if ( null === $_found_pagecache ) {
408
- $_page_cache_constants = array( 'NGINX_HELPER_BASENAME', 'KINSTA_CACHE_ZONE', 'PL_INSTANCE_REF', 'WP_NINUKIS_WP_NAME', 'CACHE_ENABLER_VERSION', 'SBP_PLUGIN_NAME', 'SERVEBOLT_PLUGIN_FILE', 'SWCFPC_PLUGIN_PATH' );
409
  $_page_cache_classes = array( 'Swift_Performance_Cache', 'WpFastestCache', 'c_ws_plugin__qcache_purging_routines', 'zencache', 'comet_cache', 'WpeCommon', 'FlywheelNginxCompat', 'PagelyCachePurge' );
410
- $_page_cache_functions = array( 'wp_cache_clear_cache', 'cachify_flush_cache', 'w3tc_pgcache_flush', 'wp_fast_cache_bulk_delete_all', 'rapidcache_clear_cache', 'sg_cachepress_purge_cache', 'prune_super_cache', 'after_rocket_clean_domain', 'wpo_cache_flush', 'rt_nginx_helper_after_fastcgi_purge_all', 'hyper_cache_purged' );
411
  $_ao_pagecache_transient = 'autoptimize_pagecache_check';
412
  $_found_pagecache = get_transient( $_ao_pagecache_transient );
413
 
@@ -458,4 +458,46 @@ class autoptimizeUtils
458
  $_is_ao_settings = ( str_replace( array( 'autoptimize', 'autoptimize_imgopt', 'ao_critcss', 'autoptimize_extra', 'ao_partners' ), '', $_SERVER['REQUEST_URI'] ) !== $_SERVER['REQUEST_URI'] ? true : false );
459
  return $_is_ao_settings;
460
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
461
  }
405
  static $_found_pagecache = null;
406
 
407
  if ( null === $_found_pagecache ) {
408
+ $_page_cache_constants = array( 'NGINX_HELPER_BASENAME', 'KINSTA_CACHE_ZONE', 'PL_INSTANCE_REF', 'WP_NINUKIS_WP_NAME', 'CACHE_ENABLER_VERSION', 'SBP_PLUGIN_NAME', 'SERVEBOLT_PLUGIN_FILE', 'SWCFPC_PLUGIN_PATH', 'CACHIFY_CACHE_DIR', 'WP_ROCKET_CACHE_PATH', 'WPO_VERSION', 'NGINX_HELPER_BASEURL' );
409
  $_page_cache_classes = array( 'Swift_Performance_Cache', 'WpFastestCache', 'c_ws_plugin__qcache_purging_routines', 'zencache', 'comet_cache', 'WpeCommon', 'FlywheelNginxCompat', 'PagelyCachePurge' );
410
+ $_page_cache_functions = array( 'wp_cache_clear_cache', 'w3tc_pgcache_flush', 'wp_fast_cache_bulk_delete_all', 'rapidcache_clear_cache', 'sg_cachepress_purge_cache', 'prune_super_cache' );
411
  $_ao_pagecache_transient = 'autoptimize_pagecache_check';
412
  $_found_pagecache = get_transient( $_ao_pagecache_transient );
413
 
458
  $_is_ao_settings = ( str_replace( array( 'autoptimize', 'autoptimize_imgopt', 'ao_critcss', 'autoptimize_extra', 'ao_partners' ), '', $_SERVER['REQUEST_URI'] ) !== $_SERVER['REQUEST_URI'] ? true : false );
459
  return $_is_ao_settings;
460
  }
461
+
462
+ /**
463
+ * Returns false if no conflicting plugins are found, the name if the plugin if found.
464
+ *
465
+ * @return bool|string
466
+ */
467
+ public static function find_potential_conflicts() {
468
+ if ( defined( 'WPFC_WP_CONTENT_BASENAME' ) ) {
469
+ $_wpfc_options = json_decode( get_option( 'WpFastestCache' ) );
470
+ foreach ( array( 'wpFastestCacheMinifyCss', 'wpFastestCacheCombineCss','wpFastestCacheCombineJs' ) as $_wpfc_conflicting ) {
471
+ if ( isset( $_wpfc_options->$_wpfc_conflicting ) && $_wpfc_options->$_wpfc_conflicting === 'on' ) {
472
+ return 'WP Fastest Cache';
473
+ }
474
+ }
475
+ } else if ( defined( 'W3TC_VERSION' ) ) {
476
+ $w3tcConfig = file_get_contents( WP_CONTENT_DIR . '/w3tc-config/master.php' );
477
+ $w3tc_minify_on = strpos( $w3tcConfig, '"minify.enabled": true' );
478
+ if ( $w3tc_minify ) {
479
+ return 'W3 Total Cache';
480
+ }
481
+ } else if ( defined('SiteGround_Optimizer\VERSION') ) {
482
+ 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 ) {
483
+ return 'Siteground Optimizer';
484
+ }
485
+ } else if ( defined( 'WPO_VERSION' ) ) {
486
+ $_wpo_options = get_site_option( 'wpo_minify_config' );
487
+ if ( is_array( $_wpo_options ) && $_wpo_options['enabled'] == 1 && ( $_wpo_options['enable_css'] == 1 || $_wpo_options['enable_js'] == 1 ) ) {
488
+ return 'WP Optimize';
489
+ }
490
+ } else if ( defined( 'WPACU_PLUGIN_VERSION' ) || defined( 'WPACU_PRO_PLUGIN_VERSION' ) ) {
491
+ $wpacuSettingsClass = new \WpAssetCleanUp\Settings();
492
+ $wpacuSettings = $wpacuSettingsClass->getAll();
493
+
494
+ if ( $wpacuSettings['minify_loaded_css'] || $wpacuSettings['minify_loaded_js'] || $wpacuSettings['combine_loaded_js'] || $wpacuSettings['combine_loaded_css'] ) {
495
+ return 'Asset Cleanup';
496
+ }
497
+ } else if ( function_exists( 'fvm_get_settings' ) ) {
498
+ return 'Fast Velocity Minify';
499
+ }
500
+
501
+ return false;
502
+ }
503
  }
classes/critcss-inc/admin_settings_queue.php CHANGED
@@ -52,7 +52,7 @@ function ao_ccss_render_queue() {
52
  <!-- BEGIN Queue UI -->
53
  <div class="howto">
54
  <div class="title-wrap">
55
- <h4 class="title"><?php _e( 'How To Use Autoptimize CriticalCSS Power-Up Queue', 'autoptimize' ); ?></h4>
56
  <p class="subtitle"><?php _e( 'Click the side arrow to toggle instructions', 'autoptimize' ); ?></p>
57
  </div>
58
  <button type="button" class="toggle-btn">
@@ -63,12 +63,12 @@ function ao_ccss_render_queue() {
63
  <ol>
64
  <li><?php _e( 'The queue operates <strong>automatically, asynchronously and on regular intervals of 10 minutes.</strong> To view updated queue status, refresh this page.', 'autoptimize' ); ?></li>
65
  <li><?php _e( 'When the conditions to create a job are met (i.e. user not logged in, no matching <span class="badge manual">MANUAL</span> rule or CSS files has changed for an <span class="badge auto">AUTO</span> rule), a <span class="badge new">N</span> job is created in the queue.', 'autoptimize' ); ?></li>
66
- <li><?php _e( "Autoptimize CriticalCSS Power-Up constantly queries the queue for <span class='badge new'>N</span> jobs. When it finds one, gears spins and jobs becomes <span class='badge pending'>P</span> while they are running and <a href='https://criticalcss.com/?aff=1' target='_blank'>criticalcss.com</a> doesn't return a result.", 'autoptimize' ); ?></li>
67
  <li><?php _e( 'As soon as <a href="https://criticalcss.com/?aff=1" target="_blank">criticalcss.com</a> returns a valid critical CSS file, the job is then finished and removed from the queue.', 'autoptimize' ); ?></li>
68
  <li><?php _e( 'When things go wrong, a job is marked as <span class="badge error">E</span>. You can retry faulty jobs, delete them or get in touch with <a href="https://criticalcss.com/?aff=1" target="_blank">criticalcss.com</a> for assistance.', 'autoptimize' ); ?></li>
69
  <li><?php _e( 'Sometimes an unknown condition can happen. In this case, the job status becomes <span class="badge unknown">U</span> and you may want to ask <a href="https://criticalcss.com/?aff=1" target="_blank">criticalcss.com</a> for help or just delete it.', 'autoptimize' ); ?></li>
70
  <li><?php _e( 'To get more information about jobs statuses, specially the ones with <span class="badge error">E</span> and <span class="badge unknown">U</span> status, hover your mouse in the status badge of that job. This information might be crucial when contacting <a href="https://criticalcss.com/?aff=1" target="_blank">criticalcss.com</a> for assistance.', 'autoptimize' ); ?></li>
71
- <li><?php _e( '<strong>A word about WordPress cron:</strong> Autoptimize CriticalCSS Power-Up watch the queue by using WordPress Cron (or WP-Cron for short.) It <a href="https://www.smashingmagazine.com/2013/10/schedule-events-using-wordpress-cron/#limitations-of-wordpress-cron-and-solutions-to-fix-em" target="_blank">could be faulty</a> on very light or very heavy loads. If your site receives just a few or thousands visits a day, it might be a good idea to <a href="https://developer.wordpress.org/plugins/cron/hooking-wp-cron-into-the-system-task-scheduler/" target="_blank">turn WP-Cron off and use your system task scheduler</a> to fire it instead.', 'autoptimize' ); ?></li>
72
  </ol>
73
  </div>
74
  </div>
@@ -81,7 +81,7 @@ function ao_ccss_render_queue() {
81
  <input class="hidden" type="text" id="ao-ccss-queue" name="autoptimize_ccss_queue" value='<?php echo( $ao_ccss_queue ); ?>'>
82
  <div class="submit jobs-btn">
83
  <div id="queuerunner-container" class="alignleft hidden">
84
- <span id="queuerunner" class="button-secondary"><?php _e( 'Manually processs the job queue', 'autoptimize' ); ?></span>
85
  </div>
86
  <div class="alignright">
87
  <span id="removeAllJobs" class="button-secondary" style="color:red;"><?php _e( 'Remove all jobs', 'autoptimize' ); ?></span>
52
  <!-- BEGIN Queue UI -->
53
  <div class="howto">
54
  <div class="title-wrap">
55
+ <h4 class="title"><?php _e( 'How To Use Autoptimize CriticalCSS Queue', 'autoptimize' ); ?></h4>
56
  <p class="subtitle"><?php _e( 'Click the side arrow to toggle instructions', 'autoptimize' ); ?></p>
57
  </div>
58
  <button type="button" class="toggle-btn">
63
  <ol>
64
  <li><?php _e( 'The queue operates <strong>automatically, asynchronously and on regular intervals of 10 minutes.</strong> To view updated queue status, refresh this page.', 'autoptimize' ); ?></li>
65
  <li><?php _e( 'When the conditions to create a job are met (i.e. user not logged in, no matching <span class="badge manual">MANUAL</span> rule or CSS files has changed for an <span class="badge auto">AUTO</span> rule), a <span class="badge new">N</span> job is created in the queue.', 'autoptimize' ); ?></li>
66
+ <li><?php _e( "Autoptimize constantly queries the queue for <span class='badge new'>N</span> jobs. When it finds one, gears spins and jobs becomes <span class='badge pending'>P</span> while they are running and <a href='https://criticalcss.com/?aff=1' target='_blank'>criticalcss.com</a> doesn't return a result.", 'autoptimize' ); ?></li>
67
  <li><?php _e( 'As soon as <a href="https://criticalcss.com/?aff=1" target="_blank">criticalcss.com</a> returns a valid critical CSS file, the job is then finished and removed from the queue.', 'autoptimize' ); ?></li>
68
  <li><?php _e( 'When things go wrong, a job is marked as <span class="badge error">E</span>. You can retry faulty jobs, delete them or get in touch with <a href="https://criticalcss.com/?aff=1" target="_blank">criticalcss.com</a> for assistance.', 'autoptimize' ); ?></li>
69
  <li><?php _e( 'Sometimes an unknown condition can happen. In this case, the job status becomes <span class="badge unknown">U</span> and you may want to ask <a href="https://criticalcss.com/?aff=1" target="_blank">criticalcss.com</a> for help or just delete it.', 'autoptimize' ); ?></li>
70
  <li><?php _e( 'To get more information about jobs statuses, specially the ones with <span class="badge error">E</span> and <span class="badge unknown">U</span> status, hover your mouse in the status badge of that job. This information might be crucial when contacting <a href="https://criticalcss.com/?aff=1" target="_blank">criticalcss.com</a> for assistance.', 'autoptimize' ); ?></li>
71
+ <li><?php _e( '<strong>A word about WordPress cron:</strong> Autoptimize watches the queue by using WordPress Cron (or WP-Cron for short.) It <a href="https://www.smashingmagazine.com/2013/10/schedule-events-using-wordpress-cron/#limitations-of-wordpress-cron-and-solutions-to-fix-em" target="_blank">could be faulty</a> on very light or very heavy loads. If your site receives just a few or thousands visits a day, it might be a good idea to <a href="https://developer.wordpress.org/plugins/cron/hooking-wp-cron-into-the-system-task-scheduler/" target="_blank">turn WP-Cron off and use your system task scheduler</a> to fire it instead.', 'autoptimize' ); ?></li>
72
  </ol>
73
  </div>
74
  </div>
81
  <input class="hidden" type="text" id="ao-ccss-queue" name="autoptimize_ccss_queue" value='<?php echo( $ao_ccss_queue ); ?>'>
82
  <div class="submit jobs-btn">
83
  <div id="queuerunner-container" class="alignleft hidden">
84
+ <span id="queuerunner" class="button-secondary"><?php _e( 'Manually process the job queue', 'autoptimize' ); ?></span>
85
  </div>
86
  <div class="alignright">
87
  <span id="removeAllJobs" class="button-secondary" style="color:red;"><?php _e( 'Remove all jobs', 'autoptimize' ); ?></span>
classes/critcss-inc/admin_settings_rules.js.php CHANGED
@@ -4,7 +4,7 @@
4
  */
5
 
6
  if ( $ao_ccss_debug ) {
7
- echo "console.log('[WARN] Autoptimize CriticalCSS Power-Up is in DEBUG MODE!');\n";
8
  echo "console.log('[WARN] Avoid using debug mode on production/live environments unless for ad-hoc troubleshooting purposes and make sure to disable it after!');\n";
9
  }
10
  ?>
@@ -37,6 +37,7 @@ if (rulesOriginEl) {
37
 
38
  function drawTable(critCssArray) {
39
  jQuery("#rules-list").empty();
 
40
  jQuery.each(critCssArray,function(k,v) {
41
  if (k=="paths") {
42
  kstring="<?php _e( 'Path Based Rules', 'autoptimize' ); ?>";
@@ -65,11 +66,9 @@ function drawTable(critCssArray) {
65
  typeClass = 'auto';
66
  }
67
  if (file && typeof file == 'string') {
68
- rmark=file.split('_');
69
- if (rmark[2] || rmark[2] == 'R.css') {
70
- rmark = '<span class="badge review rule">R</span>'
71
- } else {
72
- rmark = '';
73
  }
74
  }
75
  if ( k == "paths" ) {
@@ -77,11 +76,34 @@ function drawTable(critCssArray) {
77
  } else {
78
  target = i.replace(/(woo_|template_|custom_post_|edd_|bp_|bbp_)/,'');
79
  }
80
- jQuery("#rules-list").append("<tr class='rule "+k+"Rule'><td class='type'><span class='badge " + typeClass + "'>" + type + "</span>" + rmark + "</td><td class='target'>" + target + "</td><td class='file'>" + file + "</td><td class='btn edit'><span class=\"button-secondary\" id=\"" + nodeId + "_edit\"><?php _e( 'Edit', 'autoptimize' ); ?></span></td><td class='btn delete'><span class=\"button-secondary\" id=\"" + nodeId + "_remove\"><?php _e( 'Remove', 'autoptimize' ); ?></span></td></tr>");
81
  jQuery("#" + nodeId + "_edit").click(function(){addEditRow(this.id);});
82
  jQuery("#" + nodeId + "_remove").click(function(){confirmRemove(this.id);});
83
  })
84
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
85
  }
86
 
87
  function confirmRemove(idToRemove) {
@@ -358,18 +380,38 @@ function saveEditCritCss(){
358
  function updateAfterChange() {
359
  document.getElementById("critCssOrigin").value=JSON.stringify(critCssArray);
360
  drawTable(critCssArray);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
361
  jQuery("#unSavedWarning").show();
 
 
362
  document.getElementById('ao_title_and_button').scrollIntoView();
363
  }
364
 
365
- function displayNotice(textIn, level) {
366
- if ( '' == level ) { level = 'error'; }
367
- jQuery('<div class="notice-' + level + ' notice is-dismissable"><p>'+textIn+'</p></div>').insertBefore("#unSavedWarning");
368
  document.getElementById('ao_title_and_button').scrollIntoView();
369
  }
370
 
371
  function resetForm() {
372
- jQuery("#critcss_addedit_css").attr("placeholder", "<?php _e( 'For path based rules, paste your specific and minified critical CSS here or leave this empty to fetch it from criticalcss.com and hit submit to save. If you want to create a rule to exclude from critical CSS injection, enter \"none\"', 'autoptimize' ); ?>");
373
  jQuery("#critcss_addedit_type").attr("disabled",false);
374
  jQuery("#critcss_addedit_path_wrapper").show();
375
  jQuery("#critcss_addedit_id").val("");
4
  */
5
 
6
  if ( $ao_ccss_debug ) {
7
+ echo "console.log('[WARN] Autoptimize CriticalCSS is in debug mode!');\n";
8
  echo "console.log('[WARN] Avoid using debug mode on production/live environments unless for ad-hoc troubleshooting purposes and make sure to disable it after!');\n";
9
  }
10
  ?>
37
 
38
  function drawTable(critCssArray) {
39
  jQuery("#rules-list").empty();
40
+ rnotice = 0;
41
  jQuery.each(critCssArray,function(k,v) {
42
  if (k=="paths") {
43
  kstring="<?php _e( 'Path Based Rules', 'autoptimize' ); ?>";
66
  typeClass = 'auto';
67
  }
68
  if (file && typeof file == 'string') {
69
+ rmark_find=file.split('_');
70
+ if (rmark_find[2] || rmark_find[2] == 'R.css') {
71
+ rnotice = rnotice + 1;
 
 
72
  }
73
  }
74
  if ( k == "paths" ) {
76
  } else {
77
  target = i.replace(/(woo_|template_|custom_post_|edd_|bp_|bbp_)/,'');
78
  }
79
+ jQuery("#rules-list").append("<tr class='rule "+k+"Rule'><td class='type'><span class='badge " + typeClass + "'>" + type + "</span></td><td class='target'>" + target + "</td><td class='file'>" + file + "</td><td class='btn edit'><span class=\"button-secondary\" id=\"" + nodeId + "_edit\"><?php _e( 'Edit', 'autoptimize' ); ?></span></td><td class='btn delete'><span class=\"button-secondary\" id=\"" + nodeId + "_remove\"><?php _e( 'Remove', 'autoptimize' ); ?></span></td></tr>");
80
  jQuery("#" + nodeId + "_edit").click(function(){addEditRow(this.id);});
81
  jQuery("#" + nodeId + "_remove").click(function(){confirmRemove(this.id);});
82
  })
83
  });
84
+ if ( rnotice && rnotice != 0 ) {
85
+ // R rules were found, show a notice!
86
+ // and add some JS magic to ensure the notice works as a notice, but is shown inline
87
+ // in the rules panel instead of in the notice area where it would be too prominent.
88
+ <?php
89
+ $_ao_ccss_review_notice_id = 'autoptimize-ccss-review-rules-notice-30';
90
+ // Translators: before the 1st word a number + a space will be displayed, as in e.g. "2 of above rules".
91
+ $_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');
92
+ if ( PAnD::is_admin_notice_active( $_ao_ccss_review_notice_id ) ) {
93
+ ?>
94
+ 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>");
95
+ jQuery( document ).ready(function() {
96
+ jQuery("div.rnotice").detach().appendTo('#rules-notices');
97
+ jQuery("div.rnotice").show();
98
+ });
99
+ <?php
100
+ } else {
101
+ ?>
102
+ console.log( "Autoptimize: " + rnotice + " <?php echo $_ao_ccss_review_notice_copy; ?>" );
103
+ <?php
104
+ }
105
+ ?>
106
+ }
107
  }
108
 
109
  function confirmRemove(idToRemove) {
380
  function updateAfterChange() {
381
  document.getElementById("critCssOrigin").value=JSON.stringify(critCssArray);
382
  drawTable(critCssArray);
383
+
384
+ <?php
385
+ // autosave rules is on by default, but can be disabled with a filter.
386
+ if ( apply_filters( 'autoptimize_filter_ccss_settings_rules_autosave', true ) ) {
387
+ ?>
388
+ var data = {
389
+ 'action': 'ao_ccss_saverules',
390
+ 'ao_ccss_saverules_nonce': '<?php echo wp_create_nonce( 'ao_ccss_saverules_nonce' ); ?>',
391
+ 'critcssrules': document.getElementById("critCssOrigin").value
392
+ };
393
+
394
+ jQuery.post(ajaxurl, data, function(response) {
395
+ response_array=JSON.parse(response);
396
+ if (response_array["code"]!=200) {
397
+ displayNotice(response_array["msg"]);
398
+ jQuery("#unSavedWarning").show();
399
+ }
400
+ });
401
+ <?php } else { ?>
402
  jQuery("#unSavedWarning").show();
403
+ <?php } ?>
404
+
405
  document.getElementById('ao_title_and_button').scrollIntoView();
406
  }
407
 
408
+ function displayNotice(textIn, level = 'error') {
409
+ jQuery('<div class="notice notice-' + level + ' notice is-dismissible"><p>'+textIn+'</p></div>').insertBefore("#unSavedWarning");
 
410
  document.getElementById('ao_title_and_button').scrollIntoView();
411
  }
412
 
413
  function resetForm() {
414
+ jQuery("#critcss_addedit_css").attr("placeholder", "<?php _e( 'For path based rules, paste your specific and minified critical CSS. If you want to create a rule to exclude from critical CSS injection, enter \"none\"', 'autoptimize' ); ?>");
415
  jQuery("#critcss_addedit_type").attr("disabled",false);
416
  jQuery("#critcss_addedit_path_wrapper").show();
417
  jQuery("#critcss_addedit_id").val("");
classes/critcss-inc/admin_settings_rules.php CHANGED
@@ -150,22 +150,18 @@ function ao_ccss_render_rules() {
150
 
151
  <!-- Add/edit default critical CSS dialog -->
152
  <div id="default_critcss_wrapper" class="hidden">
153
- <textarea id="dummyDefault" rows="19" cols="10" style="width:100%;" placeholder="<?php _e( 'Paste your MINIFIED default critical CSS here and hit submit to save. This is the critical CSS to be used for every page NOT MATCHING any rule.', 'autoptimize' ); ?>"></textarea>
154
  </div>
155
 
156
  <!-- Add/edit additional critical CSS dialog -->
157
  <div id="additional_critcss_wrapper" class="hidden">
158
- <textarea id="dummyAdditional" rows="19" cols="10" style="width:100%;" placeholder="<?php _e( 'Paste your MINIFIED additional critical CSS here and hit submit to save. This is the CSS to be added AT THE END of every critical CSS provided by a matching rule, or the default one.', 'autoptimize' ); ?>"></textarea>
159
  </div>
160
 
161
- <!-- Wrapper for in screen notices -->
162
- <div id="rules-notices"></div>
163
- <!-- END Rule add/edit dialogs -->
164
-
165
  <!-- BEGIN Rules UI -->
166
  <div class="howto">
167
  <div class="title-wrap">
168
- <h4 class="title"><?php _e( 'How To Use Autoptimize CriticalCSS Power-Up Rules', 'autoptimize' ); ?></h4>
169
  <p class="subtitle"><?php _e( 'Click the side arrow to toggle instructions', 'autoptimize' ); ?></p>
170
  </div>
171
  <button type="button" class="toggle-btn">
@@ -174,13 +170,11 @@ function ao_ccss_render_rules() {
174
  <div class="howto-wrap hidden">
175
  <p><?php _e( "TL;DR:<br />Critical CSS files from <span class='badge auto'>AUTO</span> <strong>rules are updated automatically</strong> while from <span class='badge manual'>MANUAL</span> <strong>rules are not.</strong>", 'autoptimize' ); ?></p>
176
  <ol>
177
- <li><?php _e( 'When a valid <a href="https://criticalcss.com/?aff=1" target="_blank">criticalcss.com</a> API key is in place, Autoptimize CriticalCSS Power-Up starts to operate <strong>automatically</strong>.', 'autoptimize' ); ?></li>
178
  <li><?php _e( 'Upon a request to any of the frontend pages made by a <strong>not logged in user</strong>, it will <strong>asynchronously</strong> fetch and update the critical CSS from <a href="https://criticalcss.com/?aff=1" target="_blank">criticalcss.com</a> for conditional tags you have on your site (e.g. is_page, is_single, is_archive etc.)', 'autoptimize' ); ?></li>
179
  <li><?php _e( 'These requests also creates an <span class="badge auto">AUTO</span> rule for you. The critical CSS files from <span class="badge auto">AUTO</span> <strong>rules are updated automatically</strong> when a CSS file in your theme or frontend plugins changes.', 'autoptimize' ); ?></li>
180
  <li><?php _e( 'If you want to make any fine tunning in the critical CSS file of an <span class="badge auto">AUTO</span> rule, click on "Edit" button of that rule, change what you need, submit and save it. The rule you\'ve just edited becomes a <span class="badge manual">MANUAL</span> rule then.', 'autoptimize' ); ?></li>
181
  <li><?php _e( 'You can create <span class="badge manual">MANUAL</span> rules for specific page paths (URL). Longer, more specific paths have higher priority over shorter ones, which in turn have higher priority over <span class="badge auto">AUTO</span> rules. Also, critical CSS files from <span class="badge manual">MANUAL</span> <strong>rules are NEVER updated automatically.</strong>', 'autoptimize' ); ?></li>
182
- <li><?php _e( 'You can also create an <span class="badge auto">AUTO</span> rule for a path by leaving its critical CSS content empty. The critical CSS for that path will be automatically fetched from <a href="https://criticalcss.com/?aff=1" target="_blank">criticalcss.com</a> for you and updated whenever it changes.', 'autoptimize' ); ?></li>
183
- <li><?php _e( "If you see an <span class='badge auto'>AUTO</span> rule with a <span class='badge review'>R</span> besides it (R is after REVIEW), it means that the fetched critical CSS for that rule is not 100% guaranteed to work according to <a href='https://criticalcss.com/?aff=1' target='_blank'>criticalcss.com</a> analysis. It's advised that you edit and review that rule to make any required adjustments.", 'autoptimize' ); ?></li>
184
  <li><?php _e( 'At any time you can delete an <span class="badge auto">AUTO</span> or <span class="badge manual">MANUAL</span> rule by cliking on "Remove" button of the desired rule and saving your changes.', 'autoptimize' ); ?></li>
185
  </ol>
186
  </div>
@@ -189,6 +183,9 @@ function ao_ccss_render_rules() {
189
  <textarea id="autoptimize_ccss_additional" name="autoptimize_ccss_additional" rows="19" cols="10" style="width:100%;"><?php echo autoptimizeStyles::sanitize_css( get_option( 'autoptimize_ccss_additional', '' ) ); ?></textarea>
190
  <table class="rules-list" cellspacing="0"><tbody id="rules-list"></tbody></table>
191
  <input class="hidden" type="text" id="critCssOrigin" name="autoptimize_ccss_rules" value='<?php echo ( json_encode( $ao_ccss_rules, JSON_FORCE_OBJECT ) ); ?>'>
 
 
 
192
  <div class="submit rules-btn">
193
  <div class="alignleft">
194
  <span id="addCritCssButton" class="button-secondary"><?php _e( 'Add New Rule', 'autoptimize' ); ?></span>
150
 
151
  <!-- Add/edit default critical CSS dialog -->
152
  <div id="default_critcss_wrapper" class="hidden">
153
+ <textarea id="dummyDefault" rows="19" cols="10" style="width:100%;" placeholder="<?php _e( 'Paste your minified default critical CSS here and hit submit to save. This is the critical CSS to be used for every page not matching any rule.', 'autoptimize' ); ?>"></textarea>
154
  </div>
155
 
156
  <!-- Add/edit additional critical CSS dialog -->
157
  <div id="additional_critcss_wrapper" class="hidden">
158
+ <textarea id="dummyAdditional" rows="19" cols="10" style="width:100%;" placeholder="<?php _e( 'Paste your minified additional critical CSS here and hit submit to save. This is the CSS to be added AT THE END of every critical CSS provided by a matching rule, or the default one.', 'autoptimize' ); ?>"></textarea>
159
  </div>
160
 
 
 
 
 
161
  <!-- BEGIN Rules UI -->
162
  <div class="howto">
163
  <div class="title-wrap">
164
+ <h4 class="title"><?php _e( 'How To Use Autoptimize CriticalCSS Rules', 'autoptimize' ); ?></h4>
165
  <p class="subtitle"><?php _e( 'Click the side arrow to toggle instructions', 'autoptimize' ); ?></p>
166
  </div>
167
  <button type="button" class="toggle-btn">
170
  <div class="howto-wrap hidden">
171
  <p><?php _e( "TL;DR:<br />Critical CSS files from <span class='badge auto'>AUTO</span> <strong>rules are updated automatically</strong> while from <span class='badge manual'>MANUAL</span> <strong>rules are not.</strong>", 'autoptimize' ); ?></p>
172
  <ol>
173
+ <li><?php _e( 'When a valid <a href="https://criticalcss.com/?aff=1" target="_blank">criticalcss.com</a> API key is in place, Autoptimize starts to operate <strong>automatically</strong>.', 'autoptimize' ); ?></li>
174
  <li><?php _e( 'Upon a request to any of the frontend pages made by a <strong>not logged in user</strong>, it will <strong>asynchronously</strong> fetch and update the critical CSS from <a href="https://criticalcss.com/?aff=1" target="_blank">criticalcss.com</a> for conditional tags you have on your site (e.g. is_page, is_single, is_archive etc.)', 'autoptimize' ); ?></li>
175
  <li><?php _e( 'These requests also creates an <span class="badge auto">AUTO</span> rule for you. The critical CSS files from <span class="badge auto">AUTO</span> <strong>rules are updated automatically</strong> when a CSS file in your theme or frontend plugins changes.', 'autoptimize' ); ?></li>
176
  <li><?php _e( 'If you want to make any fine tunning in the critical CSS file of an <span class="badge auto">AUTO</span> rule, click on "Edit" button of that rule, change what you need, submit and save it. The rule you\'ve just edited becomes a <span class="badge manual">MANUAL</span> rule then.', 'autoptimize' ); ?></li>
177
  <li><?php _e( 'You can create <span class="badge manual">MANUAL</span> rules for specific page paths (URL). Longer, more specific paths have higher priority over shorter ones, which in turn have higher priority over <span class="badge auto">AUTO</span> rules. Also, critical CSS files from <span class="badge manual">MANUAL</span> <strong>rules are NEVER updated automatically.</strong>', 'autoptimize' ); ?></li>
 
 
178
  <li><?php _e( 'At any time you can delete an <span class="badge auto">AUTO</span> or <span class="badge manual">MANUAL</span> rule by cliking on "Remove" button of the desired rule and saving your changes.', 'autoptimize' ); ?></li>
179
  </ol>
180
  </div>
183
  <textarea id="autoptimize_ccss_additional" name="autoptimize_ccss_additional" rows="19" cols="10" style="width:100%;"><?php echo autoptimizeStyles::sanitize_css( get_option( 'autoptimize_ccss_additional', '' ) ); ?></textarea>
184
  <table class="rules-list" cellspacing="0"><tbody id="rules-list"></tbody></table>
185
  <input class="hidden" type="text" id="critCssOrigin" name="autoptimize_ccss_rules" value='<?php echo ( json_encode( $ao_ccss_rules, JSON_FORCE_OBJECT ) ); ?>'>
186
+ <!-- Wrapper for in screen notices -->
187
+ <div id="rules-notices"></div>
188
+ <!-- END Rule add/edit dialogs -->
189
  <div class="submit rules-btn">
190
  <div class="alignleft">
191
  <span id="addCritCssButton" class="button-secondary"><?php _e( 'Add New Rule', 'autoptimize' ); ?></span>
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: 5.8
7
  Requires PHP: 5.6
8
- Stable tag: 2.9.0
9
 
10
  Autoptimize speeds up your website by optimizing JS, CSS, images (incl. lazy-load), HTML and Google Fonts, asyncing JS, removing emoji cruft and more.
11
 
@@ -328,11 +328,20 @@ Just [fork Autoptimize on Github](https://github.com/futtta/autoptimize) and cod
328
 
329
  == Changelog ==
330
 
 
 
 
 
 
 
 
 
 
331
  = 2.9.0 =
332
  * New: per page/ post Autoptimize settings so one can disable specific optimizations (needs to be enabled on the main settings page under "Misc Options").
333
  * New: "defer inline JS" as sub-option of "do not aggregate but defer" allowing to defer (almost) all JS.
334
  * Improvement: Image optimization now automatically switches between AVIF & WebP & Jpeg even if lazyload is not active (AVIF has to be explicitly enabled).
335
- * Improvement: re-ordering of "JavaScript optimization" settings
336
  * Misc. other minor fixes, see the [GitHub commit log](https://github.com/futtta/autoptimize/commits/beta)
337
 
338
  This release coincides with my father's 76th birthday, who continues to be a big inspritation to me. He's a mechanical engineer who after retirement focused his technical insights, experience and never-ending inquisitiveness on fountain pen design and prototyping, inventing a new bulkfiller mechanism in the process. Search the web for `Fountainbel` to find out more about him (or read [this older blogpost I wrote in Dutch](https://blog.futtta.be/2008/04/09/mijn-vader-is-een-tovenaar/)). Love you pops!
5
  Requires at least: 4.9
6
  Tested up to: 5.8
7
  Requires PHP: 5.6
8
+ Stable tag: 2.9.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
 
328
 
329
  == Changelog ==
330
 
331
+ = 2.9.1 =
332
+ * New: logic to detect possibly conflicting plugins, with notification if found.
333
+ * Improvement: to be reviewed critical css rules UI change.
334
+ * Improvement: automatically save critical CSS rules when changed.
335
+ * Fix for no CCSS jobs being created when "aggregate CSS" is off and all files are minified.
336
+ * Fix for some page caches not being detected correctly leading to notification being shown when it should not (thanks @optimocha for warning me!)
337
+ * Fix for a (rare) lazyload-regression in 2.9.0.
338
+ * Fix for a (rare) image optimization issue when the same image is referenced multiple times as background-image in optimized CSS.
339
+
340
  = 2.9.0 =
341
  * New: per page/ post Autoptimize settings so one can disable specific optimizations (needs to be enabled on the main settings page under "Misc Options").
342
  * New: "defer inline JS" as sub-option of "do not aggregate but defer" allowing to defer (almost) all JS.
343
  * Improvement: Image optimization now automatically switches between AVIF & WebP & Jpeg even if lazyload is not active (AVIF has to be explicitly enabled).
344
+ * Improvement: re-ordering of "JavaScript optimization" settings & copy improvements.
345
  * Misc. other minor fixes, see the [GitHub commit log](https://github.com/futtta/autoptimize/commits/beta)
346
 
347
  This release coincides with my father's 76th birthday, who continues to be a big inspritation to me. He's a mechanical engineer who after retirement focused his technical insights, experience and never-ending inquisitiveness on fountain pen design and prototyping, inventing a new bulkfiller mechanism in the process. Search the web for `Fountainbel` to find out more about him (or read [this older blogpost I wrote in Dutch](https://blog.futtta.be/2008/04/09/mijn-vader-is-een-tovenaar/)). Love you pops!