Cache Enabler – WordPress Cache - Version 1.2.0

Version Description

  • Added advanced cache feature
  • Clear cache if reply to a comment in WP admin
Download this release

Release Info

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

Code changes from version 1.1.0 to 1.2.0

advanced-cache.php ADDED
@@ -0,0 +1,94 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // check if request method is GET
4
+ if ( ! isset( $_SERVER['REQUEST_METHOD'] ) || $_SERVER['REQUEST_METHOD'] != 'GET' ) {
5
+ return false;
6
+ }
7
+
8
+ // check if request with query strings
9
+ if ( ! empty($_GET) && ! isset( $_GET['utm_source'], $_GET['utm_medium'], $_GET['utm_campaign'] ) ) {
10
+ return false;
11
+ }
12
+
13
+ // check cookie values
14
+ if ( !empty($_COOKIE) ) {
15
+ foreach ( $_COOKIE as $k => $v) {
16
+ if ( preg_match('/^(wp-postpass|wordpress_logged_in|comment_author)_/', $k) ) {
17
+ return false;
18
+ }
19
+ }
20
+ }
21
+
22
+ // base path
23
+ $path = sprintf(
24
+ '%s%s%s%s',
25
+ WP_CONTENT_DIR . '/cache/cache-enabler',
26
+ DIRECTORY_SEPARATOR,
27
+ parse_url(
28
+ 'http://' .strtolower($_SERVER['HTTP_HOST']),
29
+ PHP_URL_HOST
30
+ ),
31
+ parse_url(
32
+ $_SERVER['REQUEST_URI'],
33
+ PHP_URL_PATH
34
+ )
35
+ );
36
+
37
+ // add trailing slash
38
+ $path = rtrim( $path, '/\\' ) . '/';
39
+
40
+ // path to cached variants
41
+ $path_html = $path . 'index.html';
42
+ $path_gzip = $path . 'index.html.gz';
43
+ $path_webp_html = $path . 'index-webp.html';
44
+ $path_webp_gzip = $path . 'index-webp.html.gz';
45
+
46
+ if ( is_readable( $path_html ) ) {
47
+
48
+ // set cache handler header
49
+ header('x-cache-handler: wp');
50
+
51
+ // get if-modified request headers
52
+ if ( function_exists( 'apache_request_headers' ) ) {
53
+ $headers = apache_request_headers();
54
+ $http_if_modified_since = ( isset( $headers[ 'If-Modified-Since' ] ) ) ? $headers[ 'If-Modified-Since' ] : '';
55
+ $http_accept = ( isset( $headers[ 'Accept' ] ) ) ? $headers[ 'Accept' ] : '';
56
+ $http_accept_encoding = ( isset( $headers[ 'Accept-Encoding' ] ) ) ? $headers[ 'Accept-Encoding' ] : '';
57
+ } else {
58
+ $http_if_modified_since = ( isset( $_SERVER[ 'HTTP_IF_MODIFIED_SINCE' ] ) ) ? $_SERVER[ 'HTTP_IF_MODIFIED_SINCE' ] : '';
59
+ $http_accept = ( isset( $_SERVER[ 'HTTP_ACCEPT' ] ) ) ? $_SERVER[ 'HTTP_ACCEPT' ] : '';
60
+ $http_accept_encoding = ( isset( $_SERVER[ 'HTTP_ACCEPT_ENCODING' ] ) ) ? $_SERVER[ 'HTTP_ACCEPT_ENCODING' ] : '';
61
+ }
62
+
63
+ // check modified since with cached file and return 304 if no difference
64
+ if ( $http_if_modified_since && ( strtotime( $http_if_modified_since ) == filemtime( $path_html ) ) ) {
65
+ header( $_SERVER['SERVER_PROTOCOL'] . ' 304 Not Modified', true, 304 );
66
+ exit;
67
+ }
68
+
69
+ // check webp and deliver gzip webp file if support
70
+ if ( $http_accept && ( strpos($http_accept, 'webp') !== false ) ) {
71
+ if ( is_readable( $path_webp_gzip ) ) {
72
+ header('Content-Encoding: gzip');
73
+ readfile( $path_webp_gzip );
74
+ exit;
75
+ } elseif ( is_readable( $path_webp_html ) ) {
76
+ readfile( $path_webp_html );
77
+ exit;
78
+ }
79
+ }
80
+
81
+ // check encoding and deliver gzip file if support
82
+ if ( $http_accept_encoding && ( strpos($http_accept_encoding, 'gzip') !== false ) && is_readable( $path_gzip ) ) {
83
+ header('Content-Encoding: gzip');
84
+ readfile( $path_gzip );
85
+ exit;
86
+ }
87
+
88
+ // deliver cached file (default)
89
+ readfile( $path_html );
90
+ exit;
91
+
92
+ } else {
93
+ return false;
94
+ }
cache-enabler.php CHANGED
@@ -6,12 +6,12 @@ Description: Simple and fast WordPress disk caching plugin.
6
  Author: KeyCDN
7
  Author URI: https://www.keycdn.com
8
  License: GPLv2 or later
9
- Version: 1.1.0
10
  */
11
 
12
  /*
13
- Copyright (C) 2015 KeyCDN
14
- Copyright (C) 2011-2015 Sergej Müller
15
 
16
  This program is free software; you can redistribute it and/or modify
17
  it under the terms of the GNU General Public License as published by
6
  Author: KeyCDN
7
  Author URI: https://www.keycdn.com
8
  License: GPLv2 or later
9
+ Version: 1.2.0
10
  */
11
 
12
  /*
13
+ Copyright (C) 2017 KeyCDN
14
+ Copyright (C) 2015 Sergej Müller
15
 
16
  This program is free software; you can redistribute it and/or modify
17
  it under the terms of the GNU General Public License as published by
inc/cache_enabler.class.php CHANGED
@@ -14,1768 +14,1880 @@ defined('ABSPATH') OR exit;
14
  final class Cache_Enabler {
15
 
16
 
17
- /**
18
- * plugin options
19
- *
20
- * @since 1.0.0
21
- * @var array
22
- */
23
-
24
- public static $options;
25
-
26
-
27
- /**
28
- * disk cache object
29
- *
30
- * @since 1.0.0
31
- * @var object
32
- */
33
-
34
- private static $disk;
35
-
36
-
37
- /**
38
- * minify default settings
39
- *
40
- * @since 1.0.0
41
- * @var integer
42
- */
43
-
44
- const MINIFY_DISABLED = 0;
45
- const MINIFY_HTML_ONLY = 1;
46
- const MINIFY_HTML_JS = 2;
47
-
48
-
49
- /**
50
- * constructor wrapper
51
- *
52
- * @since 1.0.0
53
- * @change 1.0.0
54
- */
55
-
56
- public static function instance()
57
- {
58
- new self();
59
- }
60
-
61
-
62
- /**
63
- * constructor
64
- *
65
- * @since 1.0.0
66
- * @change 1.0.7
67
- *
68
- * @param void
69
- * @return void
70
- */
71
-
72
- public function __construct()
73
- {
74
- // set default vars
75
- self::_set_default_vars();
76
-
77
- // register publish hook
78
- add_action(
79
- 'init',
80
- array(
81
- __CLASS__,
82
- 'register_publish_hooks'
83
- ),
84
- 99
85
- );
86
-
87
- // clear cache hooks
88
- add_action(
89
- 'ce_clear_post_cache',
90
- array(
91
- __CLASS__,
92
- 'clear_page_cache_by_post_id'
93
- )
94
- );
95
- add_action(
96
- 'ce_clear_cache',
97
- array(
98
- __CLASS__,
99
- 'clear_total_cache'
100
- )
101
- );
102
- add_action(
103
- '_core_updated_successfully',
104
- array(
105
- __CLASS__,
106
- 'clear_total_cache'
107
- )
108
- );
109
- add_action(
110
- 'switch_theme',
111
- array(
112
- __CLASS__,
113
- 'clear_total_cache'
114
- )
115
- );
116
- add_action(
117
- 'wp_trash_post',
118
- array(
119
- __CLASS__,
120
- 'clear_total_cache'
121
- )
122
- );
123
- add_action(
124
- 'autoptimize_action_cachepurged',
125
- array(
126
- __CLASS__,
127
- 'clear_total_cache'
128
- )
129
- );
130
 
131
  // add admin clear link
132
- add_action(
133
- 'admin_bar_menu',
134
- array(
135
- __CLASS__,
136
- 'add_admin_links'
137
- ),
138
- 90
139
- );
140
- add_action(
141
- 'init',
142
- array(
143
- __CLASS__,
144
- 'process_clear_request'
145
- )
146
- );
147
-
148
- // admin
149
- if ( is_admin() ) {
150
- add_action(
151
- 'wpmu_new_blog',
152
- array(
153
- __CLASS__,
154
- 'install_later'
155
- )
156
- );
157
- add_action(
158
- 'delete_blog',
159
- array(
160
- __CLASS__,
161
- 'uninstall_later'
162
- )
163
- );
164
-
165
- add_action(
166
- 'admin_init',
167
- array(
168
- __CLASS__,
169
- 'register_textdomain'
170
- )
171
- );
172
- add_action(
173
- 'admin_init',
174
- array(
175
- __CLASS__,
176
- 'register_settings'
177
- )
178
- );
179
-
180
- add_action(
181
- 'admin_menu',
182
- array(
183
- __CLASS__,
184
- 'add_settings_page'
185
- )
186
- );
187
- add_action(
188
- 'admin_enqueue_scripts',
189
- array(
190
- __CLASS__,
191
- 'add_admin_resources'
192
- )
193
- );
194
-
195
- add_action(
196
- 'transition_comment_status',
197
- array(
198
- __CLASS__,
199
- 'change_comment'
200
- ),
201
- 10,
202
- 3
203
- );
204
- add_action(
205
- 'edit_comment',
206
- array(
207
- __CLASS__,
208
- 'edit_comment'
209
- )
210
- );
211
-
212
- add_filter(
213
- 'dashboard_glance_items',
214
- array(
215
- __CLASS__,
216
- 'add_dashboard_count'
217
- )
218
- );
219
- add_action(
220
- 'post_submitbox_misc_actions',
221
- array(
222
- __CLASS__,
223
- 'add_clear_dropdown'
224
- )
225
- );
226
- add_filter(
227
- 'plugin_row_meta',
228
- array(
229
- __CLASS__,
230
- 'row_meta'
231
- ),
232
- 10,
233
- 2
234
- );
235
- add_filter(
236
- 'plugin_action_links_' .CE_BASE,
237
- array(
238
- __CLASS__,
239
- 'action_links'
240
- )
241
- );
242
-
243
- // warnings and notices
244
- add_action(
245
- 'admin_notices',
246
- array(
247
- __CLASS__,
248
- 'warning_is_permalink'
249
- )
250
- );
251
- add_action(
252
- 'admin_notices',
253
- array(
254
- __CLASS__,
255
- 'requirements_check'
256
- )
257
- );
258
-
259
- // caching
260
- } else {
261
- add_action(
262
- 'pre_comment_approved',
263
- array(
264
- __CLASS__,
265
- 'new_comment'
266
- ),
267
- 99,
268
- 2
269
- );
270
- add_action(
271
- 'template_redirect',
272
- array(
273
- __CLASS__,
274
- 'handle_cache'
275
- ),
276
- 0
277
- );
278
- }
279
- }
280
-
281
-
282
- /**
283
- * deactivation hook
284
- *
285
- * @since 1.0.0
286
- * @change 1.0.0
287
- */
288
-
289
- public static function on_deactivation() {
290
- self::clear_total_cache(true);
291
- }
292
-
293
-
294
- /**
295
- * activation hook
296
- *
297
- * @since 1.0.0
298
- * @change 1.0.0
299
- */
300
-
301
- public static function on_activation() {
302
-
303
- // multisite and network
304
- if ( is_multisite() && ! empty($_GET['networkwide']) ) {
305
- // blog ids
306
- $ids = self::_get_blog_ids();
307
-
308
- // switch to blog
309
- foreach ($ids as $id) {
310
- switch_to_blog($id);
311
- self::_install_backend();
312
- }
313
-
314
- // restore blog
315
- restore_current_blog();
316
-
317
- } else {
318
- self::_install_backend();
319
- }
320
- }
321
-
322
-
323
- /**
324
- * install on multisite setup
325
- *
326
- * @since 1.0.0
327
- * @change 1.0.0
328
- */
329
-
330
- public static function install_later($id) {
331
-
332
- // check if multisite setup
333
- if ( ! is_plugin_active_for_network(CE_BASE) ) {
334
- return;
335
- }
336
-
337
- // switch to blog
338
- switch_to_blog($id);
339
-
340
- // installation
341
- self::_install_backend();
342
-
343
- // restore
344
- restore_current_blog();
345
- }
346
-
347
-
348
- /**
349
- * installation options
350
- *
351
- * @since 1.0.0
352
- * @change 1.0.0
353
- */
354
-
355
- private static function _install_backend() {
356
-
357
- add_option(
358
- 'cache',
359
- array()
360
- );
361
-
362
- // clear
363
- self::clear_total_cache(true);
364
- }
365
-
366
-
367
- /**
368
- * uninstall per multisite blog
369
- *
370
- * @since 1.0.0
371
- * @change 1.0.0
372
- */
373
 
374
- public static function on_uninstall() {
375
- global $wpdb;
376
 
377
- // multisite and network
378
- if ( is_multisite() && ! empty($_GET['networkwide']) ) {
379
- // legacy blog
380
- $old = $wpdb->blogid;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
381
 
382
- // blog id
383
- $ids = self::_get_blog_ids();
384
 
385
- // uninstall per blog
386
- foreach ($ids as $id) {
387
- switch_to_blog($id);
388
- self::_uninstall_backend();
389
- }
 
390
 
391
- // restore
392
- switch_to_blog($old);
393
- } else {
394
- self::_uninstall_backend();
395
- }
396
- }
397
-
398
-
399
- /**
400
- * uninstall for multisite and network
401
- *
402
- * @since 1.0.0
403
- * @change 1.0.0
404
- */
405
-
406
- public static function uninstall_later($id) {
407
-
408
- // check if network plugin
409
- if ( ! is_plugin_active_for_network(CE_BASE) ) {
410
- return;
411
- }
412
 
413
- // switch
414
- switch_to_blog($id);
 
 
415
 
416
- // uninstall
417
- self::_uninstall_backend();
 
 
 
418
 
419
- // restore
420
- restore_current_blog();
421
- }
422
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
423
 
