Cache Enabler – WordPress Cache - Version 1.7.0

Version Description

  • Update cache clearing for theme, plugin, post, and upgrade actions (#215 and #216)
  • Update cache handling with cache keys (#211)
  • Update settings file deletion handling (#205)
  • Update output buffer handling (#203)
  • Update removing CSS and JavaScript comments during HTML minification (#202)
  • Update WebP URL conversion for installations in a subdirectory (#198)
  • Add CACHE_ENABLER_DIR as definable plugin directory constant (#195 @stevegrunwell)
  • Add explicit directory access permissions (#194 @stevegrunwell)
  • Add exclusive lock when writing files (#191 @nawawi)
  • Fix clear cache request handling (#212)
  • Fix getting wp-config.php (#210 @stevegrunwell)
Download this release

Release Info

Developer keycdn
Plugin Icon 128x128 Cache Enabler – WordPress Cache
Version 1.7.0
Comparing to
See all releases

Code changes from version 1.6.2 to 1.7.0

advanced-cache.php CHANGED
@@ -3,29 +3,38 @@
3
  * Cache Enabler advanced cache
4
  *
5
  * @since 1.2.0
6
- * @change 1.6.0
7
  */
8
 
9
  if ( ! defined( 'ABSPATH' ) ) {
10
  exit;
11
  }
12
 
13
- $ce_dir = ( ( defined( 'WP_PLUGIN_DIR' ) ) ? WP_PLUGIN_DIR : WP_CONTENT_DIR . '/plugins' ) . '/cache-enabler';
14
- $ce_engine_file = $ce_dir . '/inc/cache_enabler_engine.class.php';
15
- $ce_disk_file = $ce_dir . '/inc/cache_enabler_disk.class.php';
 
 
 
 
 
 
 
 
 
16
 
17
- if ( file_exists( $ce_engine_file ) && file_exists( $ce_disk_file ) ) {
18
- require_once $ce_engine_file;
19
- require_once $ce_disk_file;
20
  }
21
 
22
  if ( class_exists( 'Cache_Enabler_Engine' ) ) {
23
- $ce_engine_started = Cache_Enabler_Engine::start();
24
 
25
- if ( $ce_engine_started ) {
26
- $ce_cache_delivered = Cache_Enabler_Engine::deliver_cache();
27
 
28
- if ( ! $ce_cache_delivered ) {
29
  Cache_Enabler_Engine::start_buffering();
30
  }
31
  }
3
  * Cache Enabler advanced cache
4
  *
5
  * @since 1.2.0
6
+ * @change 1.7.0
7
  */
8
 
9
  if ( ! defined( 'ABSPATH' ) ) {
10
  exit;
11
  }
12
 
13
+ /**
14
+ * set the CACHE_ENABLER_DIR constant without trailing slash in your wp-config.php file if the plugin resides
15
+ * somewhere other than path/to/wp-content/plugins/cache-enabler
16
+ */
17
+ if ( defined( 'CACHE_ENABLER_DIR' ) ) {
18
+ $cache_enabler_dir = CACHE_ENABLER_DIR;
19
+ } else {
20
+ $cache_enabler_dir = ( ( defined( 'WP_PLUGIN_DIR' ) ) ? WP_PLUGIN_DIR : WP_CONTENT_DIR . '/plugins' ) . '/cache-enabler';
21
+ }
22
+
23
+ $cache_enabler_engine_file = $cache_enabler_dir . '/inc/cache_enabler_engine.class.php';
24
+ $cache_enabler_disk_file = $cache_enabler_dir . '/inc/cache_enabler_disk.class.php';
25
 
26
+ if ( file_exists( $cache_enabler_engine_file ) && file_exists( $cache_enabler_disk_file ) ) {
27
+ require_once $cache_enabler_engine_file;
28
+ require_once $cache_enabler_disk_file;
29
  }
30
 
31
  if ( class_exists( 'Cache_Enabler_Engine' ) ) {
32
+ $cache_enabler_engine_started = Cache_Enabler_Engine::start();
33
 
34
+ if ( $cache_enabler_engine_started ) {
35
+ $cache_enabler_cache_delivered = Cache_Enabler_Engine::deliver_cache();
36
 
37
+ if ( ! $cache_enabler_cache_delivered ) {
38
  Cache_Enabler_Engine::start_buffering();
39
  }
40
  }
cache-enabler.php CHANGED
@@ -6,11 +6,11 @@ Description: Simple and fast WordPress caching plugin.
6
  Author: KeyCDN
7
  Author URI: https://www.keycdn.com
8
  License: GPLv2 or later
9
- Version: 1.6.2
10
  */
11
 
12
  /*
13
- Copyright (C) 2020 KeyCDN
14
 
15
  This program is free software; you can redistribute it and/or modify
16
  it under the terms of the GNU General Public License as published by
@@ -32,12 +32,23 @@ if ( ! defined( 'ABSPATH' ) ) {
32
  }
33
 
34
  // constants
35
- define( 'CE_VERSION', '1.6.2' );
36
- define( 'CE_MIN_PHP', '5.6' );
37
- define( 'CE_MIN_WP', '5.1' );
38
- define( 'CE_FILE', __FILE__ );
39
- define( 'CE_BASE', plugin_basename( __FILE__ ) );
40
- define( 'CE_DIR', __DIR__ );
 
 
 
 
 
 
 
 
 
 
 
41
 
42
  // hooks
43
  add_action( 'plugins_loaded', array( 'Cache_Enabler', 'init' ) );
@@ -51,10 +62,10 @@ spl_autoload_register( 'cache_enabler_autoload' );
51
  // load required classes
52
  function cache_enabler_autoload( $class_name ) {
53
  // check if classes were loaded in advanced-cache.php
54
- if ( in_array( $class_name, array( 'Cache_Enabler', 'Cache_Enabler_Engine', 'Cache_Enabler_Disk' ) ) && ! class_exists( $class_name ) ) {
55
  require_once sprintf(
56
  '%s/inc/%s.class.php',
57
- CE_DIR,
58
  strtolower( $class_name )
59
  );
60
  }
@@ -62,5 +73,5 @@ function cache_enabler_autoload( $class_name ) {
62
 
63
  // load WP-CLI command
64
  if ( defined( 'WP_CLI' ) && WP_CLI && class_exists( 'WP_CLI' ) ) {
65
- require_once CE_DIR . '/inc/cache_enabler_cli.class.php';
66
  }
6
  Author: KeyCDN
7
  Author URI: https://www.keycdn.com
8
  License: GPLv2 or later
9
+ Version: 1.7.0
10
  */
11
 
12
  /*
13
+ Copyright (C) 2021 KeyCDN
14
 
15
  This program is free software; you can redistribute it and/or modify
16
  it under the terms of the GNU General Public License as published by
32
  }
33
 
34
  // constants
35
+ define( 'CACHE_ENABLER_VERSION', '1.7.0' );
36
+ define( 'CACHE_ENABLER_MIN_PHP', '5.6' );
37
+ define( 'CACHE_ENABLER_MIN_WP', '5.1' );
38
+ define( 'CACHE_ENABLER_FILE', __FILE__ );
39
+ define( 'CACHE_ENABLER_BASE', plugin_basename( __FILE__ ) );
40
+
41
+ if ( ! defined( 'CACHE_ENABLER_DIR' ) ) {
42
+ define( 'CACHE_ENABLER_DIR', __DIR__ );
43
+ }
44
+
45
+ // deprecated constants (1.7.0)
46
+ define( 'CE_VERSION', CACHE_ENABLER_VERSION );
47
+ define( 'CE_MIN_PHP', CACHE_ENABLER_MIN_PHP );
48
+ define( 'CE_MIN_WP', CACHE_ENABLER_MIN_WP );
49
+ define( 'CE_FILE', CACHE_ENABLER_FILE );
50
+ define( 'CE_BASE', CACHE_ENABLER_BASE );
51
+ define( 'CE_DIR', CACHE_ENABLER_DIR );
52
 
53
  // hooks
54
  add_action( 'plugins_loaded', array( 'Cache_Enabler', 'init' ) );
62
  // load required classes
63
  function cache_enabler_autoload( $class_name ) {
64
  // check if classes were loaded in advanced-cache.php
65
+ if ( in_array( $class_name, array( 'Cache_Enabler', 'Cache_Enabler_Engine', 'Cache_Enabler_Disk' ), true ) && ! class_exists( $class_name ) ) {
66
  require_once sprintf(
67
  '%s/inc/%s.class.php',
68
+ CACHE_ENABLER_DIR,
69
  strtolower( $class_name )
70
  );
71
  }
73
 
74
  // load WP-CLI command
75
  if ( defined( 'WP_CLI' ) && WP_CLI && class_exists( 'WP_CLI' ) ) {
76
+ require_once CACHE_ENABLER_DIR . '/inc/cache_enabler_cli.class.php';
77
  }
inc/cache_enabler.class.php CHANGED
@@ -50,7 +50,7 @@ final class Cache_Enabler {
50
  * constructor
51
  *
52
  * @since 1.0.0
53
- * @change 1.6.1
54
  */
55
 
56
  public function __construct() {
@@ -72,14 +72,13 @@ final class Cache_Enabler {
72
  // system clear cache hooks
73
  add_action( '_core_updated_successfully', array( __CLASS__, 'clear_complete_cache' ) );
74
  add_action( 'upgrader_process_complete', array( __CLASS__, 'on_upgrade' ), 10, 2 );
75
- add_action( 'switch_theme', array( __CLASS__, 'clear_complete_cache' ) );
76
  add_action( 'permalink_structure_changed', array( __CLASS__, 'clear_site_cache' ) );
77
  add_action( 'activated_plugin', array( __CLASS__, 'on_plugin_activation_deactivation' ), 10, 2 );
78
  add_action( 'deactivated_plugin', array( __CLASS__, 'on_plugin_activation_deactivation' ), 10, 2 );
79
- add_action( 'save_post', array( __CLASS__, 'on_save_post' ) );
80
- add_action( 'post_updated', array( __CLASS__, 'on_post_updated' ), 10, 3 );
81
- add_action( 'wp_trash_post', array( __CLASS__, 'on_trash_post' ) );
82
- add_action( 'transition_post_status', array( __CLASS__, 'on_transition_post_status' ), 10, 3 );
83
  add_action( 'comment_post', array( __CLASS__, 'on_comment_post' ), 99, 2 );
84
  add_action( 'edit_comment', array( __CLASS__, 'on_edit_comment' ), 10, 2 );
85
  add_action( 'transition_comment_status', array( __CLASS__, 'on_transition_comment_status' ), 10, 3 );
@@ -111,7 +110,7 @@ final class Cache_Enabler {
111
  add_action( 'admin_enqueue_scripts', array( __CLASS__, 'add_admin_resources' ) );
112
  // dashboard
113
  add_filter( 'dashboard_glance_items', array( __CLASS__, 'add_dashboard_cache_size' ) );
114
- add_filter( 'plugin_action_links_' . CE_BASE, array( __CLASS__, 'add_plugin_action_links' ) );
115
  add_filter( 'plugin_row_meta', array( __CLASS__, 'add_plugin_row_meta' ), 10, 2 );
116
  // notices
117
  add_action( 'admin_notices', array( __CLASS__, 'requirements_check' ) );
@@ -144,7 +143,7 @@ final class Cache_Enabler {
144
  * upgrade hook
145
  *
146
  * @since 1.2.3
147
- * @change 1.6.0
148
  *
149
  * @param WP_Upgrader $obj upgrade instance
150
  * @param array $data update data
@@ -152,16 +151,48 @@ final class Cache_Enabler {
152
 
153
  public static function on_upgrade( $obj, $data ) {
154
 
155
- // if setting enabled clear site cache on any plugin update
156
- if ( Cache_Enabler_Engine::$settings['clear_site_cache_on_changed_plugin'] ) {
157
- self::clear_site_cache();
 
 
 
 
 
 
 
 
 
 
 
 
 
158
  }
159
 
160
- // check if Cache Enabler has been updated
161
- if ( $data['action'] === 'update' && $data['type'] === 'plugin' && array_key_exists( 'plugins', $data ) ) {
162
- foreach ( (array) $data['plugins'] as $plugin_file ) {
163
- if ( $plugin_file === CE_BASE ) {
164
- self::on_ce_update();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
165
  }
166
  }
167
  }
@@ -172,10 +203,10 @@ final class Cache_Enabler {
172
  * Cache Enabler update actions
173
  *
174
  * @since 1.4.0
175
- * @change 1.6.0
176
  */
177
 
178
- public static function on_ce_update() {
179
 
180
  // clean system files
181
  self::each_site( is_multisite(), 'Cache_Enabler_Disk::clean' );
@@ -225,7 +256,7 @@ final class Cache_Enabler {
225
  * install on new site in multisite network
226
  *
227
  * @since 1.0.0
228
- * @change 1.6.0
229
  *
230
  * @param WP_Site $new_site new site instance
231
  */
@@ -233,7 +264,7 @@ final class Cache_Enabler {
233
  public static function install_later( $new_site ) {
234
 
235
  // check if network activated
236
- if ( ! is_plugin_active_for_network( CE_BASE ) ) {
237
  return;
238
  }
239
 
@@ -252,9 +283,9 @@ final class Cache_Enabler {
252
  * add or update backend requirements
253
  *
254
  * @since 1.5.0
255
- * @change 1.6.0
256
  *
257
- * @return $new_option_value new or current database option value
258
  */
259
 
260
  public static function update_backend() {
@@ -281,6 +312,9 @@ final class Cache_Enabler {
281
  // merge defined settings into default settings
282
  $new_option_value = wp_parse_args( $old_option_value, self::get_default_settings() );
283
 
 
 
 
284
  // add or update database option
285
  update_option( 'cache_enabler', $new_option_value );
286
 
@@ -348,7 +382,7 @@ final class Cache_Enabler {
348
  * enter each site
349
  *
350
  * @since 1.5.0
351
- * @change 1.5.0
352
  *
353
  * @param boolean $network whether or not each site in network
354
  * @param string $callback callback function
@@ -362,14 +396,16 @@ final class Cache_Enabler {
362
 
363
  if ( $network ) {
364
  $blog_ids = self::get_blog_ids();
 
365
  // switch to each site in network
366
  foreach ( $blog_ids as $blog_id ) {
367
  switch_to_blog( $blog_id );
368
- $callback_return[] = (int) call_user_func_array( $callback, $callback_params );
369
  restore_current_blog();
370
  }
371
  } else {
372
- $callback_return[] = (int) call_user_func_array( $callback, $callback_params );
 
373
  }
374
 
375
  return $callback_return;
@@ -396,7 +432,7 @@ final class Cache_Enabler {
396
  * get settings from database
397
  *
398
  * @since 1.0.0
399
- * @change 1.5.0
400
  *
401
  * @return array $settings current settings from database
402
  */
@@ -407,7 +443,7 @@ final class Cache_Enabler {
407
  $settings = get_option( 'cache_enabler' );
408
 
409
  // if database option does not exist or settings are outdated
410
- if ( $settings === false || isset( $settings['version'] ) && $settings['version'] !== CE_VERSION ) {
411
  $settings = self::update_backend();
412
  }
413
 
@@ -419,18 +455,19 @@ final class Cache_Enabler {
419
  * get blog IDs
420
  *
421
  * @since 1.0.0
422
- * @change 1.6.0
423
  *
424
  * @return array $blog_ids blog IDs
425
  */
426
 
427
  private static function get_blog_ids() {
428
 
429
- $blog_ids = array( '1' );
430
 
431
  if ( is_multisite() ) {
432
  global $wpdb;
433
- $blog_ids = $wpdb->get_col( "SELECT blog_id FROM $wpdb->blogs" );
 
434
  }
435
 
436
  return $blog_ids;
@@ -513,10 +550,10 @@ final class Cache_Enabler {
513
 
514
 
515
  /**
516
- * get cache size
517
  *
518
  * @since 1.0.0
519
- * @change 1.5.0
520
  *
521
  * @return integer $cache_size cache size in bytes
522
  */
@@ -526,7 +563,7 @@ final class Cache_Enabler {
526
  $cache_size = get_transient( self::get_cache_size_transient_name() );
527
 
528
  if ( ! $cache_size ) {
529
- $cache_size = Cache_Enabler_Disk::cache_size();
530
  set_transient( self::get_cache_size_transient_name(), $cache_size, MINUTE_IN_SECONDS * 15 );
531
  }
532
 
@@ -572,7 +609,7 @@ final class Cache_Enabler {
572
  * get default settings
573
  *
574
  * @since 1.0.0
575
- * @change 1.6.1
576
  *
577
  * @param string $settings_type default `system` settings
578
  * @return array $system_default_settings|$default_settings only default system settings or all default settings
@@ -581,7 +618,7 @@ final class Cache_Enabler {
581
  private static function get_default_settings( $settings_type = null ) {
582
 
583
  $system_default_settings = array(
584
- 'version' => (string) CE_VERSION,
585
  'permalink_structure' => (string) self::get_permalink_structure(),
586
  );
587
 
@@ -595,14 +632,15 @@ final class Cache_Enabler {
595
  'clear_site_cache_on_saved_post' => 0,
596
  'clear_site_cache_on_saved_comment' => 0,
597
  'clear_site_cache_on_changed_plugin' => 0,
598
- 'compress_cache' => 0,
599
  'convert_image_urls_to_webp' => 0,
 
 
 
 
600
  'excluded_post_ids' => '',
601
  'excluded_page_paths' => '',
602
  'excluded_query_strings' => '',
603
  'excluded_cookies' => '',
604
- 'minify_html' => 0,
605
- 'minify_inline_css_js' => 0,
606
  );
607
 
608
  // merge default settings
@@ -650,8 +688,8 @@ final class Cache_Enabler {
650
  'update_product_stock' => '', // deprecated
651
  'new_comment' => 'clear_site_cache_on_saved_comment',
652
  'clear_on_upgrade' => 'clear_site_cache_on_changed_plugin',
653
- 'compress' => 'compress_cache',
654
  'webp' => 'convert_image_urls_to_webp',
 
655
  'excl_ids' => 'excluded_post_ids',
656
  'excl_paths' => 'excluded_page_paths',
657
  'excl_cookies' => 'excluded_cookies',
@@ -671,6 +709,7 @@ final class Cache_Enabler {
671
  if ( ! empty( $new_name ) ) {
672
  $settings[ $new_name ] = $settings[ $old_name ];
673
  }
 
674
  unset( $settings[ $old_name ] );
675
  }
676
  }
@@ -683,7 +722,7 @@ final class Cache_Enabler {
683
  * add plugin action links in the plugins list table
684
  *
685
  * @since 1.0.0
686
- * @change 1.5.0
687
  *
688
  * @param array $action_links action links
689
  * @return array $action_links updated action links if applicable, unchanged otherwise
@@ -696,17 +735,12 @@ final class Cache_Enabler {
696
  return $action_links;
697
  }
698
 
699
- // append action link
700
- $action_links = wp_parse_args(
701
- array(
702
- sprintf(
703
- '<a href="%s">%s</a>',
704
- admin_url( 'options-general.php?page=cache-enabler' ),
705
- esc_html__( 'Settings', 'cache-enabler' )
706
- )
707
- ),
708
- $action_links
709
- );
710
 
711
  return $action_links;
712
  }
@@ -716,7 +750,7 @@ final class Cache_Enabler {
716
  * add plugin metadata in the plugins list table
717
  *
718
  * @since 1.0.0
719
- * @change 1.5.0
720
  *
721
  * @param array $plugin_meta plugin metadata, including the version, author, author URI, and plugin URI
722
  * @param string $plugin_file path to the plugin file relative to the plugins directory
@@ -726,7 +760,7 @@ final class Cache_Enabler {
726
  public static function add_plugin_row_meta( $plugin_meta, $plugin_file ) {
727
 
728
  // check if Cache Enabler row
729
- if ( $plugin_file !== CE_BASE ) {
730
  return $plugin_meta;
731
  }
732
 
@@ -783,7 +817,7 @@ final class Cache_Enabler {
783
  * @since 1.0.0
784
  * @change 1.6.0
785
  *
786
- * @param object menu properties
787
  */
788
 
789
  public static function add_admin_bar_items( $wp_admin_bar ) {
@@ -832,14 +866,14 @@ final class Cache_Enabler {
832
  * enqueue styles and scripts
833
  *
834
  * @since 1.0.0
835
- * @change 1.5.0
836
  */
837
 
838
  public static function add_admin_resources( $hook ) {
839
 
840
  // settings page
841
  if ( $hook === 'settings_page_cache-enabler' ) {
842
- wp_enqueue_style( 'cache-enabler-settings', plugins_url( 'css/settings.min.css', CE_FILE ), array(), CE_VERSION );
843
  }
844
  }
845
 
@@ -890,7 +924,7 @@ final class Cache_Enabler {
890
  * process clear cache request
891
  *
892
  * @since 1.0.0
893
- * @change 1.6.0
894
  */
895
 
896
  public static function process_clear_cache_request() {
@@ -912,8 +946,7 @@ final class Cache_Enabler {
912
 
913
  // clear page cache
914
  if ( $_GET['_action'] === 'clearurl' ) {
915
- // set clear URL without query string
916
- $clear_url = parse_url( home_url(), PHP_URL_SCHEME ) . '://' . parse_url( home_url(), PHP_URL_HOST ) . preg_replace( '/\?.*/', '', $_SERVER['REQUEST_URI'] );
917
  self::clear_page_cache_by_url( $clear_url );
918
  // clear site(s) cache
919
  } elseif ( $_GET['_action'] === 'clear' ) {
@@ -921,7 +954,7 @@ final class Cache_Enabler {
921
  }
922
 
923
  // redirect to same page
924
- wp_safe_redirect( wp_get_referer() );
925
 
926
  // set transient for clear notice
927
  if ( is_admin() ) {
@@ -937,7 +970,7 @@ final class Cache_Enabler {
937
  * admin notice after cache has been cleared
938
  *
939
  * @since 1.0.0
940
- * @change 1.6.0
941
  */
942
 
943
  public static function cache_cleared_notice() {
@@ -948,7 +981,7 @@ final class Cache_Enabler {
948
  }
949
 
950
  if ( get_transient( self::get_cache_cleared_transient_name() ) ) {
951
- echo sprintf(
952
  '<div class="notice notice-success is-dismissible"><p><strong>%s</strong></p></div>',
953
  ( is_multisite() && is_network_admin() ) ? esc_html__( 'Network cache cleared.', 'cache-enabler' ) : esc_html__( 'Site cache cleared.', 'cache-enabler' )
954
  );
@@ -959,81 +992,43 @@ final class Cache_Enabler {
959
 
960
 
961
  /**
962
- * save post hook
963
  *
964
  * @since 1.5.0
965
- * @change 1.5.0
966
  *
967
  * @param integer $post_id post ID
968
  */
969
 
970
- public static function on_save_post( $post_id ) {
971
-
972
- // if any published post type is created or updated
973
- if ( get_post_status( $post_id ) === 'publish' ) {
974
- self::clear_cache_on_post_save( $post_id );
975
- }
976
- }
977
-
978
-
979
- /**
980
- * post updated hook
981
- *
982
- * @since 1.5.0
983
- * @change 1.5.0
984
- *
985
- * @param integer $post_id post ID
986
- * @param WP_Post $post_after post instance following the update
987
- * @param WP_Post $post_before post instance before the update
988
- */
989
 
990
- public static function on_post_updated( $post_id, $post_after, $post_before ) {
991
 
992
- // if setting disabled and any published post type author changes
993
- if ( $post_before->post_author !== $post_after->post_author ) {
994
- if ( ! Cache_Enabler_Engine::$settings['clear_site_cache_on_saved_post'] ) {
995
- // clear before the update author archives
996
- self::clear_author_archives_cache_by_user_id( $post_before->post_author );
997
- }
998
  }
999
  }
1000
 
1001
 
1002
  /**
1003
- * trash post hook
1004
  *
1005
- * @since 1.4.0
1006
- * @change 1.5.0
1007
  *
1008
- * @param integer $post_id post ID
 
1009
  */
1010
 
1011
- public static function on_trash_post( $post_id ) {
1012
-
1013
- // if any published post type is trashed
1014
- if ( get_post_status( $post_id ) === 'publish' ) {
1015
- $trashed = true;
1016
- self::clear_cache_on_post_save( $post_id, $trashed );
1017
- }
1018
- }
1019
-
1020
-
1021
- /**
1022
- * transition post status hook
1023
- *
1024
- * @since 1.5.0
1025
- * @change 1.5.0
1026
- *
1027
- * @param string $new_status new post status
1028
- * @param string $old_status old post status
1029
- * @param WP_Post $post post instance
1030
- */
1031
 
1032
- public static function on_transition_post_status( $new_status, $old_status, $post ) {
 
1033
 
1034
- // if any published post type status has changed
1035
- if ( $old_status === 'publish' && in_array( $new_status, array( 'future', 'draft', 'pending', 'private' ) ) ) {
1036
- self::clear_cache_on_post_save( $post->ID );
1037
  }
1038
  }
1039
 
@@ -1221,8 +1216,8 @@ final class Cache_Enabler {
1221
  // get post type archives URL
1222
  $post_type_archives_url = get_post_type_archive_link( $post_type );
1223
 
 
1224
  if ( ! empty( $post_type_archives_url ) ) {
1225
- // clear post type archives page and its pagination page(s) cache
1226
  self::clear_page_cache_by_url( $post_type_archives_url, 'pagination' );
1227
  }
1228
  }
@@ -1232,7 +1227,7 @@ final class Cache_Enabler {
1232
  * clear taxonomies archives pages cache by post ID
1233
  *
1234
  * @since 1.5.0
1235
- * @change 1.5.0
1236
  *
1237
  * @param integer $post_id post ID
1238
  */
@@ -1246,11 +1241,13 @@ final class Cache_Enabler {
1246
  if ( wp_count_terms( $taxonomy ) > 0 ) {
1247
  // get terms attached to post
1248
  $term_ids = wp_get_post_terms( $post_id, $taxonomy, array( 'fields' => 'ids' ) );
 
1249
  foreach ( $term_ids as $term_id ) {
 
1250
  $term_archives_url = get_term_link( (int) $term_id, $taxonomy );
1251
- // validate URL and ensure it does not have a query string
1252
- if ( filter_var( $term_archives_url, FILTER_VALIDATE_URL ) && ! filter_var( $term_archives_url, FILTER_VALIDATE_URL, FILTER_FLAG_QUERY_REQUIRED ) ) {
1253
- // clear taxonomy archives page and its pagination page(s) cache
1254
  self::clear_page_cache_by_url( $term_archives_url, 'pagination' );
1255
  }
1256
  }
@@ -1312,7 +1309,7 @@ final class Cache_Enabler {
1312
  * clear page cache by post ID
1313
  *
1314
  * @since 1.0.0
1315
- * @change 1.5.0
1316
  *
1317
  * @param integer|string $post_id post ID
1318
  * @param string $clear_type clear the `pagination` cache or all `subpages` cache instead of only the `page` cache
@@ -1321,17 +1318,15 @@ final class Cache_Enabler {
1321
  public static function clear_page_cache_by_post_id( $post_id, $clear_type = 'page' ) {
1322
 
1323
  // validate integer
1324
- if ( ! is_int( $post_id ) ) {
1325
- // if string try to convert to integer
1326
- $post_id = (int) $post_id;
1327
- // conversion failed
1328
- if ( ! $post_id ) {
1329
- return;
1330
- }
1331
- }
1332
 
1333
- // clear page cache
1334
- self::clear_page_cache_by_url( get_permalink( $post_id ), $clear_type );
 
 
 
 
 
1335
  }
1336
 
1337
 
@@ -1355,7 +1350,7 @@ final class Cache_Enabler {
1355
  * clear site cache by blog ID
1356
  *
1357
  * @since 1.4.0
1358
- * @change 1.6.1
1359
  *
1360
  * @param integer|string $blog_id blog ID
1361
  * @param boolean $delete_cache_size_transient whether or not the cache size transient should be deleted
@@ -1364,17 +1359,10 @@ final class Cache_Enabler {
1364
  public static function clear_site_cache_by_blog_id( $blog_id, $delete_cache_size_transient = true ) {
1365
 
1366
  // validate integer
1367
- if ( ! is_int( $blog_id ) ) {
1368
- // if string try to convert to integer
1369
- $blog_id = (int) $blog_id;
1370
- // conversion failed
1371
- if ( ! $blog_id ) {
1372
- return;
1373
- }
1374
- }
1375
 
1376
  // check if blog ID exists
1377
- if ( ! in_array( $blog_id, self::get_blog_ids() ) ) {
1378
  return;
1379
  }
1380
 
@@ -1413,31 +1401,33 @@ final class Cache_Enabler {
1413
 
1414
 
1415
  /**
1416
- * clear cache when any post type is created or updated
1417
  *
1418
  * @since 1.5.0
1419
- * @change 1.5.0
1420
  *
1421
- * @param integer $post_id post ID
1422
- * @param boolean $trashed whether this is an existing post being trashed
1423
  */
1424
 
1425
- public static function clear_cache_on_post_save( $post_id, $trashed = false ) {
 
 
 
 
1426
 
1427
- // get post data
1428
- $post = get_post( $post_id );
 
 
 
 
1429
 
1430
  // if setting enabled clear site cache
1431
  if ( Cache_Enabler_Engine::$settings['clear_site_cache_on_saved_post'] ) {
1432
  self::clear_site_cache();
1433
  // clear page and/or associated cache otherwise
1434
  } else {
1435
- // if updated or trashed clear page cache
1436
- if ( strtotime( $post->post_modified_gmt ) > strtotime( $post->post_date_gmt ) || $trashed ) {
1437
- self::clear_page_cache_by_post_id( $post_id );
1438
- }
1439
-
1440
- // clear associated cache
1441
  self::clear_associated_cache( $post );
1442
  }
1443
  }
@@ -1447,7 +1437,7 @@ final class Cache_Enabler {
1447
  * check plugin requirements
1448
  *
1449
  * @since 1.1.0
1450
- * @change 1.6.1
1451
  */
1452
 
1453
  public static function requirements_check() {
@@ -1458,34 +1448,34 @@ final class Cache_Enabler {
1458
  }
1459
 
1460
  // check PHP version
1461
- if ( version_compare( PHP_VERSION, CE_MIN_PHP, '<' ) ) {
1462
- echo sprintf(
1463
  '<div class="notice notice-error"><p>%s</p></div>',
1464
  sprintf(
1465
  // translators: 1. Cache Enabler 2. PHP version (e.g. 5.6)
1466
  esc_html__( '%1$s requires PHP %2$s or higher to function properly. Please update PHP or disable the plugin.', 'cache-enabler' ),
1467
  '<strong>Cache Enabler</strong>',
1468
- CE_MIN_PHP
1469
  )
1470
  );
1471
  }
1472
 
1473
  // check WordPress version
1474
- if ( version_compare( $GLOBALS['wp_version'], CE_MIN_WP . 'alpha', '<' ) ) {
1475
- echo sprintf(
1476
  '<div class="notice notice-error"><p>%s</p></div>',
1477
  sprintf(
1478
  // translators: 1. Cache Enabler 2. WordPress version (e.g. 5.1)
1479
  esc_html__( '%1$s requires WordPress %2$s or higher to function properly. Please update WordPress or disable the plugin.', 'cache-enabler' ),
1480
  '<strong>Cache Enabler</strong>',
1481
- CE_MIN_WP
1482
  )
1483
  );
1484
  }
1485
 
1486
  // check advanced-cache.php drop-in
1487
  if ( ! file_exists( WP_CONTENT_DIR . '/advanced-cache.php' ) ) {
1488
- echo sprintf(
1489
  '<div class="notice notice-warning"><p>%s</p></div>',
1490
  sprintf(
1491
  // translators: 1. Cache Enabler 2. advanced-cache.php 3. wp-content/plugins/cache-enabler 4. wp-content
@@ -1500,7 +1490,7 @@ final class Cache_Enabler {
1500
 
1501
  // check permalink structure
1502
  if ( Cache_Enabler_Engine::$settings['permalink_structure'] === 'plain' && current_user_can( 'manage_options' ) ) {
1503
- echo sprintf(
1504
  '<div class="notice notice-warning"><p>%s</p></div>',
1505
  sprintf(
1506
  // translators: 1. Cache Enabler 2. Permalink Settings
@@ -1517,7 +1507,7 @@ final class Cache_Enabler {
1517
 
1518
  // check file permissions
1519
  if ( file_exists( dirname( Cache_Enabler_Disk::$cache_dir ) ) && ! is_writable( dirname( Cache_Enabler_Disk::$cache_dir ) ) ) {
1520
- echo sprintf(
1521
  '<div class="notice notice-warning"><p>%s</p></div>',
1522
  sprintf(
1523
  // translators: 1. Cache Enabler 2. 755 3. wp-content/cache 4. file permissions
@@ -1536,7 +1526,7 @@ final class Cache_Enabler {
1536
 
1537
  // check Autoptimize HTML optimization
1538
  if ( defined( 'AUTOPTIMIZE_PLUGIN_DIR' ) && Cache_Enabler_Engine::$settings['minify_html'] && get_option( 'autoptimize_html', '' ) !== '' ) {
1539
- echo sprintf(
1540
  '<div class="notice notice-warning"><p>%s</p></div>',
1541
  sprintf(
1542
  // translators: 1. Autoptimize 2. Cache Enabler Settings
@@ -1614,7 +1604,7 @@ final class Cache_Enabler {
1614
  * validate settings
1615
  *
1616
  * @since 1.0.0
1617
- * @change 1.6.1
1618
  *
1619
  * @param array $settings user defined settings
1620
  * @return array $validated_settings validated settings
@@ -1622,25 +1612,21 @@ final class Cache_Enabler {
1622
 
1623
  public static function validate_settings( $settings ) {
1624
 
1625
- // validate array
1626
- if ( ! is_array( $settings ) ) {
1627
- return;
1628
- }
1629
-
1630
  $validated_settings = array(
1631
  'cache_expires' => (int) ( ! empty( $settings['cache_expires'] ) ),
1632
- 'cache_expiry_time' => (int) @$settings['cache_expiry_time'],
1633
  'clear_site_cache_on_saved_post' => (int) ( ! empty( $settings['clear_site_cache_on_saved_post'] ) ),
1634
  'clear_site_cache_on_saved_comment' => (int) ( ! empty( $settings['clear_site_cache_on_saved_comment'] ) ),
1635
  'clear_site_cache_on_changed_plugin' => (int) ( ! empty( $settings['clear_site_cache_on_changed_plugin'] ) ),
1636
- 'compress_cache' => (int) ( ! empty( $settings['compress_cache'] ) ),
1637
  'convert_image_urls_to_webp' => (int) ( ! empty( $settings['convert_image_urls_to_webp'] ) ),
1638
- 'excluded_post_ids' => (string) sanitize_text_field( @$settings['excluded_post_ids'] ),
1639
- 'excluded_page_paths' => (string) self::validate_regex( @$settings['excluded_page_paths'] ),
1640
- 'excluded_query_strings' => (string) self::validate_regex( @$settings['excluded_query_strings'] ),
1641
- 'excluded_cookies' => (string) self::validate_regex( @$settings['excluded_cookies'] ),
1642
  'minify_html' => (int) ( ! empty( $settings['minify_html'] ) ),
1643
  'minify_inline_css_js' => (int) ( ! empty( $settings['minify_inline_css_js'] ) ),
 
 
 
 
1644
  );
1645
 
1646
  // add default system settings
@@ -1660,7 +1646,7 @@ final class Cache_Enabler {
1660
  * settings page
1661
  *
1662
  * @since 1.0.0
1663
- * @change 1.6.1
1664
  */
1665
 
1666
  public static function settings_page() {
@@ -1668,9 +1654,7 @@ final class Cache_Enabler {
1668
  ?>
1669
 
1670
  <div id="cache_enabler_settings" class="wrap">
1671
- <h2>
1672
- <?php esc_html_e( 'Cache Enabler Settings', 'cache-enabler' ); ?>
1673
- </h2>
1674
 
1675
  <?php
1676
  if ( defined( 'WP_CACHE' ) && ! WP_CACHE ) {
@@ -1690,13 +1674,13 @@ final class Cache_Enabler {
1690
 
1691
  <div class="notice notice-info">
1692
  <p>
1693
- <?php
1694
- printf(
1695
- // translators: %s: KeyCDN
1696
- esc_html__( 'Combine %s with Cache Enabler for even better WordPress performance and achieve the next level of caching with a CDN.', 'cache-enabler' ),
1697
- '<strong><a href="https://www.keycdn.com?utm_source=wp-admin&utm_medium=plugins&utm_campaign=cache-enabler">KeyCDN</a></strong>'
1698
- );
1699
- ?>
1700
  </p>
1701
  </div>
1702
 
@@ -1710,15 +1694,15 @@ final class Cache_Enabler {
1710
  <td>
1711
  <fieldset>
1712
  <p class="subheading"><?php esc_html_e( 'Expiration', 'cache-enabler' ); ?></p>
1713
- <label for="cache_expires" class="checkbox--form-control">
1714
- <input name="cache_enabler[cache_expires]" type="checkbox" id="cache_expires" value="1" <?php checked( '1', Cache_Enabler_Engine::$settings['cache_expires'] ); ?> />
1715
  </label>
1716
- <label for="cache_expiry_time">
1717
  <?php
1718
  printf(
1719
- // translators: %s: Number of hours.
1720
  esc_html__( 'Cached pages expire %s hours after being created.', 'cache-enabler' ),
1721
- '<input name="cache_enabler[cache_expiry_time]" type="number" id="cache_expiry_time" value="' . Cache_Enabler_Engine::$settings['cache_expiry_time'] . '" class="small-text">'
1722
  );
1723
  ?>
1724
  </label>
@@ -1726,30 +1710,30 @@ final class Cache_Enabler {
1726
  <br />
1727
 
1728
  <p class="subheading"><?php esc_html_e( 'Clearing', 'cache-enabler' ); ?></p>
1729
- <label for="clear_site_cache_on_saved_post">
1730
- <input name="cache_enabler[clear_site_cache_on_saved_post]" type="checkbox" id="clear_site_cache_on_saved_post" value="1" <?php checked( '1', Cache_Enabler_Engine::$settings['clear_site_cache_on_saved_post'] ); ?> />
1731
  <?php esc_html_e( 'Clear the site cache if any post type has been published, updated, or trashed (instead of only the page and/or associated cache).', 'cache-enabler' ); ?>
1732
  </label>
1733
 
1734
  <br />
1735
 
1736
- <label for="clear_site_cache_on_saved_comment">
1737
- <input name="cache_enabler[clear_site_cache_on_saved_comment]" type="checkbox" id="clear_site_cache_on_saved_comment" value="1" <?php checked( '1', Cache_Enabler_Engine::$settings['clear_site_cache_on_saved_comment'] ); ?> />
1738
  <?php esc_html_e( 'Clear the site cache if a comment has been posted, updated, spammed, or trashed (instead of only the page cache).', 'cache-enabler' ); ?>
1739
  </label>
1740
 
1741
  <br />
1742
 
1743
- <label for="clear_site_cache_on_changed_plugin">
1744
- <input name="cache_enabler[clear_site_cache_on_changed_plugin]" type="checkbox" id="clear_site_cache_on_changed_plugin" value="1" <?php checked( '1', Cache_Enabler_Engine::$settings['clear_site_cache_on_changed_plugin'] ); ?> />
1745
- <?php esc_html_e( 'Clear the site cache if a plugin has been activated, updated, or deactivated.', 'cache-enabler' ); ?>
1746
  </label>
1747
 
1748
  <br />
1749
 
1750
  <p class="subheading"><?php esc_html_e( 'Variants', 'cache-enabler' ); ?></p>
1751
- <label for="convert_image_urls_to_webp">
1752
- <input name="cache_enabler[convert_image_urls_to_webp]" type="checkbox" id="convert_image_urls_to_webp" value="1" <?php checked( '1', Cache_Enabler_Engine::$settings['convert_image_urls_to_webp'] ); ?> />
1753
  <?php
1754
  printf(
1755
  // translators: %s: Optimus
@@ -1761,24 +1745,31 @@ final class Cache_Enabler {
1761
 
1762
  <br />
1763
 
1764
- <label for="compress_cache">
1765
- <input name="cache_enabler[compress_cache]" type="checkbox" id="compress_cache" value="1" <?php checked( '1', Cache_Enabler_Engine::$settings['compress_cache'] ); ?> />
 
 
 
 
 
 
 
1766
  <?php esc_html_e( 'Pre-compress cached pages with Gzip.', 'cache-enabler' ); ?>
1767
  </label>
1768
 
1769
  <br />
1770
 
1771
  <p class="subheading"><?php esc_html_e( 'Minification', 'cache-enabler' ); ?></p>
1772
- <label for="minify_html" class="checkbox--form-control">
1773
- <input name="cache_enabler[minify_html]" type="checkbox" id="minify_html" value="1" <?php checked( '1', Cache_Enabler_Engine::$settings['minify_html'] ); ?> />
1774
  </label>
1775
- <label for="minify_inline_css_js">
1776
  <?php
1777
  $minify_inline_css_js_options = array(
1778
  esc_html__( 'excluding', 'cache-enabler' ) => 0,
1779
  esc_html__( 'including', 'cache-enabler' ) => 1,
1780
  );
1781
- $minify_inline_css_js = '<select name="cache_enabler[minify_inline_css_js]" id="minify_inline_css_js">';
1782
  foreach ( $minify_inline_css_js_options as $key => $value ) {
1783
  $minify_inline_css_js .= '<option value="' . esc_attr( $value ) . '"' . selected( $value, Cache_Enabler_Engine::$settings['minify_inline_css_js'], false ) . '>' . $key . '</option>';
1784
  }
@@ -1801,13 +1792,16 @@ final class Cache_Enabler {
1801
  <td>
1802
  <fieldset>
1803
  <p class="subheading"><?php esc_html_e( 'Post IDs', 'cache-enabler' ); ?></p>
1804
- <label for="excluded_post_ids">
1805
- <input name="cache_enabler[excluded_post_ids]" type="text" id="excluded_post_ids" value="<?php echo esc_attr( Cache_Enabler_Engine::$settings['excluded_post_ids'] ) ?>" class="regular-text" />
1806
  <p class="description">
1807
- <?php
1808
- // translators: %s: ,
1809
- printf( esc_html__( 'Post IDs separated by a %s that should bypass the cache.', 'cache-enabler' ), '<code class="code--form-control">,</code>' );
1810
- ?>
 
 
 
1811
  </p>
1812
  <p><?php esc_html_e( 'Example:', 'cache-enabler' ); ?> <code class="code--form-control">2,43,65</code></p>
1813
  </label>
@@ -1815,8 +1809,8 @@ final class Cache_Enabler {
1815
  <br />
1816
 
1817
  <p class="subheading"><?php esc_html_e( 'Page Paths', 'cache-enabler' ); ?></p>
1818
- <label for="excluded_page_paths">
1819
- <input name="cache_enabler[excluded_page_paths]" type="text" id="excluded_page_paths" value="<?php echo esc_attr( Cache_Enabler_Engine::$settings['excluded_page_paths'] ) ?>" class="regular-text code" />
1820
  <p class="description"><?php esc_html_e( 'A regex matching page paths that should bypass the cache.', 'cache-enabler' ); ?></p>
1821
  <p><?php esc_html_e( 'Example:', 'cache-enabler' ); ?> <code class="code--form-control">/^(\/|\/forums\/)$/</code></p>
1822
  </label>
@@ -1824,8 +1818,8 @@ final class Cache_Enabler {
1824
  <br />
1825
 
1826
  <p class="subheading"><?php esc_html_e( 'Query Strings', 'cache-enabler' ); ?></p>
1827
- <label for="excluded_query_strings">
1828
- <input name="cache_enabler[excluded_query_strings]" type="text" id="excluded_query_strings" value="<?php echo esc_attr( Cache_Enabler_Engine::$settings['excluded_query_strings'] ) ?>" class="regular-text code" />
1829
  <p class="description"><?php esc_html_e( 'A regex matching query strings that should bypass the cache.', 'cache-enabler' ); ?></p>
1830
  <p><?php esc_html_e( 'Example:', 'cache-enabler' ); ?> <code class="code--form-control">/^nocache$/</code></p>
1831
  <p><?php esc_html_e( 'Default if unset:', 'cache-enabler' ); ?> <code class="code--form-control">/^(?!(fbclid|ref|mc_(cid|eid)|utm_(source|medium|campaign|term|content|expid)|gclid|fb_(action_ids|action_types|source)|age-verified|usqp|cn-reloaded|_ga|_ke)).+$/</code></p>
@@ -1834,8 +1828,8 @@ final class Cache_Enabler {
1834
  <br />
1835
 
1836
  <p class="subheading"><?php esc_html_e( 'Cookies', 'cache-enabler' ); ?></p>
1837
- <label for="excluded_cookies">
1838
- <input name="cache_enabler[excluded_cookies]" type="text" id="excluded_cookies" value="<?php echo esc_attr( Cache_Enabler_Engine::$settings['excluded_cookies'] ) ?>" class="regular-text code" />
1839
  <p class="description"><?php esc_html_e( 'A regex matching cookies that should bypass the cache.', 'cache-enabler' ); ?></p>
1840
  <p><?php esc_html_e( 'Example:', 'cache-enabler' ); ?> <code class="code--form-control">/^(comment_author|woocommerce_items_in_cart|wp_woocommerce_session)_?/</code></p>
1841
  <p><?php esc_html_e( 'Default if unset:', 'cache-enabler' ); ?> <code class="code--form-control">/^(wp-postpass|wordpress_logged_in|comment_author)_/</code></p>
@@ -1846,8 +1840,8 @@ final class Cache_Enabler {
1846
  </table>
1847
 
1848
  <p class="submit">
1849
- <input type="submit" class="button-secondary" value="<?php esc_html_e( 'Save Changes', 'cache-enabler' ); ?>" />
1850
- <input name="cache_enabler[clear_site_cache_on_saved_settings]" type="submit" class="button-primary" value="<?php esc_html_e( 'Save Changes and Clear Site Cache', 'cache-enabler' ); ?>" />
1851
  </p>
1852
  </form>
1853
  </div>
50
  * constructor
51
  *
52
  * @since 1.0.0
53
+ * @change 1.7.0
54
  */
55
 
56
  public function __construct() {
72
  // system clear cache hooks
73
  add_action( '_core_updated_successfully', array( __CLASS__, 'clear_complete_cache' ) );
74
  add_action( 'upgrader_process_complete', array( __CLASS__, 'on_upgrade' ), 10, 2 );
75
+ add_action( 'switch_theme', array( __CLASS__, 'clear_site_cache' ) );
76
  add_action( 'permalink_structure_changed', array( __CLASS__, 'clear_site_cache' ) );
77
  add_action( 'activated_plugin', array( __CLASS__, 'on_plugin_activation_deactivation' ), 10, 2 );
78
  add_action( 'deactivated_plugin', array( __CLASS__, 'on_plugin_activation_deactivation' ), 10, 2 );
79
+ add_action( 'save_post', array( __CLASS__, 'on_save_trash_post' ) );
80
+ add_action( 'wp_trash_post', array( __CLASS__, 'on_save_trash_post' ) );
81
+ add_action( 'pre_post_update', array( __CLASS__, 'on_pre_post_update' ), 10, 2 );
 
82
  add_action( 'comment_post', array( __CLASS__, 'on_comment_post' ), 99, 2 );
83
  add_action( 'edit_comment', array( __CLASS__, 'on_edit_comment' ), 10, 2 );
84
  add_action( 'transition_comment_status', array( __CLASS__, 'on_transition_comment_status' ), 10, 3 );
110
  add_action( 'admin_enqueue_scripts', array( __CLASS__, 'add_admin_resources' ) );
111
  // dashboard
112
  add_filter( 'dashboard_glance_items', array( __CLASS__, 'add_dashboard_cache_size' ) );
113
+ add_filter( 'plugin_action_links_' . CACHE_ENABLER_BASE, array( __CLASS__, 'add_plugin_action_links' ) );
114
  add_filter( 'plugin_row_meta', array( __CLASS__, 'add_plugin_row_meta' ), 10, 2 );
115
  // notices
116
  add_action( 'admin_notices', array( __CLASS__, 'requirements_check' ) );
143
  * upgrade hook
144
  *
145
  * @since 1.2.3
146
+ * @change 1.7.0
147
  *
148
  * @param WP_Upgrader $obj upgrade instance
149
  * @param array $data update data
151
 
152
  public static function on_upgrade( $obj, $data ) {
153
 
154
+ if ( $data['action'] !== 'update' ) {
155
+ return;
156
+ }
157
+
158
+ // updated themes
159
+ if ( $data['type'] === 'theme' && isset( $data['themes'] ) ) {
160
+ $updated_themes = (array) $data['themes'];
161
+ $sites_themes = self::each_site( is_multisite(), 'wp_get_theme' );
162
+
163
+ // check each site
164
+ foreach ( $sites_themes as $blog_id => $site_theme ) {
165
+ // if the active or parent theme has been updated clear site cache
166
+ if ( in_array( $site_theme->stylesheet, $updated_themes, true ) || in_array( $site_theme->template, $updated_themes, true ) ) {
167
+ self::clear_site_cache_by_blog_id( $blog_id );
168
+ }
169
+ }
170
  }
171
 
172
+ // updated plugins
173
+ if ( $data['type'] === 'plugin' && isset( $data['plugins'] ) ) {
174
+ $updated_plugins = (array) $data['plugins'];
175
+
176
+ // check if Cache Enabler has been updated
177
+ if ( in_array( CACHE_ENABLER_BASE, $updated_plugins, true ) ) {
178
+ self::on_cache_enabler_update();
179
+ // check all updated plugins otherwise
180
+ } else {
181
+ $network_plugins = ( is_multisite() ) ? array_flip( (array) get_site_option( 'active_sitewide_plugins', array() ) ) : array();
182
+
183
+ // if a network activated plugin has been updated clear complete cache
184
+ if ( ! empty( array_intersect( $updated_plugins, $network_plugins ) ) ) {
185
+ self::clear_complete_cache();
186
+ // check each site otherwise
187
+ } else {
188
+ $sites_plugins = self::each_site( is_multisite(), 'get_option', array( 'active_plugins', array() ) );
189
+
190
+ foreach ( $sites_plugins as $blog_id => $site_plugins ) {
191
+ // if an activated plugin has been updated clear site cache
192
+ if ( ! empty( array_intersect( $updated_plugins, (array) $site_plugins ) ) ) {
193
+ self::clear_site_cache_by_blog_id( $blog_id );
194
+ }
195
+ }
196
  }
197
  }
198
  }
203
  * Cache Enabler update actions
204
  *
205
  * @since 1.4.0
206
+ * @change 1.7.0
207
  */
208
 
209
+ public static function on_cache_enabler_update() {
210
 
211
  // clean system files
212
  self::each_site( is_multisite(), 'Cache_Enabler_Disk::clean' );
256
  * install on new site in multisite network
257
  *
258
  * @since 1.0.0
259
+ * @change 1.7.0
260
  *
261
  * @param WP_Site $new_site new site instance
262
  */
264
  public static function install_later( $new_site ) {
265
 
266
  // check if network activated
267
+ if ( ! is_plugin_active_for_network( CACHE_ENABLER_BASE ) ) {
268
  return;
269
  }
270
 
283
  * add or update backend requirements
284
  *
285
  * @since 1.5.0
286
+ * @change 1.7.0
287
  *
288
+ * @return array $new_option_value new or current database option value
289
  */
290
 
291
  public static function update_backend() {
312
  // merge defined settings into default settings
313
  $new_option_value = wp_parse_args( $old_option_value, self::get_default_settings() );
314
 
315
+ // validate settings
316
+ $new_option_value = self::validate_settings( $new_option_value );
317
+
318
  // add or update database option
319
  update_option( 'cache_enabler', $new_option_value );
320
 
382
  * enter each site
383
  *
384
  * @since 1.5.0
385
+ * @change 1.7.0
386
  *
387
  * @param boolean $network whether or not each site in network
388
  * @param string $callback callback function
396
 
397
  if ( $network ) {
398
  $blog_ids = self::get_blog_ids();
399
+
400
  // switch to each site in network
401
  foreach ( $blog_ids as $blog_id ) {
402
  switch_to_blog( $blog_id );
403
+ $callback_return[ $blog_id ] = call_user_func_array( $callback, $callback_params );
404
  restore_current_blog();
405
  }
406
  } else {
407
+ $blog_id = 1;
408
+ $callback_return[ $blog_id ] = call_user_func_array( $callback, $callback_params );
409
  }
410
 
411
  return $callback_return;
432
  * get settings from database
433
  *
434
  * @since 1.0.0
435
+ * @change 1.7.0
436
  *
437
  * @return array $settings current settings from database
438
  */
443
  $settings = get_option( 'cache_enabler' );
444
 
445
  // if database option does not exist or settings are outdated
446
+ if ( $settings === false || ! isset( $settings['version'] ) || $settings['version'] !== CACHE_ENABLER_VERSION ) {
447
  $settings = self::update_backend();
448
  }
449
 
455
  * get blog IDs
456
  *
457
  * @since 1.0.0
458
+ * @change 1.7.0
459
  *
460
  * @return array $blog_ids blog IDs
461
  */
462
 
463
  private static function get_blog_ids() {
464
 
465
+ $blog_ids = array( 1 );
466
 
467
  if ( is_multisite() ) {
468
  global $wpdb;
469
+
470
+ $blog_ids = array_map( 'absint', $wpdb->get_col( "SELECT blog_id FROM $wpdb->blogs" ) );
471
  }
472
 
473
  return $blog_ids;
550
 
551
 
552
  /**
553
+ * get cache size from database or disk
554
  *
555
  * @since 1.0.0
556
+ * @change 1.7.0
557
  *
558
  * @return integer $cache_size cache size in bytes
559
  */
563
  $cache_size = get_transient( self::get_cache_size_transient_name() );
564
 
565
  if ( ! $cache_size ) {
566
+ $cache_size = Cache_Enabler_Disk::get_cache_size();
567
  set_transient( self::get_cache_size_transient_name(), $cache_size, MINUTE_IN_SECONDS * 15 );
568
  }
569
 
609
  * get default settings
610
  *
611
  * @since 1.0.0
612
+ * @change 1.7.0
613
  *
614
  * @param string $settings_type default `system` settings
615
  * @return array $system_default_settings|$default_settings only default system settings or all default settings
618
  private static function get_default_settings( $settings_type = null ) {
619
 
620
  $system_default_settings = array(
621
+ 'version' => (string) CACHE_ENABLER_VERSION,
622
  'permalink_structure' => (string) self::get_permalink_structure(),
623
  );
624
 
632
  'clear_site_cache_on_saved_post' => 0,
633
  'clear_site_cache_on_saved_comment' => 0,
634
  'clear_site_cache_on_changed_plugin' => 0,
 
635
  'convert_image_urls_to_webp' => 0,
636
+ 'mobile_cache' => 0,
637
+ 'compress_cache' => 0,
638
+ 'minify_html' => 0,
639
+ 'minify_inline_css_js' => 0,
640
  'excluded_post_ids' => '',
641
  'excluded_page_paths' => '',
642
  'excluded_query_strings' => '',
643
  'excluded_cookies' => '',
 
 
644
  );
645
 
646
  // merge default settings
688
  'update_product_stock' => '', // deprecated
689
  'new_comment' => 'clear_site_cache_on_saved_comment',
690
  'clear_on_upgrade' => 'clear_site_cache_on_changed_plugin',
 
691
  'webp' => 'convert_image_urls_to_webp',
692
+ 'compress' => 'compress_cache',
693
  'excl_ids' => 'excluded_post_ids',
694
  'excl_paths' => 'excluded_page_paths',
695
  'excl_cookies' => 'excluded_cookies',
709
  if ( ! empty( $new_name ) ) {
710
  $settings[ $new_name ] = $settings[ $old_name ];
711
  }
712
+
713
  unset( $settings[ $old_name ] );
714
  }
715
  }
722
  * add plugin action links in the plugins list table
723
  *
724
  * @since 1.0.0
725
+ * @change 1.7.0
726
  *
727
  * @param array $action_links action links
728
  * @return array $action_links updated action links if applicable, unchanged otherwise
735
  return $action_links;
736
  }
737
 
738
+ // prepend action link
739
+ array_unshift( $action_links, sprintf(
740
+ '<a href="%s">%s</a>',
741
+ admin_url( 'options-general.php?page=cache-enabler' ),
742
+ esc_html__( 'Settings', 'cache-enabler' )
743
+ ) );
 
 
 
 
 
744
 
745
  return $action_links;
746
  }
750
  * add plugin metadata in the plugins list table
751
  *
752
  * @since 1.0.0
753
+ * @change 1.7.0
754
  *
755
  * @param array $plugin_meta plugin metadata, including the version, author, author URI, and plugin URI
756
  * @param string $plugin_file path to the plugin file relative to the plugins directory
760
  public static function add_plugin_row_meta( $plugin_meta, $plugin_file ) {
761
 
762
  // check if Cache Enabler row
763
+ if ( $plugin_file !== CACHE_ENABLER_BASE ) {
764
  return $plugin_meta;
765
  }
766
 
817
  * @since 1.0.0
818
  * @change 1.6.0
819
  *
820
+ * @param object $wp_admin_bar menu properties
821
  */
822
 
823
  public static function add_admin_bar_items( $wp_admin_bar ) {
866
  * enqueue styles and scripts
867
  *
868
  * @since 1.0.0
869
+ * @change 1.7.0
870
  */
871
 
872
  public static function add_admin_resources( $hook ) {
873
 
874
  // settings page
875
  if ( $hook === 'settings_page_cache-enabler' ) {
876
+ wp_enqueue_style( 'cache-enabler-settings', plugins_url( 'css/settings.min.css', CACHE_ENABLER_FILE ), array(), CACHE_ENABLER_VERSION );
877
  }
878
  }
879
 
924
  * process clear cache request
925
  *
926
  * @since 1.0.0
927
+ * @change 1.7.0
928
  */
929
 
930
  public static function process_clear_cache_request() {
946
 
947
  // clear page cache
948
  if ( $_GET['_action'] === 'clearurl' ) {
949
+ $clear_url = parse_url( home_url(), PHP_URL_SCHEME ) . '://' . Cache_Enabler_Engine::$request_headers['Host'] . $_SERVER['REQUEST_URI'];
 
950
  self::clear_page_cache_by_url( $clear_url );
951
  // clear site(s) cache
952
  } elseif ( $_GET['_action'] === 'clear' ) {
954
  }
955
 
956
  // redirect to same page
957
+ wp_safe_redirect( remove_query_arg( array( '_cache', '_action', '_wpnonce' ) ) );
958
 
959
  // set transient for clear notice
960
  if ( is_admin() ) {
970
  * admin notice after cache has been cleared
971
  *
972
  * @since 1.0.0
973
+ * @change 1.7.0
974
  */
975
 
976
  public static function cache_cleared_notice() {
981
  }
982
 
983
  if ( get_transient( self::get_cache_cleared_transient_name() ) ) {
984
+ printf(
985
  '<div class="notice notice-success is-dismissible"><p><strong>%s</strong></p></div>',
986
  ( is_multisite() && is_network_admin() ) ? esc_html__( 'Network cache cleared.', 'cache-enabler' ) : esc_html__( 'Site cache cleared.', 'cache-enabler' )
987
  );
992
 
993
 
994
  /**
995
+ * save or trash post hook
996
  *
997
  * @since 1.5.0
998
+ * @change 1.7.0
999
  *
1000
  * @param integer $post_id post ID
1001
  */
1002
 
1003
+ public static function on_save_trash_post( $post_id ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1004
 
1005
+ $post_status = get_post_status( $post_id );
1006
 
1007
+ // if any published post type has been created, updated, or about to be trashed
1008
+ if ( $post_status === 'publish' ) {
1009
+ self::clear_cache_on_post_save( $post_id );
 
 
 
1010
  }
1011
  }
1012
 
1013
 
1014
  /**
1015
+ * pre post update hook
1016
  *
1017
+ * @since 1.7.0
1018
+ * @change 1.7.0
1019
  *
1020
+ * @param integer $post_id post ID
1021
+ * @param array $post_data unslashed post data
1022
  */
1023
 
1024
+ public static function on_pre_post_update( $post_id, $post_data ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1025
 
1026
+ $old_post_status = get_post_status( $post_id );
1027
+ $new_post_status = $post_data['post_status'];
1028
 
1029
+ // if any published post type is about to be updated but not trashed
1030
+ if ( $old_post_status === 'publish' && $new_post_status !== 'trash' ) {
1031
+ self::clear_cache_on_post_save( $post_id );
1032
  }
1033
  }
1034
 
1216
  // get post type archives URL
1217
  $post_type_archives_url = get_post_type_archive_link( $post_type );
1218
 
1219
+ // if post type archives URL exists clear post type archives page and its pagination page(s) cache
1220
  if ( ! empty( $post_type_archives_url ) ) {
 
1221
  self::clear_page_cache_by_url( $post_type_archives_url, 'pagination' );
1222
  }
1223
  }
1227
  * clear taxonomies archives pages cache by post ID
1228
  *
1229
  * @since 1.5.0
1230
+ * @change 1.7.0
1231
  *
1232
  * @param integer $post_id post ID
1233
  */
1241
  if ( wp_count_terms( $taxonomy ) > 0 ) {
1242
  // get terms attached to post
1243
  $term_ids = wp_get_post_terms( $post_id, $taxonomy, array( 'fields' => 'ids' ) );
1244
+
1245
  foreach ( $term_ids as $term_id ) {
1246
+ // get term archives URL
1247
  $term_archives_url = get_term_link( (int) $term_id, $taxonomy );
1248
+
1249
+ // if term archives URL exists and does not have a query string clear taxonomy archives page and its pagination page(s) cache
1250
+ if ( ! is_wp_error( $term_archives_url ) && strpos( $term_archives_url, '?' ) === false ) {
1251
  self::clear_page_cache_by_url( $term_archives_url, 'pagination' );
1252
  }
1253
  }
1309
  * clear page cache by post ID
1310
  *
1311
  * @since 1.0.0
1312
+ * @change 1.7.0
1313
  *
1314
  * @param integer|string $post_id post ID
1315
  * @param string $clear_type clear the `pagination` cache or all `subpages` cache instead of only the `page` cache
1318
  public static function clear_page_cache_by_post_id( $post_id, $clear_type = 'page' ) {
1319
 
1320
  // validate integer
1321
+ $post_id = (int) $post_id;
 
 
 
 
 
 
 
1322
 
1323
+ // get page URL
1324
+ $page_url = ( $post_id ) ? get_permalink( $post_id ) : '';
1325
+
1326
+ // if page URL exists and does not have a query string (e.g. guid) clear page cache
1327
+ if ( ! empty( $page_url ) && strpos( $page_url, '?' ) === false ) {
1328
+ self::clear_page_cache_by_url( $page_url, $clear_type );
1329
+ }
1330
  }
1331
 
1332
 
1350
  * clear site cache by blog ID
1351
  *
1352
  * @since 1.4.0
1353
+ * @change 1.7.0
1354
  *
1355
  * @param integer|string $blog_id blog ID
1356
  * @param boolean $delete_cache_size_transient whether or not the cache size transient should be deleted
1359
  public static function clear_site_cache_by_blog_id( $blog_id, $delete_cache_size_transient = true ) {
1360
 
1361
  // validate integer
1362
+ $blog_id = (int) $blog_id;
 
 
 
 
 
 
 
1363
 
1364
  // check if blog ID exists
1365
+ if ( ! in_array( $blog_id, self::get_blog_ids(), true ) ) {
1366
  return;
1367
  }
1368
 
1401
 
1402
 
1403
  /**
1404
+ * clear cache when any post type has been created, updated, or trashed
1405
  *
1406
  * @since 1.5.0
1407
+ * @change 1.7.0
1408
  *
1409
+ * @param integer|WP_Post $post post ID or post instance
 
1410
  */
1411
 
1412
+ public static function clear_cache_on_post_save( $post ) {
1413
+
1414
+ if ( is_int( $post ) ) {
1415
+ $post_id = $post;
1416
+ $post = get_post( $post_id );
1417
 
1418
+ if ( ! is_object( $post ) ) {
1419
+ return;
1420
+ }
1421
+ } elseif ( is_object( $post ) ) {
1422
+ $post_id = $post->ID;
1423
+ }
1424
 
1425
  // if setting enabled clear site cache
1426
  if ( Cache_Enabler_Engine::$settings['clear_site_cache_on_saved_post'] ) {
1427
  self::clear_site_cache();
1428
  // clear page and/or associated cache otherwise
1429
  } else {
1430
+ self::clear_page_cache_by_post_id( $post_id );
 
 
 
 
 
1431
  self::clear_associated_cache( $post );
1432
  }
1433
  }
1437
  * check plugin requirements
1438
  *
1439
  * @since 1.1.0
1440
+ * @change 1.7.0
1441
  */
1442
 
1443
  public static function requirements_check() {
1448
  }
1449
 
1450
  // check PHP version
1451
+ if ( version_compare( PHP_VERSION, CACHE_ENABLER_MIN_PHP, '<' ) ) {
1452
+ printf(
1453
  '<div class="notice notice-error"><p>%s</p></div>',
1454
  sprintf(
1455
  // translators: 1. Cache Enabler 2. PHP version (e.g. 5.6)
1456
  esc_html__( '%1$s requires PHP %2$s or higher to function properly. Please update PHP or disable the plugin.', 'cache-enabler' ),
1457
  '<strong>Cache Enabler</strong>',
1458
+ CACHE_ENABLER_MIN_PHP
1459
  )
1460
  );
1461
  }
1462
 
1463
  // check WordPress version
1464
+ if ( version_compare( $GLOBALS['wp_version'], CACHE_ENABLER_MIN_WP . 'alpha', '<' ) ) {
1465
+ printf(
1466
  '<div class="notice notice-error"><p>%s</p></div>',
1467
  sprintf(
1468
  // translators: 1. Cache Enabler 2. WordPress version (e.g. 5.1)
1469
  esc_html__( '%1$s requires WordPress %2$s or higher to function properly. Please update WordPress or disable the plugin.', 'cache-enabler' ),
1470
  '<strong>Cache Enabler</strong>',
1471
+ CACHE_ENABLER_MIN_WP
1472
  )
1473
  );
1474
  }
1475
 
1476
  // check advanced-cache.php drop-in
1477
  if ( ! file_exists( WP_CONTENT_DIR . '/advanced-cache.php' ) ) {
1478
+ printf(
1479
  '<div class="notice notice-warning"><p>%s</p></div>',
1480
  sprintf(
1481
  // translators: 1. Cache Enabler 2. advanced-cache.php 3. wp-content/plugins/cache-enabler 4. wp-content
1490
 
1491
  // check permalink structure
1492
  if ( Cache_Enabler_Engine::$settings['permalink_structure'] === 'plain' && current_user_can( 'manage_options' ) ) {
1493
+ printf(
1494
  '<div class="notice notice-warning"><p>%s</p></div>',
1495
  sprintf(
1496
  // translators: 1. Cache Enabler 2. Permalink Settings
1507
 
1508
  // check file permissions
1509
  if ( file_exists( dirname( Cache_Enabler_Disk::$cache_dir ) ) && ! is_writable( dirname( Cache_Enabler_Disk::$cache_dir ) ) ) {
1510
+ printf(
1511
  '<div class="notice notice-warning"><p>%s</p></div>',
1512
  sprintf(
1513
  // translators: 1. Cache Enabler 2. 755 3. wp-content/cache 4. file permissions
1526
 
1527
  // check Autoptimize HTML optimization
1528
  if ( defined( 'AUTOPTIMIZE_PLUGIN_DIR' ) && Cache_Enabler_Engine::$settings['minify_html'] && get_option( 'autoptimize_html', '' ) !== '' ) {
1529
+ printf(
1530
  '<div class="notice notice-warning"><p>%s</p></div>',
1531
  sprintf(
1532
  // translators: 1. Autoptimize 2. Cache Enabler Settings
1604
  * validate settings
1605
  *
1606
  * @since 1.0.0
1607
+ * @change 1.7.0
1608
  *
1609
  * @param array $settings user defined settings
1610
  * @return array $validated_settings validated settings
1612
 
1613
  public static function validate_settings( $settings ) {
1614
 
 
 
 
 
 
1615
  $validated_settings = array(
1616
  'cache_expires' => (int) ( ! empty( $settings['cache_expires'] ) ),
1617
+ 'cache_expiry_time' => (int) $settings['cache_expiry_time'],
1618
  'clear_site_cache_on_saved_post' => (int) ( ! empty( $settings['clear_site_cache_on_saved_post'] ) ),
1619
  'clear_site_cache_on_saved_comment' => (int) ( ! empty( $settings['clear_site_cache_on_saved_comment'] ) ),
1620
  'clear_site_cache_on_changed_plugin' => (int) ( ! empty( $settings['clear_site_cache_on_changed_plugin'] ) ),
 
1621
  'convert_image_urls_to_webp' => (int) ( ! empty( $settings['convert_image_urls_to_webp'] ) ),
1622
+ 'mobile_cache' => (int) ( ! empty( $settings['mobile_cache'] ) ),
1623
+ 'compress_cache' => (int) ( ! empty( $settings['compress_cache'] ) ),
 
 
1624
  'minify_html' => (int) ( ! empty( $settings['minify_html'] ) ),
1625
  'minify_inline_css_js' => (int) ( ! empty( $settings['minify_inline_css_js'] ) ),
1626
+ 'excluded_post_ids' => (string) sanitize_text_field( $settings['excluded_post_ids'] ),
1627
+ 'excluded_page_paths' => (string) self::validate_regex( $settings['excluded_page_paths'] ),
1628
+ 'excluded_query_strings' => (string) self::validate_regex( $settings['excluded_query_strings'] ),
1629
+ 'excluded_cookies' => (string) self::validate_regex( $settings['excluded_cookies'] ),
1630
  );
1631
 
1632
  // add default system settings
1646
  * settings page
1647
  *
1648
  * @since 1.0.0
1649
+ * @change 1.7.0
1650
  */
1651
 
1652
  public static function settings_page() {
1654
  ?>
1655
 
1656
  <div id="cache_enabler_settings" class="wrap">
1657
+ <h1><?php esc_html_e( 'Cache Enabler Settings', 'cache-enabler' ); ?></h1>
 
 
1658
 
1659
  <?php
1660
  if ( defined( 'WP_CACHE' ) && ! WP_CACHE ) {
1674
 
1675
  <div class="notice notice-info">
1676
  <p>
1677
+ <?php
1678
+ printf(
1679
+ // translators: %s: KeyCDN
1680
+ esc_html__( 'Combine Cache Enabler with %s for even better WordPress performance and achieve the next level of caching with a CDN.', 'cache-enabler' ),
1681
+ '<strong><a href="https://www.keycdn.com?utm_source=wp-admin&utm_medium=plugins&utm_campaign=cache-enabler" target="_blank" rel="nofollow noopener">KeyCDN</a></strong>'
1682
+ );
1683
+ ?>
1684
  </p>
1685
  </div>
1686
 
1694
  <td>
1695
  <fieldset>
1696
  <p class="subheading"><?php esc_html_e( 'Expiration', 'cache-enabler' ); ?></p>
1697
+ <label for="cache_enabler_cache_expires" class="checkbox--form-control">
1698
+ <input name="cache_enabler[cache_expires]" type="checkbox" id="cache_enabler_cache_expires" value="1" <?php checked( '1', Cache_Enabler_Engine::$settings['cache_expires'] ); ?> />
1699
  </label>
1700
+ <label for="cache_enabler_cache_expiry_time">
1701
  <?php
1702
  printf(
1703
+ // translators: %s: Form field input for number of hours.
1704
  esc_html__( 'Cached pages expire %s hours after being created.', 'cache-enabler' ),
1705
+ '<input name="cache_enabler[cache_expiry_time]" type="number" id="cache_enabler_cache_expiry_time" value="' . Cache_Enabler_Engine::$settings['cache_expiry_time'] . '" class="small-text">'
1706
  );
1707
  ?>
1708
  </label>
1710
  <br />
1711
 
1712
  <p class="subheading"><?php esc_html_e( 'Clearing', 'cache-enabler' ); ?></p>
1713
+ <label for="cache_enabler_clear_site_cache_on_saved_post">
1714
+ <input name="cache_enabler[clear_site_cache_on_saved_post]" type="checkbox" id="cache_enabler_clear_site_cache_on_saved_post" value="1" <?php checked( '1', Cache_Enabler_Engine::$settings['clear_site_cache_on_saved_post'] ); ?> />
1715
  <?php esc_html_e( 'Clear the site cache if any post type has been published, updated, or trashed (instead of only the page and/or associated cache).', 'cache-enabler' ); ?>
1716
  </label>
1717
 
1718
  <br />
1719
 
1720
+ <label for="cache_enabler_clear_site_cache_on_saved_comment">
1721
+ <input name="cache_enabler[clear_site_cache_on_saved_comment]" type="checkbox" id="cache_enabler_clear_site_cache_on_saved_comment" value="1" <?php checked( '1', Cache_Enabler_Engine::$settings['clear_site_cache_on_saved_comment'] ); ?> />
1722
  <?php esc_html_e( 'Clear the site cache if a comment has been posted, updated, spammed, or trashed (instead of only the page cache).', 'cache-enabler' ); ?>
1723
  </label>
1724
 
1725
  <br />
1726
 
1727
+ <label for="cache_enabler_clear_site_cache_on_changed_plugin">
1728
+ <input name="cache_enabler[clear_site_cache_on_changed_plugin]" type="checkbox" id="cache_enabler_clear_site_cache_on_changed_plugin" value="1" <?php checked( '1', Cache_Enabler_Engine::$settings['clear_site_cache_on_changed_plugin'] ); ?> />
1729
+ <?php esc_html_e( 'Clear the site cache if a plugin has been activated or deactivated.', 'cache-enabler' ); ?>
1730
  </label>
1731
 
1732
  <br />
1733
 
1734
  <p class="subheading"><?php esc_html_e( 'Variants', 'cache-enabler' ); ?></p>
1735
+ <label for="cache_enabler_convert_image_urls_to_webp">
1736
+ <input name="cache_enabler[convert_image_urls_to_webp]" type="checkbox" id="cache_enabler_convert_image_urls_to_webp" value="1" <?php checked( '1', Cache_Enabler_Engine::$settings['convert_image_urls_to_webp'] ); ?> />
1737
  <?php
1738
  printf(
1739
  // translators: %s: Optimus
1745
 
1746
  <br />
1747
 
1748
+ <label for="cache_enabler_mobile_cache">
1749
+ <input name="cache_enabler[mobile_cache]" type="checkbox" id="cache_enabler_mobile_cache" value="1" <?php checked( '1', Cache_Enabler_Engine::$settings['mobile_cache'] ); ?> />
1750
+ <?php esc_html_e( 'Create an additional cached version for mobile devices.', 'cache-enabler' ); ?>
1751
+ </label>
1752
+
1753
+ <br />
1754
+
1755
+ <label for="cache_enabler_compress_cache">
1756
+ <input name="cache_enabler[compress_cache]" type="checkbox" id="cache_enabler_compress_cache" value="1" <?php checked( '1', Cache_Enabler_Engine::$settings['compress_cache'] ); ?> />
1757
  <?php esc_html_e( 'Pre-compress cached pages with Gzip.', 'cache-enabler' ); ?>
1758
  </label>
1759
 
1760
  <br />
1761
 
1762
  <p class="subheading"><?php esc_html_e( 'Minification', 'cache-enabler' ); ?></p>
1763
+ <label for="cache_enabler_minify_html" class="checkbox--form-control">
1764
+ <input name="cache_enabler[minify_html]" type="checkbox" id="cache_enabler_minify_html" value="1" <?php checked( '1', Cache_Enabler_Engine::$settings['minify_html'] ); ?> />
1765
  </label>
1766
+ <label for="cache_enabler_minify_inline_css_js">
1767
  <?php
1768
  $minify_inline_css_js_options = array(
1769
  esc_html__( 'excluding', 'cache-enabler' ) => 0,
1770
  esc_html__( 'including', 'cache-enabler' ) => 1,
1771
  );
1772
+ $minify_inline_css_js = '<select name="cache_enabler[minify_inline_css_js]" id="cache_enabler_minify_inline_css_js">';
1773
  foreach ( $minify_inline_css_js_options as $key => $value ) {
1774
  $minify_inline_css_js .= '<option value="' . esc_attr( $value ) . '"' . selected( $value, Cache_Enabler_Engine::$settings['minify_inline_css_js'], false ) . '>' . $key . '</option>';
1775
  }
1792
  <td>
1793
  <fieldset>
1794
  <p class="subheading"><?php esc_html_e( 'Post IDs', 'cache-enabler' ); ?></p>
1795
+ <label for="cache_enabler_excluded_post_ids">
1796
+ <input name="cache_enabler[excluded_post_ids]" type="text" id="cache_enabler_excluded_post_ids" value="<?php echo esc_attr( Cache_Enabler_Engine::$settings['excluded_post_ids'] ) ?>" class="regular-text" />
1797
  <p class="description">
1798
+ <?php
1799
+ // translators: %s: ,
1800
+ printf(
1801
+ esc_html__( 'Post IDs separated by a %s that should bypass the cache.', 'cache-enabler' ),
1802
+ '<code class="code--form-control">,</code>'
1803
+ );
1804
+ ?>
1805
  </p>
1806
  <p><?php esc_html_e( 'Example:', 'cache-enabler' ); ?> <code class="code--form-control">2,43,65</code></p>
1807
  </label>
1809
  <br />
1810
 
1811
  <p class="subheading"><?php esc_html_e( 'Page Paths', 'cache-enabler' ); ?></p>
1812
+ <label for="cache_enabler_excluded_page_paths">
1813
+ <input name="cache_enabler[excluded_page_paths]" type="text" id="cache_enabler_excluded_page_paths" value="<?php echo esc_attr( Cache_Enabler_Engine::$settings['excluded_page_paths'] ) ?>" class="regular-text code" />
1814
  <p class="description"><?php esc_html_e( 'A regex matching page paths that should bypass the cache.', 'cache-enabler' ); ?></p>
1815
  <p><?php esc_html_e( 'Example:', 'cache-enabler' ); ?> <code class="code--form-control">/^(\/|\/forums\/)$/</code></p>
1816
  </label>
1818
  <br />
1819
 
1820
  <p class="subheading"><?php esc_html_e( 'Query Strings', 'cache-enabler' ); ?></p>
1821
+ <label for="cache_enabler_excluded_query_strings">
1822
+ <input name="cache_enabler[excluded_query_strings]" type="text" id="cache_enabler_excluded_query_strings" value="<?php echo esc_attr( Cache_Enabler_Engine::$settings['excluded_query_strings'] ) ?>" class="regular-text code" />
1823
  <p class="description"><?php esc_html_e( 'A regex matching query strings that should bypass the cache.', 'cache-enabler' ); ?></p>
1824
  <p><?php esc_html_e( 'Example:', 'cache-enabler' ); ?> <code class="code--form-control">/^nocache$/</code></p>
1825
  <p><?php esc_html_e( 'Default if unset:', 'cache-enabler' ); ?> <code class="code--form-control">/^(?!(fbclid|ref|mc_(cid|eid)|utm_(source|medium|campaign|term|content|expid)|gclid|fb_(action_ids|action_types|source)|age-verified|usqp|cn-reloaded|_ga|_ke)).+$/</code></p>
1828
  <br />
1829
 
1830
  <p class="subheading"><?php esc_html_e( 'Cookies', 'cache-enabler' ); ?></p>
1831
+ <label for="cache_enabler_excluded_cookies">
1832
+ <input name="cache_enabler[excluded_cookies]" type="text" id="cache_enabler_excluded_cookies" value="<?php echo esc_attr( Cache_Enabler_Engine::$settings['excluded_cookies'] ) ?>" class="regular-text code" />
1833
  <p class="description"><?php esc_html_e( 'A regex matching cookies that should bypass the cache.', 'cache-enabler' ); ?></p>
1834
  <p><?php esc_html_e( 'Example:', 'cache-enabler' ); ?> <code class="code--form-control">/^(comment_author|woocommerce_items_in_cart|wp_woocommerce_session)_?/</code></p>
1835
  <p><?php esc_html_e( 'Default if unset:', 'cache-enabler' ); ?> <code class="code--form-control">/^(wp-postpass|wordpress_logged_in|comment_author)_/</code></p>
1840
  </table>
1841
 
1842
  <p class="submit">
1843
+ <input type="submit" class="button-secondary" value="<?php esc_html_e( 'Save Changes', 'cache-enabler' ); ?>" />
1844
+ <input name="cache_enabler[clear_site_cache_on_saved_settings]" type="submit" class="button-primary" value="<?php esc_html_e( 'Save Changes and Clear Site Cache', 'cache-enabler' ); ?>" />
1845
  </p>
1846
  </form>
1847
  </div>
inc/cache_enabler_disk.class.php CHANGED
@@ -47,32 +47,17 @@ final class Cache_Enabler_Disk {
47
  private static $dir_cleared = array();
48
 
49
 
50
- /**
51
- * base cache file names
52
- *
53
- * @since 1.0.7
54
- * @change 1.6.0
55
- *
56
- * @var string
57
- */
58
-
59
- const CACHE_FILE_HTML = 'index.html';
60
- const CACHE_FILE_GZIP = 'index.html.gz';
61
- const CACHE_FILE_WEBP_HTML = 'index-webp.html';
62
- const CACHE_FILE_WEBP_GZIP = 'index-webp.html.gz';
63
-
64
-
65
  /**
66
  * configure system files
67
  *
68
  * @since 1.5.0
69
- * @change 1.5.0
70
  */
71
 
72
  public static function setup() {
73
 
74
  // add advanced-cache.php drop-in
75
- copy( CE_DIR . '/advanced-cache.php', WP_CONTENT_DIR . '/advanced-cache.php' );
76
 
77
  // set WP_CACHE constant in config file if not already set
78
  self::set_wp_cache_constant();
@@ -106,23 +91,24 @@ final class Cache_Enabler_Disk {
106
 
107
 
108
  /**
109
- * store cached page(s)
110
  *
111
  * @since 1.0.0
112
- * @change 1.5.0
113
  *
114
  * @param string $page_contents contents of a page from the output buffer
115
  */
116
 
117
  public static function cache_page( $page_contents ) {
118
 
119
- // check if page is empty
120
- if ( empty( $page_contents ) ) {
121
- return;
122
- }
123
 
124
- // create cached page(s)
125
- self::create_cache_files( $page_contents );
 
 
 
126
  }
127
 
128
 
@@ -130,14 +116,15 @@ final class Cache_Enabler_Disk {
130
  * check if cached page exists
131
  *
132
  * @since 1.0.0
133
- * @change 1.0.0
134
  *
135
- * @return boolean true if cached page exists, false otherwise
 
136
  */
137
 
138
- public static function cache_exists() {
139
 
140
- return is_readable( self::cache_file_html() );
141
  }
142
 
143
 
@@ -145,12 +132,13 @@ final class Cache_Enabler_Disk {
145
  * check if cached page expired
146
  *
147
  * @since 1.0.1
148
- * @change 1.5.1
149
  *
150
- * @return boolean true if cached page expired, false otherwise
 
151
  */
152
 
153
- public static function cache_expired() {
154
 
155
  // check if cached pages are set to expire
156
  if ( ! Cache_Enabler_Engine::$settings['cache_expires'] || Cache_Enabler_Engine::$settings['cache_expiry_time'] === 0 ) {
@@ -161,7 +149,7 @@ final class Cache_Enabler_Disk {
161
  $expires_seconds = 60 * 60 * Cache_Enabler_Engine::$settings['cache_expiry_time'];
162
 
163
  // check if cached page has expired
164
- if ( ( filemtime( self::cache_file_html() ) + $expires_seconds ) <= $now ) {
165
  return true;
166
  }
167
 
@@ -169,72 +157,11 @@ final class Cache_Enabler_Disk {
169
  }
170
 
171
 
172
- /**
173
- * create signature
174
- *
175
- * @since 1.0.0
176
- * @change 1.5.0
177
- *
178
- * @return string signature
179
- */
180
-
181
- private static function cache_signature() {
182
-
183
- return sprintf(
184
- '<!-- %s @ %s',
185
- 'Cache Enabler by KeyCDN',
186
- date_i18n( 'd.m.Y H:i:s', current_time( 'timestamp' ) )
187
- );
188
- }
189
-
190
-
191
- /**
192
- * get cache size
193
- *
194
- * @since 1.0.0
195
- * @change 1.6.0
196
- *
197
- * @param string $dir directory path
198
- * @return integer $cache_size cache size in bytes
199
- */
200
-
201
- public static function cache_size( $dir = null ) {
202
-
203
- $cache_size = 0;
204
-
205
- // get directory objects if provided directory exists
206
- if ( is_dir( $dir ) ) {
207
- $dir_objects = self::get_dir_objects( $dir );
208
- // get site objects otherwise
209
- } else {
210
- $dir_objects = self::get_site_objects( home_url() );
211
- }
212
-
213
- // check if directory is empty
214
- if ( empty( $dir_objects ) ) {
215
- return $cache_size;
216
- }
217
-
218
- foreach ( $dir_objects as $dir_object ) {
219
- // get full path
220
- $dir_object = trailingslashit( ( $dir ) ? $dir : ( self::$cache_dir . '/' . parse_url( home_url(), PHP_URL_HOST ) . parse_url( home_url(), PHP_URL_PATH ) ) ) . $dir_object;
221
-
222
- if ( is_dir( $dir_object ) ) {
223
- $cache_size += self::cache_size( $dir_object );
224
- } elseif ( is_file( $dir_object ) ) {
225
- $cache_size += filesize( $dir_object );
226
- }
227
- }
228
-
229
- return $cache_size;
230
- }
231
-
232
-
233
  /**
234
  * clear cached page(s)
235
  *
236
  * @since 1.0.0
237
- * @change 1.6.0
238
  *
239
  * @param string $clear_url full URL to potentially cached page
240
  * @param string $clear_type clear the `pagination` cache or all `subpages` cache instead of only the `page` cache
@@ -248,17 +175,13 @@ final class Cache_Enabler_Disk {
248
  }
249
 
250
  // get directory
251
- $dir = self::cache_file_dir_path( $clear_url );
252
 
253
  // check if directory exists
254
  if ( ! is_dir( $dir ) ) {
255
  return;
256
  }
257
 
258
- if ( $clear_type === 'dir' ) {
259
- $clear_type = 'subpages';
260
- }
261
-
262
  // check if page and subpages cache should be cleared
263
  if ( $clear_type === 'subpages' ) {
264
  self::clear_dir( $dir );
@@ -270,7 +193,7 @@ final class Cache_Enabler_Disk {
270
  if ( $clear_type === 'pagination' ) {
271
  $pagination_base = $GLOBALS['wp_rewrite']->pagination_base;
272
  if ( strlen( $pagination_base ) > 0 ) {
273
- $pagination_dir = $dir . $pagination_base;
274
  self::clear_dir( $pagination_dir );
275
  }
276
  }
@@ -298,7 +221,7 @@ final class Cache_Enabler_Disk {
298
  }
299
 
300
  // site cache cleared hook
301
- if ( $dir === untrailingslashit( self::cache_file_dir_path( home_url() ) ) ) {
302
  $site_cleared_url = home_url();
303
  $site_cleared_id = get_current_blog_id();
304
  do_action( 'cache_enabler_site_cache_cleared', $site_cleared_url, $site_cleared_id );
@@ -317,13 +240,13 @@ final class Cache_Enabler_Disk {
317
  * @since 1.0.0
318
  * @change 1.6.0
319
  *
320
- * @param string $dir directory path
321
  * @param boolean $skip_child_dir whether or not child directories should be skipped
322
  */
323
 
324
  private static function clear_dir( $dir, $skip_child_dir = false ) {
325
 
326
- // remove trailing slash
327
  $dir = untrailingslashit( $dir );
328
 
329
  // check if directory exists
@@ -358,99 +281,65 @@ final class Cache_Enabler_Disk {
358
 
359
 
360
  /**
361
- * create files for cache
362
  *
363
  * @since 1.0.0
364
- * @change 1.6.1
365
  *
366
  * @param string $page_contents contents of a page from the output buffer
367
  */
368
 
369
- private static function create_cache_files( $page_contents ) {
370
-
371
- // get base signature
372
- $cache_signature = self::cache_signature();
373
 
374
- // make directory if necessary
375
- if ( ! wp_mkdir_p( self::cache_file_dir_path() ) ) {
376
- wp_die( 'Unable to create directory.' );
377
  }
378
 
379
- // minify HTML
380
- $page_contents = self::minify_html( $page_contents );
381
-
382
- // create default file
383
- self::create_cache_file( self::cache_file_html(), $page_contents . $cache_signature . ' (' . self::cache_file_scheme() . ' html) -->' );
384
 
385
- // create pre-compressed file
386
- if ( Cache_Enabler_Engine::$settings['compress_cache'] ) {
387
- $compressed_page_contents = gzencode( $page_contents . $cache_signature . ' (' . self::cache_file_scheme() . ' gzip) -->', 9 );
388
- // validate compression
389
- if ( is_string( $compressed_page_contents ) ) {
390
- self::create_cache_file( self::cache_file_gzip(), $compressed_page_contents );
391
- }
392
  }
393
 
394
- // create WebP supported files
395
- if ( Cache_Enabler_Engine::$settings['convert_image_urls_to_webp'] ) {
396
- // attributes to convert during WebP conversion hook
397
- $attributes = (array) apply_filters( 'cache_enabler_convert_webp_attributes', array( 'src', 'srcset', 'data-[^=]+' ) );
398
-
399
- // stringify
400
- $attributes_regex = implode( '|', $attributes );
401
-
402
- // magic regex rule
403
- $image_urls_regex = '#(?:(?:(' . $attributes_regex . ')\s*=|(url)\()\s*[\'\"]?\s*)\K(?:[^\?\"\'\s>]+)(?:\.jpe?g|\.png)(?:\s\d+[wx][^\"\'>]*)?(?=\/?[\"\'\s\)>])(?=[^<{]*(?:\)[^<{]*\}|>))#i';
404
-
405
- // ignore query strings during WebP conversion hook
406
- if ( ! apply_filters( 'cache_enabler_convert_webp_ignore_query_strings', true ) ) {
407
- $image_urls_regex = '#(?:(?:(' . $attributes_regex . ')\s*=|(url)\()\s*[\'\"]?\s*)\K(?:[^\"\'\s>]+)(?:\.jpe?g|\.png)(?:\s\d+[wx][^\"\'>]*)?(?=\/?[\?\"\'\s\)>])(?=[^<{]*(?:\)[^<{]*\}|>))#i';
408
- }
409
-
410
- // page contents after WebP conversion hook
411
- $converted_page_contents = apply_filters( 'cache_enabler_page_contents_after_webp_conversion', preg_replace_callback( $image_urls_regex, 'self::convert_webp', $page_contents ) );
412
 
413
- // deprecated page contents after WebP conversion hook
414
- $converted_page_contents = apply_filters_deprecated( 'cache_enabler_disk_webp_converted_data', array( $converted_page_contents ), '1.6.0', 'cache_enabler_page_contents_after_webp_conversion' );
 
 
415
 
416
- // create default WebP file
417
- self::create_cache_file( self::cache_file_webp_html(), $converted_page_contents . $cache_signature . ' (' . self::cache_file_scheme() . ' webp html) -->' );
 
418
 
419
- // create pre-compressed file
420
- if ( Cache_Enabler_Engine::$settings['compress_cache'] ) {
421
- $compressed_converted_page_contents = gzencode( $converted_page_contents . $cache_signature . ' (' . self::cache_file_scheme() . ' webp gzip) -->', 9 );
422
- // validate compression
423
- if ( is_string( $compressed_converted_page_contents ) ) {
424
- self::create_cache_file( self::cache_file_webp_gzip(), $compressed_converted_page_contents );
425
- }
426
  }
427
  }
428
- }
429
-
430
-
431
- /**
432
- * create file for cache
433
- *
434
- * @since 1.0.0
435
- * @change 1.5.0
436
- *
437
- * @param string $file_path file path
438
- * @param string $page_contents contents of a page from the output buffer
439
- */
440
 
441
- private static function create_cache_file( $file_path, $page_contents ) {
 
 
 
442
 
443
- // write page contents from output buffer to file
444
- file_put_contents( $file_path, $page_contents );
445
 
446
  // clear file status cache
447
  clearstatcache();
448
 
449
- // set permissions
450
- $file_stats = @stat( dirname( $file_path ) );
451
- $permissions = $file_stats['mode'] & 0007777;
452
- $permissions = $permissions & 0000666;
453
- @chmod( $file_path, $permissions );
454
 
455
  // clear file status cache
456
  clearstatcache();
@@ -461,32 +350,22 @@ final class Cache_Enabler_Disk {
461
  * create settings file
462
  *
463
  * @since 1.2.3
464
- * @change 1.6.0
465
  *
466
  * @param array $settings settings from database
467
- * @return string $new_settings_file new settings file
468
  */
469
 
470
  public static function create_settings_file( $settings ) {
471
 
472
- // validate array
473
- if ( ! is_array( $settings ) ) {
474
- return;
475
- }
476
-
477
  // check settings file requirements
478
- if ( ! function_exists( 'home_url' ) ) {
479
  return;
480
  }
481
 
482
  // get new settings file
483
  $new_settings_file = self::get_settings_file();
484
 
485
- // make directory if necessary
486
- if ( ! wp_mkdir_p( dirname( $new_settings_file ) ) ) {
487
- wp_die( 'Unable to create directory.' );
488
- }
489
-
490
  // add new settings file contents
491
  $new_settings_file_contents = '<?php' . PHP_EOL;
492
  $new_settings_file_contents .= '/**' . PHP_EOL;
@@ -495,179 +374,217 @@ final class Cache_Enabler_Disk {
495
  $new_settings_file_contents .= ' * @since 1.5.0' . PHP_EOL;
496
  $new_settings_file_contents .= ' * @change 1.5.0' . PHP_EOL;
497
  $new_settings_file_contents .= ' *' . PHP_EOL;
498
- $new_settings_file_contents .= ' * @generated ' . date_i18n( 'd.m.Y H:i:s', current_time( 'timestamp' ) ) . PHP_EOL;
499
  $new_settings_file_contents .= ' */' . PHP_EOL;
500
  $new_settings_file_contents .= PHP_EOL;
501
  $new_settings_file_contents .= 'return ' . var_export( $settings, true ) . ';';
502
 
503
- file_put_contents( $new_settings_file, $new_settings_file_contents );
 
 
 
 
 
 
504
 
505
  return $new_settings_file;
506
  }
507
 
508
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
509
  /**
510
  * get cache file directory path
511
  *
512
  * @since 1.0.0
513
- * @change 1.6.0
514
  *
515
- * @param string $url full URL to potentially cached page
516
- * @return string $file_dir_path file directory path to new or potentially cached page
517
  */
518
 
519
- private static function cache_file_dir_path( $url = null ) {
520
 
521
- $file_dir_path = '';
522
 
523
  // validate URL
524
  if ( $url && ! filter_var( $url, FILTER_VALIDATE_URL ) ) {
525
- return $file_dir_path;
526
  }
527
 
528
- $file_dir_path = sprintf(
529
  '%s/%s%s',
530
  self::$cache_dir,
531
- parse_url(
532
- ( $url ) ? $url : 'http://' . strtolower( $_SERVER['HTTP_HOST'] ),
533
- PHP_URL_HOST
534
- ),
535
- parse_url(
536
- ( $url ) ? $url : $_SERVER['REQUEST_URI'],
537
- PHP_URL_PATH
538
- )
539
  );
540
 
541
- // add trailing slash
542
- $file_dir_path = rtrim( $file_dir_path, '/\\' ) . '/';
543
 
544
- return $file_dir_path;
545
  }
546
 
547
 
548
  /**
549
- * get cache file scheme
550
  *
551
- * @since 1.4.0
552
- * @change 1.5.0
553
  *
554
- * @return string https or http
555
  */
556
 
557
- private static function cache_file_scheme() {
558
-
559
- return ( ( isset( $_SERVER['HTTPS'] ) && $_SERVER['HTTPS'] !== 'off' ) || $_SERVER['SERVER_PORT'] == '443' ) ? 'https' : 'http';
560
- }
561
-
562
 
563
- /**
564
- * get complete cache file path (HTML)
565
- *
566
- * @since 1.0.0
567
- * @change 1.4.0
568
- *
569
- * @return string file path to new or potentially cached page
570
- */
571
 
572
- private static function cache_file_html() {
573
-
574
- return self::cache_file_dir_path() . self::cache_file_scheme() . '-' . self::CACHE_FILE_HTML;
575
  }
576
 
577
 
578
  /**
579
- * get complete cache file path (Gzip)
580
  *
581
- * @since 1.0.1
582
- * @change 1.4.0
583
  *
584
- * @return string file path to new or potentially cached page
585
  */
586
 
587
- private static function cache_file_gzip() {
588
 
589
- return self::cache_file_dir_path() . self::cache_file_scheme() . '-' . self::CACHE_FILE_GZIP;
590
- }
 
 
 
 
 
591
 
 
 
 
 
 
 
 
 
592
 
593
- /**
594
- * get complete cache file path (WebP HTML)
595
- *
596
- * @since 1.0.7
597
- * @change 1.4.0
598
- *
599
- * @return string file path to new or potentially cached page
600
- */
 
 
 
 
 
 
 
 
 
 
 
 
601
 
602
- private static function cache_file_webp_html() {
 
 
 
 
 
603
 
604
- return self::cache_file_dir_path() . self::cache_file_scheme() . '-' . self::CACHE_FILE_WEBP_HTML;
605
  }
606
 
607
 
608
  /**
609
- * get complete cache file path (WebP Gzip)
610
  *
611
- * @since 1.0.1
612
- * @change 1.4.0
613
  *
614
- * @return string file path to new or potentially cached page
 
615
  */
616
 
617
- private static function cache_file_webp_gzip() {
 
 
 
 
 
 
 
618
 
619
- return self::cache_file_dir_path() . self::cache_file_scheme() . '-' . self::CACHE_FILE_WEBP_GZIP;
620
  }
621
 
622
 
623
  /**
624
- * get cached page
625
  *
626
  * @since 1.0.0
627
- * @change 1.5.0
 
 
 
628
  */
629
 
630
- public static function get_cache() {
631
 
632
- // set X-Cache-Handler response header
633
- header( 'X-Cache-Handler: cache-enabler-engine' );
634
 
635
- // get request headers
636
- if ( function_exists( 'apache_request_headers' ) ) {
637
- $headers = apache_request_headers();
638
- $http_if_modified_since = ( isset( $headers[ 'If-Modified-Since' ] ) ) ? $headers[ 'If-Modified-Since' ] : '';
639
- $http_accept = ( isset( $headers[ 'Accept' ] ) ) ? $headers[ 'Accept' ] : '';
640
- $http_accept_encoding = ( isset( $headers[ 'Accept-Encoding' ] ) ) ? $headers[ 'Accept-Encoding' ] : '';
641
  } else {
642
- $http_if_modified_since = ( isset( $_SERVER[ 'HTTP_IF_MODIFIED_SINCE' ] ) ) ? $_SERVER[ 'HTTP_IF_MODIFIED_SINCE' ] : '';
643
- $http_accept = ( isset( $_SERVER[ 'HTTP_ACCEPT' ] ) ) ? $_SERVER[ 'HTTP_ACCEPT' ] : '';
644
- $http_accept_encoding = ( isset( $_SERVER[ 'HTTP_ACCEPT_ENCODING' ] ) ) ? $_SERVER[ 'HTTP_ACCEPT_ENCODING' ] : '';
645
  }
646
 
647
- // check modified since with cached file and return 304 if no difference
648
- if ( $http_if_modified_since && ( strtotime( $http_if_modified_since ) >= filemtime( self::cache_file_html() ) ) ) {
649
- header( $_SERVER['SERVER_PROTOCOL'] . ' 304 Not Modified', true, 304 );
650
- exit;
651
  }
652
 
653
- // check webp and deliver gzip webp file if support
654
- if ( $http_accept && ( strpos( $http_accept, 'webp' ) !== false ) ) {
655
- if ( is_readable( self::cache_file_webp_gzip() ) ) {
656
- header( 'Content-Encoding: gzip' );
657
- return self::cache_file_webp_gzip();
658
- } elseif ( is_readable( self::cache_file_webp_html() ) ) {
659
- return self::cache_file_webp_html();
660
- }
661
- }
662
 
663
- // check encoding and deliver gzip file if support
664
- if ( $http_accept_encoding && ( strpos( $http_accept_encoding, 'gzip' ) !== false ) && is_readable( self::cache_file_gzip() ) ) {
665
- header( 'Content-Encoding: gzip' );
666
- return self::cache_file_gzip();
 
667
  }
668
 
669
- // get default cached file
670
- return self::cache_file_html();
671
  }
672
 
673
 
@@ -697,7 +614,7 @@ final class Cache_Enabler_Disk {
697
  * get settings file name
698
  *
699
  * @since 1.5.5
700
- * @change 1.6.0
701
  *
702
  * @param boolean $fallback whether or not fallback settings file name should be returned
703
  * @param boolean $skip_blog_path whether or not blog path should be included in settings file name
@@ -726,13 +643,12 @@ final class Cache_Enabler_Disk {
726
  $settings_file_regex = '/\.php$/';
727
 
728
  if ( is_multisite() ) {
729
- $settings_file_regex = '/^' . parse_url( 'http://' . strtolower( $_SERVER['HTTP_HOST'] ), PHP_URL_HOST );
730
  $settings_file_regex = str_replace( '.', '\.', $settings_file_regex );
731
 
732
  // subdirectory network
733
  if ( defined( 'SUBDOMAIN_INSTALL' ) && ! SUBDOMAIN_INSTALL && ! $skip_blog_path ) {
734
- $url_path = $_SERVER['REQUEST_URI'];
735
- $url_path = trim( $url_path, '/');
736
 
737
  if ( ! empty( $url_path ) ) {
738
  $url_path_regex = str_replace( '/', '|', $url_path );
@@ -754,7 +670,7 @@ final class Cache_Enabler_Disk {
754
  $settings_file_name = self::get_settings_file_name( $fallback, $skip_blog_path );
755
  }
756
  } else {
757
- $settings_file_name = parse_url( 'http://' . strtolower( $_SERVER['HTTP_HOST'] ), PHP_URL_HOST );
758
 
759
  // subdirectory network
760
  if ( is_multisite() && defined( 'SUBDOMAIN_INSTALL' ) && ! SUBDOMAIN_INSTALL && ! $skip_blog_path ) {
@@ -832,7 +748,7 @@ final class Cache_Enabler_Disk {
832
  * @since 1.4.7
833
  * @change 1.6.0
834
  *
835
- * @param string $dir directory path
836
  * @return array $dir_objects directory objects
837
  */
838
 
@@ -854,7 +770,7 @@ final class Cache_Enabler_Disk {
854
  * get site file system objects
855
  *
856
  * @since 1.6.0
857
- * @change 1.6.0
858
  *
859
  * @param string $site_url site URL
860
  * @return array $site_objects site objects
@@ -865,7 +781,7 @@ final class Cache_Enabler_Disk {
865
  $site_objects = array();
866
 
867
  // get directory
868
- $dir = self::cache_file_dir_path( $site_url );
869
 
870
  // check if directory exists
871
  if ( ! is_dir( $dir ) ) {
@@ -881,10 +797,10 @@ final class Cache_Enabler_Disk {
881
  $blog_paths = Cache_Enabler::get_blog_paths();
882
 
883
  // check if main site in subdirectory network
884
- if ( ! in_array( $blog_path, $blog_paths ) ) {
885
  foreach ( $site_objects as $key => $site_object ) {
886
  // delete site object if it does not belong to main site
887
- if ( in_array( '/' . $site_object . '/', $blog_paths ) ) {
888
  unset( $site_objects[ $key ] );
889
  }
890
  }
@@ -895,11 +811,147 @@ final class Cache_Enabler_Disk {
895
  }
896
 
897
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
898
  /**
899
  * set or unset WP_CACHE constant in wp-config.php
900
  *
901
  * @since 1.1.1
902
- * @change 1.5.0
903
  *
904
  * @param boolean $set true to set WP_CACHE constant, false to unset
905
  */
@@ -913,10 +965,12 @@ final class Cache_Enabler_Disk {
913
  } elseif ( @file_exists( dirname( ABSPATH ) . '/wp-config.php' ) && ! @file_exists( dirname( ABSPATH ) . '/wp-settings.php' ) ) {
914
  // config file resides one level above ABSPATH but is not part of another installation
915
  $wp_config_file = dirname( ABSPATH ) . '/wp-config.php';
 
 
916
  }
917
 
918
  // check if config file can be written to
919
- if ( ! is_writable( $wp_config_file ) ) {
920
  return;
921
  }
922
 
@@ -948,32 +1002,43 @@ final class Cache_Enabler_Disk {
948
  }
949
 
950
  // update config file
951
- file_put_contents( $wp_config_file, $wp_config_file_contents );
952
  }
953
 
954
 
955
  /**
956
- * get image path
957
  *
958
- * @since 1.4.8
959
- * @change 1.5.0
960
  *
961
- * @param string $image_url full or relative URL with or without intrinsic width or density descriptor
962
- * @return string $image_path path to image
963
  */
964
 
965
- private static function image_path( $image_url ) {
966
 
967
- // in case image has intrinsic width or density descriptor
968
- $image_parts = explode( ' ', $image_url );
969
- $image_url = $image_parts[0];
970
 
971
- // in case installation is in a subdirectory
972
- $image_url_path = ltrim( parse_url( $image_url, PHP_URL_PATH ), '/' );
973
- $installation_dir = preg_replace( '/^[^\/]+\/\K.+/', '', $image_url_path );
974
- $image_path = str_replace( $installation_dir, '', ABSPATH ) . $image_url_path;
975
 
976
- return $image_path;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
977
  }
978
 
979
 
@@ -1000,14 +1065,14 @@ final class Cache_Enabler_Disk {
1000
  foreach ( $image_urls as &$image_url ) {
1001
  $image_url = trim( $image_url, ' ' );
1002
  $image_url_webp = preg_replace( $image_extension_regex, '$1.webp', $image_url ); // append .webp extension
1003
- $image_path_webp = self::image_path( $image_url_webp );
1004
 
1005
  // check if WebP image exists
1006
  if ( is_file( $image_path_webp ) ) {
1007
  $image_url = $image_url_webp;
1008
  } else {
1009
  $image_url_webp = preg_replace( $image_extension_regex, '', $image_url_webp ); // remove default extension
1010
- $image_path_webp = self::image_path( $image_url_webp );
1011
 
1012
  // check if WebP image exists
1013
  if ( is_file( $image_path_webp ) ) {
@@ -1027,21 +1092,16 @@ final class Cache_Enabler_Disk {
1027
  * minify HTML
1028
  *
1029
  * @since 1.0.0
1030
- * @change 1.6.2
1031
  *
1032
  * @param string $page_contents contents of a page from the output buffer
1033
- * @return string $minified_html|$page_contents minified page contents if applicable, unchanged otherwise
1034
  */
1035
 
1036
  private static function minify_html( $page_contents ) {
1037
 
1038
- // check if setting is enabled
1039
- if ( ! Cache_Enabler_Engine::$settings['minify_html'] ) {
1040
- return $page_contents;
1041
- }
1042
-
1043
  // HTML character limit
1044
- if ( strlen( $page_contents ) > 700000) {
1045
  return $page_contents;
1046
  }
1047
 
@@ -1070,7 +1130,7 @@ final class Cache_Enabler_Disk {
1070
  // if setting selected remove CSS and JavaScript comments
1071
  if ( Cache_Enabler_Engine::$settings['minify_inline_css_js'] ) {
1072
  $minified_html = preg_replace(
1073
- '#/\*[\s\S]*?\*/|([^\'\"\\:\w]|^)//.*$#m',
1074
  '$1',
1075
  $minified_html
1076
  );
@@ -1123,7 +1183,7 @@ final class Cache_Enabler_Disk {
1123
  * delete settings file
1124
  *
1125
  * @since 1.5.0
1126
- * @change 1.5.0
1127
  */
1128
 
1129
  private static function delete_settings_file() {
@@ -1136,6 +1196,9 @@ final class Cache_Enabler_Disk {
1136
 
1137
  // delete settings directory if empty
1138
  @rmdir( self::$settings_dir );
 
 
 
1139
  }
1140
 
1141
 
@@ -1152,6 +1215,19 @@ final class Cache_Enabler_Disk {
1152
  wp_die( 'URL is empty.' );
1153
  }
1154
 
1155
- self::clear_dir( self::cache_file_dir_path( $url ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
1156
  }
1157
  }
47
  private static $dir_cleared = array();
48
 
49
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50
  /**
51
  * configure system files
52
  *
53
  * @since 1.5.0
54
+ * @change 1.7.0
55
  */
56
 
57
  public static function setup() {
58
 
59
  // add advanced-cache.php drop-in
60
+ copy( CACHE_ENABLER_DIR . '/advanced-cache.php', WP_CONTENT_DIR . '/advanced-cache.php' );
61
 
62
  // set WP_CACHE constant in config file if not already set
63
  self::set_wp_cache_constant();
91
 
92
 
93
  /**
94
+ * store cached page
95
  *
96
  * @since 1.0.0
97
+ * @change 1.7.0
98
  *
99
  * @param string $page_contents contents of a page from the output buffer
100
  */
101
 
102
  public static function cache_page( $page_contents ) {
103
 
104
+ // page contents before store hook
105
+ $page_contents = apply_filters( 'cache_enabler_page_contents_before_store', $page_contents );
 
 
106
 
107
+ // deprecated page contents before store hook
108
+ $page_contents = apply_filters_deprecated( 'cache_enabler_before_store', array( $page_contents ), '1.6.0', 'cache_enabler_page_contents_before_store' );
109
+
110
+ // create cached page to be stored
111
+ self::create_cache_file( $page_contents );
112
  }
113
 
114
 
116
  * check if cached page exists
117
  *
118
  * @since 1.0.0
119
+ * @change 1.7.0
120
  *
121
+ * @param string $cache_file file path to potentially cached page
122
+ * @return boolean true if cached page exists and is readable, false otherwise
123
  */
124
 
125
+ public static function cache_exists( $cache_file ) {
126
 
127
+ return is_readable( $cache_file );
128
  }
129
 
130
 
132
  * check if cached page expired
133
  *
134
  * @since 1.0.1
135
+ * @change 1.7.0
136
  *
137
+ * @param string $cache_file file path to existing cached page
138
+ * @return boolean true if cached page expired, false otherwise
139
  */
140
 
141
+ public static function cache_expired( $cache_file ) {
142
 
143
  // check if cached pages are set to expire
144
  if ( ! Cache_Enabler_Engine::$settings['cache_expires'] || Cache_Enabler_Engine::$settings['cache_expiry_time'] === 0 ) {
149
  $expires_seconds = 60 * 60 * Cache_Enabler_Engine::$settings['cache_expiry_time'];
150
 
151
  // check if cached page has expired
152
+ if ( ( filemtime( $cache_file ) + $expires_seconds ) <= $now ) {
153
  return true;
154
  }
155
 
157
  }
158
 
159
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
160
  /**
161
  * clear cached page(s)
162
  *
163
  * @since 1.0.0
164
+ * @change 1.7.0
165
  *
166
  * @param string $clear_url full URL to potentially cached page
167
  * @param string $clear_type clear the `pagination` cache or all `subpages` cache instead of only the `page` cache
175
  }
176
 
177
  // get directory
178
+ $dir = self::get_cache_file_dir( $clear_url );
179
 
180
  // check if directory exists
181
  if ( ! is_dir( $dir ) ) {
182
  return;
183
  }
184
 
 
 
 
 
185
  // check if page and subpages cache should be cleared
186
  if ( $clear_type === 'subpages' ) {
187
  self::clear_dir( $dir );
193
  if ( $clear_type === 'pagination' ) {
194
  $pagination_base = $GLOBALS['wp_rewrite']->pagination_base;
195
  if ( strlen( $pagination_base ) > 0 ) {
196
+ $pagination_dir = $dir . '/' . $pagination_base;
197
  self::clear_dir( $pagination_dir );
198
  }
199
  }
221
  }
222
 
223
  // site cache cleared hook
224
+ if ( $dir === self::get_cache_file_dir( home_url() ) ) {
225
  $site_cleared_url = home_url();
226
  $site_cleared_id = get_current_blog_id();
227
  do_action( 'cache_enabler_site_cache_cleared', $site_cleared_url, $site_cleared_id );
240
  * @since 1.0.0
241
  * @change 1.6.0
242
  *
243
+ * @param string $dir directory path to clear
244
  * @param boolean $skip_child_dir whether or not child directories should be skipped
245
  */
246
 
247
  private static function clear_dir( $dir, $skip_child_dir = false ) {
248
 
249
+ // remove trailing slash if there happens to be one
250
  $dir = untrailingslashit( $dir );
251
 
252
  // check if directory exists
281
 
282
 
283
  /**
284
+ * create file for cache
285
  *
286
  * @since 1.0.0
287
+ * @change 1.7.0
288
  *
289
  * @param string $page_contents contents of a page from the output buffer
290
  */
291
 
292
+ private static function create_cache_file( $page_contents ) {
 
 
 
293
 
294
+ // check cache file requirements
295
+ if ( ! is_string( $page_contents ) || strlen( $page_contents ) === 0 ) {
296
+ return;
297
  }
298
 
299
+ // get new cache file
300
+ $new_cache_file = self::get_cache_file();
301
+ $new_cache_file_dir = dirname( $new_cache_file );
302
+ $new_cache_file_name = basename( $new_cache_file );
 
303
 
304
+ // if setting enabled minify HTML
305
+ if ( Cache_Enabler_Engine::$settings['minify_html'] ) {
306
+ $page_contents = self::minify_html( $page_contents );
 
 
 
 
307
  }
308
 
309
+ // append cache signature
310
+ $page_contents = $page_contents . self::get_cache_signature( $new_cache_file_name );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
311
 
312
+ // convert image URLs to WebP if applicable
313
+ if ( strpos( $new_cache_file_name, 'webp' ) !== false ) {
314
+ $page_contents = self::converter( $page_contents );
315
+ }
316
 
317
+ // compress page contents with Gzip if applicable
318
+ if ( strpos( $new_cache_file_name, 'gz' ) !== false ) {
319
+ $page_contents = gzencode( $page_contents, 9 );
320
 
321
+ // check if Gzip compression failed
322
+ if ( $page_contents === false ) {
323
+ return;
 
 
 
 
324
  }
325
  }
 
 
 
 
 
 
 
 
 
 
 
 
326
 
327
+ // create directory if necessary
328
+ if ( ! self::mkdir_p( $new_cache_file_dir ) ) {
329
+ return;
330
+ }
331
 
332
+ // create new cache file
333
+ file_put_contents( $new_cache_file, $page_contents, LOCK_EX );
334
 
335
  // clear file status cache
336
  clearstatcache();
337
 
338
+ // set file permissions
339
+ $new_cache_file_stats = @stat( $new_cache_file_dir );
340
+ $new_cache_file_perms = $new_cache_file_stats['mode'] & 0007777;
341
+ $new_cache_file_perms = $new_cache_file_perms & 0000666;
342
+ @chmod( $new_cache_file, $new_cache_file_perms );
343
 
344
  // clear file status cache
345
  clearstatcache();
350
  * create settings file
351
  *
352
  * @since 1.2.3
353
+ * @change 1.7.0
354
  *
355
  * @param array $settings settings from database
356
+ * @return string $new_settings_file file path to new settings file
357
  */
358
 
359
  public static function create_settings_file( $settings ) {
360
 
 
 
 
 
 
361
  // check settings file requirements
362
+ if ( ! is_array( $settings ) || ! function_exists( 'home_url' ) ) {
363
  return;
364
  }
365
 
366
  // get new settings file
367
  $new_settings_file = self::get_settings_file();
368
 
 
 
 
 
 
369
  // add new settings file contents
370
  $new_settings_file_contents = '<?php' . PHP_EOL;
371
  $new_settings_file_contents .= '/**' . PHP_EOL;
374
  $new_settings_file_contents .= ' * @since 1.5.0' . PHP_EOL;
375
  $new_settings_file_contents .= ' * @change 1.5.0' . PHP_EOL;
376
  $new_settings_file_contents .= ' *' . PHP_EOL;
377
+ $new_settings_file_contents .= ' * @generated ' . self::get_current_time() . PHP_EOL;
378
  $new_settings_file_contents .= ' */' . PHP_EOL;
379
  $new_settings_file_contents .= PHP_EOL;
380
  $new_settings_file_contents .= 'return ' . var_export( $settings, true ) . ';';
381
 
382
+ // create directory if necessary
383
+ if ( ! self::mkdir_p( dirname( $new_settings_file ) ) ) {
384
+ return;
385
+ }
386
+
387
+ // create new settings file
388
+ file_put_contents( $new_settings_file, $new_settings_file_contents, LOCK_EX );
389
 
390
  return $new_settings_file;
391
  }
392
 
393
 
394
+ /**
395
+ * get cache file
396
+ *
397
+ * @since 1.7.0
398
+ * @change 1.7.0
399
+ *
400
+ * @return string $cache_file file path to new or potentially cached page
401
+ */
402
+
403
+ public static function get_cache_file() {
404
+
405
+ $cache_file = sprintf(
406
+ '%s/%s',
407
+ self::get_cache_file_dir(),
408
+ self::get_cache_file_name()
409
+ );
410
+
411
+ return $cache_file;
412
+ }
413
+
414
+
415
  /**
416
  * get cache file directory path
417
  *
418
  * @since 1.0.0
419
+ * @change 1.7.0
420
  *
421
+ * @param string $url full URL to potentially cached page
422
+ * @return string $cache_file_dir directory path to new or potentially cached page, empty if provided URL is invalid
423
  */
424
 
425
+ private static function get_cache_file_dir( $url = null ) {
426
 
427
+ $cache_file_dir = '';
428
 
429
  // validate URL
430
  if ( $url && ! filter_var( $url, FILTER_VALIDATE_URL ) ) {
431
+ return $cache_file_dir;
432
  }
433
 
434
+ $cache_file_dir = sprintf(
435
  '%s/%s%s',
436
  self::$cache_dir,
437
+ ( $url ) ? parse_url( $url, PHP_URL_HOST ) : strtolower( Cache_Enabler_Engine::$request_headers['Host'] ),
438
+ parse_url( ( $url ) ? $url : $_SERVER['REQUEST_URI'], PHP_URL_PATH )
 
 
 
 
 
 
439
  );
440
 
441
+ // remove trailing slash
442
+ $cache_file_dir = rtrim( $cache_file_dir, '/\\' );
443
 
444
+ return $cache_file_dir;
445
  }
446
 
447
 
448
  /**
449
+ * get cache file name
450
  *
451
+ * @since 1.7.0
452
+ * @change 1.7.0
453
  *
454
+ * @return string $cache_file_name file name for new or potentially cached page
455
  */
456
 
457
+ private static function get_cache_file_name() {
 
 
 
 
458
 
459
+ $cache_keys = self::get_cache_keys();
460
+ $cache_file_name = $cache_keys['scheme'] . 'index' . $cache_keys['device'] . $cache_keys['webp'] . '.html' . $cache_keys['compression'];
 
 
 
 
 
 
461
 
462
+ return $cache_file_name;
 
 
463
  }
464
 
465
 
466
  /**
467
+ * get cache keys
468
  *
469
+ * @since 1.7.0
470
+ * @change 1.7.0
471
  *
472
+ * @return array $cache_keys cache keys to new or potentially cached page
473
  */
474
 
475
+ private static function get_cache_keys() {
476
 
477
+ // set default cache keys
478
+ $cache_keys = array(
479
+ 'scheme' => 'http-',
480
+ 'device' => '',
481
+ 'webp' => '',
482
+ 'compression' => '',
483
+ );
484
 
485
+ // scheme
486
+ if ( isset( $_SERVER['HTTPS'] ) && ( strtolower( $_SERVER['HTTPS'] ) === 'on' || $_SERVER['HTTPS'] == '1' ) ) {
487
+ $cache_keys['scheme'] = 'https-';
488
+ } elseif ( isset( $_SERVER['SERVER_PORT'] ) && $_SERVER['SERVER_PORT'] == '443' ) {
489
+ $cache_keys['scheme'] = 'https-';
490
+ } elseif ( Cache_Enabler_Engine::$request_headers['X-Forwarded-Proto'] === 'https' || Cache_Enabler_Engine::$request_headers['X-Forwarded-Scheme'] === 'https' ) {
491
+ $cache_keys['scheme'] = 'https-';
492
+ }
493
 
494
+ // device
495
+ if ( Cache_Enabler_Engine::$settings['mobile_cache'] ) {
496
+ if ( strpos( Cache_Enabler_Engine::$request_headers['User-Agent'], 'Mobile' ) !== false
497
+ || strpos( Cache_Enabler_Engine::$request_headers['User-Agent'], 'Android' ) !== false
498
+ || strpos( Cache_Enabler_Engine::$request_headers['User-Agent'], 'Silk/' ) !== false
499
+ || strpos( Cache_Enabler_Engine::$request_headers['User-Agent'], 'Kindle' ) !== false
500
+ || strpos( Cache_Enabler_Engine::$request_headers['User-Agent'], 'BlackBerry' ) !== false
501
+ || strpos( Cache_Enabler_Engine::$request_headers['User-Agent'], 'Opera Mini' ) !== false
502
+ || strpos( Cache_Enabler_Engine::$request_headers['User-Agent'], 'Opera Mobi' ) !== false
503
+ ) {
504
+ $cache_keys['device'] = '-mobile';
505
+ }
506
+ }
507
+
508
+ // WebP
509
+ if ( Cache_Enabler_Engine::$settings['convert_image_urls_to_webp'] ) {
510
+ if ( strpos( Cache_Enabler_Engine::$request_headers['Accept'], 'image/webp' ) !== false ) {
511
+ $cache_keys['webp'] = '-webp';
512
+ }
513
+ }
514
 
515
+ // compression
516
+ if ( Cache_Enabler_Engine::$settings['compress_cache'] ) {
517
+ if ( strpos( Cache_Enabler_Engine::$request_headers['Accept-Encoding'], 'gzip' ) !== false ) {
518
+ $cache_keys['compression'] = '.gz';
519
+ }
520
+ }
521
 
522
+ return $cache_keys;
523
  }
524
 
525
 
526
  /**
527
+ * get cache signature
528
  *
529
+ * @since 1.0.0
530
+ * @change 1.7.0
531
  *
532
+ * @param string $cache_file_name file name for new cached page
533
+ * @return string $cache_signature cache signature
534
  */
535
 
536
+ private static function get_cache_signature( $cache_file_name ) {
537
+
538
+ $cache_signature = sprintf(
539
+ '<!-- %s @ %s (%s) -->',
540
+ 'Cache Enabler by KeyCDN',
541
+ self::get_current_time(),
542
+ $cache_file_name
543
+ );
544
 
545
+ return $cache_signature;
546
  }
547
 
548
 
549
  /**
550
+ * get cache size from disk
551
  *
552
  * @since 1.0.0
553
+ * @change 1.7.0
554
+ *
555
+ * @param string $dir directory path to scan recursively
556
+ * @return integer $cache_size cache size in bytes
557
  */
558
 
559
+ public static function get_cache_size( $dir = null ) {
560
 
561
+ $cache_size = 0;
 
562
 
563
+ // get directory objects if provided directory exists
564
+ if ( is_dir( $dir ) ) {
565
+ $dir_objects = self::get_dir_objects( $dir );
566
+ // get site objects otherwise
 
 
567
  } else {
568
+ $dir_objects = self::get_site_objects( home_url() );
 
 
569
  }
570
 
571
+ // check if directory is empty
572
+ if ( empty( $dir_objects ) ) {
573
+ return $cache_size;
 
574
  }
575
 
576
+ foreach ( $dir_objects as $dir_object ) {
577
+ // get full path
578
+ $dir_object = trailingslashit( ( $dir ) ? $dir : ( self::$cache_dir . '/' . parse_url( home_url(), PHP_URL_HOST ) . parse_url( home_url(), PHP_URL_PATH ) ) ) . $dir_object;
 
 
 
 
 
 
579
 
580
+ if ( is_dir( $dir_object ) ) {
581
+ $cache_size += self::get_cache_size( $dir_object );
582
+ } elseif ( is_file( $dir_object ) ) {
583
+ $cache_size += filesize( $dir_object );
584
+ }
585
  }
586
 
587
+ return $cache_size;
 
588
  }
589
 
590
 
614
  * get settings file name
615
  *
616
  * @since 1.5.5
617
+ * @change 1.7.0
618
  *
619
  * @param boolean $fallback whether or not fallback settings file name should be returned
620
  * @param boolean $skip_blog_path whether or not blog path should be included in settings file name
643
  $settings_file_regex = '/\.php$/';
644
 
645
  if ( is_multisite() ) {
646
+ $settings_file_regex = '/^' . strtolower( Cache_Enabler_Engine::$request_headers['Host'] );
647
  $settings_file_regex = str_replace( '.', '\.', $settings_file_regex );
648
 
649
  // subdirectory network
650
  if ( defined( 'SUBDOMAIN_INSTALL' ) && ! SUBDOMAIN_INSTALL && ! $skip_blog_path ) {
651
+ $url_path = trim( parse_url( $_SERVER['REQUEST_URI'], PHP_URL_PATH ), '/' );
 
652
 
653
  if ( ! empty( $url_path ) ) {
654
  $url_path_regex = str_replace( '/', '|', $url_path );
670
  $settings_file_name = self::get_settings_file_name( $fallback, $skip_blog_path );
671
  }
672
  } else {
673
+ $settings_file_name = strtolower( Cache_Enabler_Engine::$request_headers['Host'] );
674
 
675
  // subdirectory network
676
  if ( is_multisite() && defined( 'SUBDOMAIN_INSTALL' ) && ! SUBDOMAIN_INSTALL && ! $skip_blog_path ) {
748
  * @since 1.4.7
749
  * @change 1.6.0
750
  *
751
+ * @param string $dir directory path to scan
752
  * @return array $dir_objects directory objects
753
  */
754
 
770
  * get site file system objects
771
  *
772
  * @since 1.6.0
773
+ * @change 1.7.0
774
  *
775
  * @param string $site_url site URL
776
  * @return array $site_objects site objects
781
  $site_objects = array();
782
 
783
  // get directory
784
+ $dir = self::get_cache_file_dir( $site_url );
785
 
786
  // check if directory exists
787
  if ( ! is_dir( $dir ) ) {
797
  $blog_paths = Cache_Enabler::get_blog_paths();
798
 
799
  // check if main site in subdirectory network
800
+ if ( ! in_array( $blog_path, $blog_paths, true ) ) {
801
  foreach ( $site_objects as $key => $site_object ) {
802
  // delete site object if it does not belong to main site
803
+ if ( in_array( '/' . $site_object . '/', $blog_paths, true ) ) {
804
  unset( $site_objects[ $key ] );
805
  }
806
  }
811
  }
812
 
813
 
814
+ /**
815
+ * get current time
816
+ *
817
+ * @since 1.7.0
818
+ * @change 1.7.0
819
+ *
820
+ * @return string $current_time current time in HTTP-date format
821
+ */
822
+
823
+ private static function get_current_time() {
824
+
825
+ $current_time = current_time( 'D, d M Y H:i:s', true ) . ' GMT';
826
+
827
+ return $current_time;
828
+ }
829
+
830
+
831
+ /**
832
+ * get image path
833
+ *
834
+ * @since 1.4.8
835
+ * @change 1.7.0
836
+ *
837
+ * @param string $image_url full or relative URL with or without intrinsic width or density descriptor
838
+ * @return string $image_path file path to image
839
+ */
840
+
841
+ private static function get_image_path( $image_url ) {
842
+
843
+ // in case image has intrinsic width or density descriptor
844
+ $image_parts = explode( ' ', $image_url );
845
+ $image_url = $image_parts[0];
846
+
847
+ // in case installation is in a subdirectory
848
+ $image_url_path = ltrim( parse_url( $image_url, PHP_URL_PATH ), '/' );
849
+ $installation_dir = ltrim( parse_url( site_url( '/' ), PHP_URL_PATH ), '/' );
850
+ $image_path = str_replace( $installation_dir, '', ABSPATH ) . $image_url_path;
851
+
852
+ return $image_path;
853
+ }
854
+
855
+
856
+ /**
857
+ * get current WP Filesystem instance
858
+ *
859
+ * @since 1.7.0
860
+ * @change 1.7.0
861
+ *
862
+ * @throws \RuntimeException if filesystem could not be initialized
863
+ * @return WP_Filesystem_Base $wp_filesystem filesystem instance
864
+ */
865
+
866
+ public static function get_filesystem() {
867
+
868
+ global $wp_filesystem;
869
+
870
+ // check if we already have a filesystem instance
871
+ if ( $wp_filesystem instanceof WP_Filesystem_Base ) {
872
+ return $wp_filesystem;
873
+ }
874
+
875
+ // try initializing filesystem instance and cache the result
876
+ try {
877
+ require_once ABSPATH . 'wp-admin/includes/file.php';
878
+
879
+ $filesystem = WP_Filesystem();
880
+
881
+ if ( $filesystem === null ) {
882
+ throw new \RuntimeException( 'The provided filesystem method is unavailable.' );
883
+ }
884
+
885
+ if ( $filesystem === false ) {
886
+ if ( is_wp_error( $wp_filesystem->errors ) && $wp_filesystem->errors->has_errors() ) {
887
+ throw new \RuntimeException(
888
+ $wp_filesystem->get_error_message,
889
+ ( is_numeric( $wp_error->get_error_code() ) ) ? (int) $wp_error->get_error_code() : 0
890
+ );
891
+ }
892
+
893
+ throw new \RuntimeException( 'Unspecified failure.' );
894
+ }
895
+
896
+ if ( ! is_object( $wp_filesystem ) || ! $wp_filesystem instanceof WP_Filesystem_Base ) {
897
+ throw new \RuntimeException( '$wp_filesystem is not an instance of WP_Filesystem_Base.' );
898
+ }
899
+ } catch ( \Exception $e ) {
900
+ throw new \RuntimeException(
901
+ sprintf( 'There was an error initializing the WP_Filesystem class: %1$s', $e->getMessage() ),
902
+ $e->getCode(),
903
+ $e
904
+ );
905
+ }
906
+
907
+ return $wp_filesystem;
908
+ }
909
+
910
+
911
+ /**
912
+ * makes directory recursively based on directory path
913
+ *
914
+ * @since 1.7.0
915
+ * @change 1.7.0
916
+ *
917
+ * @param string $dir directory path to create
918
+ * @return boolean true if the directory either already exists or was created and has the correct permissions, false otherwise
919
+ */
920
+
921
+ private static function mkdir_p( $dir ) {
922
+
923
+ $parent_dir = dirname( $dir );
924
+ $fs = self::get_filesystem();
925
+
926
+ // check if directory and its parent have 755 permissions
927
+ if ( $fs->is_dir( $dir ) && $fs->getchmod( $dir ) === '755' && $fs->getchmod( $parent_dir ) === '755' ) {
928
+ return true;
929
+ }
930
+
931
+ // create any directories that do not exist yet
932
+ if ( ! wp_mkdir_p( $dir ) ) {
933
+ return false;
934
+ }
935
+
936
+ // check parent directory permissions
937
+ if ( $fs->getchmod( $parent_dir ) !== '755' ) {
938
+ return $fs->chmod( $parent_dir, 0755, true );
939
+ }
940
+
941
+ // check directory permissions
942
+ if ( $fs->getchmod( $dir ) !== '755' ) {
943
+ return $fs->chmod( $dir, 0755 );
944
+ }
945
+
946
+ return true;
947
+ }
948
+
949
+
950
  /**
951
  * set or unset WP_CACHE constant in wp-config.php
952
  *
953
  * @since 1.1.1
954
+ * @change 1.7.0
955
  *
956
  * @param boolean $set true to set WP_CACHE constant, false to unset
957
  */
965
  } elseif ( @file_exists( dirname( ABSPATH ) . '/wp-config.php' ) && ! @file_exists( dirname( ABSPATH ) . '/wp-settings.php' ) ) {
966
  // config file resides one level above ABSPATH but is not part of another installation
967
  $wp_config_file = dirname( ABSPATH ) . '/wp-config.php';
968
+ } else {
969
+ $wp_config_file = false;
970
  }
971
 
972
  // check if config file can be written to
973
+ if ( ! $wp_config_file || ! is_writable( $wp_config_file ) ) {
974
  return;
975
  }
976
 
1002
  }
1003
 
1004
  // update config file
1005
+ file_put_contents( $wp_config_file, $wp_config_file_contents, LOCK_EX );
1006
  }
1007
 
1008
 
1009
  /**
1010
+ * convert page contents
1011
  *
1012
+ * @since 1.7.0
1013
+ * @change 1.7.0
1014
  *
1015
+ * @param string $page_contents contents of a page from the output buffer
1016
+ * @return string $converted_page_contents converted contents of a page from the output buffer
1017
  */
1018
 
1019
+ private static function converter( $page_contents ) {
1020
 
1021
+ // attributes to convert during WebP conversion hook
1022
+ $attributes = (array) apply_filters( 'cache_enabler_convert_webp_attributes', array( 'src', 'srcset', 'data-[^=]+' ) );
 
1023
 
1024
+ // stringify
1025
+ $attributes_regex = implode( '|', $attributes );
 
 
1026
 
1027
+ // magic regex rule
1028
+ $image_urls_regex = '#(?:(?:(' . $attributes_regex . ')\s*=|(url)\()\s*[\'\"]?\s*)\K(?:[^\?\"\'\s>]+)(?:\.jpe?g|\.png)(?:\s\d+[wx][^\"\'>]*)?(?=\/?[\"\'\s\)>])(?=[^<{]*(?:\)[^<{]*\}|>))#i';
1029
+
1030
+ // ignore query strings during WebP conversion hook
1031
+ if ( ! apply_filters( 'cache_enabler_convert_webp_ignore_query_strings', true ) ) {
1032
+ $image_urls_regex = '#(?:(?:(' . $attributes_regex . ')\s*=|(url)\()\s*[\'\"]?\s*)\K(?:[^\"\'\s>]+)(?:\.jpe?g|\.png)(?:\s\d+[wx][^\"\'>]*)?(?=\/?[\?\"\'\s\)>])(?=[^<{]*(?:\)[^<{]*\}|>))#i';
1033
+ }
1034
+
1035
+ // page contents after WebP conversion hook
1036
+ $converted_page_contents = apply_filters( 'cache_enabler_page_contents_after_webp_conversion', preg_replace_callback( $image_urls_regex, 'self::convert_webp', $page_contents ) );
1037
+
1038
+ // deprecated page contents after WebP conversion hook
1039
+ $converted_page_contents = apply_filters_deprecated( 'cache_enabler_disk_webp_converted_data', array( $converted_page_contents ), '1.6.0', 'cache_enabler_page_contents_after_webp_conversion' );
1040
+
1041
+ return $converted_page_contents;
1042
  }
1043
 
1044
 
1065
  foreach ( $image_urls as &$image_url ) {
1066
  $image_url = trim( $image_url, ' ' );
1067
  $image_url_webp = preg_replace( $image_extension_regex, '$1.webp', $image_url ); // append .webp extension
1068
+ $image_path_webp = self::get_image_path( $image_url_webp );
1069
 
1070
  // check if WebP image exists
1071
  if ( is_file( $image_path_webp ) ) {
1072
  $image_url = $image_url_webp;
1073
  } else {
1074
  $image_url_webp = preg_replace( $image_extension_regex, '', $image_url_webp ); // remove default extension
1075
+ $image_path_webp = self::get_image_path( $image_url_webp );
1076
 
1077
  // check if WebP image exists
1078
  if ( is_file( $image_path_webp ) ) {
1092
  * minify HTML
1093
  *
1094
  * @since 1.0.0
1095
+ * @change 1.7.0
1096
  *
1097
  * @param string $page_contents contents of a page from the output buffer
1098
+ * @return string $page_contents|$minified_html minified page contents if applicable, unchanged otherwise
1099
  */
1100
 
1101
  private static function minify_html( $page_contents ) {
1102
 
 
 
 
 
 
1103
  // HTML character limit
1104
+ if ( strlen( $page_contents ) > 700000 ) {
1105
  return $page_contents;
1106
  }
1107
 
1130
  // if setting selected remove CSS and JavaScript comments
1131
  if ( Cache_Enabler_Engine::$settings['minify_inline_css_js'] ) {
1132
  $minified_html = preg_replace(
1133
+ '#/\*(?!!)[\s\S]*?\*/|(?:^[ \t]*)//.*$|((?<!\()[ \t>;,{}[\]])//[^;\n]*$#m',
1134
  '$1',
1135
  $minified_html
1136
  );
1183
  * delete settings file
1184
  *
1185
  * @since 1.5.0
1186
+ * @change 1.7.0
1187
  */
1188
 
1189
  private static function delete_settings_file() {
1196
 
1197
  // delete settings directory if empty
1198
  @rmdir( self::$settings_dir );
1199
+
1200
+ // delete parent directory of settings directory if empty
1201
+ @rmdir( dirname( self::$settings_dir ) );
1202
  }
1203
 
1204
 
1215
  wp_die( 'URL is empty.' );
1216
  }
1217
 
1218
+ self::clear_dir( self::get_cache_file_dir( $url ) );
1219
+ }
1220
+
1221
+
1222
+ /**
1223
+ * get cache size
1224
+ *
1225
+ * @since 1.0.0
1226
+ * @deprecated 1.7.0
1227
+ */
1228
+
1229
+ public static function cache_size( $dir = null ) {
1230
+
1231
+ return self::get_cache_size( $dir );
1232
  }
1233
  }
inc/cache_enabler_engine.class.php CHANGED
@@ -29,6 +29,7 @@ final class Cache_Enabler_Engine {
29
  return self::$started;
30
  }
31
 
 
32
  /**
33
  * engine status
34
  *
@@ -41,6 +42,18 @@ final class Cache_Enabler_Engine {
41
  public static $started = false;
42
 
43
 
 
 
 
 
 
 
 
 
 
 
 
 
44
  /**
45
  * engine settings from disk or database
46
  *
@@ -57,11 +70,14 @@ final class Cache_Enabler_Engine {
57
  * constructor
58
  *
59
  * @since 1.5.0
60
- * @change 1.6.0
61
  */
62
 
63
  public function __construct() {
64
 
 
 
 
65
  // get settings from disk if directory index file
66
  if ( self::is_index() ) {
67
  self::$settings = Cache_Enabler_Disk::get_settings();
@@ -84,7 +100,7 @@ final class Cache_Enabler_Engine {
84
  * check if engine should start
85
  *
86
  * @since 1.5.2
87
- * @change 1.5.4
88
  *
89
  * @return boolean true if engine should start, false otherwise
90
  */
@@ -111,11 +127,6 @@ final class Cache_Enabler_Engine {
111
  return false;
112
  }
113
 
114
- // check if Host request header is empty
115
- if ( empty( $_SERVER['HTTP_HOST'] ) ) {
116
- return false;
117
- }
118
-
119
  // check request URI
120
  if ( str_replace( array( '.ico', '.txt', '.xml', '.xsl' ), '', $_SERVER['REQUEST_URI'] ) !== $_SERVER['REQUEST_URI'] ) {
121
  return false;
@@ -142,28 +153,49 @@ final class Cache_Enabler_Engine {
142
  * end output buffering and cache page if applicable
143
  *
144
  * @since 1.0.0
145
- * @change 1.6.0
146
  *
147
- * @param string $page_contents contents of a page from the output buffer
148
- * @param integer $phase bitmask of PHP_OUTPUT_HANDLER_* constants
149
- * @return string $page_contents contents of a page from the output buffer
150
  */
151
 
152
- private static function end_buffering( $page_contents, $phase ) {
153
 
154
  if ( $phase & PHP_OUTPUT_HANDLER_FINAL || $phase & PHP_OUTPUT_HANDLER_END ) {
155
- if ( ! self::is_cacheable( $page_contents ) || self::bypass_cache() ) {
156
- return $page_contents;
157
  }
 
158
 
159
- $page_contents = apply_filters( 'cache_enabler_page_contents_before_store', $page_contents );
 
160
 
161
- $page_contents = apply_filters_deprecated( 'cache_enabler_before_store', array( $page_contents ), '1.6.0', 'cache_enabler_page_contents_before_store' );
162
 
163
- Cache_Enabler_Disk::cache_page( $page_contents );
 
 
 
 
 
 
 
164
 
165
- return $page_contents;
166
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
167
  }
168
 
169
 
@@ -187,20 +219,20 @@ final class Cache_Enabler_Engine {
187
 
188
 
189
  /**
190
- * check if page can be cached
191
  *
192
  * @since 1.5.0
193
- * @change 1.5.0
194
  *
195
- * @param string $page_contents contents of a page from the output buffer
196
- * @return boolean true if page contents are cacheable, false otherwise
197
  */
198
 
199
- private static function is_cacheable( $page_contents ) {
200
 
201
- $has_html_tag = ( stripos( $page_contents, '<html' ) !== false );
202
- $has_html5_doctype = preg_match( '/^<!DOCTYPE.+html>/i', ltrim( $page_contents ) );
203
- $has_xsl_stylesheet = ( stripos( $page_contents, '<xsl:stylesheet' ) !== false || stripos( $page_contents, '<?xml-stylesheet' ) !== false );
204
 
205
  if ( $has_html_tag && $has_html5_doctype && ! $has_xsl_stylesheet ) {
206
  return true;
@@ -248,7 +280,7 @@ final class Cache_Enabler_Engine {
248
  * check if page is excluded from cache
249
  *
250
  * @since 1.5.0
251
- * @change 1.5.3
252
  *
253
  * @return boolean true if page is excluded from the cache, false otherwise
254
  */
@@ -257,7 +289,10 @@ final class Cache_Enabler_Engine {
257
 
258
  // if post ID excluded
259
  if ( ! empty( self::$settings['excluded_post_ids'] ) && function_exists( 'is_singular' ) && is_singular() ) {
260
- if ( in_array( get_queried_object_id(), (array) explode( ',', self::$settings['excluded_post_ids'] ) ) ) {
 
 
 
261
  return true;
262
  }
263
  }
@@ -296,7 +331,7 @@ final class Cache_Enabler_Engine {
296
  $cookies_regex = '/^(wp-postpass|wordpress_logged_in|comment_author)_/';
297
  }
298
  // bypass cache if an excluded cookie is found
299
- foreach ( $_COOKIE as $key => $value) {
300
  if ( preg_match( $cookies_regex, $key ) ) {
301
  return true;
302
  }
@@ -326,26 +361,11 @@ final class Cache_Enabler_Engine {
326
  }
327
 
328
 
329
- /**
330
- * check if mobile template
331
- *
332
- * @since 1.0.0
333
- * @change 1.0.0
334
- *
335
- * @return boolean true if mobile template, false otherwise
336
- */
337
-
338
- private static function is_mobile() {
339
-
340
- return ( strpos( TEMPLATEPATH, 'wptouch' ) || strpos( TEMPLATEPATH, 'carrington' ) || strpos( TEMPLATEPATH, 'jetpack' ) || strpos( TEMPLATEPATH, 'handheld' ) );
341
- }
342
-
343
-
344
  /**
345
  * check if cache should be bypassed
346
  *
347
  * @since 1.0.0
348
- * @change 1.6.0
349
  *
350
  * @return boolean true if cache should be bypassed, false otherwise
351
  */
@@ -384,7 +404,7 @@ final class Cache_Enabler_Engine {
384
 
385
  // check conditional tags when output buffering has ended
386
  if ( class_exists( 'WP' ) ) {
387
- if ( is_admin() || self::is_search() || is_feed() || is_trackback() || is_robots() || is_preview() || post_password_required() || self::is_mobile() ) {
388
  return true;
389
  }
390
  }
@@ -397,15 +417,32 @@ final class Cache_Enabler_Engine {
397
  * deliver cache
398
  *
399
  * @since 1.5.0
400
- * @change 1.6.0
401
  *
402
  * @return boolean false if cached page was not delivered
403
  */
404
 
405
  public static function deliver_cache() {
406
 
407
- if ( Cache_Enabler_Disk::cache_exists() && ! Cache_Enabler_Disk::cache_expired() && ! self::bypass_cache() ) {
408
- readfile( Cache_Enabler_Disk::get_cache() );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
409
  exit;
410
  }
411
 
29
  return self::$started;
30
  }
31
 
32
+
33
  /**
34
  * engine status
35
  *
42
  public static $started = false;
43
 
44
 
45
+ /**
46
+ * specific HTTP request headers from current request
47
+ *
48
+ * @since 1.7.0
49
+ * @change 1.7.0
50
+ *
51
+ * @var array
52
+ */
53
+
54
+ public static $request_headers;
55
+
56
+
57
  /**
58
  * engine settings from disk or database
59
  *
70
  * constructor
71
  *
72
  * @since 1.5.0
73
+ * @change 1.7.0
74
  */
75
 
76
  public function __construct() {
77
 
78
+ // get request headers
79
+ self::$request_headers = self::get_request_headers();
80
+
81
  // get settings from disk if directory index file
82
  if ( self::is_index() ) {
83
  self::$settings = Cache_Enabler_Disk::get_settings();
100
  * check if engine should start
101
  *
102
  * @since 1.5.2
103
+ * @change 1.7.0
104
  *
105
  * @return boolean true if engine should start, false otherwise
106
  */
127
  return false;
128
  }
129
 
 
 
 
 
 
130
  // check request URI
131
  if ( str_replace( array( '.ico', '.txt', '.xml', '.xsl' ), '', $_SERVER['REQUEST_URI'] ) !== $_SERVER['REQUEST_URI'] ) {
132
  return false;
153
  * end output buffering and cache page if applicable
154
  *
155
  * @since 1.0.0
156
+ * @change 1.7.0
157
  *
158
+ * @param string $contents contents from the output buffer
159
+ * @param integer $phase bitmask of PHP_OUTPUT_HANDLER_* constants
160
+ * @return string $contents unchanged contents from the output buffer
161
  */
162
 
163
+ private static function end_buffering( $contents, $phase ) {
164
 
165
  if ( $phase & PHP_OUTPUT_HANDLER_FINAL || $phase & PHP_OUTPUT_HANDLER_END ) {
166
+ if ( self::is_cacheable( $contents ) && ! self::bypass_cache() ) {
167
+ Cache_Enabler_Disk::cache_page( $contents );
168
  }
169
+ }
170
 
171
+ return $contents;
172
+ }
173
 
 
174
 
175
+ /**
176
+ * get specific HTTP request headers from current request
177
+ *
178
+ * @since 1.7.0
179
+ * @change 1.7.0
180
+ *
181
+ * @return array $request_headers specific HTTP request headers from current request
182
+ */
183
 
184
+ private static function get_request_headers() {
185
+
186
+ $request_headers = ( function_exists( 'apache_request_headers' ) ) ? apache_request_headers() : array();
187
+
188
+ $request_headers = array(
189
+ 'Accept' => ( isset( $request_headers['Accept'] ) ) ? $request_headers['Accept'] : ( ( isset( $_SERVER[ 'HTTP_ACCEPT' ] ) ) ? $_SERVER[ 'HTTP_ACCEPT' ] : '' ),
190
+ 'Accept-Encoding' => ( isset( $request_headers['Accept-Encoding'] ) ) ? $request_headers['Accept-Encoding'] : ( ( isset( $_SERVER[ 'HTTP_ACCEPT_ENCODING' ] ) ) ? $_SERVER[ 'HTTP_ACCEPT_ENCODING' ] : '' ),
191
+ 'Host' => ( isset( $request_headers['Host'] ) ) ? $request_headers['Host'] : ( ( isset( $_SERVER[ 'HTTP_HOST' ] ) ) ? $_SERVER[ 'HTTP_HOST' ] : '' ),
192
+ 'If-Modified-Since' => ( isset( $request_headers['If-Modified-Since'] ) ) ? $request_headers['If-Modified-Since'] : ( ( isset( $_SERVER[ 'HTTP_IF_MODIFIED_SINCE' ] ) ) ? $_SERVER[ 'HTTP_IF_MODIFIED_SINCE' ] : '' ),
193
+ 'User-Agent' => ( isset( $request_headers['User-Agent'] ) ) ? $request_headers['User-Agent'] : ( ( isset( $_SERVER[ 'HTTP_USER_AGENT' ] ) ) ? $_SERVER[ 'HTTP_USER_AGENT' ] : '' ),
194
+ 'X-Forwarded-Proto' => ( isset( $request_headers['X-Forwarded-Proto'] ) ) ? $request_headers['X-Forwarded-Proto'] : ( ( isset( $_SERVER[ 'HTTP_X_FORWARDED_PROTO' ] ) ) ? $_SERVER[ 'HTTP_X_FORWARDED_PROTO' ] : '' ),
195
+ 'X-Forwarded-Scheme' => ( isset( $request_headers['X-Forwarded-Scheme'] ) ) ? $request_headers['X-Forwarded-Scheme'] : ( ( isset( $_SERVER[ 'HTTP_X_FORWARDED_SCHEME' ] ) ) ? $_SERVER[ 'HTTP_X_FORWARDED_SCHEME' ] : '' ),
196
+ );
197
+
198
+ return $request_headers;
199
  }
200
 
201
 
219
 
220
 
221
  /**
222
+ * check if contents from the output buffer can be cached
223
  *
224
  * @since 1.5.0
225
+ * @change 1.7.0
226
  *
227
+ * @param string $contents contents from the output buffer
228
+ * @return boolean true if contents from the output buffer are cacheable, false otherwise
229
  */
230
 
231
+ private static function is_cacheable( $contents ) {
232
 
233
+ $has_html_tag = ( stripos( $contents, '<html' ) !== false );
234
+ $has_html5_doctype = preg_match( '/^<!DOCTYPE.+html>/i', ltrim( $contents ) );
235
+ $has_xsl_stylesheet = ( stripos( $contents, '<xsl:stylesheet' ) !== false || stripos( $contents, '<?xml-stylesheet' ) !== false );
236
 
237
  if ( $has_html_tag && $has_html5_doctype && ! $has_xsl_stylesheet ) {
238
  return true;
280
  * check if page is excluded from cache
281
  *
282
  * @since 1.5.0
283
+ * @change 1.7.0
284
  *
285
  * @return boolean true if page is excluded from the cache, false otherwise
286
  */
289
 
290
  // if post ID excluded
291
  if ( ! empty( self::$settings['excluded_post_ids'] ) && function_exists( 'is_singular' ) && is_singular() ) {
292
+ $post_id = get_queried_object_id();
293
+ $excluded_post_ids = array_map( 'absint', (array) explode( ',', self::$settings['excluded_post_ids'] ) );
294
+
295
+ if ( in_array( $post_id, $excluded_post_ids, true ) ) {
296
  return true;
297
  }
298
  }
331
  $cookies_regex = '/^(wp-postpass|wordpress_logged_in|comment_author)_/';
332
  }
333
  // bypass cache if an excluded cookie is found
334
+ foreach ( $_COOKIE as $key => $value ) {
335
  if ( preg_match( $cookies_regex, $key ) ) {
336
  return true;
337
  }
361
  }
362
 
363
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
364
  /**
365
  * check if cache should be bypassed
366
  *
367
  * @since 1.0.0
368
+ * @change 1.7.0
369
  *
370
  * @return boolean true if cache should be bypassed, false otherwise
371
  */
404
 
405
  // check conditional tags when output buffering has ended
406
  if ( class_exists( 'WP' ) ) {
407
+ if ( is_admin() || self::is_search() || is_feed() || is_trackback() || is_robots() || is_preview() || post_password_required() ) {
408
  return true;
409
  }
410
  }
417
  * deliver cache
418
  *
419
  * @since 1.5.0
420
+ * @change 1.7.0
421
  *
422
  * @return boolean false if cached page was not delivered
423
  */
424
 
425
  public static function deliver_cache() {
426
 
427
+ $cache_file = Cache_Enabler_Disk::get_cache_file();
428
+
429
+ if ( Cache_Enabler_Disk::cache_exists( $cache_file ) && ! Cache_Enabler_Disk::cache_expired( $cache_file ) && ! self::bypass_cache() ) {
430
+ // set X-Cache-Handler response header
431
+ header( 'X-Cache-Handler: cache-enabler-engine' );
432
+
433
+ // return 304 Not Modified with empty body if applicable
434
+ if ( strtotime( self::$request_headers['If-Modified-Since'] >= filemtime( $cache_file ) ) ) {
435
+ header( $_SERVER['SERVER_PROTOCOL'] . ' 304 Not Modified', true, 304 );
436
+ exit;
437
+ }
438
+
439
+ // set Content-Encoding response header if applicable
440
+ if ( strpos( basename( $cache_file ), 'gz' ) !== false ) {
441
+ header( 'Content-Encoding: gzip' );
442
+ }
443
+
444
+ // deliver cache
445
+ readfile( $cache_file );
446
  exit;
447
  }
448
 
readme.txt CHANGED
@@ -2,7 +2,7 @@
2
  Contributors: keycdn
3
  Tags: cache, caching, performance, gzip, webp, speed
4
  Requires at least: 5.1
5
- Tested up to: 5.6
6
  Requires PHP: 5.6
7
  Stable tag: trunk
8
  License: GPLv2 or later
@@ -13,7 +13,7 @@ A lightweight caching plugin for WordPress that makes your website faster by gen
13
 
14
 
15
  == Description ==
16
- Cache Enabler is a simple, yet powerful WordPress caching plugin that is easy to use, needs minimal configuration, and best of all helps improve site performance for a faster load time. It creates static HTML files and stores them on the server's disk. This allows the web server to deliver the static HTML files avoiding resource intensive backend processes from the WordPress core, plugins, and database lookups.
17
 
18
 
19
  = Features =
@@ -25,15 +25,15 @@ Cache Enabler is a simple, yet powerful WordPress caching plugin that is easy to
25
  * Cache size display in the WordPress dashboard
26
  * Minification of HTML excluding or including inline CSS and JavaScript
27
  * WordPress multisite network support
28
- * WebP support (convert images to WebP with [Optimus](https://optimus.io "Optimus"))
29
  * Gzip pre-compression support
30
  * Custom post type support
31
  * `304 Not Modified` support
32
- * Works perfectly with [Autoptimize](https://wordpress.org/plugins/autoptimize/) and the majority of third party plugins
33
 
34
 
35
  = How does the caching work? =
36
- Cache Enabler captures page contents and saves it as a static HTML file on the server’s disk. Converting inline image URLs to WebP as a separate static HTML file and pre-compressing both static HTML files with Gzip is possible. The accepted static HTML file is then delivered to users without any database lookups or on the fly compression for a faster site load time.
37
 
38
 
39
  = Documentation =
@@ -46,7 +46,7 @@ Cache Enabler captures page contents and saves it as a static HTML file on the s
46
 
47
 
48
  = Want to help? =
49
- * Want to file a bug, contribute some code, or improve translations? Excellent! Check out our [GitHub issues](https://github.com/keycdn/cache-enabler) or [translations](https://translate.wordpress.org/projects/wp-plugins/cache-enabler/).
50
 
51
 
52
  = Maintainer =
@@ -55,6 +55,19 @@ Cache Enabler captures page contents and saves it as a static HTML file on the s
55
 
56
  == Changelog ==
57
 
 
 
 
 
 
 
 
 
 
 
 
 
 
58
  = 1.6.2 =
59
  * Fix removing CSS and JavaScript comments during HTML minification (#188)
60
 
2
  Contributors: keycdn
3
  Tags: cache, caching, performance, gzip, webp, speed
4
  Requires at least: 5.1
5
+ Tested up to: 5.7
6
  Requires PHP: 5.6
7
  Stable tag: trunk
8
  License: GPLv2 or later
13
 
14
 
15
  == Description ==
16
+ Cache Enabler is a simple, yet powerful WordPress caching plugin that is easy to use, needs minimal configuration, and best of all helps improve site performance for a faster load time. It creates static HTML files and stores them on the server's disk. This allows the web server to deliver the static HTML files avoiding resource intensive backend processes from the WordPress core, plugins, and database.
17
 
18
 
19
  = Features =
25
  * Cache size display in the WordPress dashboard
26
  * Minification of HTML excluding or including inline CSS and JavaScript
27
  * WordPress multisite network support
28
+ * WebP support (convert images to WebP with [Optimus](https://optimus.io))
29
  * Gzip pre-compression support
30
  * Custom post type support
31
  * `304 Not Modified` support
32
+ * Works perfectly with [Autoptimize](https://wordpress.org/plugins/autoptimize/) and the majority of other third party plugins
33
 
34
 
35
  = How does the caching work? =
36
+ Cache Enabler captures page contents and saves it as a static HTML file on the server’s disk. Converting inline image URLs to WebP as a separate static HTML file and pre-compressing both static HTML files with Gzip is possible. The accepted static HTML file is then delivered to users without any database queries or on the fly compression for a faster site load time.
37
 
38
 
39
  = Documentation =
46
 
47
 
48
  = Want to help? =
49
+ * Want to file a bug, contribute some code, or improve translations? Excellent! Check out our [GitHub issues](https://github.com/keycdn/cache-enabler/issues) or [translations](https://translate.wordpress.org/projects/wp-plugins/cache-enabler/).
50
 
51
 
52
  = Maintainer =
55
 
56
  == Changelog ==
57
 
58
+ = 1.7.0 =
59
+ * Update cache clearing for theme, plugin, post, and upgrade actions (#215 and #216)
60
+ * Update cache handling with cache keys (#211)
61
+ * Update settings file deletion handling (#205)
62
+ * Update output buffer handling (#203)
63
+ * Update removing CSS and JavaScript comments during HTML minification (#202)
64
+ * Update WebP URL conversion for installations in a subdirectory (#198)
65
+ * Add `CACHE_ENABLER_DIR` as definable plugin directory constant (#195 @stevegrunwell)
66
+ * Add explicit directory access permissions (#194 @stevegrunwell)
67
+ * Add exclusive lock when writing files (#191 @nawawi)
68
+ * Fix clear cache request handling (#212)
69
+ * Fix getting `wp-config.php` (#210 @stevegrunwell)
70
+
71
  = 1.6.2 =
72
  * Fix removing CSS and JavaScript comments during HTML minification (#188)
73