424
- /**
425
- * uninstall
426
- *
427
- * @since 1.0.0
428
- * @change 1.0.0
429
- */
430
-
431
- private static function _uninstall_backend() {
432
-
433
- // delete options
434
- delete_option('cache');
435
 
436
- // clear cache
437
- self::clear_total_cache(true);
438
- }
439
-
440
-
441
- /**
442
- * get blog ids
443
- *
444
- * @since 1.0.0
445
- * @change 1.0.0
446
- *
447
- * @return array blog ids array
448
- */
449
-
450
- private static function _get_blog_ids() {
451
- global $wpdb;
452
-
453
- return $wpdb->get_col("SELECT blog_id FROM `$wpdb->blogs`");
454
- }
455
-
456
-
457
- /**
458
- * set default vars
459
- *
460
- * @since 1.0.0
461
- * @change 1.0.0
462
- */
463
-
464
- private static function _set_default_vars() {
465
-
466
- // get options
467
- self::$options = self::_get_options();
468
-
469
- // disk cache
470
- if ( Cache_Enabler_Disk::is_permalink() ) {
471
- self::$disk = new Cache_Enabler_Disk;
472
- }
473
- }
474
-
475
-
476
- /**
477
- * get options
478
- *
479
- * @since 1.0.0
480
- * @change 1.1.0
481
- *
482
- * @return array options array
483
- */
484
-
485
- private static function _get_options() {
486
-
487
- return wp_parse_args(
488
- get_option('cache'),
489
- array(
490
- 'expires' => 0,
491
- 'new_post' => 0,
492
- 'new_comment' => 0,
493
- 'compress' => 0,
494
- 'webp' => 0,
495
- 'excl_ids' => '',
496
- 'minify_html' => self::MINIFY_DISABLED,
497
- )
498
- );
499
- }
500
-
501
-
502
- /**
503
- * warning if no custom permlinks
504
- *
505
- * @since 1.0.0
506
- * @change 1.0.0
507
- *
508
- * @return array options array
509
- */
510
-
511
- public static function warning_is_permalink() {
512
-
513
- if ( !Cache_Enabler_Disk::is_permalink() AND current_user_can('manage_options') ) { ?>
514
-
515
- <div class="error">
516
- <p><?php printf( __('The <b>%s</b> plugin requires a custom permalink structure to start caching properly. Please go to <a href="%s">Permalink</a> to enable it.', 'cache-enabler'), 'Cache Enabler', admin_url( 'options-permalink.php' ) ); ?></p>
517
- </div>
518
-
519
- <?php
520
- }
521
- }
522
-
523
-
524
- /**
525
- * add action links
526
- *
527
- * @since 1.0.0
528
- * @change 1.0.0
529
- *
530
- * @param array $data existing links
531
- * @return array $data appended links
532
- */
533
-
534
- public static function action_links($data) {
535
-
536
- // check user role
537
- if ( ! current_user_can('manage_options') ) {
538
- return $data;
539
- }
540
-
541
- return array_merge(
542
- $data,
543
- array(
544
- sprintf(
545
- '<a href="%s">%s</a>',
546
- add_query_arg(
547
- array(
548
- 'page' => 'cache-enabler'
549
- ),
550
- admin_url('options-general.php')
551
- ),
552
- esc_html__('Settings')
553
- )
554
- )
555
- );
556
- }
557
-
558
-
559
- /**
560
- * cache enabler meta links
561
- *
562
- * @since 1.0.0
563
- * @change 1.0.0
564
- *
565
- * @param array $input existing links
566
- * @param string $page page
567
- * @return array $data appended links
568
- */
569
-
570
- public static function row_meta($input, $page) {
571
-
572
- // check permissions
573
- if ( $page != CE_BASE ) {
574
- return $input;
575
- }
576
-
577
- return array_merge(
578
- $input,
579
- array(
580
- '<a href="https://www.keycdn.com/support/wordpress-cache-enabler-plugin/" target="_blank">Support Page</a>',
581
- )
582
- );
583
- }
584
-
585
-
586
- /**
587
- * add dashboard cache size count
588
- *
589
- * @since 1.0.0
590
- * @change 1.1.0
591
- *
592
- * @param array $items initial array with dashboard items
593
- * @return array $items merged array with dashboard items
594
- */
595
-
596
- public static function add_dashboard_count( $items = array() ) {
597
-
598
- // check user role
599
  if ( ! current_user_can('manage_options') ) {
600
- return $items;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
601
  }
602
 
603
- // get cache size
604
- $size = self::get_cache_size();
 
 
 
 
 
 
605
 
606
- // display items
607
- $items[] = sprintf(
608
- '<a href="%s" title="%s">%s %s</a>',
609
- add_query_arg(
610
- array(
611
- 'page' => 'cache-enabler'
612
- ),
613
- admin_url('options-general.php')
614
- ),
615
- esc_html__('Disk Cache', 'cache-enabler'),
616
- ( empty($size) ? esc_html__('Empty', 'cache-enabler') : size_format($size) ),
617
- esc_html__('Cache Size', 'cache-enabler')
618
- );
619
 
620
- return $items;
621
- }
622
 
 
 
 
 
623
 
624
- /**
625
- * get cache size
626
- *
627
- * @since 1.0.0
628
- * @change 1.0.0
629
- *
630
- * @param integer $size cache size (bytes)
631
- */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
632
 
633
- public static function get_cache_size() {
634
 
635
- if ( ! $size = get_transient('cache_size') ) {
636
 
637
- $size = (int) self::$disk->cache_size(CE_CACHE_DIR);
638
 
639
- // set transient
640
- set_transient(
641
- 'cache_size',
642
- $size,
643
- 60 * 15
644
- );
645
- }
646
 
647
- return $size;
648
- }
649
 
650
 
651
- /**
652
- * add admin links
653
- *
654
- * @since 1.0.0
655
- * @change 1.1.0
656
  *
657
  * @hook mixed
658
- *
659
- * @param object menu properties
660
- */
661
-
662
- public static function add_admin_links($wp_admin_bar) {
663
-
664
- // check user role
665
- if ( ! is_admin_bar_showing() OR ! apply_filters('user_can_clear_cache', current_user_can('manage_options')) ) {
666
- return;
667
- }
668
-
669
- // add admin purge link
670
- $wp_admin_bar->add_menu(
671
- array(
672
- 'id' => 'clear-cache',
673
- 'href' => wp_nonce_url( add_query_arg('_cache', 'clear'), '_cache__clear_nonce'),
674
- 'parent' => 'top-secondary',
675
- 'title' => '<span class="ab-item">'.esc_html__('Clear Cache', 'cache-enabler').'</span>',
676
- 'meta' => array( 'title' => esc_html__('Clear Cache', 'cache-enabler') )
677
- )
678
- );
679
-
680
- if ( ! is_admin() ) {
681
- // add admin purge link
682
- $wp_admin_bar->add_menu(
683
- array(
684
- 'id' => 'clear-url-cache',
685
- 'href' => wp_nonce_url( add_query_arg('_cache', 'clearurl'), '_cache__clear_nonce'),
686
- 'parent' => 'top-secondary',
687
- 'title' => '<span class="ab-item">'.esc_html__('Clear URL Cache', 'cache-enabler').'</span>',
688
- 'meta' => array( 'title' => esc_html__('Clear URL Cache', 'cache-enabler') )
689
- )
690
- );
691
- }
692
- }
693
-
694
-
695
- /**
696
- * process clear request
697
- *
698
- * @since 1.0.0
699
- * @change 1.1.0
700
- *
701
- * @param array $data array of metadata
702
- */
703
-
704
- public static function process_clear_request($data) {
705
-
706
- // check if clear request
707
- if ( empty($_GET['_cache']) OR ( $_GET['_cache'] !== 'clear' && $_GET['_cache'] !== 'clearurl' ) ) {
708
- return;
709
- }
710
 
711
  // validate nonce
712
  if ( empty($_GET['_wpnonce']) OR ! wp_verify_nonce($_GET['_wpnonce'], '_cache__clear_nonce') ) {
713
  return;
714
  }
715
 
716
- // check user role
717
- if ( ! is_admin_bar_showing() OR ! apply_filters('user_can_clear_cache', current_user_can('manage_options')) ) {
718
- return;
719
- }
720
-
721
- // load if network
722
- if ( ! function_exists('is_plugin_active_for_network') ) {
723
- require_once( ABSPATH. 'wp-admin/includes/plugin.php' );
724
- }
725
-
726
- // set clear url w/o query string
727
- $clear_url = preg_replace('/\?.*/', '', home_url( add_query_arg( NULL, NULL ) ));
728
-
729
- // multisite and network setup
730
- if ( is_multisite() && is_plugin_active_for_network(CE_BASE) ) {
731
-
732
- if ( is_network_admin() ) {
733
-
734
- // legacy blog
735
- $legacy = $GLOBALS['wpdb']->blogid;
736
-
737
- // blog ids
738
- $ids = self::_get_blog_ids();
739
-
740
- // switch blogs
741
- foreach ($ids as $id) {
742
- switch_to_blog($id);
743
- self::clear_page_cache_by_url(home_url());
744
- }
745
-
746
- // restore
747
- switch_to_blog($legacy);
748
-
749
- // clear notice
750
- if ( is_admin() ) {
751
- add_action(
752
- 'network_admin_notices',
753
- array(
754
- __CLASS__,
755
- 'clear_notice'
756
- )
757
- );
758
- }
759
- } else {
760
- if ($_GET['_cache'] == 'clearurl') {
761
- // clear specific multisite url cache
762
- self::clear_page_cache_by_url($clear_url);
763
- } else {
764
- // clear specific multisite cache
765
- self::clear_page_cache_by_url(home_url());
766
-
767
- // clear notice
768
- if ( is_admin() ) {
769
- add_action(
770
- 'admin_notices',
771
- array(
772
- __CLASS__,
773
- 'clear_notice'
774
- )
775
- );
776
- }
777
- }
778
- }
779
- } else {
780
- if ($_GET['_cache'] == 'clearurl') {
781
- // clear url cache
782
- self::clear_page_cache_by_url($clear_url);
783
- } else {
784
- // clear cache
785
- self::clear_total_cache();
786
-
787
- // clear notice
788
- if ( is_admin() ) {
789
- add_action(
790
- 'admin_notices',
791
- array(
792
- __CLASS__,
793
- 'clear_notice'
794
- )
795
- );
796
- }
797
- }
798
- }
799
-
800
- if ( ! is_admin() ) {
801
- wp_safe_redirect(
802
- remove_query_arg(
803
- '_cache',
804
- wp_get_referer()
805
- )
806
- );
807
-
808
- exit();
809
- }
810
- }
811
-
812
-
813
- /**
814
- * notification after clear cache
815
- *
816
- * @since 1.0.0
817
- * @change 1.0.0
818
  *
819
  * @hook mixed user_can_clear_cache
820
- */
821
-
822
- public static function clear_notice() {
823
-
824
- // check if admin
825
- if ( ! is_admin_bar_showing() OR ! apply_filters('user_can_clear_cache', current_user_can('manage_options')) ) {
826
- return false;
827
- }
828
-
829
- echo sprintf(
830
- '<div class="notice notice-success is-dismissible"><p>%s</p></div>',
831
- esc_html__('The cache has been cleared.', 'cache-enabler')
832
- );
833
- }
834
-
835
-
836
- /**
837
- * clear cache if edit comment
838
- *
839
- * @since 1.0.0
840
- * @change 1.0.0
841
- *
842
- * @param integer $id id of the comment
843
- */
844
-
845
- public static function edit_comment($id) {
846
-
847
- // clear complete cache if option enabled
848
- if ( self::$options['new_comment'] ) {
849
- self::clear_total_cache();
850
- } else {
851
- self::clear_page_cache_by_post_id(
852
- get_comment($id)->comment_post_ID
853
- );
854
- }
855
- }
856
-
857
-
858
- /**
859
- * clear cache if new comment
860
- *
861
- * @since 1.0.0
862
- * @change 1.0.0
863
- *
864
- * @param mixed $approved approval status
865
- * @param array $comment
866
- * @return mixed $approved approval status
867
- */
868
-
869
- public static function new_comment($approved, $comment) {
870
-
871
- // check if comment is approved
872
- if ( $approved === 1 ) {
873
- if ( self::$options['new_comment'] ) {
874
- self::clear_total_cache();
875
- } else {
876
- self::clear_page_cache_by_post_id( $comment['comment_post_ID'] );
877
- }
878
- }
879
-
880
- return $approved;
881
- }
882
-
883
-
884
- /**
885
- * clear cache if comment changes
886
- *
887
- * @since 1.0.0
888
- * @change 1.0.0
889
- *
890
- * @param string $after_status
891
- * @param string $before_status
892
- * @param object $comment
893
- */
894
-
895
- public static function change_comment($after_status, $before_status, $comment) {
896
-
897
- // check if changes occured
898
- if ( $after_status != $before_status ) {
899
- if ( self::$options['new_comment'] ) {
900
- self::clear_total_cache();
901
- } else {
902
- self::clear_page_cache_by_post_id( $comment->comment_post_ID );
903
- }
904
- }
905
- }
906
-
907
-
908
- /**
909
- * register publish hooks for custom post types
910
- *
911
- * @since 1.0.0
912
- * @since 1.0.0
913
- *
914
- * @param void
915
- * @return void
916
- */
917
-
918
- public static function register_publish_hooks() {
919
-
920
- // get post types
921
- $post_types = get_post_types(
922
- array('public' => true)
923
- );
924
-
925
- // check if empty
926
- if ( empty($post_types) ) {
927
- return;
928
- }
929
-
930
- // post type actions
931
- foreach ( $post_types as $post_type ) {
932
- add_action(
933
- 'publish_' .$post_type,
934
- array(
935
- __CLASS__,
936
- 'publish_post_types'
937
- ),
938
- 10,
939
- 2
940
- );
941
- add_action(
942
- 'publish_future_' .$post_type,
943
- array(
944
- __CLASS__,
945
- 'clear_total_cache'
946
- )
947
- );
948
- }
949
- }
950
-
951
-
952
- /**
953
- * delete post type cache on post updates
954
- *
955
- * @since 1.0.0
956
- * @change 1.0.7
957
- *
958
- * @param integer $post_ID Post ID
959
- */
960
-
961
- public static function publish_post_types($post_ID, $post) {
962
-
963
- // check if post id or post is empty
964
- if ( empty($post_ID) OR empty($post) ) {
965
- return;
966
- }
967
-
968
- // check post status
969
- if ( ! in_array( $post->post_status, array('publish', 'future') ) ) {
970
- return;
971
- }
972
-
973
- // purge cache if clean post on update
974
- if ( ! isset($_POST['_clear_post_cache_on_update']) ) {
975
-
976
- // clear complete cache if option enabled
977
- if ( self::$options['new_post'] ) {
978
- return self::clear_total_cache();
979
- } else {
980
- return self::clear_home_page_cache();
981
- }
982
-
983
- }
984
-
985
- // validate nonce
986
- if ( ! isset($_POST['_cache__status_nonce_' .$post_ID]) OR ! wp_verify_nonce($_POST['_cache__status_nonce_' .$post_ID], CE_BASE) ) {
987
- return;
988
- }
989
-
990
- // validate user role
991
- if ( ! current_user_can('publish_posts') ) {
992
- return;
993
- }
994
-
995
- // save as integer
996
- $clear_post_cache = (int)$_POST['_clear_post_cache_on_update'];
997
-
998
- // save user metadata
999
- update_user_meta(
1000
- get_current_user_id(),
1001
- '_clear_post_cache_on_update',
1002
- $clear_post_cache
1003
- );
1004
-
1005
- // purge complete cache or specific post
1006
- if ( $clear_post_cache ) {
1007
- self::clear_page_cache_by_post_id( $post_ID );
1008
- } else {
1009
- self::clear_total_cache();
1010
- }
1011
- }
1012
-
1013
-
1014
- /**
1015
- * clear page cache by post id
1016
- *
1017
- * @since 1.0.0
1018
- * @change 1.0.0
1019
- *
1020
- * @param integer $post_ID Post ID
1021
- */
1022
-
1023
- public static function clear_page_cache_by_post_id($post_ID) {
1024
-
1025
- // is int
1026
- if ( ! $post_ID = (int)$post_ID ) {
1027
- return;
1028
- }
1029
-
1030
- // clear cache by URL
1031
- self::clear_page_cache_by_url(
1032
- get_permalink( $post_ID )
1033
- );
1034
- }
1035
-
1036
-
1037
- /**
1038
- * clear page cache by url
1039
- *
1040
- * @since 1.0.0
1041
- * @change 1.0.0
1042
- *
1043
- * @param string $url url of a page
1044
- */
1045
-
1046
- public static function clear_page_cache_by_url($url) {
1047
-
1048
- // validate string
1049
- if ( ! $url = (string)$url ) {
1050
- return;
1051
- }
1052
-
1053
- call_user_func(
1054
- array(
1055
- self::$disk,
1056
- 'delete_asset'
1057
- ),
1058
- $url
1059
- );
1060
- }
1061
-
1062
-
1063
- /**
1064
- * clear home page cache
1065
- *
1066
- * @since 1.0.7
1067
- * @change 1.0.7
1068
- *
1069
- */
1070
-
1071
- public static function clear_home_page_cache() {
1072
-
1073
- call_user_func(
1074
- array(
1075
- self::$disk,
1076
- 'clear_home'
1077
- )
1078
- );
1079
-
1080
- }
1081
-
1082
-
1083
- /**
1084
- * explode on comma
1085
- *
1086
- * @since 1.0.0
1087
- * @change 1.0.0
1088
- *
1089
- * @param string $input input string
1090
- * @return array array of strings
1091
- */
1092
-
1093
- private static function _preg_split($input) {
1094
- return (array)preg_split('/,/', $input, -1, PREG_SPLIT_NO_EMPTY);
1095
- }
1096
-
1097
-
1098
- /**
1099
- * check if index.php
1100
- *
1101
- * @since 1.0.0
1102
- * @change 1.0.0
1103
- *
1104
- * @return boolean true if index.php
1105
- */
1106
-
1107
- private static function _is_index() {
1108
- return basename($_SERVER['SCRIPT_NAME']) != 'index.php';
1109
- }
1110
-
1111
-
1112
- /**
1113
- * check if mobile
1114
- *
1115
- * @since 1.0.0
1116
- * @change 1.0.0
1117
- *
1118
- * @return boolean true if mobile
1119
- */
1120
-
1121
- private static function _is_mobile() {
1122
- return ( strpos(TEMPLATEPATH, 'wptouch') OR strpos(TEMPLATEPATH, 'carrington') OR strpos(TEMPLATEPATH, 'jetpack') OR strpos(TEMPLATEPATH, 'handheld') );
1123
- }
1124
-
1125
-
1126
- /**
1127
- * check if logged in
1128
- *
1129
- * @since 1.0.0
1130
- * @change 1.0.0
1131
- *
1132
- * @return boolean true if logged in or cookie set
1133
- */
1134
-
1135
- private static function _is_logged_in() {
1136
-
1137
- // check if logged in
1138
- if ( is_user_logged_in() ) {
1139
- return true;
1140
- }
1141
-
1142
- // check cookie
1143
- if ( empty($_COOKIE) ) {
1144
- return false;
1145
- }
1146
-
1147
- // check cookie values
1148
- foreach ( $_COOKIE as $k => $v) {
1149
- if ( preg_match('/^(wp-postpass|wordpress_logged_in|comment_author)_/', $k) ) {
1150
- return true;
1151
- }
1152
- }
1153
- }
1154
-
1155
-
1156
- /**
1157
- * check to bypass the cache
1158
- *
1159
- * @since 1.0.0
1160
- * @change 1.0.7
1161
- *
1162
- * @return boolean true if exception
1163
- *
1164
- * @hook boolean bypass cache
1165
- */
1166
-
1167
- private static function _bypass_cache() {
1168
-
1169
- // bypass cache hook
1170
- if ( apply_filters('bypass_cache', false) ) {
1171
- return true;
1172
- }
1173
-
1174
- // conditional tags
1175
- if ( self::_is_index() OR is_search() OR is_404() OR is_feed() OR is_trackback() OR is_robots() OR is_preview() OR post_password_required() ) {
1176
- return true;
1177
- }
1178
-
1179
- // DONOTCACHEPAGE check e.g. woocommerce
1180
- if ( defined('DONOTCACHEPAGE') && DONOTCACHEPAGE ) {
1181
- return true;
1182
- }
1183
-
1184
- // cache enabler options
1185
- $options = self::$options;
1186
-
1187
- // Request method GET
1188
- if ( ! isset( $_SERVER['REQUEST_METHOD'] ) || $_SERVER['REQUEST_METHOD'] != 'GET' ) {
1189
- return true;
1190
- }
1191
-
1192
- // Request with query strings
1193
- if ( ! empty($_GET) && ! isset( $_GET['utm_source'], $_GET['utm_medium'], $_GET['utm_campaign'] ) && get_option('permalink_structure') ) {
1194
- return true;
1195
- }
1196
-
1197
- // if logged in
1198
- if ( self::_is_logged_in() ) {
1199
- return true;
1200
- }
1201
-
1202
- // if mobile request
1203
- if ( self::_is_mobile() ) {
1204
- return true;
1205
- }
1206
-
1207
- // if post id excluded
1208
- if ( $options['excl_ids'] && is_singular() ) {
1209
- if ( in_array( $GLOBALS['wp_query']->get_queried_object_id(), self::_preg_split($options['excl_ids']) ) ) {
1210
- return true;
1211
- }
1212
- }
1213
-
1214
- return false;
1215
- }
1216
-
1217
-
1218
- /**
1219
- * minify html
1220
- *
1221
- * @since 1.0.0
1222
- * @change 1.0.0
1223
- *
1224
- * @param string $data minify request data
1225
- * @return string $data minify response data
1226
- *
1227
- * @hook array cache_minify_ignore_tags
1228
- */
1229
-
1230
- private static function _minify_cache($data) {
1231
-
1232
- // check if disabled
1233
- if ( ! self::$options['minify_html'] ) {
1234
- return $data;
1235
- }
1236
-
1237
- // strlen limit
1238
- if ( strlen($data) > 700000) {
1239
- return $data;
1240
- }
1241
-
1242
- // ignore this tags
1243
- $ignore_tags = (array)apply_filters(
1244
- 'cache_minify_ignore_tags',
1245
- array(
1246
- 'textarea',
1247
- 'pre'
1248
- )
1249
- );
1250
-
1251
- // ignore JS if selected
1252
- if ( self::$options['minify_html'] !== self::MINIFY_HTML_JS ) {
1253
- $ignore_tags[] = 'script';
1254
- }
1255
-
1256
- // return of no ignore tags
1257
- if ( ! $ignore_tags ) {
1258
- return $data;
1259
- }
1260
-
1261
- // stringify
1262
- $ignore_regex = implode('|', $ignore_tags);
1263
-
1264
- // regex minification
1265
- $cleaned = preg_replace(
1266
- array(
1267
- '/<!--[^\[><](.*?)-->/s',
1268
- '#(?ix)(?>[^\S ]\s*|\s{2,})(?=(?:(?:[^<]++|<(?!/?(?:' .$ignore_regex. ')\b))*+)(?:<(?>' .$ignore_regex. ')\b|\z))#'
1269
- ),
1270
- array(
1271
- '',
1272
- ' '
1273
- ),
1274
- $data
1275
- );
1276
-
1277
- // something went wrong
1278
- if ( strlen($cleaned) <= 1 ) {
1279
- return $data;
1280
- }
1281
-
1282
- return $cleaned;
1283
- }
1284
-
1285
-
1286
- /**
1287
- * clear complete cache
1288
- *
1289
- * @since 1.0.0
1290
- * @change 1.0.0
1291
- */
1292
-
1293
- public static function clear_total_cache() {
1294
-
1295
- // clear disk cache
1296
- Cache_Enabler_Disk::clear_cache();
1297
-
1298
- // delete transient
1299
- delete_transient('cache_size');
1300
- }
1301
-
1302
-
1303
- /**
1304
- * set cache
1305
- *
1306
- * @since 1.0.0
1307
- * @change 1.0.0
1308
- *
1309
- * @param string $data content of a page
1310
- * @return string $data content of a page
1311
- */
1312
-
1313
- public static function set_cache($data) {
1314
-
1315
- // check if empty
1316
- if ( empty($data) ) {
1317
- return '';
1318
- }
1319
-
1320
- // store as asset
1321
- call_user_func(
1322
- array(
1323
- self::$disk,
1324
- 'store_asset'
1325
- ),
1326
- self::_minify_cache($data)
1327
- );
1328
-
1329
- return $data;
1330
- }
1331
-
1332
-
1333
- /**
1334
- * handle cache
1335
- *
1336
- * @since 1.0.0
1337
- * @change 1.0.1
1338
- */
1339
-
1340
- public static function handle_cache() {
1341
-
1342
- // bypass cache
1343
- if ( self::_bypass_cache() ) {
1344
- return;
1345
- }
1346
-
1347
- // get asset cache status
1348
- $cached = call_user_func(
1349
- array(
1350
- self::$disk,
1351
- 'check_asset'
1352
- )
1353
- );
1354
-
1355
- // check if cache empty
1356
- if ( empty($cached) ) {
1357
- ob_start('Cache_Enabler::set_cache');
1358
- return;
1359
- }
1360
-
1361
- // get expiry status
1362
- $expired = call_user_func(
1363
- array(
1364
- self::$disk,
1365
- 'check_expiry'
1366
- )
1367
- );
1368
-
1369
- // check if expired
1370
- if ( $expired ) {
1371
- ob_start('Cache_Enabler::set_cache');
1372
- return;
1373
- }
1374
-
1375
- // return cached asset
1376
- call_user_func(
1377
- array(
1378
- self::$disk,
1379
- 'get_asset'
1380
- )
1381
- );
1382
- }
1383
-
1384
-
1385
- /**
1386
- * add clear option dropdown on post publish widget
1387
- *
1388
- * @since 1.0.0
1389
- * @change 1.0.0
1390
- */
1391
-
1392
- public static function add_clear_dropdown() {
1393
-
1394
- // on published post page only
1395
- if ( empty($GLOBALS['pagenow']) OR $GLOBALS['pagenow'] !== 'post.php' OR empty($GLOBALS['post']) OR ! is_object($GLOBALS['post']) OR $GLOBALS['post']->post_status !== 'publish' ) {
1396
- return;
1397
- }
1398
-
1399
- // check user role
1400
- if ( ! current_user_can('publish_posts') ) {
1401
- return;
1402
- }
1403
-
1404
- // validate nonce
1405
- wp_nonce_field(CE_BASE, '_cache__status_nonce_' .$GLOBALS['post']->ID);
1406
-
1407
- // get current action
1408
- $current_action = (int)get_user_meta(
1409
- get_current_user_id(),
1410
- '_clear_post_cache_on_update',
1411
- true
1412
- );
1413
-
1414
- // init variables
1415
- $dropdown_options = '';
1416
- $available_options = array(
1417
- esc_html__('Completely', 'cache-enabler'),
1418
- esc_html__('Page specific', 'cache-enabler')
1419
- );
1420
-
1421
- // set dropdown options
1422
- foreach( $available_options as $key => $value ) {
1423
- $dropdown_options .= sprintf(
1424
- '<option value="%1$d" %3$s>%2$s</option>',
1425
- $key,
1426
- $value,
1427
- selected($key, $current_action, false)
1428
- );
1429
- }
1430
-
1431
- // output drowdown
1432
- echo sprintf(
1433
- '<div class="misc-pub-section" style="border-top:1px solid #eee">
1434
- <label for="cache_action">
1435
- %1$s: <span id="output-cache-action">%2$s</span>
1436
- </label>
1437
- <a href="#" class="edit-cache-action hide-if-no-js">%3$s</a>
1438
-
1439
- <div class="hide-if-js">
1440
- <select name="_clear_post_cache_on_update" id="cache_action">
1441
- %4$s
1442
- </select>
1443
-
1444
- <a href="#" class="save-cache-action hide-if-no-js button">%5$s</a>
1445
- <a href="#" class="cancel-cache-action hide-if-no-js button-cancel">%6$s</a>
1446
- </div>
1447
- </div>',
1448
- esc_html__('Clear cache', 'cache-enabler'),
1449
- $available_options[$current_action],
1450
- esc_html__('Edit'),
1451
- $dropdown_options,
1452
- esc_html__('OK'),
1453
- esc_html__('Cancel')
1454
- );
1455
- }
1456
-
1457
-
1458
- /**
1459
- * enqueue scripts
1460
- *
1461
- * @since 1.0.0
1462
- * @change 1.0.0
1463
- */
1464
-
1465
- public static function add_admin_resources($hook) {
1466
-
1467
- // hook check
1468
- if ( $hook !== 'index.php' AND $hook !== 'post.php' ) {
1469
- return;
1470
- }
1471
-
1472
- // plugin data
1473
- $plugin_data = get_plugin_data(CE_FILE);
1474
-
1475
- // enqueue scripts
1476
- switch($hook) {
1477
-
1478
- case 'post.php':
1479
- wp_enqueue_script(
1480
- 'cache-post',
1481
- plugins_url('js/post.js', CE_FILE),
1482
- array('jquery'),
1483
- $plugin_data['Version'],
1484
- true
1485
- );
1486
- break;
1487
-
1488
- default:
1489
- break;
1490
- }
1491
- }
1492
-
1493
-
1494
- /**
1495
- * add settings page
1496
- *
1497
- * @since 1.0.0
1498
- * @change 1.0.0
1499
- */
1500
-
1501
- public static function add_settings_page() {
1502
-
1503
- add_options_page(
1504
- 'Cache Enabler',
1505
- 'Cache Enabler',
1506
- 'manage_options',
1507
- 'cache-enabler',
1508
- array(
1509
- __CLASS__,
1510
- 'settings_page'
1511
- )
1512
- );
1513
- }
1514
-
1515
-
1516
- /**
1517
- * minify caching dropdown
1518
- *
1519
- * @since 1.0.0
1520
- * @change 1.0.0
1521
- *
1522
- * @return array Key => value array
1523
- */
1524
-
1525
- private static function _minify_select() {
1526
-
1527
- return array(
1528
- self::MINIFY_DISABLED => esc_html__('Disabled', 'cache-enabler'),
1529
- self::MINIFY_HTML_ONLY => esc_html__('HTML', 'cache-enabler'),
1530
- self::MINIFY_HTML_JS => esc_html__('HTML & Inline JS', 'cache-enabler')
1531
- );
1532
- }
1533
-
1534
-
1535
- /**
1536
- * Check plugin requirements
1537
- *
1538
- * @since 1.1.0
1539
- * @change 1.1.0
1540
- */
1541
-
1542
- public static function requirements_check() {
1543
-
1544
- // cache enabler options
1545
- $options = self::$options;
1546
-
1547
- // WordPress version check
1548
- if ( version_compare($GLOBALS['wp_version'], CE_MIN_WP.'alpha', '<') ) {
1549
- show_message(
1550
- sprintf(
1551
- '<div class="error"><p>%s</p></div>',
1552
- sprintf(
1553
- __('The <b>%s</b> is optimized for WordPress %s. Please disable the plugin or upgrade your WordPress installation (recommended).', 'cache-enabler'),
1554
- 'Cache Enabler',
1555
- CE_MIN_WP
1556
- )
1557
- )
1558
- );
1559
- }
1560
-
1561
- // permission check
1562
- if ( file_exists( CE_CACHE_DIR ) && !is_writable( CE_CACHE_DIR ) ) {
1563
- show_message(
1564
- sprintf(
1565
- '<div class="error"><p>%s</p></div>',
1566
- sprintf(
1567
- __('The <b>%s</b> requires write permissions %s on %s. Please <a href="%s" target="_blank">change the permissions</a>.', 'cache-enabler'),
1568
- 'Cache Enabler',
1569
- '<code>755</code>',
1570
- '<code>wp-content/cache</code>',
1571
- 'http://codex.wordpress.org/Changing_File_Permissions',
1572
- CE_MIN_WP
1573
- )
1574
- )
1575
- );
1576
- }
1577
-
1578
- // mb string check
1579
- if ( !function_exists('mb_convert_encoding') && $options['webp'] ) {
1580
- show_message(
1581
- sprintf(
1582
- '<div class="error"><p>%s</p></div>',
1583
- sprintf(
1584
- __('The <b>%s</b> WebP option requires the <a href="%s" target="_blank">PHP Multibyte String Library (php-mbstring)</a>. Please contact your hosting provider to get <b>php-mbstring</b> installed.', 'cache-enabler'),
1585
- 'Cache Enabler',
1586
- 'http://php.net/manual/en/book.mbstring.php'
1587
- )
1588
- )
1589
- );
1590
- }
1591
- }
1592
-
1593
-
1594
- /**
1595
- * register textdomain
1596
- *
1597
- * @since 1.0.0
1598
- * @change 1.0.0
1599
- */
1600
-
1601
- public static function register_textdomain() {
1602
-
1603
- load_plugin_textdomain(
1604
- 'cache-enabler',
1605
- false,
1606
- 'cache-enabler/lang'
1607
- );
1608
- }
1609
-
1610
-
1611
- /**
1612
- * register settings
1613
- *
1614
- * @since 1.0.0
1615
- * @change 1.0.0
1616
- */
1617
-
1618
- public static function register_settings() {
1619
-
1620
- register_setting(
1621
- 'cache-enabler',
1622
- 'cache',
1623
- array(
1624
- __CLASS__,
1625
- 'validate_settings'
1626
- )
1627
- );
1628
- }
1629
-
1630
-
1631
- /**
1632
- * validate settings
1633
- *
1634
- * @since 1.0.0
1635
- * @change 1.0.9
1636
- *
1637
- * @param array $data array form data
1638
- * @return array array form data valid
1639
- */
1640
-
1641
- public static function validate_settings($data) {
1642
-
1643
- // check if empty
1644
- if ( empty($data) ) {
1645
- return;
1646
- }
1647
-
1648
- // clear complete cache
1649
- self::clear_total_cache(true);
1650
-
1651
- return array(
1652
- 'expires' => (int)$data['expires'],
1653
- 'new_post' => (int)(!empty($data['new_post'])),
1654
- 'new_comment' => (int)(!empty($data['new_comment'])),
1655
- 'webp' => (int)(!empty($data['webp'])),
1656
- 'compress' => (int)(!empty($data['compress'])),
1657
- 'excl_ids' => (string)sanitize_text_field(@$data['excl_ids']),
1658
- 'minify_html' => (int)$data['minify_html']
1659
- );
1660
- }
1661
-
1662
-
1663
- /**
1664
- * settings page
1665
- *
1666
- * @since 1.0.0
1667
- * @change 1.1.0
1668
- */
1669
-
1670
- public static function settings_page() { ?>
1671
-
1672
- <div class="wrap" id="cache-settings">
1673
- <h2>
1674
- <?php _e("Cache Enabler Settings", "cache-enabler") ?>
1675
- </h2>
1676
-
1677
- <div class="notice notice-info" style="margin-bottom: 35px;">
1678
- <p><?php printf( __('Combine <b><a href="%s">%s</a></b> with Cache Enabler for even better WordPress performance and achieve the next level of caching with a CDN.', 'cache-enabler'), 'https://www.keycdn.com?utm_source=wp-admin&utm_medium=plugins&utm_campaign=cache-enabler', 'KeyCDN'); ?></p>
1679
- </div>
1680
-
1681
- <p><?php $size=self::get_cache_size(); printf( __("Current cache size: <b>%s</b>", "cache-enabler"), ( empty($size) ? esc_html__("Empty", "cache-enabler") : size_format($size) ) ); ?></p>
1682
-
1683
- <form method="post" action="options.php">
1684
- <?php settings_fields('cache-enabler') ?>
1685
-
1686
- <?php $options = self::_get_options() ?>
1687
-
1688
- <table class="form-table">
1689
- <tr valign="top">
1690
- <th scope="row">
1691
- <?php _e("Cache Expiry", "cache-enabler") ?>
1692
- </th>
1693
- <td>
1694
- <fieldset>
1695
- <label for="cache_expires">
1696
- <input type="text" name="cache[expires]" id="cache_expires" value="<?php echo esc_attr($options['expires']) ?>" />
1697
- <p class="description"><?php _e("Cache expiry in hours. An expiry time of 0 means that the cache never expires.", "cache-enabler"); ?></p>
1698
- </label>
1699
- </fieldset>
1700
- </td>
1701
- </tr>
1702
- <tr valign="top">
1703
- <th scope="row">
1704
- <?php _e("Cache Behavior", "cache-enabler") ?>
1705
- </th>
1706
- <td>
1707
- <fieldset>
1708
- <label for="cache_new_post">
1709
- <input type="checkbox" name="cache[new_post]" id="cache_new_post" value="1" <?php checked('1', $options['new_post']); ?> />
1710
- <?php _e("Clear the complete cache if a new post has been published (instead of only the home page cache).", "cache-enabler") ?>
1711
- </label>
1712
-
1713
- <br />
1714
-
1715
- <label for="cache_new_comment">
1716
- <input type="checkbox" name="cache[new_comment]" id="cache_new_comment" value="1" <?php checked('1', $options['new_comment']); ?> />
1717
- <?php _e("Clear the complete cache if a new comment has been posted (instead of only the page specific cache).", "cache-enabler") ?>
1718
- </label>
1719
-
1720
- <br />
1721
-
1722
- <label for="cache_compress">
1723
- <input type="checkbox" name="cache[compress]" id="cache_compress" value="1" <?php checked('1', $options['compress']); ?> />
1724
- <?php _e("Pre-compression of cached pages. Needs to be disabled if the decoding fails in the web browser.", "cache-enabler") ?>
1725
- </label>
1726
-
1727
- <br />
1728
-
1729
- <label for="cache_webp">
1730
- <input type="checkbox" name="cache[webp]" id="cache_webp" value="1" <?php checked('1', $options['webp']); ?> />
1731
- <?php _e("Create an additional cached version for WebP image support. Convert your images to WebP with <a href=\"https://optimus.io/en/\" target=\"_blank\">Optimus</a>.", "cache-enabler") ?>
1732
- </label>
1733
- </fieldset>
1734
- </td>
1735
- </tr>
1736
-
1737
- <tr valign="top">
1738
- <th scope="row">
1739
- <?php _e("Cache Exclusions", "cache-enabler") ?>
1740
- </th>
1741
- <td>
1742
- <fieldset>
1743
- <label for="cache_excl_ids">
1744
- <input type="text" name="cache[excl_ids]" id="cache_excl_ids" value="<?php echo esc_attr($options['excl_ids']) ?>" />
1745
- <p class="description"><?php _e("Post or Pages IDs separated by a <code>,</code> that should not be cached.", "cache-enabler"); ?></p>
1746
- </label>
1747
- </fieldset>
1748
- </td>
1749
- </tr>
1750
-
1751
- <tr valign="top">
1752
- <th scope="row">
1753
- <?php _e("Cache Minification", "cache-enabler") ?>
1754
- </th>
1755
- <td>
1756
- <label for="cache_minify_html">
1757
- <select name="cache[minify_html]" id="cache_minify_html">
1758
- <?php foreach( self::_minify_select() as $k => $v ) { ?>
1759
- <option value="<?php echo esc_attr($k) ?>" <?php selected($options['minify_html'], $k); ?>>
1760
- <?php echo esc_html($v) ?>
1761
- </option>
1762
- <?php } ?>
1763
- </select>
1764
- </label>
1765
- </td>
1766
- </tr>
1767
-
1768
- <tr valign="top">
1769
- <th scope="row">
1770
- <?php submit_button() ?>
1771
- </th>
1772
- <td>
1773
- <p class="description"><?php _e("Saving these settings will clear the complete cache.", "cache-enabler") ?></p>
1774
- </td>
1775
- </tr>
1776
- </table>
1777
- </form>
1778
- <p class="description"><?php _e("It is recommended to enable HTTP/2 on your origin server and use a CDN that supports HTTP/2. Avoid domain sharding and concatenation of your assets to benefit from parallelism of HTTP/2.", "cache-enabler") ?></p>
1779
- </div><?php
1780
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1781
  }
14
  final class Cache_Enabler {
15
 
16
 
17
+ /**
18
+ * plugin options
19
+ *
20
+ * @since 1.0.0
21
+ * @var array
22
+ */
23
+
24
+ public static $options;
25
+
26
+
27
+ /**
28
+ * disk cache object
29
+ *
30
+ * @since 1.0.0
31
+ * @var object
32
+ */
33
+
34
+ private static $disk;
35
+
36
+
37
+ /**
38
+ * minify default settings
39
+ *
40
+ * @since 1.0.0
41
+ * @var integer
42
+ */
43
+
44
+ const MINIFY_DISABLED = 0;
45
+ const MINIFY_HTML_ONLY = 1;
46
+ const MINIFY_HTML_JS = 2;
47
+
48
+
49
+ /**
50
+ * constructor wrapper
51
+ *
52
+ * @since 1.0.0
53
+ * @change 1.0.0
54
+ */
55
+
56
+ public static function instance()
57
+ {
58
+ new self();
59
+ }
60
+
61
+
62
+ /**
63
+ * constructor
64
+ *
65
+ * @since 1.0.0
66
+ * @change 1.2.0
67
+ *
68
+ * @param void
69
+ * @return void
70
+ */
71
+
72
+ public function __construct()
73
+ {
74
+ // set default vars
75
+ self::_set_default_vars();
76
+
77
+ // register publish hook
78
+ add_action(
79
+ 'init',
80
+ array(
81
+ __CLASS__,
82
+ 'register_publish_hooks'
83
+ ),
84
+ 99
85
+ );
86
+
87
+ // clear cache hooks
88
+ add_action(
89
+ 'ce_clear_post_cache',
90
+ array(
91
+ __CLASS__,
92
+ 'clear_page_cache_by_post_id'
93
+ )
94
+ );
95
+ add_action(
96
+ 'ce_clear_cache',
97
+ array(
98
+ __CLASS__,
99
+ 'clear_total_cache'
100
+ )
101
+ );
102
+ add_action(
103
+ '_core_updated_successfully',
104
+ array(
105
+ __CLASS__,
106
+ 'clear_total_cache'
107
+ )
108
+ );
109
+ add_action(
110
+ 'switch_theme',
111
+ array(
112
+ __CLASS__,
113
+ 'clear_total_cache'
114
+ )
115
+ );
116
+ add_action(
117
+ 'wp_trash_post',
118
+ array(
119
+ __CLASS__,
120
+ 'clear_total_cache'
121
+ )
122
+ );
123
+ add_action(
124
+ 'autoptimize_action_cachepurged',
125
+ array(
126
+ __CLASS__,
127
+ 'clear_total_cache'
128
+ )
129
+ );
130
 
131
  // add admin clear link
132
+ add_action(
133
+ 'admin_bar_menu',
134
+ array(
135
+ __CLASS__,
136
+ 'add_admin_links'
137
+ ),
138
+ 90
139
+ );
140
+ add_action(
141
+ 'init',
142
+ array(
143
+ __CLASS__,
144
+ 'process_clear_request'
145
+ )
146
+ );
147
+
148
+ // admin
149
+ if ( is_admin() ) {
150
+ add_action(
151
+ 'wpmu_new_blog',
152
+ array(
153
+ __CLASS__,
154
+ 'install_later'
155
+ )
156
+ );
157
+ add_action(
158
+ 'delete_blog',
159
+ array(
160
+ __CLASS__,
161
+ 'uninstall_later'
162
+ )
163
+ );
164
+
165
+ add_action(
166
+ 'admin_init',
167
+ array(
168
+ __CLASS__,
169
+ 'register_textdomain'
170
+ )
171
+ );
172
+ add_action(
173
+ 'admin_init',
174
+ array(
175
+ __CLASS__,
176
+ 'register_settings'
177
+ )
178
+ );
179
+
180
+ add_action(
181
+ 'admin_menu',
182
+ array(
183
+ __CLASS__,
184
+ 'add_settings_page'
185
+ )
186
+ );
187
+ add_action(
188
+ 'admin_enqueue_scripts',
189
+ array(
190
+ __CLASS__,
191
+ 'add_admin_resources'
192
+ )
193
+ );
194
+
195
+ add_action(
196
+ 'transition_comment_status',
197
+ array(
198
+ __CLASS__,
199
+ 'change_comment'
200
+ ),
201
+ 10,
202
+ 3
203
+ );
204
+ add_action(
205
+ 'comment_post',
206
+ array(
207
+ __CLASS__,
208
+ 'comment_post'
209
+ ),
210
+ 99,
211
+ 2
212
+ );
213
+ add_action(
214
+ 'edit_comment',
215
+ array(
216
+ __CLASS__,
217
+ 'edit_comment'
218
+ )
219
+ );
220
+
221
+ add_filter(
222
+ 'dashboard_glance_items',
223
+ array(
224
+ __CLASS__,
225
+ 'add_dashboard_count'
226
+ )
227
+ );
228
+ add_action(
229
+ 'post_submitbox_misc_actions',
230
+ array(
231
+ __CLASS__,
232
+ 'add_clear_dropdown'
233
+ )
234
+ );
235
+ add_filter(
236
+ 'plugin_row_meta',
237
+ array(
238
+ __CLASS__,
239
+ 'row_meta'
240
+ ),
241
+ 10,
242
+ 2
243
+ );
244
+ add_filter(
245
+ 'plugin_action_links_' .CE_BASE,
246
+ array(
247
+ __CLASS__,
248
+ 'action_links'
249
+ )
250
+ );
251
+
252
+ // warnings and notices
253
+ add_action(
254
+ 'admin_notices',
255
+ array(
256
+ __CLASS__,
257
+ 'warning_is_permalink'
258
+ )
259
+ );
260
+ add_action(
261
+ 'admin_notices',
262
+ array(
263
+ __CLASS__,
264
+ 'requirements_check'
265
+ )
266
+ );
267
+
268
+ // caching
269
+ } else {
270
+ add_action(
271
+ 'pre_comment_approved',
272
+ array(
273
+ __CLASS__,
274
+ 'new_comment'
275
+ ),
276
+ 99,
277
+ 2
278
+ );
279
+
280
+ add_action(
281
+ 'template_redirect',
282
+ array(
283
+ __CLASS__,
284
+ 'handle_cache'
285
+ ),
286
+ 0
287
+ );
288
+ }
289
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
290
 
 
 
291
 
292
+ /**
293
+ * deactivation hook
294
+ *
295
+ * @since 1.0.0
296
+ * @change 1.1.1
297
+ */
298
+
299
+ public static function on_deactivation() {
300
+ self::clear_total_cache(true);
301
+
302
+ if ( defined( 'WP_CACHE' ) && WP_CACHE ) {
303
+ // unset WP_CACHE
304
+ self::_set_wp_cache(false);
305
+ }
306
+
307
+ // delete advanced cache file
308
+ unlink(WP_CONTENT_DIR . '/advanced-cache.php');
309
+ }
310
 
 
 
311
 
312
+ /**
313
+ * activation hook
314
+ *
315
+ * @since 1.0.0
316
+ * @change 1.1.1
317
+ */
318
 
319
+ public static function on_activation() {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
320
 
321
+ // multisite and network
322
+ if ( is_multisite() && ! empty($_GET['networkwide']) ) {
323
+ // blog ids
324
+ $ids = self::_get_blog_ids();
325
 
326
+ // switch to blog
327
+ foreach ($ids as $id) {
328
+ switch_to_blog($id);
329
+ self::_install_backend();
330
+ }
331
 
332
+ // restore blog
333
+ restore_current_blog();
 
334
 
335
+ } else {
336
+ self::_install_backend();
337
+ }
338
+
339
+ if ( !defined( 'WP_CACHE' ) || !WP_CACHE ) {
340
+ // set WP_CACHE
341
+ self::_set_wp_cache(true);
342
+ }
343
+
344
+ // copy advanced cache file
345
+ copy(CE_DIR . '/advanced-cache.php', WP_CONTENT_DIR . '/advanced-cache.php');
346
+ }
347
+
348
+
349
+ /**
350
+ * install on multisite setup
351
+ *
352
+ * @since 1.0.0
353
+ * @change 1.0.0
354
+ */
355
+
356
+ public static function install_later($id) {
357
+
358
+ // check if multisite setup
359
+ if ( ! is_plugin_active_for_network(CE_BASE) ) {
360
+ return;
361
+ }
362
+
363
+ // switch to blog
364
+ switch_to_blog($id);
365
+
366
+ // installation
367
+ self::_install_backend();
368
+
369
+ // restore
370
+ restore_current_blog();
371
+ }
372
+
373
+
374
+ /**
375
+ * installation options
376
+ *
377
+ * @since 1.0.0
378
+ * @change 1.0.0
379
+ */
380
+
381
+ private static function _install_backend() {
382
+
383
+ add_option(
384
+ 'cache',
385
+ array()
386
+ );
387
+
388
+ // clear
389
+ self::clear_total_cache(true);
390
+ }
391
+
392
+
393
+ /**
394
+ * installation WP_CACHE (advanced cache)
395
+ *
396
+ * @since 1.1.1
397
+ * @change 1.1.1
398
+ */
399
+
400
+ private static function _set_wp_cache($wp_cache_value = true) {
401
+ $wp_config_file = ABSPATH . 'wp-config.php';
402
+
403
+ if ( file_exists( $wp_config_file ) && is_writable( $wp_config_file ) ) {
404
+ // get wp config as array
405
+ $wp_config = file( $wp_config_file );
406
+
407
+ if ($wp_cache_value) {
408
+ $wp_cache_ce_line = "define('WP_CACHE', true); // Added by Cache Enabler". "\r\n";
409
+ } else {
410
+ $wp_cache_ce_line = '';
411
+ }
412
+
413
+ $found_wp_cache = false;
414
+
415
+ foreach ( $wp_config as &$line ) {
416
+ if ( preg_match( '/^\s*define\s*\(\s*[\'\"]WP_CACHE[\'\"]\s*,\s*(.*)\s*\)/', $line ) ) {
417
+ $line = $wp_cache_ce_line;
418
+ $found_wp_cache = true;
419
+ break;
420
+ }
421
+ }
422
+
423
+ // add wp cache ce line if not found yet
424
+ if ( ! $found_wp_cache ) {
425
+ array_shift( $wp_config );
426
+ array_unshift( $wp_config, "<?php\r\n", $wp_cache_ce_line );
427
+ }
428
+
429
+ // write wp-config.php file
430
+ $fh = @fopen( $wp_config_file, 'w' );
431
+ foreach( $wp_config as $ln ) {
432
+ @fwrite( $fh, $ln );
433
+ }
434
+
435
+ @fclose( $fh );
436
+ }
437
+ }
438
+
439
+
440
+ /**
441
+ * uninstall per multisite blog
442
+ *
443
+ * @since 1.0.0
444
+ * @change 1.0.0
445
+ */
446
+
447
+ public static function on_uninstall() {
448
+ global $wpdb;
449
+
450
+ // multisite and network
451
+ if ( is_multisite() && ! empty($_GET['networkwide']) ) {
452
+ // legacy blog
453
+ $old = $wpdb->blogid;
454
+
455
+ // blog id
456
+ $ids = self::_get_blog_ids();
457
+
458
+ // uninstall per blog
459
+ foreach ($ids as $id) {
460
+ switch_to_blog($id);
461
+ self::_uninstall_backend();
462
+ }
463
+
464
+ // restore
465
+ switch_to_blog($old);
466
+ } else {
467
+ self::_uninstall_backend();
468
+ }
469
+ }
470
+
471
+
472
+ /**
473
+ * uninstall for multisite and network
474
+ *
475
+ * @since 1.0.0
476
+ * @change 1.0.0
477
+ */
478
+
479
+ public static function uninstall_later($id) {
480
+
481
+ // check if network plugin
482
+ if ( ! is_plugin_active_for_network(CE_BASE) ) {
483
+ return;
484
+ }
485
+
486
+ // switch
487
+ switch_to_blog($id);
488
+
489
+ // uninstall
490
+ self::_uninstall_backend();
491
+
492
+ // restore
493
+ restore_current_blog();
494
+ }
495
+
496
+
497
+ /**
498
+ * uninstall
499
+ *
500
+ * @since 1.0.0
501
+ * @change 1.0.0
502
+ */
503
+
504
+ private static function _uninstall_backend() {
505
+
506
+ // delete options
507
+ delete_option('cache');
508
+
509
+ // clear cache
510
+ self::clear_total_cache(true);
511
+ }
512
+
513
+
514
+ /**
515
+ * get blog ids
516
+ *
517
+ * @since 1.0.0
518
+ * @change 1.0.0
519
+ *
520
+ * @return array blog ids array
521
+ */
522
+
523
+ private static function _get_blog_ids() {
524
+ global $wpdb;
525
+
526
+ return $wpdb->get_col("SELECT blog_id FROM `$wpdb->blogs`");
527
+ }
528
+
529
+
530
+ /**
531
+ * set default vars
532
+ *
533
+ * @since 1.0.0
534
+ * @change 1.0.0
535
+ */
536
+
537
+ private static function _set_default_vars() {
538
+
539
+ // get options
540
+ self::$options = self::_get_options();
541
+
542
+ // disk cache
543
+ if ( Cache_Enabler_Disk::is_permalink() ) {
544
+ self::$disk = new Cache_Enabler_Disk;
545
+ }
546
+ }
547
+
548
+
549
+ /**
550
+ * get options
551
+ *
552
+ * @since 1.0.0
553
+ * @change 1.1.0
554
+ *
555
+ * @return array options array
556
+ */
557
+
558
+ private static function _get_options() {
559
+
560
+ return wp_parse_args(
561
+ get_option('cache'),
562
+ array(
563
+ 'expires' => 0,
564
+ 'new_post' => 0,
565
+ 'new_comment' => 0,
566
+ 'compress' => 0,
567
+ 'webp' => 0,
568
+ 'excl_ids' => '',
569
+ 'minify_html' => self::MINIFY_DISABLED,
570
+ )
571
+ );
572
+ }
573
+
574
+
575
+ /**
576
+ * warning if no custom permlinks
577
+ *
578
+ * @since 1.0.0
579
+ * @change 1.0.0
580
+ *
581
+ * @return array options array
582
+ */
583
+
584
+ public static function warning_is_permalink() {
585
+
586
+ if ( !Cache_Enabler_Disk::is_permalink() AND current_user_can('manage_options') ) { ?>
587
+
588
+ <div class="error">
589
+ <p><?php printf( __('The <b>%s</b> plugin requires a custom permalink structure to start caching properly. Please go to <a href="%s">Permalink</a> to enable it.', 'cache-enabler'), 'Cache Enabler', admin_url( 'options-permalink.php' ) ); ?></p>
590
+ </div>
591
+
592
+ <?php
593
+ }
594
+ }
595
+
596
+
597
+ /**
598
+ * add action links
599
+ *
600
+ * @since 1.0.0
601
+ * @change 1.0.0
602
+ *
603
+ * @param array $data existing links
604
+ * @return array $data appended links
605
+ */
606
 
607
+ public static function action_links($data) {
 
 
 
 
 
 
 
 
 
 
608
 
609
+ // check user role
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
610
  if ( ! current_user_can('manage_options') ) {
611
+ return $data;
612
+ }
613
+
614
+ return array_merge(
615
+ $data,
616
+ array(
617
+ sprintf(
618
+ '<a href="%s">%s</a>',
619
+ add_query_arg(
620
+ array(
621
+ 'page' => 'cache-enabler'
622
+ ),
623
+ admin_url('options-general.php')
624
+ ),
625
+ esc_html__('Settings')
626
+ )
627
+ )
628
+ );
629
+ }
630
+
631
+
632
+ /**
633
+ * cache enabler meta links
634
+ *
635
+ * @since 1.0.0
636
+ * @change 1.0.0
637
+ *
638
+ * @param array $input existing links
639
+ * @param string $page page
640
+ * @return array $data appended links
641
+ */
642
+
643
+ public static function row_meta($input, $page) {
644
+
645
+ // check permissions
646
+ if ( $page != CE_BASE ) {
647
+ return $input;
648
  }
649
 
650
+ return array_merge(
651
+ $input,
652
+ array(
653
+ '<a href="https://www.keycdn.com/support/wordpress-cache-enabler-plugin/" target="_blank">Support Page</a>',
654
+ )
655
+ );
656
+ }
657
+
658
 
659
+ /**
660
+ * add dashboard cache size count
661
+ *
662
+ * @since 1.0.0
663
+ * @change 1.1.0
664
+ *
665
+ * @param array $items initial array with dashboard items
666
+ * @return array $items merged array with dashboard items
667
+ */
 
 
 
 
668
 
669
+ public static function add_dashboard_count( $items = array() ) {
 
670
 
671
+ // check user role
672
+ if ( ! current_user_can('manage_options') ) {
673
+ return $items;
674
+ }
675
 
676
+ // get cache size
677
+ $size = self::get_cache_size();
678
+
679
+ // display items
680
+ $items[] = sprintf(
681
+ '<a href="%s" title="%s">%s %s</a>',
682
+ add_query_arg(
683
+ array(
684
+ 'page' => 'cache-enabler'
685
+ ),
686
+ admin_url('options-general.php')
687
+ ),
688
+ esc_html__('Disk Cache', 'cache-enabler'),
689
+ ( empty($size) ? esc_html__('Empty', 'cache-enabler') : size_format($size) ),
690
+ esc_html__('Cache Size', 'cache-enabler')
691
+ );
692
+
693
+ return $items;
694
+ }
695
+
696
+
697
+ /**
698
+ * get cache size
699
+ *
700
+ * @since 1.0.0
701
+ * @change 1.0.0
702
+ *
703
+ * @param integer $size cache size (bytes)
704
+ */
705
 
706
+ public static function get_cache_size() {
707
 
708
+ if ( ! $size = get_transient('cache_size') ) {
709
 
710
+ $size = (int) self::$disk->cache_size(CE_CACHE_DIR);
711
 
712
+ // set transient
713
+ set_transient(
714
+ 'cache_size',
715
+ $size,
716
+ 60 * 15
717
+ );
718
+ }
719
 
720
+ return $size;
721
+ }
722
 
723
 
724
+ /**
725
+ * add admin links
726
+ *
727
+ * @since 1.0.0
728
+ * @change 1.1.0
729
  *
730
  * @hook mixed
731
+ *
732
+ * @param object menu properties
733
+ */
734
+
735
+ public static function add_admin_links($wp_admin_bar) {
736
+
737
+ // check user role
738
+ if ( ! is_admin_bar_showing() OR ! apply_filters('user_can_clear_cache', current_user_can('manage_options')) ) {
739
+ return;
740
+ }
741
+
742
+ // add admin purge link
743
+ $wp_admin_bar->add_menu(
744
+ array(
745
+ 'id' => 'clear-cache',
746
+ 'href' => wp_nonce_url( add_query_arg('_cache', 'clear'), '_cache__clear_nonce'),
747
+ 'parent' => 'top-secondary',
748
+ 'title' => '<span class="ab-item">'.esc_html__('Clear Cache', 'cache-enabler').'</span>',
749
+ 'meta' => array( 'title' => esc_html__('Clear Cache', 'cache-enabler') )
750
+ )
751
+ );
752
+
753
+ if ( ! is_admin() ) {
754
+ // add admin purge link
755
+ $wp_admin_bar->add_menu(
756
+ array(
757
+ 'id' => 'clear-url-cache',
758
+ 'href' => wp_nonce_url( add_query_arg('_cache', 'clearurl'), '_cache__clear_nonce'),
759
+ 'parent' => 'top-secondary',
760
+ 'title' => '<span class="ab-item">'.esc_html__('Clear URL Cache', 'cache-enabler').'</span>',
761
+ 'meta' => array( 'title' => esc_html__('Clear URL Cache', 'cache-enabler') )
762
+ )
763
+ );
764
+ }
765
+ }
766
+
767
+
768
+ /**
769
+ * process clear request
770
+ *
771
+ * @since 1.0.0
772
+ * @change 1.1.0
773
+ *
774
+ * @param array $data array of metadata
775
+ */
776
+
777
+ public static function process_clear_request($data) {
778
+
779
+ // check if clear request
780
+ if ( empty($_GET['_cache']) OR ( $_GET['_cache'] !== 'clear' && $_GET['_cache'] !== 'clearurl' ) ) {
781
+ return;
782
+ }
783
 
784
  // validate nonce
785
  if ( empty($_GET['_wpnonce']) OR ! wp_verify_nonce($_GET['_wpnonce'], '_cache__clear_nonce') ) {
786
  return;
787
  }
788
 
789
+ // check user role
790
+ if ( ! is_admin_bar_showing() OR ! apply_filters('user_can_clear_cache', current_user_can('manage_options')) ) {
791
+ return;
792
+ }
793
+
794
+ // load if network
795
+ if ( ! function_exists('is_plugin_active_for_network') ) {
796
+ require_once( ABSPATH. 'wp-admin/includes/plugin.php' );
797
+ }
798
+
799
+ // set clear url w/o query string
800
+ $clear_url = preg_replace('/\?.*/', '', home_url( add_query_arg( NULL, NULL ) ));
801
+
802
+ // multisite and network setup
803
+ if ( is_multisite() && is_plugin_active_for_network(CE_BASE) ) {
804
+
805
+ if ( is_network_admin() ) {
806
+
807
+ // legacy blog
808
+ $legacy = $GLOBALS['wpdb']->blogid;
809
+
810
+ // blog ids
811
+ $ids = self::_get_blog_ids();
812
+
813
+ // switch blogs
814
+ foreach ($ids as $id) {
815
+ switch_to_blog($id);
816
+ self::clear_page_cache_by_url(home_url());
817
+ }
818
+
819
+ // restore
820
+ switch_to_blog($legacy);
821
+
822
+ // clear notice
823
+ if ( is_admin() ) {
824
+ add_action(
825
+ 'network_admin_notices',
826
+ array(
827
+ __CLASS__,
828
+ 'clear_notice'
829
+ )
830
+ );
831
+ }
832
+ } else {
833
+ if ($_GET['_cache'] == 'clearurl') {
834
+ // clear specific multisite url cache
835
+ self::clear_page_cache_by_url($clear_url);
836
+ } else {
837
+ // clear specific multisite cache
838
+ self::clear_page_cache_by_url(home_url());
839
+
840
+ // clear notice
841
+ if ( is_admin() ) {
842
+ add_action(
843
+ 'admin_notices',
844
+ array(
845
+ __CLASS__,
846
+ 'clear_notice'
847
+ )
848
+ );
849
+ }
850
+ }
851
+ }
852
+ } else {
853
+ if ($_GET['_cache'] == 'clearurl') {
854
+ // clear url cache
855
+ self::clear_page_cache_by_url($clear_url);
856
+ } else {
857
+ // clear cache
858
+ self::clear_total_cache();
859
+
860
+ // clear notice
861
+ if ( is_admin() ) {
862
+ add_action(
863
+ 'admin_notices',
864
+ array(
865
+ __CLASS__,
866
+ 'clear_notice'
867
+ )
868
+ );
869
+ }
870
+ }
871
+ }
872
+
873
+ if ( ! is_admin() ) {
874
+ wp_safe_redirect(
875
+ remove_query_arg(
876
+ '_cache',
877
+ wp_get_referer()
878
+ )
879
+ );
880
+
881
+ exit();
882
+ }
883
+ }
884
+
885
+
886
+ /**
887
+ * notification after clear cache
888
+ *
889
+ * @since 1.0.0
890
+ * @change 1.0.0
891
  *
892
  * @hook mixed user_can_clear_cache
893
+ */
894
+
895
+ public static function clear_notice() {
896
+
897
+ // check if admin
898
+ if ( ! is_admin_bar_showing() OR ! apply_filters('user_can_clear_cache', current_user_can('manage_options')) ) {
899
+ return false;
900
+ }
901
+
902
+ echo sprintf(
903
+ '<div class="notice notice-success is-dismissible"><p>%s</p></div>',
904
+ esc_html__('The cache has been cleared.', 'cache-enabler')
905
+ );
906
+ }
907
+
908
+
909
+ /**
910
+ * clear cache if post comment
911
+ *
912
+ * @since 1.2.0
913
+ * @change 1.2.0
914
+ *
915
+ * @param integer $id id of the comment
916
+ * @param mixed $approved approval status
917
+ */
918
+
919
+ public static function comment_post($id, $approved) {
920
+
921
+ // check if comment is approved
922
+ if ( $approved === 1 ) {
923
+ if ( self::$options['new_comment'] ) {
924
+ self::clear_total_cache();
925
+ } else {
926
+ self::clear_page_cache_by_post_id(
927
+ get_comment($id)->comment_post_ID
928
+ );
929
+ }
930
+ }
931
+ }
932
+
933
+
934
+ /**
935
+ * clear cache if edit comment
936
+ *
937
+ * @since 1.0.0
938
+ * @change 1.0.0
939
+ *
940
+ * @param integer $id id of the comment
941
+ */
942
+
943
+ public static function edit_comment($id) {
944
+
945
+ // clear complete cache if option enabled
946
+ if ( self::$options['new_comment'] ) {
947
+ self::clear_total_cache();
948
+ } else {
949
+ self::clear_page_cache_by_post_id(
950
+ get_comment($id)->comment_post_ID
951
+ );
952
+ }
953
+ }
954
+
955
+
956
+ /**
957
+ * clear cache if new comment
958
+ *
959
+ * @since 1.0.0
960
+ * @change 1.0.0
961
+ *
962
+ * @param mixed $approved approval status
963
+ * @param array $comment
964
+ * @return mixed $approved approval status
965
+ */
966
+
967
+ public static function new_comment($approved, $comment) {
968
+
969
+ // check if comment is approved
970
+ if ( $approved === 1 ) {
971
+ if ( self::$options['new_comment'] ) {
972
+ self::clear_total_cache();
973
+ } else {
974
+ self::clear_page_cache_by_post_id( $comment['comment_post_ID'] );
975
+ }
976
+ }
977
+
978
+ return $approved;
979
+ }
980
+
981
+
982
+ /**
983
+ * clear cache if comment changes
984
+ *
985
+ * @since 1.0.0
986
+ * @change 1.0.0
987
+ *
988
+ * @param string $after_status
989
+ * @param string $before_status
990
+ * @param object $comment
991
+ */
992
+
993
+ public static function change_comment($after_status, $before_status, $comment) {
994
+
995
+ // check if changes occured
996
+ if ( $after_status != $before_status ) {
997
+ if ( self::$options['new_comment'] ) {
998
+ self::clear_total_cache();
999
+ } else {
1000
+ self::clear_page_cache_by_post_id( $comment->comment_post_ID );
1001
+ }
1002
+ }
1003
+ }
1004
+
1005
+
1006
+ /**
1007
+ * register publish hooks for custom post types
1008
+ *
1009
+ * @since 1.0.0
1010
+ * @since 1.0.0
1011
+ *
1012
+ * @param void
1013
+ * @return void
1014
+ */
1015
+
1016
+ public static function register_publish_hooks() {
1017
+
1018
+ // get post types
1019
+ $post_types = get_post_types(
1020
+ array('public' => true)
1021
+ );
1022
+
1023
+ // check if empty
1024
+ if ( empty($post_types) ) {
1025
+ return;
1026
+ }
1027
+
1028
+ // post type actions
1029
+ foreach ( $post_types as $post_type ) {
1030
+ add_action(
1031
+ 'publish_' .$post_type,
1032
+ array(
1033
+ __CLASS__,
1034
+ 'publish_post_types'
1035
+ ),
1036
+ 10,
1037
+ 2
1038
+ );
1039
+ add_action(
1040
+ 'publish_future_' .$post_type,
1041
+ array(
1042
+ __CLASS__,
1043
+ 'clear_total_cache'
1044
+ )
1045
+ );
1046
+ }
1047
+ }
1048
+
1049
+
1050
+ /**
1051
+ * delete post type cache on post updates
1052
+ *
1053
+ * @since 1.0.0
1054
+ * @change 1.0.7
1055
+ *
1056
+ * @param integer $post_ID Post ID
1057
+ */
1058
+
1059
+ public static function publish_post_types($post_ID, $post) {
1060
+
1061
+ // check if post id or post is empty
1062
+ if ( empty($post_ID) OR empty($post) ) {
1063
+ return;
1064
+ }
1065
+
1066
+ // check post status
1067
+ if ( ! in_array( $post->post_status, array('publish', 'future') ) ) {
1068
+ return;
1069
+ }
1070
+
1071
+ // purge cache if clean post on update
1072
+ if ( ! isset($_POST['_clear_post_cache_on_update']) ) {
1073
+
1074
+ // clear complete cache if option enabled
1075
+ if ( self::$options['new_post'] ) {
1076
+ return self::clear_total_cache();
1077
+ } else {
1078
+ return self::clear_home_page_cache();
1079
+ }
1080
+
1081
+ }
1082
+
1083
+ // validate nonce
1084
+ if ( ! isset($_POST['_cache__status_nonce_' .$post_ID]) OR ! wp_verify_nonce($_POST['_cache__status_nonce_' .$post_ID], CE_BASE) ) {
1085
+ return;
1086
+ }
1087
+
1088
+ // validate user role
1089
+ if ( ! current_user_can('publish_posts') ) {
1090
+ return;
1091
+ }
1092
+
1093
+ // save as integer
1094
+ $clear_post_cache = (int)$_POST['_clear_post_cache_on_update'];
1095
+
1096
+ // save user metadata
1097
+ update_user_meta(
1098
+ get_current_user_id(),
1099
+ '_clear_post_cache_on_update',
1100
+ $clear_post_cache
1101
+ );
1102
+
1103
+ // purge complete cache or specific post
1104
+ if ( $clear_post_cache ) {
1105
+ self::clear_page_cache_by_post_id( $post_ID );
1106
+ } else {
1107
+ self::clear_total_cache();
1108
+ }
1109
+ }
1110
+
1111
+
1112
+ /**
1113
+ * clear page cache by post id
1114
+ *
1115
+ * @since 1.0.0
1116
+ * @change 1.0.0
1117
+ *
1118
+ * @param integer $post_ID Post ID
1119
+ */
1120
+
1121
+ public static function clear_page_cache_by_post_id($post_ID) {
1122
+
1123
+ // is int
1124
+ if ( ! $post_ID = (int)$post_ID ) {
1125
+ return;
1126
+ }
1127
+
1128
+ // clear cache by URL
1129
+ self::clear_page_cache_by_url(
1130
+ get_permalink( $post_ID )
1131
+ );
1132
+ }
1133
+
1134
+
1135
+ /**
1136
+ * clear page cache by url
1137
+ *
1138
+ * @since 1.0.0
1139
+ * @change 1.0.0
1140
+ *
1141
+ * @param string $url url of a page
1142
+ */
1143
+
1144
+ public static function clear_page_cache_by_url($url) {
1145
+
1146
+ // validate string
1147
+ if ( ! $url = (string)$url ) {
1148
+ return;
1149
+ }
1150
+
1151
+ call_user_func(
1152
+ array(
1153
+ self::$disk,
1154
+ 'delete_asset'
1155
+ ),
1156
+ $url
1157
+ );
1158
+ }
1159
+
1160
+
1161
+ /**
1162
+ * clear home page cache
1163
+ *
1164
+ * @since 1.0.7
1165
+ * @change 1.0.7
1166
+ *
1167
+ */
1168
+
1169
+ public static function clear_home_page_cache() {
1170
+
1171
+ call_user_func(
1172
+ array(
1173
+ self::$disk,
1174
+ 'clear_home'
1175
+ )
1176
+ );
1177
+
1178
+ }
1179
+
1180
+
1181
+ /**
1182
+ * explode on comma
1183
+ *
1184
+ * @since 1.0.0
1185
+ * @change 1.0.0
1186
+ *
1187
+ * @param string $input input string
1188
+ * @return array array of strings
1189
+ */
1190
+
1191
+ private static function _preg_split($input) {
1192
+ return (array)preg_split('/,/', $input, -1, PREG_SPLIT_NO_EMPTY);
1193
+ }
1194
+
1195
+
1196
+ /**
1197
+ * check if index.php
1198
+ *
1199
+ * @since 1.0.0
1200
+ * @change 1.0.0
1201
+ *
1202
+ * @return boolean true if index.php
1203
+ */
1204
+
1205
+ private static function _is_index() {
1206
+ return basename($_SERVER['SCRIPT_NAME']) != 'index.php';
1207
+ }
1208
+
1209
+
1210
+ /**
1211
+ * check if mobile
1212
+ *
1213
+ * @since 1.0.0
1214
+ * @change 1.0.0
1215
+ *
1216
+ * @return boolean true if mobile
1217
+ */
1218
+
1219
+ private static function _is_mobile() {
1220
+ return ( strpos(TEMPLATEPATH, 'wptouch') OR strpos(TEMPLATEPATH, 'carrington') OR strpos(TEMPLATEPATH, 'jetpack') OR strpos(TEMPLATEPATH, 'handheld') );
1221
+ }
1222
+
1223
+
1224
+ /**
1225
+ * check if logged in
1226
+ *
1227
+ * @since 1.0.0
1228
+ * @change 1.0.0
1229
+ *
1230
+ * @return boolean true if logged in or cookie set
1231
+ */
1232
+
1233
+ private static function _is_logged_in() {
1234
+
1235
+ // check if logged in
1236
+ if ( is_user_logged_in() ) {
1237
+ return true;
1238
+ }
1239
+
1240
+ // check cookie
1241
+ if ( empty($_COOKIE) ) {
1242
+ return false;
1243
+ }
1244
+
1245
+ // check cookie values
1246
+ foreach ( $_COOKIE as $k => $v) {
1247
+ if ( preg_match('/^(wp-postpass|wordpress_logged_in|comment_author)_/', $k) ) {
1248
+ return true;
1249
+ }
1250
+ }
1251
+ }
1252
+
1253
+
1254
+ /**
1255
+ * check to bypass the cache
1256
+ *
1257
+ * @since 1.0.0
1258
+ * @change 1.0.7
1259
+ *
1260
+ * @return boolean true if exception
1261
+ *
1262
+ * @hook boolean bypass cache
1263
+ */
1264
+
1265
+ private static function _bypass_cache() {
1266
+
1267
+ // bypass cache hook
1268
+ if ( apply_filters('bypass_cache', false) ) {
1269
+ return true;
1270
+ }
1271
+
1272
+ // conditional tags
1273
+ if ( self::_is_index() OR is_search() OR is_404() OR is_feed() OR is_trackback() OR is_robots() OR is_preview() OR post_password_required() ) {
1274
+ return true;
1275
+ }
1276
+
1277
+ // DONOTCACHEPAGE check e.g. woocommerce
1278
+ if ( defined('DONOTCACHEPAGE') && DONOTCACHEPAGE ) {
1279
+ return true;
1280
+ }
1281
+
1282
+ // cache enabler options
1283
+ $options = self::$options;
1284
+
1285
+ // Request method GET
1286
+ if ( ! isset( $_SERVER['REQUEST_METHOD'] ) || $_SERVER['REQUEST_METHOD'] != 'GET' ) {
1287
+ return true;
1288
+ }
1289
+
1290
+ // Request with query strings
1291
+ if ( ! empty($_GET) && ! isset( $_GET['utm_source'], $_GET['utm_medium'], $_GET['utm_campaign'] ) && get_option('permalink_structure') ) {
1292
+ return true;
1293
+ }
1294
+
1295
+ // if logged in
1296
+ if ( self::_is_logged_in() ) {
1297
+ return true;
1298
+ }
1299
+
1300
+ // if mobile request
1301
+ if ( self::_is_mobile() ) {
1302
+ return true;
1303
+ }
1304
+
1305
+ // if post id excluded
1306
+ if ( $options['excl_ids'] && is_singular() ) {
1307
+ if ( in_array( $GLOBALS['wp_query']->get_queried_object_id(), self::_preg_split($options['excl_ids']) ) ) {
1308
+ return true;
1309
+ }
1310
+ }
1311
+
1312
+ return false;
1313
+ }
1314
+
1315
+
1316
+ /**
1317
+ * minify html
1318
+ *
1319
+ * @since 1.0.0
1320
+ * @change 1.0.0
1321
+ *
1322
+ * @param string $data minify request data
1323
+ * @return string $data minify response data
1324
+ *
1325
+ * @hook array cache_minify_ignore_tags
1326
+ */
1327
+
1328
+ private static function _minify_cache($data) {
1329
+
1330
+ // check if disabled
1331
+ if ( ! self::$options['minify_html'] ) {
1332
+ return $data;
1333
+ }
1334
+
1335
+ // strlen limit
1336
+ if ( strlen($data) > 700000) {
1337
+ return $data;
1338
+ }
1339
+
1340
+ // ignore this tags
1341
+ $ignore_tags = (array)apply_filters(
1342
+ 'cache_minify_ignore_tags',
1343
+ array(
1344
+ 'textarea',
1345
+ 'pre'
1346
+ )
1347
+ );
1348
+
1349
+ // ignore JS if selected
1350
+ if ( self::$options['minify_html'] !== self::MINIFY_HTML_JS ) {
1351
+ $ignore_tags[] = 'script';
1352
+ }
1353
+
1354
+ // return of no ignore tags
1355
+ if ( ! $ignore_tags ) {
1356
+ return $data;
1357
+ }
1358
+
1359
+ // stringify
1360
+ $ignore_regex = implode('|', $ignore_tags);
1361
+
1362
+ // regex minification
1363
+ $cleaned = preg_replace(
1364
+ array(
1365
+ '/<!--[^\[><](.*?)-->/s',
1366
+ '#(?ix)(?>[^\S ]\s*|\s{2,})(?=(?:(?:[^<]++|<(?!/?(?:' .$ignore_regex. ')\b))*+)(?:<(?>' .$ignore_regex. ')\b|\z))#'
1367
+ ),
1368
+ array(
1369
+ '',
1370
+ ' '
1371
+ ),
1372
+ $data
1373
+ );
1374
+
1375
+ // something went wrong
1376
+ if ( strlen($cleaned) <= 1 ) {
1377
+ return $data;
1378
+ }
1379
+
1380
+ return $cleaned;
1381
+ }
1382
+
1383
+
1384
+ /**
1385
+ * clear complete cache
1386
+ *
1387
+ * @since 1.0.0
1388
+ * @change 1.0.0
1389
+ */
1390
+
1391
+ public static function clear_total_cache() {
1392
+
1393
+ // clear disk cache
1394
+ Cache_Enabler_Disk::clear_cache();
1395
+
1396
+ // delete transient
1397
+ delete_transient('cache_size');
1398
+ }
1399
+
1400
+
1401
+ /**
1402
+ * set cache
1403
+ *
1404
+ * @since 1.0.0
1405
+ * @change 1.0.0
1406
+ *
1407
+ * @param string $data content of a page
1408
+ * @return string $data content of a page
1409
+ */
1410
+
1411
+ public static function set_cache($data) {
1412
+
1413
+ // check if empty
1414
+ if ( empty($data) ) {
1415
+ return '';
1416
+ }
1417
+
1418
+ // store as asset
1419
+ call_user_func(
1420
+ array(
1421
+ self::$disk,
1422
+ 'store_asset'
1423
+ ),
1424
+ self::_minify_cache($data)
1425
+ );
1426
+
1427
+ return $data;
1428
+ }
1429
+
1430
+
1431
+ /**
1432
+ * handle cache
1433
+ *
1434
+ * @since 1.0.0
1435
+ * @change 1.0.1
1436
+ */
1437
+
1438
+ public static function handle_cache() {
1439
+
1440
+ // bypass cache
1441
+ if ( self::_bypass_cache() ) {
1442
+ return;
1443
+ }
1444
+
1445
+ // get asset cache status
1446
+ $cached = call_user_func(
1447
+ array(
1448
+ self::$disk,
1449
+ 'check_asset'
1450
+ )
1451
+ );
1452
+
1453
+ // check if cache empty
1454
+ if ( empty($cached) ) {
1455
+ ob_start('Cache_Enabler::set_cache');
1456
+ return;
1457
+ }
1458
+
1459
+ // get expiry status
1460
+ $expired = call_user_func(
1461
+ array(
1462
+ self::$disk,
1463
+ 'check_expiry'
1464
+ )
1465
+ );
1466
+
1467
+ // check if expired
1468
+ if ( $expired ) {
1469
+ ob_start('Cache_Enabler::set_cache');
1470
+ return;
1471
+ }
1472
+
1473
+ // return cached asset
1474
+ call_user_func(
1475
+ array(
1476
+ self::$disk,
1477
+ 'get_asset'
1478
+ )
1479
+ );
1480
+ }
1481
+
1482
+
1483
+ /**
1484
+ * add clear option dropdown on post publish widget
1485
+ *
1486
+ * @since 1.0.0
1487
+ * @change 1.0.0
1488
+ */
1489
+
1490
+ public static function add_clear_dropdown() {
1491
+
1492
+ // on published post page only
1493
+ if ( empty($GLOBALS['pagenow']) OR $GLOBALS['pagenow'] !== 'post.php' OR empty($GLOBALS['post']) OR ! is_object($GLOBALS['post']) OR $GLOBALS['post']->post_status !== 'publish' ) {
1494
+ return;
1495
+ }
1496
+
1497
+ // check user role
1498
+ if ( ! current_user_can('publish_posts') ) {
1499
+ return;
1500
+ }
1501
+
1502
+ // validate nonce
1503
+ wp_nonce_field(CE_BASE, '_cache__status_nonce_' .$GLOBALS['post']->ID);
1504
+
1505
+ // get current action
1506
+ $current_action = (int)get_user_meta(
1507
+ get_current_user_id(),
1508
+ '_clear_post_cache_on_update',
1509
+ true
1510
+ );
1511
+
1512
+ // init variables
1513
+ $dropdown_options = '';
1514
+ $available_options = array(
1515
+ esc_html__('Completely', 'cache-enabler'),
1516
+ esc_html__('Page specific', 'cache-enabler')
1517
+ );
1518
+
1519
+ // set dropdown options
1520
+ foreach( $available_options as $key => $value ) {
1521
+ $dropdown_options .= sprintf(
1522
+ '<option value="%1$d" %3$s>%2$s</option>',
1523
+ $key,
1524
+ $value,
1525
+ selected($key, $current_action, false)
1526
+ );
1527
+ }
1528
+
1529
+ // output drowdown
1530
+ echo sprintf(
1531
+ '<div class="misc-pub-section" style="border-top:1px solid #eee">
1532
+ <label for="cache_action">
1533
+ %1$s: <span id="output-cache-action">%2$s</span>
1534
+ </label>
1535
+ <a href="#" class="edit-cache-action hide-if-no-js">%3$s</a>
1536
+
1537
+ <div class="hide-if-js">
1538
+ <select name="_clear_post_cache_on_update" id="cache_action">
1539
+ %4$s
1540
+ </select>
1541
+
1542
+ <a href="#" class="save-cache-action hide-if-no-js button">%5$s</a>
1543
+ <a href="#" class="cancel-cache-action hide-if-no-js button-cancel">%6$s</a>
1544
+ </div>
1545
+ </div>',
1546
+ esc_html__('Clear cache', 'cache-enabler'),
1547
+ $available_options[$current_action],
1548
+ esc_html__('Edit'),
1549
+ $dropdown_options,
1550
+ esc_html__('OK'),
1551
+ esc_html__('Cancel')
1552
+ );
1553
+ }
1554
+
1555
+
1556
+ /**
1557
+ * enqueue scripts
1558
+ *
1559
+ * @since 1.0.0
1560
+ * @change 1.0.0
1561
+ */
1562
+
1563
+ public static function add_admin_resources($hook) {
1564
+
1565
+ // hook check
1566
+ if ( $hook !== 'index.php' AND $hook !== 'post.php' ) {
1567
+ return;
1568
+ }
1569
+
1570
+ // plugin data
1571
+ $plugin_data = get_plugin_data(CE_FILE);
1572
+
1573
+ // enqueue scripts
1574
+ switch($hook) {
1575
+
1576
+ case 'post.php':
1577
+ wp_enqueue_script(
1578
+ 'cache-post',
1579
+ plugins_url('js/post.js', CE_FILE),
1580
+ array('jquery'),
1581
+ $plugin_data['Version'],
1582
+ true
1583
+ );
1584
+ break;
1585
+
1586
+ default:
1587
+ break;
1588
+ }
1589
+ }
1590
+
1591
+
1592
+ /**
1593
+ * add settings page
1594
+ *
1595
+ * @since 1.0.0
1596
+ * @change 1.0.0
1597
+ */
1598
+
1599
+ public static function add_settings_page() {
1600
+
1601
+ add_options_page(
1602
+ 'Cache Enabler',
1603
+ 'Cache Enabler',
1604
+ 'manage_options',
1605
+ 'cache-enabler',
1606
+ array(
1607
+ __CLASS__,
1608
+ 'settings_page'
1609
+ )
1610
+ );
1611
+ }
1612
+
1613
+
1614
+ /**
1615
+ * minify caching dropdown
1616
+ *
1617
+ * @since 1.0.0
1618
+ * @change 1.0.0
1619
+ *
1620
+ * @return array Key => value array
1621
+ */
1622
+
1623
+ private static function _minify_select() {
1624
+
1625
+ return array(
1626
+ self::MINIFY_DISABLED => esc_html__('Disabled', 'cache-enabler'),
1627
+ self::MINIFY_HTML_ONLY => esc_html__('HTML', 'cache-enabler'),
1628
+ self::MINIFY_HTML_JS => esc_html__('HTML & Inline JS', 'cache-enabler')
1629
+ );
1630
+ }
1631
+
1632
+
1633
+ /**
1634
+ * Check plugin requirements
1635
+ *
1636
+ * @since 1.1.0
1637
+ * @change 1.1.0
1638
+ */
1639
+
1640
+ public static function requirements_check() {
1641
+
1642
+ // cache enabler options
1643
+ $options = self::$options;
1644
+
1645
+ // WordPress version check
1646
+ if ( version_compare($GLOBALS['wp_version'], CE_MIN_WP.'alpha', '<') ) {
1647
+ show_message(
1648
+ sprintf(
1649
+ '<div class="error"><p>%s</p></div>',
1650
+ sprintf(
1651
+ __('The <b>%s</b> is optimized for WordPress %s. Please disable the plugin or upgrade your WordPress installation (recommended).', 'cache-enabler'),
1652
+ 'Cache Enabler',
1653
+ CE_MIN_WP
1654
+ )
1655
+ )
1656
+ );
1657
+ }
1658
+
1659
+ // permission check
1660
+ if ( file_exists( CE_CACHE_DIR ) && !is_writable( CE_CACHE_DIR ) ) {
1661
+ show_message(
1662
+ sprintf(
1663
+ '<div class="error"><p>%s</p></div>',
1664
+ sprintf(
1665
+ __('The <b>%s</b> requires write permissions %s on %s. Please <a href="%s" target="_blank">change the permissions</a>.', 'cache-enabler'),
1666
+ 'Cache Enabler',
1667
+ '<code>755</code>',
1668
+ '<code>wp-content/cache</code>',
1669
+ 'http://codex.wordpress.org/Changing_File_Permissions',
1670
+ CE_MIN_WP
1671
+ )
1672
+ )
1673
+ );
1674
+ }
1675
+
1676
+ // autoptimize minification check
1677
+ if ( defined('AUTOPTIMIZE_PLUGIN_DIR') && $options['minify_html'] ) {
1678
+ show_message(
1679
+ sprintf(
1680
+ '<div class="error"><p>%s</p></div>',
1681
+ sprintf(
1682
+ __('The <b>%s</b> plugin is already active. Please disable minification in the <b>%s</b> settings.', 'cache-enabler'),
1683
+ 'Autoptimize',
1684
+ 'Cache Enabler'
1685
+ )
1686
+ )
1687
+ );
1688
+ }
1689
+ }
1690
+
1691
+
1692
+ /**
1693
+ * register textdomain
1694
+ *
1695
+ * @since 1.0.0
1696
+ * @change 1.0.0
1697
+ */
1698
+
1699
+ public static function register_textdomain() {
1700
+
1701
+ load_plugin_textdomain(
1702
+ 'cache-enabler',
1703
+ false,
1704
+ 'cache-enabler/lang'
1705
+ );
1706
+ }
1707
+
1708
+
1709
+ /**
1710
+ * register settings
1711
+ *
1712
+ * @since 1.0.0
1713
+ * @change 1.0.0
1714
+ */
1715
+
1716
+ public static function register_settings() {
1717
+
1718
+ register_setting(
1719
+ 'cache-enabler',
1720
+ 'cache',
1721
+ array(
1722
+ __CLASS__,
1723
+ 'validate_settings'
1724
+ )
1725
+ );
1726
+ }
1727
+
1728
+
1729
+ /**
1730
+ * validate settings
1731
+ *
1732
+ * @since 1.0.0
1733
+ * @change 1.0.9
1734
+ *
1735
+ * @param array $data array form data
1736
+ * @return array array form data valid
1737
+ */
1738
+
1739
+ public static function validate_settings($data) {
1740
+
1741
+ // check if empty
1742
+ if ( empty($data) ) {
1743
+ return;
1744
+ }
1745
+
1746
+ // clear complete cache
1747
+ self::clear_total_cache(true);
1748
+
1749
+ return array(
1750
+ 'expires' => (int)$data['expires'],
1751
+ 'new_post' => (int)(!empty($data['new_post'])),
1752
+ 'new_comment' => (int)(!empty($data['new_comment'])),
1753
+ 'webp' => (int)(!empty($data['webp'])),
1754
+ 'compress' => (int)(!empty($data['compress'])),
1755
+ 'excl_ids' => (string)sanitize_text_field(@$data['excl_ids']),
1756
+ 'minify_html' => (int)$data['minify_html']
1757
+ );
1758
+ }
1759
+
1760
+
1761
+ /**
1762
+ * settings page
1763
+ *
1764
+ * @since 1.0.0
1765
+ * @change 1.1.1
1766
+ */
1767
+
1768
+ public static function settings_page() {
1769
+
1770
+ // wp cache check
1771
+ if ( !defined('WP_CACHE') || !WP_CACHE ) {
1772
+ echo sprintf(
1773
+ '<div class="notice notice-warning"><p>%s</p></div>',
1774
+ sprintf(
1775
+ __("%s is not set in %s.", 'cache-enabler'),
1776
+ "<code>define('WP_CACHE', true);</code>",
1777
+ "wp-config.php"
1778
+ )
1779
+ );
1780
+ }
1781
+
1782
+ ?>
1783
+
1784
+ <div class="wrap" id="cache-settings">
1785
+ <h2>
1786
+ <?php _e("Cache Enabler Settings", "cache-enabler") ?>
1787
+ </h2>
1788
+
1789
+ <div class="notice notice-info" style="margin-bottom: 35px;">
1790
+ <p><?php printf( __('Combine <b><a href="%s">%s</a></b> with Cache Enabler for even better WordPress performance and achieve the next level of caching with a CDN.', 'cache-enabler'), 'https://www.keycdn.com?utm_source=wp-admin&utm_medium=plugins&utm_campaign=cache-enabler', 'KeyCDN'); ?></p>
1791
+ </div>
1792
+
1793
+ <p><?php $size=self::get_cache_size(); printf( __("Current cache size: <b>%s</b>", "cache-enabler"), ( empty($size) ? esc_html__("Empty", "cache-enabler") : size_format($size) ) ); ?></p>
1794
+
1795
+ <form method="post" action="options.php">
1796
+ <?php settings_fields('cache-enabler') ?>
1797
+
1798
+ <?php $options = self::_get_options() ?>
1799
+
1800
+ <table class="form-table">
1801
+ <tr valign="top">
1802
+ <th scope="row">
1803
+ <?php _e("Cache Expiry", "cache-enabler") ?>
1804
+ </th>
1805
+ <td>
1806
+ <fieldset>
1807
+ <label for="cache_expires">
1808
+ <input type="text" name="cache[expires]" id="cache_expires" value="<?php echo esc_attr($options['expires']) ?>" />
1809
+ <p class="description"><?php _e("Cache expiry in hours. An expiry time of 0 means that the cache never expires.", "cache-enabler"); ?></p>
1810
+ </label>
1811
+ </fieldset>
1812
+ </td>
1813
+ </tr>
1814
+ <tr valign="top">
1815
+ <th scope="row">
1816
+ <?php _e("Cache Behavior", "cache-enabler") ?>
1817
+ </th>
1818
+ <td>
1819
+ <fieldset>
1820
+ <label for="cache_new_post">
1821
+ <input type="checkbox" name="cache[new_post]" id="cache_new_post" value="1" <?php checked('1', $options['new_post']); ?> />
1822
+ <?php _e("Clear the complete cache if a new post has been published (instead of only the home page cache).", "cache-enabler") ?>
1823
+ </label>
1824
+
1825
+ <br />
1826
+
1827
+ <label for="cache_new_comment">
1828
+ <input type="checkbox" name="cache[new_comment]" id="cache_new_comment" value="1" <?php checked('1', $options['new_comment']); ?> />
1829
+ <?php _e("Clear the complete cache if a new comment has been posted (instead of only the page specific cache).", "cache-enabler") ?>
1830
+ </label>
1831
+
1832
+ <br />
1833
+
1834
+ <label for="cache_compress">
1835
+ <input type="checkbox" name="cache[compress]" id="cache_compress" value="1" <?php checked('1', $options['compress']); ?> />
1836
+ <?php _e("Pre-compression of cached pages. Needs to be disabled if the decoding fails in the web browser.", "cache-enabler") ?>
1837
+ </label>
1838
+
1839
+ <br />
1840
+
1841
+ <label for="cache_webp">
1842
+ <input type="checkbox" name="cache[webp]" id="cache_webp" value="1" <?php checked('1', $options['webp']); ?> />
1843
+ <?php _e("Create an additional cached version for WebP image support. Convert your images to WebP with <a href=\"https://optimus.io/en/\" target=\"_blank\">Optimus</a>.", "cache-enabler") ?>
1844
+ </label>
1845
+ </fieldset>
1846
+ </td>
1847
+ </tr>
1848
+
1849
+ <tr valign="top">
1850
+ <th scope="row">
1851
+ <?php _e("Cache Exclusions", "cache-enabler") ?>
1852
+ </th>
1853
+ <td>
1854
+ <fieldset>
1855
+ <label for="cache_excl_ids">
1856
+ <input type="text" name="cache[excl_ids]" id="cache_excl_ids" value="<?php echo esc_attr($options['excl_ids']) ?>" />
1857
+ <p class="description"><?php _e("Post or Pages IDs separated by a <code>,</code> that should not be cached.", "cache-enabler"); ?></p>
1858
+ </label>
1859
+ </fieldset>
1860
+ </td>
1861
+ </tr>
1862
+
1863
+ <tr valign="top">
1864
+ <th scope="row">
1865
+ <?php _e("Cache Minification", "cache-enabler") ?>
1866
+ </th>
1867
+ <td>
1868
+ <label for="cache_minify_html">
1869
+ <select name="cache[minify_html]" id="cache_minify_html">
1870
+ <?php foreach( self::_minify_select() as $k => $v ) { ?>
1871
+ <option value="<?php echo esc_attr($k) ?>" <?php selected($options['minify_html'], $k); ?>>
1872
+ <?php echo esc_html($v) ?>
1873
+ </option>
1874
+ <?php } ?>
1875
+ </select>
1876
+ </label>
1877
+ </td>
1878
+ </tr>
1879
+
1880
+ <tr valign="top">
1881
+ <th scope="row">
1882
+ <?php submit_button() ?>
1883
+ </th>
1884
+ <td>
1885
+ <p class="description"><?php _e("Saving these settings will clear the complete cache.", "cache-enabler") ?></p>
1886
+ </td>
1887
+ </tr>
1888
+ </table>
1889
+ </form>
1890
+ <p class="description"><?php _e("It is recommended to enable HTTP/2 on your origin server and use a CDN that supports HTTP/2. Avoid domain sharding and concatenation of your assets to benefit from parallelism of HTTP/2.", "cache-enabler") ?></p>
1891
+ </div><?php
1892
+ }
1893
  }
inc/cache_enabler_disk.class.php CHANGED
@@ -185,7 +185,7 @@ final class Cache_Enabler_Disk {
185
  public static function get_asset() {
186
 
187
  // set cache handler header
188
- header('X-Cache-Handler: php');
189
 
190
  // get if-modified request headers
191
  if ( function_exists( 'apache_request_headers' ) ) {
@@ -255,7 +255,7 @@ final class Cache_Enabler_Disk {
255
  * create files
256
  *
257
  * @since 1.0.0
258
- * @change 1.0.9
259
  *
260
  * @param string $data html content
261
  */
@@ -283,7 +283,12 @@ final class Cache_Enabler_Disk {
283
 
284
  // create webp supported files
285
  if ($options['webp']) {
286
- $converted_data = self::_convert_webp($data);
 
 
 
 
 
287
  self::_create_file( self::_file_webp_html(), $converted_data.$cache_signature." (webp) -->" );
288
 
289
  // create pre-compressed file
@@ -514,50 +519,22 @@ final class Cache_Enabler_Disk {
514
  * convert to webp
515
  *
516
  * @since 1.0.1
517
- * @change 1.1.0
518
  *
519
  * @return string converted HTML file
520
  */
521
 
522
- private static function _convert_webp($data) {
523
-
524
- // convert encoding to UTF-8
525
- if(function_exists('mb_convert_encoding')) $data = mb_convert_encoding($data, 'HTML-ENTITIES', 'UTF-8');
526
-
527
- $dom = new DOMDocument();
528
- @$dom->loadHTML($data);
529
-
530
- $imgs = $dom->getElementsByTagName("img");
531
-
532
- foreach($imgs as $img){
533
-
534
- $src = $img->getAttribute('src');
535
- $src_webp = self::_convert_webp_src($src);
536
- if ($src != $src_webp) {
537
- $img->setAttribute('src', $src_webp);
538
-
539
- // convert srcset attributes
540
- if ($img->hasAttribute('srcset')) {
541
- $srcset = $img->getAttribute('srcset');
542
- $img->setAttribute('srcset', self::_convert_webp_srcset($srcset));
543
- }
544
- }
545
-
546
- }
547
-
548
- $img_links = $dom->getElementsByTagName("a");
549
-
550
- foreach($img_links as $img_link){
551
-
552
- $src = $img_link->getAttribute('href');
553
- $src_webp = self::_convert_webp_src($src);
554
- if ($src != $src_webp) {
555
- $img_link->setAttribute('href' , $src_webp);
556
- }
557
 
 
 
 
 
 
 
558
  }
559
 
560
- return $dom->saveHtml();
561
 
562
  }
563
 
185
  public static function get_asset() {
186
 
187
  // set cache handler header
188
+ header('x-cache-handler: php');
189
 
190
  // get if-modified request headers
191
  if ( function_exists( 'apache_request_headers' ) ) {
255
  * create files
256
  *
257
  * @since 1.0.0
258
+ * @change 1.1.1
259
  *
260
  * @param string $data html content
261
  */
283
 
284
  // create webp supported files
285
  if ($options['webp']) {
286
+ // magic regex rule
287
+ $regex_rule = '#(?<=(?:(ref|src|set)=[\"\']))(?:http[s]?[^\"\']+)(\.png|\.jp[e]?g)(?:[^\"\']+)?(?=[\"\')])#';
288
+
289
+ // call the webp converter callback
290
+ $converted_data = preg_replace_callback($regex_rule,'self::_convert_webp',$data);
291
+
292
  self::_create_file( self::_file_webp_html(), $converted_data.$cache_signature." (webp) -->" );
293
 
294
  // create pre-compressed file
519
  * convert to webp
520
  *
521
  * @since 1.0.1
522
+ * @change 1.1.1
523
  *
524
  * @return string converted HTML file
525
  */
526
 
527
+ private static function _convert_webp($asset) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
528
 
529
+ if ($asset[1] == 'src') {
530
+ return self::_convert_webp_src($asset[0]);
531
+ } elseif ($asset[1] == 'ref') {
532
+ return self::_convert_webp_src($asset[0]);
533
+ } elseif ($asset[1] == 'set') {
534
+ return self::_convert_webp_srcset($asset[0]);
535
  }
536
 
537
+ return $asset[0];
538
 
539
  }
540
 
readme.txt CHANGED
@@ -2,7 +2,7 @@
2
  Contributors: keycdn
3
  Tags: cache, caching, wordpress cache, wp cache, performance, gzip, webp, http2
4
  Requires at least: 4.1
5
- Tested up to: 4.5
6
  Stable tag: trunk
7
  License: GPLv2 or later
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
@@ -31,6 +31,7 @@ The Cache Enabler plugin creates static HTML files and stores them on the server
31
  * Support of *304 Not Modified* if the page has not modified since last cached
32
  * WebP Support (when combined with [Optimus](https://optimus.io/en/ "Optimus"))
33
  * Supports responsive images via srcset since WP 4.4
 
34
  * HTTP/2 Focused
35
 
36
  > Cache Enabler is the first WP plugin to allow you to serve WebP images without JavaScript and also fully supports srcset since WP 4.4. WebP is a new image format that provides lossless and lossy compression for images on the web. WebP lossless images are [26% smaller](https://developers.google.com/speed/webp/docs/webp_lossless_alpha_study#results "webp lossless alpha study") in size compared to PNGs.
@@ -39,13 +40,13 @@ The Cache Enabler plugin creates static HTML files and stores them on the server
39
  = How does the caching work? =
40
  This plugin requires minimal setup time and allows you to easily take advantage of the benefits that come from using Wordpress caching.
41
 
42
- The Wordpress Cache Enabler has the ability to create 2 cached files. One is plain HTML and the other version is gzipped (gzip level 9). These static files are then used to deliver content faster to your users directly via PHP without any database lookups or gzipping as the files are already pre-compressed. You can use our [advanced configuration snippets](https://www.keycdn.com/support/wordpress-cache-enabler-plugin/#advanced-configuration "WP cache config snippet") to even *bypass PHP* calls required to fetch the static HTML files.
43
 
44
- When combined with Optimus, the Wordpress Cache Enabler allows you to easily deliver WebP images. The plugin will check your wp-content/uploads directory for any JPG or PNG images that have an equivalent WebP file. If there is, the URI of these image will be cached in a WebP static file by Cache Enabler. It is not required for all images to be converted to WebP when the "Create an additional cached version for WebP image support" option is enabled. This will not break any images that are not in WebP format. The plugin will deliver images that do have a WebP equivalent and will fall back to the JPG or PNG format for images that don't.
45
 
46
 
47
- = Support =
48
- Just [contact us](https://www.keycdn.com/contacts "Support Request") directly to get support on this plugin.
49
 
50
 
51
  = System Requirements =
@@ -53,13 +54,7 @@ Just [contact us](https://www.keycdn.com/contacts "Support Request") directly to
53
  * WordPress >=4.1
54
 
55
 
56
- = Website =
57
- * [WordPress Cache Enabler - Documentation](https://www.keycdn.com/support/wordpress-cache-enabler-plugin/ "WordPress Cache Enabler - Documentation")
58
-
59
-
60
  = Maintainer =
61
- * [Twitter](https://twitter.com/keycdn)
62
- * [Google+](https://plus.google.com/+Keycdn "Google+")
63
  * [KeyCDN](https://www.keycdn.com "KeyCDN")
64
 
65
 
@@ -69,6 +64,10 @@ This WordPress cache plugin is partially based on Cachify developed by [Sergej M
69
 
70
  == Changelog ==
71
 
 
 
 
 
72
  = 1.1.0 =
73
  * Added the possibility to clear the cache of a specific URL
74
  * Supports now Windows filesystems
2
  Contributors: keycdn
3
  Tags: cache, caching, wordpress cache, wp cache, performance, gzip, webp, http2
4
  Requires at least: 4.1
5
+ Tested up to: 4.7
6
  Stable tag: trunk
7
  License: GPLv2 or later
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
31
  * Support of *304 Not Modified* if the page has not modified since last cached
32
  * WebP Support (when combined with [Optimus](https://optimus.io/en/ "Optimus"))
33
  * Supports responsive images via srcset since WP 4.4
34
+ * Works perfectly with [Autoptimize](https://wordpress.org/plugins/autoptimize/)
35
  * HTTP/2 Focused
36
 
37
  > Cache Enabler is the first WP plugin to allow you to serve WebP images without JavaScript and also fully supports srcset since WP 4.4. WebP is a new image format that provides lossless and lossy compression for images on the web. WebP lossless images are [26% smaller](https://developers.google.com/speed/webp/docs/webp_lossless_alpha_study#results "webp lossless alpha study") in size compared to PNGs.
40
  = How does the caching work? =
41
  This plugin requires minimal setup time and allows you to easily take advantage of the benefits that come from using Wordpress caching.
42
 
43
+ The Wordpress Cache Enabler has the ability to create 2 cached files. One is plain HTML and the other version is gzipped (gzip level 9). These static files are then used to deliver content faster to your users without any database lookups or gzipping as the files are already pre-compressed.
44
 
45
+ When combined with Optimus, the Wordpress Cache Enabler allows you to easily deliver WebP images. The plugin will check your upload directory for any JPG or PNG images that have an equivalent WebP file. If there is, the URI of these image will be cached in a WebP static file by Cache Enabler. It is not required for all images to be converted to WebP when the "Create an additional cached version for WebP image support" option is enabled. This will not break any images that are not in WebP format. The plugin will deliver images that do have a WebP equivalent and will fall back to the JPG or PNG format for images that don't.
46
 
47
 
48
+ = Website =
49
+ * [WordPress Cache Enabler - Documentation](https://www.keycdn.com/support/wordpress-cache-enabler-plugin/ "WordPress Cache Enabler - Documentation")
50
 
51
 
52
  = System Requirements =
54
  * WordPress >=4.1
55
 
56
 
 
 
 
 
57
  = Maintainer =
 
 
58
  * [KeyCDN](https://www.keycdn.com "KeyCDN")
59
 
60
 
64
 
65
  == Changelog ==
66
 
67
+ = 1.2.0 =
68
+ * Added advanced cache feature
69
+ * Clear cache if reply to a comment in WP admin
70
+
71
  = 1.1.0 =
72
  * Added the possibility to clear the cache of a specific URL
73
  * Supports now Windows filesystems