Varnish HTTP Purge - Version 4.6.0

Version Description

  • July 2018
  • Moved Varnish to it's own menu with a new custom icon (props Olesya)
  • Add option to enable development for 24 hours (for super-admins only)
  • Change debug mode to development mode and greatly improved overall
  • Translation improvements
  • Add new action hook for after a full purge (props @futtta)
  • Change check for age-header to not require a second run (props @danielbachhuber)
  • Confirm plugin and theme blacklist check (props @danielbachhuber)
  • WP-CLI: add debug option to show all header output (props @danielbachhuber)
  • WP-CLI: add debug option to grep content for known issues (props @danielbachhuber)
  • WP-CLI: add new command to change devmode state
Download this release

Release Info

Developer Ipstenu
Plugin Icon 128x128 Varnish HTTP Purge
Version 4.6.0
Comparing to
See all releases

Code changes from version 4.5.2 to 4.6.0

Files changed (9) hide show
  1. changelog.txt +1 -1
  2. debug.php +494 -225
  3. readme.txt +79 -40
  4. settings.php +475 -0
  5. status.php +0 -338
  6. style.css +14 -7
  7. uninstall.php +20 -16
  8. varnish-http-purge.php +489 -279
  9. wp-cli.php +258 -117
changelog.txt CHANGED
@@ -77,7 +77,7 @@
77
  * Update readme with list of filters.
78
  * Added wp-cli commands to flush specific URLs and wildcards
79
  * Requires wp-cli 0.25+ to work [3315](https://github.com/wp-cli/wp-cli/issues/3315) for WP 4.6+
80
- * Update `purgePost()` to validate page_for_posts ([Props JeremyClarke](https://github.com/Ipstenu/varnish-http-purge/pull/20))
81
  * Add check for AMP ([Props JeremyClarke](https://wordpress.org/support/topic/varnish-http-purge-doesnt-update-amp-urls-on-post-update/))
82
  * Purge 'default' AMP URL as well
83
  * Cleanup on Uninstall
77
  * Update readme with list of filters.
78
  * Added wp-cli commands to flush specific URLs and wildcards
79
  * Requires wp-cli 0.25+ to work [3315](https://github.com/wp-cli/wp-cli/issues/3315) for WP 4.6+
80
+ * Update `purge_post()` to validate page_for_posts ([Props JeremyClarke](https://github.com/Ipstenu/varnish-http-purge/pull/20))
81
  * Add check for AMP ([Props JeremyClarke](https://wordpress.org/support/topic/varnish-http-purge-doesnt-update-amp-urls-on-post-update/))
82
  * Purge 'default' AMP URL as well
83
  * Cleanup on Uninstall
debug.php CHANGED
@@ -1,46 +1,168 @@
1
  <?php
2
  /**
3
- Copyright 2016-2018 Mika Epstein (email: ipstenu@halfelf.org)
4
-
5
- This file is part of Varnish HTTP Purge, a plugin for WordPress.
6
-
7
- Varnish HTTP Purge is free software: you can redistribute it and/or modify
8
- it under the terms of the Apache License 2.0 license.
9
-
10
- Varnish HTTP Purge is distributed in the hope that it will be useful,
11
- but WITHOUT ANY WARRANTY; without even the implied warranty of
12
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13
- */
 
 
 
 
14
 
15
- if ( !defined( 'ABSPATH' ) ) die();
 
 
16
 
17
  /**
18
  * Varnish Debug
19
  *
20
  * @since 4.4
21
  */
22
-
23
  class VarnishDebug {
24
 
25
  /**
26
- * Remote Get Varnish URL
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
  *
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
  * @since 4.4.0
29
  */
30
- static function remote_get( $url = '' ) {
31
 
32
- // Make sure it's not a stupid URL
33
  $url = esc_url( $url );
34
 
35
  $args = array(
36
- 'headers' => array(
37
  'timeout' => 30,
38
  'redirection' => 10,
39
- )
40
  );
41
 
42
- // Lazy run twice to make sure we get a primed cache page
43
  $response1 = wp_remote_get( $url, $args );
 
 
 
 
44
  $response2 = wp_remote_get( $url, $args );
45
 
46
  return $response2;
@@ -49,11 +171,16 @@ class VarnishDebug {
49
  /**
50
  * Basic checks that should stop a scan
51
  *
52
- * @since 4.4.0
 
 
 
 
 
53
  */
54
- static function preflight( $response ) {
55
 
56
- // Defaults
57
  $preflight = true;
58
  $message = __( 'Success', 'varnish-http-purge' );
59
 
@@ -61,16 +188,16 @@ class VarnishDebug {
61
  $preflight = false;
62
  $message = __( 'This request cannot be performed: ', 'varnish-http-purge' );
63
  $message .= $response->get_error_message();
64
- } elseif ( wp_remote_retrieve_response_code( $response ) == '404' ) {
65
  $preflight = false;
66
- $message = __( 'This URL is a 404. Please check your typing and try again.', 'varnish-http-purge' );
67
  }
68
 
69
- $return = array(
70
  'preflight' => $preflight,
71
  'message' => $message,
72
  );
73
-
74
  return $return;
75
  }
76
 
@@ -78,171 +205,204 @@ class VarnishDebug {
78
  * Check for remote IP
79
  *
80
  * @since 4.4.0
 
 
 
 
 
81
  */
82
- static function remote_ip( $headers ) {
83
 
84
  if ( isset( $headers['X-Forwarded-For'] ) && filter_var( $headers['X-Forwarded-For'], FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 ) ) {
85
  $remote_ip = $headers['X-Forwarded-For'];
86
  } elseif ( isset( $headers['HTTP_X_FORWARDED_FOR'] ) && filter_var( $headers['HTTP_X_FORWARDED_FOR'], FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 )
87
  ) {
88
  $remote_ip = $headers['HTTP_X_FORWARDED_FOR'];
89
- } elseif ( isset( $headers['Server'] ) && strpos( $headers['Server'] ,'cloudflare') !== false ) {
90
  $remote_ip = 'cloudflare';
91
  } else {
92
  $remote_ip = false;
93
  }
94
-
95
  return $remote_ip;
96
  }
97
 
98
  /**
99
- * Varnish
100
- *
101
  * Results on the Varnish calls
102
  *
103
  * @since 4.4.0
 
 
 
 
 
104
  */
105
- static function varnish_results( $headers = '' ) {
 
 
106
 
107
- // If we have headers:
108
- if ( $headers == '' ) {
109
  $kronk = false;
110
  } else {
111
  $kronk = true;
112
 
113
- // Check if the headers are set AND if the values are valid
114
- $x_cachable = ( isset( $headers['X-Cacheable'] ) && strpos( $headers['X-Cacheable'], 'YES') !== false )? true : false;
115
- $x_varnish = ( isset( $headers['X-Varnish'] ) )? true : false;
116
- $x_via = ( is_numeric( strpos( $headers['Via'], 'arnish' ) ) )? true : false;
117
- $x_nginx = ( isset( $headers['server'] ) && strpos( $headers['server'], 'nginx') !== false )? true : false;
 
 
 
118
 
119
- $x_age = ( isset( $headers['Age'] ) && $headers['Age'] > 0 )? true : false;
 
 
 
120
 
121
- $x_cache = ( isset( $headers['x-cache-status'] ) && strpos( $headers['x-cache-status'], 'HIT') !== false )? true : false;
122
- $x_p_cache = ( isset( $headers['X-Proxy-Cache'] ) && strpos( $headers['X-Proxy-Cache'], 'HIT') !== false )? true : false;
 
123
 
124
- // If this is TRUE it's NOT Cachable
125
- $not_cachable = (
126
- ( isset( $headers['X-Cacheable'] ) && strpos( $headers['X-Cacheable'] ,'NO') !== false ) ||
127
- ( isset( $headers['Pragma'] ) && strpos( $headers['Pragma'] ,'no-cache') !== false ) ||
128
- ( isset( $headers['X-Proxy-Cache'] ) && strpos( $headers['X-Proxy-Cache'] ,'HIT') !== false ) ||
129
- !$x_age
130
- )? true : false;
131
 
132
  // Are cache HEADERS set?
133
- $cacheheaders_set = ( isset( $headers['X-Cacheable'] ) || isset( $headers['X-Varnish'] ) || isset( $headers['X-Cache'] ) || $x_via )? true : false;
 
 
 
 
134
 
135
  // Which service are we?
136
- $cache_service = ' ';
137
  if ( $x_varnish && $x_nginx ) {
138
- $cache_service = ' Nginx ';
139
- } elseif ( $x_varnish && !$x_nginx ) {
140
- $cache_service = ' Varnish ';
 
 
141
  }
142
 
143
- // Set the default message:
144
- $return = array(
145
- 'icon' => 'good',
146
- 'message' => __( 'Your' . $cache_service . 'caching service appears to be running properly.', 'varnish-http-purge' ),
147
- );
 
148
  }
149
 
150
- if ( !$kronk ) {
151
  $return['icon'] = 'bad';
152
- $return['message'] = __( 'Something went very wrong with this request. Please contact your webhost if it happens again.', 'varnish-http-purge' );
153
- } elseif ( !$cacheheaders_set ) {
154
- $return['icon'] = 'warning';
155
- $return['message'] = __( 'We were unable find a caching service active for this domain. This can occur if you use a proxy service (such as CloudFlare or Sucuri) in front of your domain, or if you\'re in the middle of a DNS move.', 'varnish-http-purge' );
156
- } elseif ( !$not_cachable && ( $x_cachable || $x_varnish ) ) {
157
- $return['icon'] = 'awesome';
 
 
 
158
  } else {
 
 
159
  $return['icon'] = 'warning';
160
- $return['message'] = __( 'A caching service is running but is unable to cache your site.', 'varnish-http-purge' );
161
  }
162
 
163
  return $return;
164
  }
165
-
166
  /**
167
  * Remote IP
168
  *
169
  * Results on if we have a proxy going on and what that means
170
  *
171
  * @since 4.4.0
 
 
 
 
 
 
172
  */
173
- static function remote_ip_results( $remote_ip, $varniship ) {
174
-
175
- // Set the defaults
176
  $return = false;
177
 
178
- if ( $remote_ip == false && !empty( $varniship) ) {
179
- $return = array(
 
 
180
  'icon' => 'warning',
181
- 'message' => __( 'You have a Varnish IP address set but a proxy like Cloudflare or Sucuri has not been detected. This is mostly harmless, but if you have issues with your cache not emptying when you make a post, you may need to remove your Varnish IP. Please check with your webhost or server admin before doing so.', 'varnish-http-purge' ),
182
  );
183
- } elseif ( $remote_ip !== false && $remote_ip !== $varniship ) {
184
- $return = array(
185
  'icon' => 'warning',
186
  'message' => __( 'You\'re using a custom Varnish IP that doesn\'t appear to match your server IP address. If you\'re using multiple caching servers or IPv6, this is fine. Please make sure you\'ve properly configured it according to your webhost\'s specifications.', 'varnish-http-purge' ),
187
  );
188
  } else {
189
- $return = array(
190
  'icon' => 'awesome',
191
  'message' => __( 'Your server IP setup looks good.', 'varnish-http-purge' ),
192
  );
193
  }
194
 
195
  return $return;
196
- }
197
 
198
  /**
199
  * Server Details
200
  *
201
  * Includes nginx, hhvm, cloudflare, and more
202
  *
203
- * @since 4.4.0
 
 
 
 
 
204
  */
205
- static function server_results( $headers ) {
206
 
207
- // Set the defaults
208
  $return = array();
209
 
210
  if ( isset( $headers['Server'] ) ) {
211
- // Apache
212
- if ( strpos( $headers['Server'] ,'Apache') !== false && strpos( $headers['Server'] ,'cloudflare') == false ) {
213
- $return['Apache'] = array(
214
  'icon' => 'awesome',
215
- 'message' => __( 'Your server is running Apache.', 'varnish-http-purge' )
216
  );
217
  }
218
 
219
- // nginx
220
- if ( strpos( $headers['Server'] ,'nginx') !== false && strpos( $headers['Server'] ,'cloudflare') == false ) {
221
- $return['Nginx'] = array(
222
  'icon' => 'awesome',
223
- 'message' => __( 'Your server is running Nginx.', 'varnish-http-purge' )
224
  );
225
  }
226
-
227
- // Cloudflare
228
- if ( strpos( $headers['Server'] ,'cloudflare') !== false ) {
229
- $return['CloudFlare'] = array(
230
  'icon' => 'warning',
231
  'message' => __( 'CloudFlare has been detected. Make sure you configure WordPress properly by adding your Varnish IP and to flush the CloudFlare cache if you see inconsistencies.', 'varnish-http-purge' ),
232
  );
233
  }
234
 
235
- // HHVM: Note, WP is dropping support so ...
236
- if ( isset( $headers['X-Powered-By'] ) && strpos( $headers['X-Powered-By'] ,'HHVM') !== false ) {
237
- $return['HHVM'] = array(
238
- 'icon' => 'awkward',
239
  'message' => __( 'You are running HHVM instead of PHP. While that is compatible with Varnish, you should consider PHP 7. WordPress will cease support for HHVM in 2018.', 'varnish-http-purge' ),
240
  );
241
  }
242
 
243
- // Pagely
244
- if ( strpos( $headers['Server'] ,'Pagely') !== false ) {
245
- $return['Pagely'] = array(
246
  'icon' => 'good',
247
  'message' => __( 'This site is hosted on Pagely. The results of this scan may not be accurate.', 'varnish-http-purge' ),
248
  );
@@ -250,14 +410,14 @@ class VarnishDebug {
250
  }
251
 
252
  if ( isset( $headers['X-hacker'] ) ) {
253
- $return['WordPress.com'] = array(
254
  'icon' => 'bad',
255
  'message' => __( 'This site is hosted on WordPress.com. The results of this scan may not be accurate.', 'varnish-http-purge' ),
256
  );
257
  }
258
-
259
- if ( isset( $headers['X-Backend'] ) && strpos( $headers['X-Backend'] ,'wpaas_web_') !== false ) {
260
- $return['GoDaddy'] = array(
261
  'icon' => 'good',
262
  'message' => __( 'This site is hosted on GoDaddy. The results of this scan may not be accurate.', 'varnish-http-purge' ),
263
  );
@@ -267,28 +427,30 @@ class VarnishDebug {
267
  }
268
 
269
  /**
270
- * GZIP
271
- *
272
  * Results on GZIP
273
  *
274
  * @since 4.4.0
 
 
 
 
 
275
  */
276
- static function gzip_results( $headers ) {
277
 
278
- // Set the defaults
279
  $return = false;
280
 
281
- // GZip
282
- if( strpos( $headers['Content-Encoding'] ,'gzip') !== false || ( isset( $headers['Vary'] ) && strpos( $headers['Vary'] ,'gzip' ) !== false ) ) {
283
- $return = array(
284
  'icon' => 'good',
285
  'message' => __( 'Your site is compressing content and making the internet faster.', 'varnish-http-purge' ),
286
  );
287
  }
288
 
289
- // Fastly
290
- if ( strpos( $headers['Content-Encoding'] ,'Fastly') !== false ) {
291
- $return = array(
292
  'icon' => 'good',
293
  'message' => __( 'Fastly is speeding up your site. Remember to empty all caches in all locations when necessary.', 'varnish-http-purge' ),
294
  );
@@ -298,55 +460,74 @@ class VarnishDebug {
298
  }
299
 
300
  /**
301
- * Cookies
302
- *
303
  * Cookies break Varnish. Sometimes.
304
  *
305
  * @since 4.4.0
 
 
 
 
 
306
  */
307
- static function cookie_results( $headers ) {
308
 
309
- // Defaults
310
- $return = $almost = array();
311
 
312
  // Early check. If there are no cookies, skip!
313
- if ( !isset( $headers['Set-Cookie'] ) ) return $return;
314
-
315
- // We have at least one cookie, so let's set this now:
316
- $return['Cookies Active'] = array(
317
- 'icon' => 'warning',
318
- 'message' => __( 'Cookies have been detected. Unless your caching service is configured properly for the specific cookies, it may not cache properly. Please contact your webhost or administrator with information about the cookies found.', 'varnish-http-purge' ),
319
- );
320
-
321
- // Call the cookies!
322
- $request = wp_remote_get( 'https://varnish-http-purge.objects-us-east-1.dream.io/cookies.json' );
323
-
324
- if( is_wp_error( $request ) ) return $return; // Bail if we can't hit the server
325
 
326
- $body = wp_remote_retrieve_body( $request );
327
- $cookies = json_decode( $body );
328
 
329
- if( empty( $cookies ) ) {
330
- if ( WP_DEBUG ) {
331
- $return[ 'cookie-error' ] = array( 'icon' => 'warning', 'message' => __( 'Error: Cookie data cannot be loaded.', 'varnish-http-purge' ) );
332
  }
333
 
334
- return $return; // Bail if the data was empty for some reason
335
- }
336
-
337
- foreach ( $cookies as $cookie => $info ) {
338
- $has_cookie = false;
339
-
340
- // If cookies are an array, scan the whole thing. Otherwise, we can use strpos.
341
- if ( is_array( $headers['Set-Cookie'] ) ) {
342
- if ( in_array( $info->cookie, $headers['Set-Cookie'], true ) ) $has_cookie = true;
343
- } else {
344
- $strpos = strpos( $headers['Set-Cookie'], $info->cookie );
345
- if ( $strpos !== false ) $has_cookie = true;
346
  }
347
 
348
- if ( $has_cookie ) {
349
- $return[ 'Cookie: ' . $cookie ] = array( 'icon' => $info->type, 'message' => $info->message );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
350
  }
351
  }
352
 
@@ -359,32 +540,37 @@ class VarnishDebug {
359
  * Checking Age, Max Age, Cache Control, Pragma and more
360
  *
361
  * @since 4.4.0
 
 
 
 
 
362
  */
363
- static function cache_results( $headers ) {
364
 
365
  $return = array();
366
 
367
- // Cache Control
368
  if ( isset( $headers['Cache-Control'] ) ) {
369
 
370
- if ( is_array( $headers['Cache-Control'] ) ) {
371
- $no_cache = array_search( 'no-cache', $headers['Cache-Control'] );
372
- $max_age = array_search( 'max-age=0', $headers['Cache-Control'] );
373
  } else {
374
  $no_cache = strpos( $headers['Cache-Control'], 'no-cache' );
375
  $max_age = strpos( $headers['Cache-Control'], 'max-age=0' );
376
  }
377
 
378
- // No-Cache Set
379
- if ( $no_cache !== false ) {
380
- $return['no_cache'] = array(
381
  'icon' => 'bad',
382
  'message' => __( 'The header Cache-Control is returning "no-cache", which means visitors will never get cached pages.', 'varnish-http-purge' ),
383
  );
384
  }
385
 
386
- // Max-Age is 0
387
- if ( $max_age !== false ) {
388
  $return['max_age'] = array(
389
  'icon' => 'bad',
390
  'message' => __( 'The header Cache-Control is returning "max-age=0", which means a page can be no older than 0 seconds before it needs to regenerate the cache.', 'varnish-http-purge' ),
@@ -392,57 +578,58 @@ class VarnishDebug {
392
  }
393
  }
394
 
395
- // Age Headers
396
- if ( !isset( $headers['Age'] ) ) {
397
  $return['Age Headers'] = array(
398
  'icon' => 'bad',
399
- 'message' => __( 'Your domain does not report an "Age" header, which means we can\'t tell if the page is actually serving from cache.', 'varnish-http-purge' ),
400
  );
401
- } elseif( ( $headers['Age'] <= 0 || $headers['Age'] == 0 ) && (bool)strtotime( $headers['Age'] ) == false ) {
402
- $age_header = (int)$headers['Age'];
403
  $return['Age Headers'] = array(
 
 
404
  'icon' => 'warning',
405
- 'message' => __( 'The "Age" header is set to less than 1 second which means the page was generated without caching. This can occur when a page is visited for the first time, or if caching was just emptied. Please check again; if the header remains 0 then either the URL is intentionally excluded from caching, or a theme or plugin is sending cache headers or cookies that instruct your server not to cache.', 'varnish-http-purge' ),
406
  );
407
- } elseif ( (bool)strtotime( $headers['Age'] ) && time() <= strtotime( $headers['Age'] ) ) {
408
  $return['Age Headers'] = array(
409
  'icon' => 'bad',
410
- 'message' => __( 'The "Age" header is set to an invalid time. Either you checked right when the cache was clearned for that url or your server is not serving cached content for that url. Please check again, and if it happens again then a theme or plugin is requesting the URL not be cached.', 'varnish-http-purge' ),
411
  );
412
  } else {
413
  $return['Age Headers'] = array(
414
- 'icon' => 'good',
415
  'message' => __( 'Your site is returning proper "Age" headers.', 'varnish-http-purge' ),
416
  );
417
  }
418
 
419
- // Pragma
420
- if ( isset( $headers['Pragma'] ) && strpos( $headers['Pragma'] ,'no-cache') !== false ) {
421
  $return['Pragma Headers'] = array(
422
  'icon' => 'bad',
423
- 'message' => __( 'A plugin or theme is setting the header Pragma to "no-cache" which means visitors will never get cached pages.', 'varnish-http-purge' ),
424
  );
425
  }
426
 
427
- // X-Cache
428
- if ( isset( $headers['X-Cache-Status'] ) && strpos( $headers['X-Cache-Status'] ,'MISS') !== false ) {
429
  $return['X-Cache Satus'] = array(
430
  'icon' => 'bad',
431
- 'message' => __( 'X-Cache missed, which means it was not able to serve this page as cached. This may be resolved by re-running the scan. If not, then a plugin or theme is forcing this setting.', 'varnish-http-purge' ),
432
  );
433
  }
434
 
435
- // Mod-PageSpeed
436
  if ( isset( $headers['X-Mod-Pagespeed'] ) ) {
437
- if ( strpos( $headers['X-Cacheable'] , 'YES:Forced') !== false ) {
438
  $return['Mod Pagespeed'] = array(
439
  'icon' => 'good',
440
- 'message' => __( 'Mod Pagespeed is active and configured to work properly with caching services.', 'varnish-http-purge' ),
441
  );
442
  } else {
443
  $return['Mod Pagespeed'] = array(
444
  'icon' => 'bad',
445
- 'message' => __( 'Mod Pagespeed is active but it looks like your caching headers may not be right. This may be a false negative if other parts of your site are overwriting headers. Fix all other errors listed, then come back to this. If you are still having errors, you will need to look into using .htaccess or Nginx to override the Pagespeed headers.', 'varnish-http-purge' ),
446
  );
447
  }
448
  }
@@ -456,37 +643,70 @@ class VarnishDebug {
456
  * Themes known to be problematic
457
  *
458
  * @since 4.5.0
 
 
 
 
459
  */
460
- static function bad_themes_results() {
461
 
462
  $return = array();
463
  $request = wp_remote_get( 'https://varnish-http-purge.objects-us-east-1.dream.io/themes.json' );
464
 
465
- if( is_wp_error( $request ) ) {
466
- return $return; // Bail early
 
 
 
 
 
 
467
  }
468
 
469
- $body = wp_remote_retrieve_body( $request );
470
- $themes = json_decode( $body );
471
 
472
- if( empty( $themes ) ) {
473
  if ( WP_DEBUG ) {
474
- $return[ 'Theme Error' ] = array( 'icon' => 'warning', 'message' => __( 'Error: Theme data cannot be loaded.', 'varnish-http-purge' ) );
 
 
 
475
  }
476
-
477
- return $return; // Bail early
478
  }
479
 
480
- // Check all the themes. If one of the questionable ones are active, warn
481
  foreach ( $themes as $theme => $info ) {
482
  $my_theme = wp_get_theme( $theme );
483
- $message = __( 'Active Theme ', 'varnish-http-purge') . ucfirst( $theme ) . ': ' . $info->message;
484
- $warning = $info->type;
485
  if ( $my_theme->exists() ) {
486
- $return[ 'Theme: ' . ucfirst( $theme ) ] = array( 'icon' => $warning, 'message' => $message );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
487
  }
488
  }
489
 
 
 
 
 
 
 
 
 
490
  return $return;
491
  }
492
 
@@ -496,44 +716,77 @@ class VarnishDebug {
496
  * Plugins known to be problematic
497
  *
498
  * @since 4.5.0
 
 
 
 
499
  */
500
- static function bad_plugins_results() {
501
 
502
  $return = array();
503
  $messages = array(
504
  'incompatible' => __( 'This plugin has unexpected results with caching, making not function properly.', 'varnish-http-purge' ),
505
  'translation' => __( 'Translation plugins that use cookies and/or sessions prevent most server side caching from running properly.', 'varnish-http-purge' ),
506
  'sessions' => __( 'This plugin uses sessions, which conflicts with server side caching.', 'varnish-http-purge' ),
507
- 'cookies' => __( 'This plugin uses cookies, which prevents server side caching.', 'varnish-http-purge' ),
508
  'cache' => __( 'This type of caching plugin does not work well with server side caching.', 'varnish-http-purge' ),
509
  'ancient' => __( 'This plugin is not up to date with WordPress best practices and breaks caching.', 'varnish-http-purge' ),
510
  'removed' => __( 'This plugin was removed from WordPress.org and we do not recommend it\'s use.', 'varnish-http-purge' ),
 
511
  );
512
- $request = wp_remote_get( 'https://varnish-http-purge.objects-us-east-1.dream.io/plugins.json' );
513
 
514
- if( is_wp_error( $request ) ) {
 
515
  if ( WP_DEBUG ) {
516
- $return[ 'Plugin Error' ] = array( 'icon' => 'warning', 'message' => __( 'Error: Plugin data cannot be loaded.', 'varnish-http-purge' ) );
 
 
 
517
  }
518
- return $return; // Bail early
519
  }
520
 
521
  $body = wp_remote_retrieve_body( $request );
522
- $plugins = json_decode( $body );
523
 
524
- if( empty( $plugins ) ) {
525
- return $return; // Bail early
 
 
 
 
 
 
526
  }
527
 
528
- // Check all the plugins. If one of the questionable ones are active, warn
529
  foreach ( $plugins as $plugin => $info ) {
530
- if ( is_plugin_active( $info->path ) ) {
531
- $message = $messages[ $info->reason ];
532
- $warning = $info->type;
533
- $return[ 'Plugin: ' . ucfirst( $plugin ) ] = array( 'icon' => $warning, 'message' => $message );
 
 
 
 
 
 
 
 
 
 
 
534
  }
535
  }
536
 
 
 
 
 
 
 
 
 
537
  return $return;
538
  }
539
 
@@ -541,37 +794,53 @@ class VarnishDebug {
541
  * Get all the results
542
  *
543
  * Collect everything, get all the data spit it out.
544
- *
545
  * @since 4.4.0
 
 
 
 
 
 
 
546
  */
547
- static function get_all_the_results( $headers, $remote_ip, $varniship ) {
548
  $output = array();
549
- $output['Cache Service'] = self::varnish_results( $headers );
550
- $output['Remote IP'] = self::remote_ip_results( $remote_ip, $varniship );
551
 
552
- // Server Results
553
- $server_results = self::server_results( $headers, $remote_ip, $varniship );
554
- $output = array_merge( $output, $server_results );
 
 
 
 
 
 
 
 
555
 
556
- // Cache Results
557
- $cache_results = self::cache_results( $headers );
558
- $output = array_merge( $output, $cache_results );
559
 
560
- // Cookies
561
- $cookie_results = self::cookie_results( $headers );
562
- $output = array_merge( $output, $cookie_results );
563
 
564
- // Themes that don't play nicely with Varnish)
565
- $bad_themes_results = self::bad_themes_results();
566
- $output = array_merge( $output, $bad_themes_results );
567
 
568
- // Plugins that don't play nicely with Varnish)
569
  $bad_plugins_results = self::bad_plugins_results();
570
  $output = array_merge( $output, $bad_plugins_results );
571
 
 
 
 
 
572
  return $output;
573
  }
574
-
575
  }
576
 
577
- $varnish_debug = new VarnishDebug();
1
  <?php
2
  /**
3
+ * Debug Code
4
+ *
5
+ * @package varnish-http-purge
6
+ *
7
+ * Copyright 2016-2018 Mika Epstein (email: ipstenu@halfelf.org)
8
+ *
9
+ * This file is part of Varnish HTTP Purge, a plugin for WordPress.
10
+ *
11
+ * Varnish HTTP Purge is free software: you can redistribute it and/or modify
12
+ * it under the terms of the Apache License 2.0 license.
13
+ *
14
+ * Varnish HTTP Purge is distributed in the hope that it will be useful,
15
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17
+ */
18
 
19
+ if ( ! defined( 'ABSPATH' ) ) {
20
+ die();
21
+ }
22
 
23
  /**
24
  * Varnish Debug
25
  *
26
  * @since 4.4
27
  */
 
28
  class VarnishDebug {
29
 
30
  /**
31
+ * Devmode Check
32
+ * See if Dev Mode is active
33
+ *
34
+ * @since 4.6.0
35
+ * @returns true|false
36
+ */
37
+ public static function devmode_check() {
38
+ $return = false;
39
+ $newmode = get_site_option( 'vhp_varnish_devmode', VarnishPurger::$devmode );
40
+
41
+ if ( VHP_DEVMODE ) {
42
+ $return = true;
43
+ } elseif ( isset( $newmode['active'] ) && $newmode['active'] ) {
44
+ // if expire is less that NOW, it's over.
45
+ if ( $newmode['expire'] <= current_time( 'timestamp' ) ) {
46
+ $newmode['active'] = false;
47
+ update_site_option( 'vhp_varnish_devmode', $newmode );
48
+ } else {
49
+ $return = true;
50
+ }
51
+ }
52
+ return $return;
53
+ }
54
+
55
+ /**
56
+ * Toggle devmode on or off.
57
+ *
58
+ * @access public
59
+ * @static
60
+ * @param string $state (default: 'deactivate').
61
+ * @return true|false
62
+ */
63
+ public static function devmode_toggle( $state = 'deactivate' ) {
64
+ $newmode = get_site_option( 'vhp_varnish_devmode', VarnishPurger::$devmode );
65
+
66
+ // Weirdly this doesn't actually matter.
67
+ $newmode['expire'] = current_time( 'timestamp' ) + DAY_IN_SECONDS;
68
+
69
+ switch ( sanitize_text_field( $state ) ) {
70
+ case 'activate':
71
+ $newmode['active'] = true;
72
+ break;
73
+ case 'toggle':
74
+ $newmode['active'] = ( self::devmode_check() ) ? false : true;
75
+ break;
76
+ case 'deactivate':
77
+ default:
78
+ $newmode['active'] = false;
79
+ break;
80
+ }
81
+
82
+ update_site_option( 'vhp_varnish_devmode', $newmode );
83
+
84
+ return $newmode['active'];
85
+ }
86
+
87
+ /**
88
+ * Append the ?nocache parameter to JS and CSS files
89
+ *
90
+ * @access public
91
+ * @static
92
+ * @param mixed $src - URL of CSS or JS file.
93
+ * @return url
94
+ * @since 4.6.0
95
+ */
96
+ public static function nocache_cssjs( $src ) {
97
+ $src = remove_query_arg( 'ver', $src );
98
+ $src = add_query_arg( 'nocache', '', $src );
99
+ return $src;
100
+ }
101
+
102
+ /**
103
+ * Validate URL.
104
  *
105
+ * @access public
106
+ * @static
107
+ * @param mixed $input - The URL to validate.
108
+ * @return string
109
+ * @since 4.6.0
110
+ */
111
+ public static function is_url_valid( $input ) {
112
+
113
+ $default = esc_url( VarnishPurger::the_home_url() );
114
+
115
+ if ( ! empty( $input ) ) {
116
+ $parsed_input = wp_parse_url( $input );
117
+ if ( empty( $parsed_input['scheme'] ) ) {
118
+ $schema_input = 'http://';
119
+ if ( is_ssl() ) {
120
+ $schema_input = 'https://';
121
+ }
122
+ $input = $schema_input . ltrim( $input, '/' );
123
+ }
124
+ }
125
+
126
+ if ( empty( $input ) ) {
127
+ $output = 'empty';
128
+ } elseif ( wp_parse_url( $default, PHP_URL_HOST ) !== wp_parse_url( $input, PHP_URL_HOST ) ) {
129
+ $output = 'domain';
130
+ } elseif ( ! filter_var( $input, FILTER_VALIDATE_URL ) ) {
131
+ $output = 'invalid';
132
+ } else {
133
+ $output = 'valid';
134
+ }
135
+
136
+ return $output;
137
+ }
138
+
139
+ /**
140
+ * Get Remote URL.
141
+ *
142
+ * @access public
143
+ * @static
144
+ * @param string $url (default: '').
145
+ * @return array
146
  * @since 4.4.0
147
  */
148
+ public static function remote_get( $url = '' ) {
149
 
150
+ // Make sure it's not a stupid URL.
151
  $url = esc_url( $url );
152
 
153
  $args = array(
154
+ 'headers' => array(
155
  'timeout' => 30,
156
  'redirection' => 10,
157
+ ),
158
  );
159
 
160
+ // Lazy run twice to make sure we get a primed cache page.
161
  $response1 = wp_remote_get( $url, $args );
162
+
163
+ // Because the 'Age' header is an important check, wait a second before fetching again.
164
+ sleep( 1 );
165
+
166
  $response2 = wp_remote_get( $url, $args );
167
 
168
  return $response2;
171
  /**
172
  * Basic checks that should stop a scan
173
  *
174
+ * @since 4.4.0.
175
+ *
176
+ * @access public
177
+ * @static
178
+ * @param mixed $response - Message for if the URL is scannable.
179
+ * @return array
180
  */
181
+ public static function preflight( $response ) {
182
 
183
+ // Defaults.
184
  $preflight = true;
185
  $message = __( 'Success', 'varnish-http-purge' );
186
 
188
  $preflight = false;
189
  $message = __( 'This request cannot be performed: ', 'varnish-http-purge' );
190
  $message .= $response->get_error_message();
191
+ } elseif ( '404' === wp_remote_retrieve_response_code( $response ) ) {
192
  $preflight = false;
193
+ $message = __( 'This URL does not resolve properly. Either it\'s was not found or it redirects incorrectly.', 'varnish-http-purge' );
194
  }
195
 
196
+ $return = array(
197
  'preflight' => $preflight,
198
  'message' => $message,
199
  );
200
+
201
  return $return;
202
  }
203
 
205
  * Check for remote IP
206
  *
207
  * @since 4.4.0
208
+ *
209
+ * @access public
210
+ * @static
211
+ * @param mixed $headers - headers from wp_remote_get.
212
+ * @return string
213
  */
214
+ public static function remote_ip( $headers ) {
215
 
216
  if ( isset( $headers['X-Forwarded-For'] ) && filter_var( $headers['X-Forwarded-For'], FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 ) ) {
217
  $remote_ip = $headers['X-Forwarded-For'];
218
  } elseif ( isset( $headers['HTTP_X_FORWARDED_FOR'] ) && filter_var( $headers['HTTP_X_FORWARDED_FOR'], FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 )
219
  ) {
220
  $remote_ip = $headers['HTTP_X_FORWARDED_FOR'];
221
+ } elseif ( isset( $headers['Server'] ) && strpos( $headers['Server'], 'cloudflare' ) !== false ) {
222
  $remote_ip = 'cloudflare';
223
  } else {
224
  $remote_ip = false;
225
  }
226
+
227
  return $remote_ip;
228
  }
229
 
230
  /**
 
 
231
  * Results on the Varnish calls
232
  *
233
  * @since 4.4.0
234
+ *
235
+ * @access public
236
+ * @static
237
+ * @param string $headers (default: false) - headers from wp_remote_get.
238
+ * @return array
239
  */
240
+ public static function varnish_results( $headers = false ) {
241
+
242
+ $return = array();
243
 
244
+ // If we have headers...
245
+ if ( ! $headers ) {
246
  $kronk = false;
247
  } else {
248
  $kronk = true;
249
 
250
+ // Get some basic truthy/falsy from the headers.
251
+ // Headers used by both.
252
+ $x_varnish = ( isset( $headers['X-Varnish'] ) ) ? true : false;
253
+ $x_date = ( isset( $headers['Date'] ) && strtotime( $headers['Date'] ) !== false ) ? true : false;
254
+ $x_age = ( isset( $headers['Age'] ) ) ? true : false;
255
+
256
+ // Is this Nginx or not?
257
+ $x_nginx = ( isset( $headers['server'] ) && ( strpos( $headers['server'], 'nginx' ) !== false || strpos( $headers['server'], 'openresty' ) !== false ) ) ? true : false;
258
 
259
+ // Headers used by Nginx.
260
+ $x_varn_hit = ( $x_varnish && strpos( $headers['X-Varnish'], 'HIT' ) !== false ) ? true : false;
261
+ $x_age_nginx = ( $x_age && $x_date && strtotime( $headers['Age'] ) < strtotime( $headers['Date'] ) ) ? true : false;
262
+ $x_pragma = ( isset( $headers['Pragma'] ) && strpos( $headers['Pragma'], 'no-cache' ) === false ) ? true : false;
263
 
264
+ // Headers used ONLY by Apache/Varnish.
265
+ $x_cachable = ( isset( $headers['X-Cacheable'] ) && strpos( $headers['X-Cacheable'], 'YES' ) !== false ) ? true : false;
266
+ $x_age_vapc = ( $x_age && $headers['Age'] > 0 ) ? true : false;
267
 
268
+ // Optional Headers.
269
+ $x_via = ( is_numeric( strpos( $headers['Via'], 'arnish' ) ) ) ? true : false;
270
+ $x_cache = ( isset( $headers['x-cache-status'] ) && strpos( $headers['x-cache-status'], 'HIT' ) !== false ) ? true : false;
271
+ $x_p_cache = ( isset( $headers['X-Proxy-Cache'] ) && strpos( $headers['X-Proxy-Cache'], 'HIT' ) !== false ) ? true : false;
 
 
 
272
 
273
  // Are cache HEADERS set?
274
+ $cacheheaders_set = ( isset( $headers['X-Cacheable'] ) || $x_varnish || isset( $headers['X-Cache'] ) || $x_via ) ? true : false;
275
+
276
+ // Is Cacheable?
277
+ $is_cachable = ( $x_varnish && $x_age ) ? true : false;
278
+ $still_cachable = true;
279
 
280
  // Which service are we?
281
+ $cache_service = false;
282
  if ( $x_varnish && $x_nginx ) {
283
+ $cache_service = __( 'Nginx', 'varnish-http-purge' );
284
+ $still_cachable = ( $is_cachable && $x_pragma && $x_age_nginx && $x_varn_hit ) ? true : false;
285
+ } elseif ( $x_varnish && ! $x_nginx ) {
286
+ $cache_service = __( 'Varnish', 'varnish-http-purge' );
287
+ $still_cachable = ( $is_cachable && $x_cachable && $x_age_vapc ) ? true : false;
288
  }
289
 
290
+ // Determine the default message.
291
+ if ( false !== $cache_service ) {
292
+ // translators: %1 is the type of caching service detected (i.e. nginx or varnish).
293
+ $return['message'] = sprintf( __( 'Your %1 caching service appears to be running properly.', 'varnish-http-purge' ), $cache_service );
294
+ $return['icon'] = 'good';
295
+ }
296
  }
297
 
298
+ if ( ! $cache_service ) {
299
  $return['icon'] = 'bad';
300
+ $return['message'] = __( 'No known cache service has been detected on your site.', 'varnish-http-purge' );
301
+ } elseif ( ! $kronk ) {
302
+ $return['icon'] = 'bad';
303
+ $return['message'] = __( 'Your site is not responding. If this happens again, please contact your webhost.', 'varnish-http-purge' );
304
+ } elseif ( ! $cacheheaders_set ) {
305
+ $return['icon'] = 'notice';
306
+ $return['message'] = __( 'We were unable find a caching service active for this domain. This may occur if you use a proxy service (such as CloudFlare or Sucuri) or if you\'re in the middle of a DNS move.', 'varnish-http-purge' );
307
+ } elseif ( $is_cachable && $still_cachable ) {
308
+ $return['icon'] = 'awesome';
309
  } else {
310
+ // translators: %1 is the type of caching service detected (i.e. nginx or varnish).
311
+ $return['message'] = sprintf( __( '%s caching service is running but is unable to cache your site.', 'varnish-http-purge' ), $cache_service );
312
  $return['icon'] = 'warning';
 
313
  }
314
 
315
  return $return;
316
  }
317
+
318
  /**
319
  * Remote IP
320
  *
321
  * Results on if we have a proxy going on and what that means
322
  *
323
  * @since 4.4.0
324
+ *
325
+ * @access public
326
+ * @static
327
+ * @param mixed $remote_ip - IP detected.
328
+ * @param mixed $varniship - Varnish IP.
329
+ * @return array
330
  */
331
+ public static function remote_ip_results( $remote_ip, $varniship ) {
 
 
332
  $return = false;
333
 
334
+ if ( false === $remote_ip && ! empty( $varniship ) ) {
335
+ $return = array(
336
+ // translators: %s is an IP address.
337
+ 'message' => sprintf( __( 'Your Varnish IP address is set to %s but a proxy (like Cloudflare or Sucuri) has not been detected. This is mostly harmless, but if you have issues with your cache not emptying when you make a post, you may need to remove your Varnish IP. Please check with your webhost or server admin before doing so.', 'varnish-http-purge' ), $varniship ),
338
  'icon' => 'warning',
 
339
  );
340
+ } elseif ( false !== $remote_ip && $remote_ip !== $varniship ) {
341
+ $return = array(
342
  'icon' => 'warning',
343
  'message' => __( 'You\'re using a custom Varnish IP that doesn\'t appear to match your server IP address. If you\'re using multiple caching servers or IPv6, this is fine. Please make sure you\'ve properly configured it according to your webhost\'s specifications.', 'varnish-http-purge' ),
344
  );
345
  } else {
346
+ $return = array(
347
  'icon' => 'awesome',
348
  'message' => __( 'Your server IP setup looks good.', 'varnish-http-purge' ),
349
  );
350
  }
351
 
352
  return $return;
353
+ }
354
 
355
  /**
356
  * Server Details
357
  *
358
  * Includes nginx, hhvm, cloudflare, and more
359
  *
360
+ * @since 4.4.0.
361
+ *
362
+ * @access public
363
+ * @static
364
+ * @param mixed $headers - headers from wp_remote_get
365
+ * @return array
366
  */
367
+ public static function server_results( $headers ) {
368
 
 
369
  $return = array();
370
 
371
  if ( isset( $headers['Server'] ) ) {
372
+ // Apache.
373
+ if ( strpos( $headers['Server'], 'Apache' ) !== false && strpos( $headers['Server'], 'cloudflare' ) === false ) {
374
+ $return['Apache'] = array(
375
  'icon' => 'awesome',
376
+ 'message' => __( 'Your server is running Apache.', 'varnish-http-purge' ),
377
  );
378
  }
379
 
380
+ // nginx.
381
+ if ( strpos( $headers['Server'], 'nginx' ) !== false && strpos( $headers['Server'], 'cloudflare' ) === false ) {
382
+ $return['Nginx'] = array(
383
  'icon' => 'awesome',
384
+ 'message' => __( 'Your server is running Nginx.', 'varnish-http-purge' ),
385
  );
386
  }
387
+
388
+ // Cloudflare.
389
+ if ( strpos( $headers['Server'], 'cloudflare' ) !== false ) {
390
+ $return['CloudFlare'] = array(
391
  'icon' => 'warning',
392
  'message' => __( 'CloudFlare has been detected. Make sure you configure WordPress properly by adding your Varnish IP and to flush the CloudFlare cache if you see inconsistencies.', 'varnish-http-purge' ),
393
  );
394
  }
395
 
396
+ // HHVM: Note, WP is dropping support.
397
+ if ( isset( $headers['X-Powered-By'] ) && strpos( $headers['X-Powered-By'], 'HHVM' ) !== false ) {
398
+ $return['HHVM'] = array(
399
+ 'icon' => 'notice',
400
  'message' => __( 'You are running HHVM instead of PHP. While that is compatible with Varnish, you should consider PHP 7. WordPress will cease support for HHVM in 2018.', 'varnish-http-purge' ),
401
  );
402
  }
403
 
404
+ if ( strpos( $headers['Server'], 'Pagely' ) !== false ) {
405
+ $return['Pagely'] = array(
 
406
  'icon' => 'good',
407
  'message' => __( 'This site is hosted on Pagely. The results of this scan may not be accurate.', 'varnish-http-purge' ),
408
  );
410
  }
411
 
412
  if ( isset( $headers['X-hacker'] ) ) {
413
+ $return['WordPress.com'] = array(
414
  'icon' => 'bad',
415
  'message' => __( 'This site is hosted on WordPress.com. The results of this scan may not be accurate.', 'varnish-http-purge' ),
416
  );
417
  }
418
+
419
+ if ( isset( $headers['X-Backend'] ) && strpos( $headers['X-Backend'], 'wpaas_web_' ) !== false ) {
420
+ $return['GoDaddy'] = array(
421
  'icon' => 'good',
422
  'message' => __( 'This site is hosted on GoDaddy. The results of this scan may not be accurate.', 'varnish-http-purge' ),
423
  );
427
  }
428
 
429
  /**
 
 
430
  * Results on GZIP
431
  *
432
  * @since 4.4.0
433
+ *
434
+ * @access public
435
+ * @static
436
+ * @param mixed $headers - headers from wp_remote_get.
437
+ * @return array
438
  */
439
+ public static function gzip_results( $headers ) {
440
 
 
441
  $return = false;
442
 
443
+ // GZip.
444
+ if ( strpos( $headers['Content-Encoding'], 'gzip' ) !== false || ( isset( $headers['Vary'] ) && strpos( $headers['Vary'], 'gzip' ) !== false ) ) {
445
+ $return = array(
446
  'icon' => 'good',
447
  'message' => __( 'Your site is compressing content and making the internet faster.', 'varnish-http-purge' ),
448
  );
449
  }
450
 
451
+ // Fastly.
452
+ if ( strpos( $headers['Content-Encoding'], 'Fastly' ) !== false ) {
453
+ $return = array(
454
  'icon' => 'good',
455
  'message' => __( 'Fastly is speeding up your site. Remember to empty all caches in all locations when necessary.', 'varnish-http-purge' ),
456
  );
460
  }
461
 
462
  /**
 
 
463
  * Cookies break Varnish. Sometimes.
464
  *
465
  * @since 4.4.0
466
+ *
467
+ * @access public
468
+ * @static
469
+ * @param mixed $headers - headers from wp_remote_get.
470
+ * @return array
471
  */
472
+ public static function cookie_results( $headers ) {
473
 
474
+ $return = array();
475
+ $almost = array();
476
 
477
  // Early check. If there are no cookies, skip!
478
+ if ( ! isset( $headers['Set-Cookie'] ) ) {
479
+ $return['No Cookies'] = array(
480
+ 'icon' => 'awesome',
481
+ 'message' => __( 'No active cookies have been detected on your site. You may safely ignore any warnings about cookies set by plugins or themes, as your server has properly accounted for them.', 'varnish-http-purge' ),
482
+ );
483
+ } else {
484
+ // We have at least one cookie, so let's set this now.
485
+ $return['Cookies Found'] = array(
486
+ 'icon' => 'warning',
487
+ 'message' => __( 'Cookies have been detected. Unless your caching service is configured properly for the specific cookies, it may not cache properly. Please contact your webhost or administrator with information about the cookies found.', 'varnish-http-purge' ),
488
+ );
 
489
 
490
+ // Let's check our known bad cookies.
491
+ $request = wp_remote_get( 'https://varnish-http-purge.objects-us-east-1.dream.io/cookies.json' );
492
 
493
+ if ( is_wp_error( $request ) ) {
494
+ return $return; // Bail if we can't hit the server.
 
495
  }
496
 
497
+ $body = wp_remote_retrieve_body( $request );
498
+ $cookies = json_decode( $body );
499
+
500
+ if ( empty( $cookies ) ) {
501
+ if ( WP_DEBUG ) {
502
+ $return['cookie-error'] = array(
503
+ 'icon' => 'warning',
504
+ 'message' => __( 'Error: Cookie data cannot be loaded.', 'varnish-http-purge' ),
505
+ );
506
+ }
507
+ return $return; // Bail if the data was empty for some reason.
 
508
  }
509
 
510
+ foreach ( $cookies as $cookie => $info ) {
511
+ $has_cookie = false;
512
+
513
+ // If cookies are an array, scan the whole thing. Otherwise, we can use strpos.
514
+ if ( is_array( $headers['Set-Cookie'] ) ) {
515
+ if ( in_array( $info->cookie, $headers['Set-Cookie'], true ) ) {
516
+ $has_cookie = true;
517
+ }
518
+ } else {
519
+ $strpos = strpos( $headers['Set-Cookie'], $info->cookie );
520
+ if ( false !== $strpos ) {
521
+ $has_cookie = true;
522
+ }
523
+ }
524
+
525
+ if ( $has_cookie ) {
526
+ $return[ 'Cookie: ' . $cookie ] = array(
527
+ 'icon' => $info->type,
528
+ 'message' => $info->message,
529
+ );
530
+ }
531
  }
532
  }
533
 
540
  * Checking Age, Max Age, Cache Control, Pragma and more
541
  *
542
  * @since 4.4.0
543
+ *
544
+ * @access public
545
+ * @static
546
+ * @param mixed $headers - headers from wp_remote_get.
547
+ * @return array
548
  */
549
+ public static function cache_results( $headers ) {
550
 
551
  $return = array();
552
 
553
+ // Cache Control.
554
  if ( isset( $headers['Cache-Control'] ) ) {
555
 
556
+ if ( is_array( $headers['Cache Control'] ) ) {
557
+ $no_cache = array_search( 'no-cache', $headers['Cache-Control'], true );
558
+ $max_age = array_search( 'max-age=0', $headers['Cache-Control'], true );
559
  } else {
560
  $no_cache = strpos( $headers['Cache-Control'], 'no-cache' );
561
  $max_age = strpos( $headers['Cache-Control'], 'max-age=0' );
562
  }
563
 
564
+ // No-Cache Set.
565
+ if ( $no_cache ) {
566
+ $return['No Cache Header'] = array(
567
  'icon' => 'bad',
568
  'message' => __( 'The header Cache-Control is returning "no-cache", which means visitors will never get cached pages.', 'varnish-http-purge' ),
569
  );
570
  }
571
 
572
+ // Max-Age is 0.
573
+ if ( $max_age ) {
574
  $return['max_age'] = array(
575
  'icon' => 'bad',
576
  'message' => __( 'The header Cache-Control is returning "max-age=0", which means a page can be no older than 0 seconds before it needs to regenerate the cache.', 'varnish-http-purge' ),
578
  }
579
  }
580
 
581
+ // Age Headers.
582
+ if ( ! isset( $headers['Age'] ) ) {
583
  $return['Age Headers'] = array(
584
  'icon' => 'bad',
585
+ 'message' => __( 'Your domain does not report an "Age" header, making it impossible to determine if the page is actually serving from cache.', 'varnish-http-purge' ),
586
  );
587
+ } elseif ( ( $headers['Age'] <= 0 || 0 === $headers['Age'] ) && (bool) strtotime( $headers['Age'] ) === false ) {
588
+ $age_header = (int) $headers['Age']; // a number from 0 to infinity.
589
  $return['Age Headers'] = array(
590
+ // translators: %s is a number indicating how many seconds old the content is.
591
+ 'message' => sprintf( __( 'The "Age" header is returning %s, which means it is not properly caching. Either this URL is intentionally excluded from caching, or a theme or plugin is instructing WordPress not to cache.', 'varnish-http-purge' ), $age_header ),
592
  'icon' => 'warning',
 
593
  );
594
+ } elseif ( (bool) strtotime( $headers['Age'] ) && time() <= strtotime( $headers['Age'] ) ) {
595
  $return['Age Headers'] = array(
596
  'icon' => 'bad',
597
+ 'message' => __( 'The "Age" header is set to an invalid time, which will result in incorrect caching.', 'varnish-http-purge' ),
598
  );
599
  } else {
600
  $return['Age Headers'] = array(
601
+ 'icon' => 'awesome',
602
  'message' => __( 'Your site is returning proper "Age" headers.', 'varnish-http-purge' ),
603
  );
604
  }
605
 
606
+ // Pragma.
607
+ if ( isset( $headers['Pragma'] ) && strpos( $headers['Pragma'], 'no-cache' ) !== false ) {
608
  $return['Pragma Headers'] = array(
609
  'icon' => 'bad',
610
+ 'message' => __( 'The header Pragma is set to to "no-cache" which means visitors will never get cached content.', 'varnish-http-purge' ),
611
  );
612
  }
613
 
614
+ // X-Cache.
615
+ if ( isset( $headers['X-Cache-Status'] ) && strpos( $headers['X-Cache-Status'], 'MISS' ) !== false ) {
616
  $return['X-Cache Satus'] = array(
617
  'icon' => 'bad',
618
+ 'message' => __( 'X-Cache missed, which means your site was not able to serve this page as cached.', 'varnish-http-purge' ),
619
  );
620
  }
621
 
622
+ // Mod-PageSpeed.
623
  if ( isset( $headers['X-Mod-Pagespeed'] ) ) {
624
+ if ( strpos( $headers['X-Cacheable'], 'YES:Forced' ) !== false ) {
625
  $return['Mod Pagespeed'] = array(
626
  'icon' => 'good',
627
+ 'message' => __( 'Mod Pagespeed is active and configured to work properly with caching services.', 'varnish-http-purge' ),
628
  );
629
  } else {
630
  $return['Mod Pagespeed'] = array(
631
  'icon' => 'bad',
632
+ 'message' => __( 'Mod Pagespeed is active but your caching headers may not be right. This may be a false negative if other parts of your site are overwriting headers. Fix all other errors listed, then come back to this. If you are still having errors, you will need to look into using .htaccess or Nginx to override the Pagespeed headers.', 'varnish-http-purge' ),
633
  );
634
  }
635
  }
643
  * Themes known to be problematic
644
  *
645
  * @since 4.5.0
646
+ *
647
+ * @access public
648
+ * @static
649
+ * @return array
650
  */
651
+ public static function bad_themes_results() {
652
 
653
  $return = array();
654
  $request = wp_remote_get( 'https://varnish-http-purge.objects-us-east-1.dream.io/themes.json' );
655
 
656
+ if ( is_wp_error( $request ) ) {
657
+ if ( WP_DEBUG ) {
658
+ $return['Theme Check'] = array(
659
+ 'icon' => 'warning',
660
+ 'message' => __( 'Error: Theme data cannot be loaded.', 'varnish-http-purge' ),
661
+ );
662
+ }
663
+ return $return; // Bail early.
664
  }
665
 
666
+ $body = wp_remote_retrieve_body( $request );
667
+ $themes = json_decode( $body );
668
 
669
+ if ( empty( $themes ) ) {
670
  if ( WP_DEBUG ) {
671
+ $return['Theme Check'] = array(
672
+ 'icon' => 'warning',
673
+ 'message' => __( 'Error: Theme data was empty.', 'varnish-http-purge' ),
674
+ );
675
  }
676
+ return $return; // Bail early.
 
677
  }
678
 
679
+ // Check all the themes. If one of the questionable ones are active, warn.
680
  foreach ( $themes as $theme => $info ) {
681
  $my_theme = wp_get_theme( $theme );
 
 
682
  if ( $my_theme->exists() ) {
683
+ $active = ( get_template() === $theme ) ? true : false;
684
+ $message = $info->message . ' (';
685
+ $warning = $info->type;
686
+
687
+ if ( $active ) {
688
+ $message .= __( 'Active', 'varnish-http-purge' );
689
+ } else {
690
+ $message .= __( 'Inactive', 'varnish-http-purge' );
691
+ $warning = 'notice';
692
+ }
693
+ $message .= ')';
694
+
695
+ $return[ 'Theme: ' . ucfirst( $theme ) ] = array(
696
+ 'icon' => $warning,
697
+ 'message' => $message,
698
+ );
699
  }
700
  }
701
 
702
+ // If no questionable themes are found, let the user know with a success message.
703
+ if ( empty( $return ) ) {
704
+ $return['Theme Check'] = array(
705
+ 'icon' => 'good',
706
+ 'message' => __( 'No installed themes were found on the known conflicts list.', 'varnish-http-purge' ),
707
+ );
708
+ }
709
+
710
  return $return;
711
  }
712
 
716
  * Plugins known to be problematic
717
  *
718
  * @since 4.5.0
719
+ *
720
+ * @access public
721
+ * @static
722
+ * @return array
723
  */
724
+ public static function bad_plugins_results() {
725
 
726
  $return = array();
727
  $messages = array(
728
  'incompatible' => __( 'This plugin has unexpected results with caching, making not function properly.', 'varnish-http-purge' ),
729
  'translation' => __( 'Translation plugins that use cookies and/or sessions prevent most server side caching from running properly.', 'varnish-http-purge' ),
730
  'sessions' => __( 'This plugin uses sessions, which conflicts with server side caching.', 'varnish-http-purge' ),
731
+ 'cookies' => __( 'This plugin uses cookies, which may prevent server side caching.', 'varnish-http-purge' ),
732
  'cache' => __( 'This type of caching plugin does not work well with server side caching.', 'varnish-http-purge' ),
733
  'ancient' => __( 'This plugin is not up to date with WordPress best practices and breaks caching.', 'varnish-http-purge' ),
734
  'removed' => __( 'This plugin was removed from WordPress.org and we do not recommend it\'s use.', 'varnish-http-purge' ),
735
+ 'maybe' => __( 'This plugin is usually fine, but may be configured in a way that breaks caching. Please resolve all other errors. If this is the only one left, and caching is running, you may safely ignore this message.', 'varnish-http-purge' ),
736
  );
 
737
 
738
+ $request = wp_remote_get( 'https://varnish-http-purge.objects-us-east-1.dream.io/plugins.json' );
739
+ if ( is_wp_error( $request ) ) {
740
  if ( WP_DEBUG ) {
741
+ $return['Plugin Check'] = array(
742
+ 'icon' => 'warning',
743
+ 'message' => __( 'Error: Plugin data cannot be loaded.', 'varnish-http-purge' ),
744
+ );
745
  }
746
+ return $return; // Bail early.
747
  }
748
 
749
  $body = wp_remote_retrieve_body( $request );
750
+ $plugins = json_decode( $body );
751
 
752
+ if ( empty( $plugins ) ) {
753
+ if ( WP_DEBUG ) {
754
+ $return['Plugin Check'] = array(
755
+ 'icon' => 'warning',
756
+ 'message' => __( 'Error: Plugin data was empty.', 'varnish-http-purge' ),
757
+ );
758
+ }
759
+ return $return; // Bail early.
760
  }
761
 
762
+ // Check all the plugins. If one of the questionable ones are active, warn.
763
  foreach ( $plugins as $plugin => $info ) {
764
+ if ( file_exists( plugin_dir_path( __DIR__ ) . $info->path ) ) {
765
+ $message = $messages[ $info->reason ];
766
+ $warning = 'notice';
767
+ $status = __( 'Inactive', 'varnish-http-purge' );
768
+
769
+ // If the plugin is inactive, change the warning.
770
+ if ( is_plugin_active( $info->path ) ) {
771
+ $warning = $info->type;
772
+ $status = __( 'Active', 'varnish-http-purge' );
773
+ }
774
+
775
+ $return[ 'Plugin: ' . ucfirst( $plugin ) ] = array(
776
+ 'icon' => $warning,
777
+ 'message' => $message . ' (' . $status . ')',
778
+ );
779
  }
780
  }
781
 
782
+ // If no questionable plugins are found, let the user know with a success message.
783
+ if ( empty( $return ) ) {
784
+ $return['Plugin Check'] = array(
785
+ 'icon' => 'good',
786
+ 'message' => __( 'No installed plugins were found on the known conflicts list.', 'varnish-http-purge' ),
787
+ );
788
+ }
789
+
790
  return $return;
791
  }
792
 
794
  * Get all the results
795
  *
796
  * Collect everything, get all the data spit it out.
797
+ *
798
  * @since 4.4.0
799
+ *
800
+ * @access public
801
+ * @static
802
+ * @param mixed $headers - results from wp_remote_get.
803
+ * @param mixed $remote_ip - IP address detected.
804
+ * @param mixed $varniship - IP address defined.
805
+ * @return array
806
  */
807
+ public static function get_all_the_results( $headers, $remote_ip, $varniship ) {
808
  $output = array();
 
 
809
 
810
+ // Preface with Debugging Warning.
811
+ if ( self::devmode_check() ) {
812
+ $output['Development Mode'] = array(
813
+ 'icon' => 'notice',
814
+ 'message' => __( 'NOTICE: Caching is disabled while Development Mode is active.', 'varnish-http-purge' ),
815
+ );
816
+ }
817
+
818
+ // Basic Checks.
819
+ $output['Cache Service'] = self::varnish_results( $headers );
820
+ $output['Remote IP'] = self::remote_ip_results( $remote_ip, $varniship );
821
 
822
+ // Server Results.
823
+ $server_results = self::server_results( $headers, $remote_ip, $varniship );
824
+ $output = array_merge( $output, $server_results );
825
 
826
+ // Cache Results.
827
+ $cache_results = self::cache_results( $headers );
828
+ $output = array_merge( $output, $cache_results );
829
 
830
+ // Cookies.
831
+ $cookie_results = self::cookie_results( $headers );
832
+ $output = array_merge( $output, $cookie_results );
833
 
834
+ // Plugins that don't play nicely with Varnish.
835
  $bad_plugins_results = self::bad_plugins_results();
836
  $output = array_merge( $output, $bad_plugins_results );
837
 
838
+ // Themes that don't play nicely with Varnish.
839
+ $bad_themes_results = self::bad_themes_results();
840
+ $output = array_merge( $output, $bad_themes_results );
841
+
842
  return $output;
843
  }
 
844
  }
845
 
846
+ $varnish_debug = new VarnishDebug();
readme.txt CHANGED
@@ -1,9 +1,9 @@
1
  = Varnish HTTP Purge =
2
- Contributors: Ipstenu, mikeschroder, techpriester
3
  Tags: varnish, purge, cache
4
  Requires at least: 4.7
5
  Tested up to: 4.9
6
- Stable tag: 4.5.2
7
  Requires PHP: 5.6
8
 
9
  Automatically empty Varnish Cache when content on your site is modified.
@@ -14,9 +14,13 @@ Automatically empty Varnish Cache when content on your site is modified.
14
 
15
  The Varnish HTTP Purge plugin sends a request to delete (aka flush) the cached data of a page or post every time it it modified. This happens when updating, publishing, commenting on, or deleting an post, and when changing themes.
16
 
17
- In addition, it provides debugging tools to help you determine how effective your site setup is with Varnish. In order to provide the most up to date compatibility information, this tool contacts a service hosted on DreamObjects. [Public information about this service is available on DreamObjects](https://varnish-http-purge.objects-us-east-1.dream.io/readme.txt). The service is <em>ONLY</em> accessed when using the Varnish Debugging tool.
18
 
19
- Not all page caches are deleted every time, depending on your Varnish configuration. For example, when a post, page, or custom post type is edited, or a new comment is added, <em>only</em> the following pages will purge:
 
 
 
 
20
 
21
  * The front page
22
  * The post/page edited
@@ -33,27 +37,35 @@ Plugins can hook into the purge actions as well, to filter their own events to t
33
 
34
  On a multisite network using subfolders, only <strong>network admins</strong> can purge the main site. This is a security decision, as emptying the cache too often can be computationally expensive and cause server outages for a network.
35
 
36
- = WP CLI =
37
-
38
- * `wp varnish purge` - Flush the entire cache
39
- * `wp varnish debug` - Help for debugging how well Varnish is (or isn't) working
40
 
41
- = Debugging =
42
 
43
- If you're working on a site and need to turn off caching, add this to your wp-config file: `define( 'VHP_DEBUG', true );`
 
44
 
45
  That will break cache on page loads. It is _not_ recommended for production!
46
 
47
- = Requirements =
48
 
49
- * Pretty Permalinks enabled
50
- * Varnish 3.x or higher
 
51
 
52
  = Privacy Policy =
53
 
54
  By default, no data is tracked. If you use the site scanner/debugging tool, your domain and IP address will access [a remote service hosted on DreamObjects](https://varnish-http-purge.objects-us-east-1.dream.io/readme.txt). No personally identifying transaction data is recorded or stored, only overall usage. IP addresses of the website making the request may be recorded by the service, but there is no way to access them and use it to correspond with individuals or processes.
55
 
56
- Use of this service is required for the debugging tool, in order to provide up to date compatibility checks on plugins and themes that may conflict with running a server based cache (such as Varnish or Nginx) without needing to update the plugin every day.
 
 
 
 
 
 
 
 
 
57
 
58
  == Frequently Asked Questions ==
59
 
@@ -65,13 +77,9 @@ If you have code patches, [pull requests are welcome](https://github.com/Ipstenu
65
 
66
  No. This plugin tells your cache system when content is updated, and to delete the cached data at that time.
67
 
68
- = How does this plugin know what to delete? =
69
-
70
- When you update content on your site, like making a post or editing one, or someone leaving a comment, WordPress triggers a command on your server to purge (aka empty) the cache for any related pages, including the REST API.
71
-
72
  = Why doesn't the plugin automatically delete the whole cache? =
73
 
74
- Philosophy. There are many other plugins out there which will allow you to granularly select what pages should and should not be deleted on updates. With that in mind, the choice was made for decisions instead of options, and simplicity was the driving principle. The plugin decides what's best to delete on updates, and provides hooks for developers to use as needed.
75
 
76
  = Can I delete the entire cache? =
77
 
@@ -79,9 +87,9 @@ Yes! Click the 'Empty Cache' button on the "Right Now" Dashboard (see the screen
79
 
80
  If you don't see a button, then your account doesn't have the appropriate permissions. Only administrators can empty the entire cache. In the case of a subfolder multisite network, only the <em>network</em> admins can empty the cache for the primary site.
81
 
82
- = Will the plugin delete my cache when I edit my theme or plugins? =
83
 
84
- No. WordPress can't detect file changes like that, and you really don't want it to. That would empty the cache every time you edited any file, which would cause your site to become unstable. You will need to use the Empty Cache buttons when you're done editing your code.
85
 
86
  = Does every WordPress plugin and theme work with Varnish? =
87
 
@@ -93,15 +101,29 @@ Yes! [Full documentation can be found on Custom Filters in the wiki](https://git
93
 
94
  = Can I turn off caching? =
95
 
96
- Yes and no. Remember, the plugin isn't doing the caching so it really depends on your server setup. You can set the following define in your `wp-config.php` file to attempt and disable caching, however this may not work on all setups: `define( 'VHP_DEBUG', true );`
97
 
98
- = How can I tell if everything's caching? =
 
 
 
 
99
 
100
- From your WordPress Dashboard, go to <em>Tools</em> -> <em>Varnish Debugging</em>. There a page will auto-scan your front page and report back any issues found. This includes any known problematic plugins. You can use it to scan any URL on your domain (but ONLY on your own domain).
101
 
102
- = Why doesn't the debug page autoload anymore? =
103
 
104
- The scan files were off-loaded to a service to allow for more frequent updates without having to require people to update the plugin. In order to ensure no one is scanned without consent, the auto-scanning was disabled.
 
 
 
 
 
 
 
 
 
 
105
 
106
  = Why is nothing caching when I use PageSpeed? =
107
 
@@ -113,11 +135,15 @@ If you're using nginx, it's `pagespeed ModifyCachingHeaders off;`
113
 
114
  When you use CloudFlare or any other similar service, you've put a proxy in front of the Varnish proxy. In general this isn't a bad thing, though it can introduce some network latency (that means your site may run slower because it has to go through multiple layers to get to the content). The problem arises when WordPress tries to send the purge request to your domain name and, with a proxy, that means the proxy service and not your website.
115
 
116
- On single-site, you can edit this via the Tools -> Varnish Status page. On Multisite, you'll need to add the following to your wp-config.php file: `define('VHP_VARNISH_IP','123.45.67.89');`
 
 
 
 
117
 
118
- Replace "123.45.67.89" with the IP of your <em>Varnish Server</em> (not CloudFlare, Varnish). <em>DO NOT</em> put in http in this define.
119
 
120
- If you want to use WP-CLI, you can set an option in the database. This will NOT take precedence over the define, it's just there to let hosts who are using something like wp-cli do this for you in an automated fashion: `wp option update vhp_varnish_ip 123.45.67.890`
121
 
122
  = How do I find my Varnish IP? =
123
 
@@ -133,19 +159,15 @@ If your webhost set up Varnish, you may need to ask them for the specifics if th
133
 
134
  Multiple IPs are not supported at this time.
135
 
136
- = Will you fix my site? =
137
-
138
- No. I will try to point you towards solving it on your own. This may mean you have to decide if using a specific plugin or theme is worth an imperfect cache.
139
-
140
  = What version of Varnish is supported? =
141
 
142
  This was built and tested on Varnish 3.x. While it is reported to work on 2.x and 4.x, it is only supported on v3 at this time.
143
 
144
  = Does this work with Nginx caching? =
145
 
146
- It can, if you configured nginx caching to respect the curl PURGE request. If this doesn't work, I recommend setting your Varnish IP to `localhost` as Nginx requires a service control installed for the IP address to work.
147
 
148
- = Will you write my cache rules for me? =
149
 
150
  This is a question beyond the support of plugin. I do not have the resources available to offer any configuration help. Here are some basic gotchas to be aware of:
151
 
@@ -166,6 +188,20 @@ This plugin is installed by default for _all_ DreamPress installs on DreamHost,
166
 
167
  == Changelog ==
168
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
169
  = 4.5.2 =
170
 
171
  * June 2018
@@ -178,7 +214,7 @@ This plugin is installed by default for _all_ DreamPress installs on DreamHost,
178
  * Add carrot icon to collapsed (mobile) toolbar
179
  * Better button hiding
180
  * Fixed a stupid argument issue with flushing memcached and I should have known better but oh well
181
- * FAQ update re nginx
182
 
183
  = 4.5.0 =
184
 
@@ -191,12 +227,15 @@ This plugin is installed by default for _all_ DreamPress installs on DreamHost,
191
  == Screenshots ==
192
 
193
  1. Purge button on Right Now (Dashboard Admin)
194
- 2. Purge button on Toolbar
195
- 3. Scanner results
196
- 4. Change Varnish IP address
 
 
 
197
 
198
  == Upgrade Notice ==
199
 
200
  = 4.5.0 =
201
 
202
- As of this release, the Varnish debugger uses remote data to collect a list of cookies, plugins, and themes known to conflict with Varnish. This will reduce the need to update the plugin for informational changes only. [Public information about this service is available on DreamObjects](https://varnish-http-purge.objects-us-east-1.dream.io/readme.txt).
1
  = Varnish HTTP Purge =
2
+ Contributors: Ipstenu, mikeschroder, techpriester, danielbachhuber
3
  Tags: varnish, purge, cache
4
  Requires at least: 4.7
5
  Tested up to: 4.9
6
+ Stable tag: 4.6.0
7
  Requires PHP: 5.6
8
 
9
  Automatically empty Varnish Cache when content on your site is modified.
14
 
15
  The Varnish HTTP Purge plugin sends a request to delete (aka flush) the cached data of a page or post every time it it modified. This happens when updating, publishing, commenting on, or deleting an post, and when changing themes.
16
 
17
+ In addition, it provides debugging tools to help you determine how effective your site setup is with Varnish. In order to provide the most up to date compatibility information, this tool contacts a service hosted on DreamObjects. [Public information about this service is available on DreamObjects](https://varnish-http-purge.objects-us-east-1.dream.io/readme.txt). The service is <em>ONLY</em> accessed when using the Varnish Debugging tool to check if Caching is working properly.
18
 
19
+ = How it Works =
20
+
21
+ When content on a site is updated by WordPress, the plugin reaches out to the Varnish service with the URL of the page, requesting the cache be deleted.
22
+
23
+ Not all page are deleted from the cache on every change. For example, when a post, page, or custom post type is edited, or a new comment is added, <em>only</em> the following pages will purge:
24
 
25
  * The front page
26
  * The post/page edited
37
 
38
  On a multisite network using subfolders, only <strong>network admins</strong> can purge the main site. This is a security decision, as emptying the cache too often can be computationally expensive and cause server outages for a network.
39
 
40
+ = Development Mode =
 
 
 
41
 
42
+ If you're working on a site and need to turn off caching in one of two ways:
43
 
44
+ 1. Add `define( 'VHP_DEVMODE', true );` to your `wp-config.php` file
45
+ 2. Go to Varnish -> Settings and enable debug mode for 24 hours at a time
46
 
47
  That will break cache on page loads. It is _not_ recommended for production!
48
 
49
+ = WP CLI =
50
 
51
+ * `wp varnish purge` - Flush the entire cache
52
+ * `wp varnish debug [<url>]` - Help for debugging how well Varnish is (or isn't) working
53
+ * `wp varnish devmode [<activate|deactivate|toggle>` - Change development mode state
54
 
55
  = Privacy Policy =
56
 
57
  By default, no data is tracked. If you use the site scanner/debugging tool, your domain and IP address will access [a remote service hosted on DreamObjects](https://varnish-http-purge.objects-us-east-1.dream.io/readme.txt). No personally identifying transaction data is recorded or stored, only overall usage. IP addresses of the website making the request may be recorded by the service, but there is no way to access them and use it to correspond with individuals or processes.
58
 
59
+ Use of this service is required for the cache checking in order to provide up to date compatibility checks on plugins and themes that may conflict with running a server based cache (such as Varnish or Nginx) without needing to update the plugin every day.
60
+
61
+ == Installation ==
62
+
63
+ No special instructions apply. If you have a 3rd party proxy service (such as Sucuri or Cloudflare) you will need to add a Varnish IP address on the <em>Varnish -> Settings</em> page.
64
+
65
+ = Requirements =
66
+
67
+ * Pretty Permalinks enabled
68
+ * Varnish 3.x or higher
69
 
70
  == Frequently Asked Questions ==
71
 
77
 
78
  No. This plugin tells your cache system when content is updated, and to delete the cached data at that time.
79
 
 
 
 
 
80
  = Why doesn't the plugin automatically delete the whole cache? =
81
 
82
+ By design, this plugin embraces decisions, not options, as well as simplicity. Emptying too much of a cache on every change can slow a server down. In addition, users generally want things to 'just work.' With that in mind, this plugin determines what's best to delete on updates, and provides hooks for developers to use as needed.
83
 
84
  = Can I delete the entire cache? =
85
 
87
 
88
  If you don't see a button, then your account doesn't have the appropriate permissions. Only administrators can empty the entire cache. In the case of a subfolder multisite network, only the <em>network</em> admins can empty the cache for the primary site.
89
 
90
+ = Will the plugin delete my cache when I edit files on the server? =
91
 
92
+ No. WordPress can't detect those file changes so it can't tell Varnish what to do. You will need to use the Empty Cache buttons when you're done editing your code.
93
 
94
  = Does every WordPress plugin and theme work with Varnish? =
95
 
101
 
102
  = Can I turn off caching? =
103
 
104
+ The plugin itself does not perform caching, but you can use development mode to have WordPress tell Varnish not to serve cached content. In order to do this, you must enter development mode. There are three ways to do this:
105
 
106
+ 1. Chose 'Pause Cache (24hrs)' from the Cache dropdown menu in your toolbar
107
+
108
+ 2. Go to Varnish -> Settings and enable development mode
109
+
110
+ 3. Add `define( 'VHP_DEVMODE', true );` to your `wp-config.php` file
111
 
112
+ The first two options will enable development mode for 24 hours. If you're working on long term development, you can should use the define.
113
 
114
+ It is _not_ recommended you use development mode on production sites for extended periods of time, as it _will_ will slow your site down and lose all the benefits of caching in the first place.
115
 
116
+ = Why don't I have access to development mode? =
117
+
118
+ Due to the damage this can cause a site, access is limited to admins only. In the case of a multisite network, only <em>Network Admins</em> can disable caching.
119
+
120
+ = Why do I still see cached content in development mode? =
121
+
122
+ Remember, the plugin isn't doing the caching itself. While development mode is on, your server will actually continue to cache content but WordPress will tell it not to use the cached content. That means files that exist outside of WordPress (like CSS or images) will still be cached and _may_ serve cached content. The plugin does its best to add a No Cache parameter to javascript and CSS, however if a theme or plugin _doesn't_ use proper WordPress enqueues, then their content will be shown cached.
123
+
124
+ = How can I tell if everything's caching? =
125
+
126
+ From your WordPress Dashboard, go to <em>Varnish > Check Caching</em>. There a page will auto-scan your front page and report back any issues found. This includes any known problematic plugins. You can use it to scan any URL on your domain.
127
 
128
  = Why is nothing caching when I use PageSpeed? =
129
 
135
 
136
  When you use CloudFlare or any other similar service, you've put a proxy in front of the Varnish proxy. In general this isn't a bad thing, though it can introduce some network latency (that means your site may run slower because it has to go through multiple layers to get to the content). The problem arises when WordPress tries to send the purge request to your domain name and, with a proxy, that means the proxy service and not your website.
137
 
138
+ On single-site, you can edit this via the <em>Varnish > Check Caching</em> page. On Multisite, you'll need to add the following to your wp-config.php file: `define('VHP_VARNISH_IP','123.45.67.89');`
139
+
140
+ Replace "123.45.67.89" with the IP of your <em>Varnish Server</em> (not CloudFlare, Varnish). **DO NOT** put http in this define.
141
+
142
+ If you want to use WP-CLI, you can set an option in the database. This will not take precedence over the define, and exists for people who want to use automation tools: `wp option update vhp_varnish_ip 123.45.67.890`
143
 
144
+ = Why do I get a 503 or 504 error on every post update? =
145
 
146
+ Your Varnish IP address is probably wrong. Check the IP of your server and then the setting for your Varnish IP. If they're _not_ the same, that's likely why.
147
 
148
  = How do I find my Varnish IP? =
149
 
159
 
160
  Multiple IPs are not supported at this time.
161
 
 
 
 
 
162
  = What version of Varnish is supported? =
163
 
164
  This was built and tested on Varnish 3.x. While it is reported to work on 2.x and 4.x, it is only supported on v3 at this time.
165
 
166
  = Does this work with Nginx caching? =
167
 
168
+ It can, if you've configured nginx caching to respect the curl PURGE request. If this doesn't work, I recommend setting your Varnish IP to `localhost` as Nginx requires a service control installed for the IP address to work.
169
 
170
+ = What should my cache rules be? =
171
 
172
  This is a question beyond the support of plugin. I do not have the resources available to offer any configuration help. Here are some basic gotchas to be aware of:
173
 
188
 
189
  == Changelog ==
190
 
191
+ = 4.6.0 =
192
+
193
+ * July 2018
194
+ * Moved Varnish to it's own menu with a new custom icon (props Olesya)
195
+ * Add option to enable development for 24 hours (for super-admins only)
196
+ * Change debug mode to development mode and greatly improved overall
197
+ * Translation improvements
198
+ * Add new action hook for after a full purge (props @futtta)
199
+ * Change check for age-header to not require a second run (props @danielbachhuber)
200
+ * Confirm plugin and theme blacklist check (props @danielbachhuber)
201
+ * WP-CLI: add debug option to show all header output (props @danielbachhuber)
202
+ * WP-CLI: add debug option to grep content for known issues (props @danielbachhuber)
203
+ * WP-CLI: add new command to change devmode state
204
+
205
  = 4.5.2 =
206
 
207
  * June 2018
214
  * Add carrot icon to collapsed (mobile) toolbar
215
  * Better button hiding
216
  * Fixed a stupid argument issue with flushing memcached and I should have known better but oh well
217
+ * FAQ update re nginx
218
 
219
  = 4.5.0 =
220
 
227
  == Screenshots ==
228
 
229
  1. Purge button on Right Now (Dashboard Admin)
230
+ 2. Toolbar menu (with cache enabled)
231
+ 3. Toolbar menu (with cache disabled)
232
+ 4. Scanner results
233
+ 5. Change Varnish IP address
234
+ 6. Activate Dev Mode
235
+ 7. Dev Mode Warning (24 hour notice)
236
 
237
  == Upgrade Notice ==
238
 
239
  = 4.5.0 =
240
 
241
+ As of this release, the Varnish debugger uses remote data to collect a list of cookies, plugins, and themes known to conflict with Varnish. This will reduce the need to update the plugin for informational changes only. [Public information about this service is available on DreamObjects](https://varnish-http-purge.objects-us-east-1.dream.io/readme.txt).
settings.php ADDED
@@ -0,0 +1,475 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ *
4
+ * Settings Code
5
+ *
6
+ * @package varnish-http-purge
7
+ *
8
+ * Copyright 2016-2018 Mika Epstein (email: ipstenu@halfelf.org)
9
+ *
10
+ * This file is part of Varnish HTTP Purge, a plugin for WordPress.
11
+ *
12
+ * Varnish HTTP Purge is free software: you can redistribute it and/or modify
13
+ * it under the terms of the Apache License 2.0 license.
14
+ *
15
+ * Varnish HTTP Purge is distributed in the hope that it will be useful,
16
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18
+ */
19
+
20
+ if ( ! defined( 'ABSPATH' ) ) {
21
+ die();
22
+ }
23
+
24
+ /**
25
+ * Varnish Status Class
26
+ *
27
+ * @since 4.0
28
+ */
29
+ class VarnishStatus {
30
+
31
+ /**
32
+ * Construct
33
+ * Fires when class is constructed, adds init hook
34
+ *
35
+ * @since 4.0
36
+ */
37
+ public function __construct() {
38
+ add_action( 'admin_init', array( &$this, 'admin_init' ) );
39
+ add_action( 'admin_menu', array( &$this, 'admin_menu' ) );
40
+ }
41
+
42
+ /**
43
+ * Admin init Callback
44
+ *
45
+ * @since 4.0
46
+ */
47
+ public function admin_init() {
48
+ $this->register_settings();
49
+ $this->register_check_caching();
50
+ }
51
+
52
+ /**
53
+ * Admin Menu Callback
54
+ *
55
+ * @since 4.0
56
+ */
57
+ public function admin_menu() {
58
+ add_menu_page( __( 'Varnish HTTP Purge', 'varnish-http-purge' ), __( 'Varnish', 'varnish-http-purge' ), 'manage_options', 'varnish-page', array( &$this, 'settings_page' ), VarnishPurger::get_icon_svg( true, '#82878c' ), 75 );
59
+ add_submenu_page( 'varnish-page', __( 'Varnish HTTP Purge', 'varnish-http-purge' ), __( 'Settings', 'varnish-http-purge' ), 'manage_options', 'varnish-page', array( &$this, 'settings_page' ) );
60
+ add_submenu_page( 'varnish-page', __( 'Check Caching', 'varnish-http-purge' ), __( 'Check Caching', 'varnish-http-purge' ), 'manage_options', 'varnish-check-caching', array( &$this, 'check_caching_page' ) );
61
+ }
62
+
63
+ /**
64
+ * Register Settings
65
+ *
66
+ * @since 4.0.2
67
+ */
68
+ public function register_settings() {
69
+ if ( ! is_multisite() || current_user_can( 'manage_network' ) ) {
70
+ // Development Mode Settings.
71
+ register_setting( 'vhp-settings-devmode', 'vhp_varnish_devmode', array( &$this, 'settings_devmode_sanitize' ) );
72
+ add_settings_section( 'vhp-settings-devmode-section', __( 'Development Mode Settings', 'varnish-http-purge' ), array( &$this, 'options_settings_devmode' ), 'varnish-devmode-settings' );
73
+ add_settings_field( 'varnish_devmode', __( 'Development Mode', 'varnish-http-purge' ), array( &$this, 'settings_devmode_callback' ), 'varnish-devmode-settings', 'vhp-settings-devmode-section' );
74
+
75
+ // IP Settings.
76
+ register_setting( 'vhp-settings-ip', 'vhp_varnish_ip', array( &$this, 'settings_ip_sanitize' ) );
77
+ add_settings_section( 'vhp-settings-ip-section', __( 'Configure Custom IP', 'varnish-http-purge' ), array( &$this, 'options_settings_ip' ), 'varnish-ip-settings' );
78
+ add_settings_field( 'varnish_ip', __( 'Set Custom IP', 'varnish-http-purge' ), array( &$this, 'settings_ip_callback' ), 'varnish-ip-settings', 'vhp-settings-ip-section' );
79
+ }
80
+ }
81
+
82
+ /**
83
+ * Options Settings - Dev Mode
84
+ *
85
+ * @since 4.6
86
+ */
87
+ public function options_settings_devmode() {
88
+ ?>
89
+ <p><a name="#configuredevmode"></a><?php esc_html_e( 'In Development Mode, WordPress will prevent visitors from seeing cached content on your site. You can enable this for 24 hours, after which it will automatically disable itself. This will make your site run slower, so please use with caution.', 'varnish-http-purge' ); ?></p>
90
+ <p><?php echo wp_kses_post( __( 'If you need to activate development mode for extended periods of time, you can add <code>define( \'VHP_DEVMODE\', true );</code> in your wp-config file.', 'varnish-http-purge' ) ); ?></p>
91
+ <?php
92
+ }
93
+
94
+ /**
95
+ * Settings Dev Mode Callback
96
+ *
97
+ * @since 4.0
98
+ */
99
+ public function settings_devmode_callback() {
100
+
101
+ $devmode = get_site_option( 'vhp_varnish_devmode', VarnishPurger::$devmode );
102
+ $active = ( isset( $devmode['active'] ) ) ? $devmode['active'] : false;
103
+ $expire = current_time( 'timestamp' ) + DAY_IN_SECONDS;
104
+
105
+ ?>
106
+ <input type="hidden" name="vhp_varnish_devmode[expire]" value="<?php $expire; ?>" />
107
+ <input type="checkbox" name="vhp_varnish_devmode[active]" value="true" <?php checked( $active, true ); ?> />
108
+ <label for="vhp_varnish_devmode['active']">
109
+ <?php
110
+ if ( $active && isset( $devmode['expire'] ) ) {
111
+ $timestamp = date_i18n( get_site_option( 'date_format' ), $devmode['expire'] ) . ' @ ' . date_i18n( get_site_option( 'time_format' ), $devmode['expire'] );
112
+ // translators: %s is the time (in hours) until Development Mode expires.
113
+ echo sprintf( esc_html__( 'Development Mode is active until %s. After that, it will automatically disable the next time someone visits your site.', 'varnish-http-purge' ), esc_html( $timestamp ) );
114
+ } else {
115
+ esc_attr_e( 'Activate Development Mode', 'varnish-http-purge' );
116
+ }
117
+ ?>
118
+ </label>
119
+ <?php
120
+ }
121
+
122
+ /**
123
+ * Sanitization and validation for Dev Mode
124
+ *
125
+ * @param mixed $input - the input to be sanitized.
126
+ * @since 4.6.0
127
+ */
128
+ public function settings_devmode_sanitize( $input ) {
129
+
130
+ $output = array();
131
+ $expire = current_time( 'timestamp' ) + DAY_IN_SECONDS;
132
+ $set_message = __( 'Something has gone wrong!', 'varnish-http-purge' );
133
+ $set_type = 'error';
134
+
135
+ if ( empty( $input ) ) {
136
+ return; // do nothing.
137
+ } else {
138
+ $output['active'] = ( isset( $input['active'] ) || $input['active'] ) ? true : false;
139
+ $output['expire'] = ( isset( $input['expire'] ) && is_int( $input['expire'] ) ) ? $input['expire'] : $expire;
140
+ $set_message = ( $output['active'] ) ? __( 'Development Mode activated for the next 24 hours', 'varnish-http-purge' ) : __( 'Development Mode dectivated', 'varnish-http-purge' );
141
+ $set_type = 'updated';
142
+ }
143
+
144
+ // If it's true then we're activating so let's kill the cache.
145
+ if ( $output['active'] ) {
146
+ VarnishPurger::purge_url( VarnishPurger::the_home_url() . '/?vhp-regex' );
147
+ }
148
+
149
+ add_settings_error( 'vhp_varnish_devmode', 'varnish-devmode', $set_message, $set_type );
150
+ return $output;
151
+ }
152
+
153
+ /**
154
+ * Options Settings - IP Address
155
+ *
156
+ * @since 4.0
157
+ */
158
+ public function options_settings_ip() {
159
+ ?>
160
+ <p><a name="#configureip"></a><?php esc_html_e( 'There are cases when a custom Varnish IP Address will need to be set, in order to tell the plugin to empty the cache in a specific location. If you\'re using a CDN like Cloudflare or a Firewall Proxy like Sucuri, you will want to set this.', 'varnish-http-purge' ); ?></p>
161
+ <p><?php esc_html_e( 'Your Varnish IP is the IP address of the server where your caching service (i.e. Varnish or Nginx) is installed. It must be one of the IPs used by your cache service. If you use multiple IPs, or have customized your ACLs, you\'ll need to pick one that doesn\'t conflict with your other settings. For example, if you have Varnish listening on a public and private IP, pick the private. On the other hand, if you told Varnish to listen on 0.0.0.0 (i.e. "listen on every interface you can") you would need to check what IP you set your purge ACL to allow (commonly 127.0.0.1 aka localhost), and use that (i.e. 127.0.0.1).', 'varnish-http-purge' ); ?></p>
162
+ <p><?php esc_html_e( 'If your webhost set the service up for you, as is the case with DreamPress or WP Engine, ask them for the specifics if they don\'t have it documented. I\'ve listed the ones I know about here, however you should still check with them if you\'re not sure.', 'varnish-http-purge' ); ?></p>
163
+ <p><strong><?php esc_html_e( 'If you aren\'t sure what to do, contact your webhost or server admin before making any changes.', 'varnish-http-purge' ); ?></strong></p>
164
+ <ul>
165
+ <li><?php esc_html_e( 'DreamHost - Go into the Panel and click on the DNS settings for the domain. The entry for <em>resolve-to.domain</em> (if set) will be your cache server. If it\'s not set, then you don\'t need to worry about this at all. Example:', 'varnish-http-purge' ); ?> <code>resolve-to.www A 208.97.157.172</code></li>
166
+ </ul>
167
+ <?php
168
+ }
169
+
170
+ /**
171
+ * Settings IP Callback
172
+ *
173
+ * @since 4.0
174
+ */
175
+ public function settings_ip_callback() {
176
+
177
+ $disabled = false;
178
+ if ( false !== VHP_VARNISH_IP ) {
179
+ $disabled = true;
180
+ $varniship = VHP_VARNISH_IP;
181
+ } else {
182
+ $varniship = get_site_option( 'vhp_varnish_ip' );
183
+ }
184
+
185
+ echo '<input type="text" id="vhp_varnish_ip" name="vhp_varnish_ip" value="' . esc_attr( $varniship ) . '" size="25" ' . disabled( $disabled, true ) . '/>';
186
+ echo '<label for="vhp_varnish_ip">';
187
+
188
+ if ( $disabled ) {
189
+ esc_html_e( 'A Varnish IP has been defined in your wp-config file, so it is not editable here.', 'varnish-http-purge' );
190
+ } else {
191
+ esc_html_e( 'Example:', 'varnish-http-purge' );
192
+ echo '<code>123.45.67.89</code>';
193
+ }
194
+
195
+ echo '</label>';
196
+ }
197
+
198
+ /**
199
+ * Sanitization and validation for IP
200
+ *
201
+ * @param mixed $input - the input to be sanitized.
202
+ * @since 4.0
203
+ */
204
+ public function settings_ip_sanitize( $input ) {
205
+
206
+ $output = '';
207
+ $set_message = __( 'You have entered an invalid IP address.', 'varnish-http-purge' );
208
+ $set_type = 'error';
209
+
210
+ if ( empty( $input ) ) {
211
+ return; // do nothing.
212
+ } elseif ( filter_var( $input, FILTER_VALIDATE_IP ) ) {
213
+ $set_message = 'IP Updated.';
214
+ $set_type = 'updated';
215
+ $output = filter_var( $input, FILTER_VALIDATE_IP );
216
+ }
217
+
218
+ add_settings_error( 'vhp_varnish_ip', 'varnish-ip', $set_message, $set_type );
219
+ return $output;
220
+ }
221
+
222
+ /**
223
+ * Register Check Caching
224
+ *
225
+ * @since 4.0
226
+ */
227
+ public function register_check_caching() {
228
+ register_setting( 'varnish-http-purge-url', 'vhp_varnish_url', array( &$this, 'varnish_url_sanitize' ) );
229
+ add_settings_section( 'varnish-url-settings-section', __( 'Check Caching Status', 'varnish-http-purge' ), array( &$this, 'options_check_caching_scan' ), 'varnish-url-settings' );
230
+ add_settings_field( 'varnish_url', __( 'Check A URL On Your Site:', 'varnish-http-purge' ), array( &$this, 'check_caching_callback' ), 'varnish-url-settings', 'varnish-url-settings-section' );
231
+ }
232
+
233
+ /**
234
+ * Options Callback - URL Scanner
235
+ *
236
+ * @since 4.0
237
+ */
238
+ public function options_check_caching_scan() {
239
+ ?>
240
+ <p><?php esc_html_e( 'While it is impossible to detect all possible conflicts, this status page performs a check of the most common issues that prevents your site from caching properly. This feature is provided to help you in resolve potential conflicts on your own. When filing an issue with your web-host, we recommend you include the output in your ticket.', 'varnish-http-purge' ); ?></p>
241
+ <p>
242
+ <?php
243
+ // translators: %s is a link to the readme for the detection service.
244
+ printf( wp_kses_post( __( '<strong>This check uses <a href="%s">a remote service hosted on DreamObjects</a></strong>. The service used only for providing up to date compatibility checks on plugins and themes that may conflict with running a server based cache (such as Varnish or Nginx). No personally identifying information regarding persons running this check, nor the plugins and themes in use on this site will be transmitted. The bare minimum of usage information is collected, concerning only IPs and domains making requests of the service. If you do not wish to use this service, please do not use this service.', 'varnish-http-purge' ) ), 'https://varnish-http-purge.objects-us-east-1.dream.io/readme.txt' );
245
+ ?>
246
+ </p>
247
+ <?php
248
+
249
+ // If there's no post made, let's not...
250
+ // @codingStandardsIgnoreStart
251
+ if ( ! isset( $_REQUEST['settings-updated'] ) || ! $_REQUEST['settings-updated'] ) {
252
+ return;
253
+ }
254
+ // @codingStandardsIgnoreEnd
255
+
256
+ // Set icons.
257
+ $icons = array(
258
+ 'awesome' => '<span class="dashicons dashicons-heart" style="color:#46B450;"></span>',
259
+ 'good' => '<span class="dashicons dashicons-thumbs-up" style="color:#00A0D2;"></span>',
260
+ 'warning' => '<span class="dashicons dashicons-warning" style="color:#FFB900"></span>',
261
+ 'notice' => '<span class="dashicons dashicons-flag" style="color:#826EB4;">',
262
+ 'bad' => '<span class="dashicons dashicons-thumbs-down" style="color:#DC3232;"></span>',
263
+ );
264
+
265
+ // Get the base URL to start.
266
+ $url = esc_url( VarnishPurger::the_home_url() );
267
+ $varnishurl = get_site_option( 'vhp_varnish_url', $url );
268
+
269
+ // Is this a good URL?
270
+ $valid_url = VarnishDebug::is_url_valid( $varnishurl );
271
+ if ( 'valid' === $valid_url ) {
272
+ // Get the response and headers.
273
+ $remote_get = VarnishDebug::remote_get( $varnishurl );
274
+ $headers = wp_remote_retrieve_headers( $remote_get );
275
+
276
+ // Preflight checklist.
277
+ $preflight = VarnishDebug::preflight( $remote_get );
278
+
279
+ // Check for Remote IP.
280
+ $remote_ip = VarnishDebug::remote_ip( $headers );
281
+
282
+ // Get the Varnish IP.
283
+ if ( false !== VHP_VARNISH_IP ) {
284
+ $varniship = VHP_VARNISH_IP;
285
+ } else {
286
+ $varniship = get_site_option( 'vhp_varnish_ip' );
287
+ }
288
+ ?>
289
+
290
+ <h4>
291
+ <?php
292
+ // translators: %s is the URL someone asked to scan.
293
+ printf( esc_html__( 'Results for %s', 'varnish-http-purge' ), esc_url_raw( $varnishurl ) );
294
+ ?>
295
+ </h4>
296
+
297
+ <table class="wp-list-table widefat fixed posts">
298
+
299
+ <?php
300
+ // If we failed the preflight checks, we fail.
301
+ if ( ! $preflight['preflight'] ) {
302
+ ?>
303
+ <tr>
304
+ <td width="40px"><?php echo wp_kses_post( $icons['bad'] ); ?></td>
305
+ <td><?php echo wp_kses_post( $preflight['message'] ); ?></td>
306
+ </tr>
307
+ <?php
308
+ } else {
309
+ // We passed the checks, let's get the data!
310
+ $output = VarnishDebug::get_all_the_results( $headers, $remote_ip, $varniship );
311
+
312
+ foreach ( $output as $subject => $item ) {
313
+ if ( $item && is_array( $item ) ) {
314
+ ?>
315
+ <tr>
316
+ <td width="20px"><?php echo wp_kses_post( $icons[ $item['icon'] ] ); ?></td>
317
+ <td width="180px"><strong><?php echo wp_kses_post( $subject ); ?></strong></td>
318
+ <td><?php echo wp_kses_post( $item['message'] ); ?></td>
319
+ </tr>
320
+ <?php
321
+ }
322
+ }
323
+ }
324
+ ?>
325
+ </table>
326
+
327
+ <?php
328
+ if ( false !== $preflight['preflight'] ) {
329
+ ?>
330
+ <h4><?php esc_html_e( 'Technical Details', 'varnish-http-purge' ); ?></h4>
331
+ <table class="wp-list-table widefat fixed posts">
332
+ <?php
333
+ if ( ! empty( $headers[0] ) ) {
334
+ echo '<tr><td width="200px">&nbsp;</td><td>' . wp_kses_post( $headers[0] ) . '</td></tr>';
335
+ }
336
+ foreach ( $headers as $header => $key ) {
337
+ if ( '0' !== $header ) {
338
+ if ( is_array( $key ) ) {
339
+ $content = print_r( $key, true );
340
+ } else {
341
+ $content = wp_kses_post( $key );
342
+ }
343
+ echo '<tr><td width="200px" style="text-align:right;">' . wp_kses_post( ucfirst( $header ) ) . ':</td><td>' . wp_kses_post( $content ) . '</td></tr>';
344
+ }
345
+ }
346
+ ?>
347
+ </table>
348
+ <?php
349
+ }
350
+ }
351
+ }
352
+
353
+ /**
354
+ * Varnish URL Callback
355
+ *
356
+ * @since 4.0
357
+ */
358
+ public function check_caching_callback() {
359
+ $url = esc_url( VarnishPurger::the_home_url() );
360
+ $varnishurl = get_site_option( 'vhp_varnish_url', $url );
361
+ echo '<input type="text" id="vhp_varnish_url" name="vhp_varnish_url" value="' . esc_url( $varnishurl ) . '" size="50" />';
362
+ }
363
+
364
+ /**
365
+ * Sanitization and validation for URL
366
+ *
367
+ * @param mixed $input - the input to be sanitized.
368
+ * @since 4.0
369
+ */
370
+ public function varnish_url_sanitize( $input ) {
371
+
372
+ // Defaults values.
373
+ $output = esc_url( VarnishPurger::the_home_url() );
374
+ $set_type = 'error';
375
+
376
+ if ( empty( $input ) ) {
377
+ $set_message = __( 'You must enter a URL from your own domain to scan.', 'varnish-http-purge' );
378
+ } else {
379
+ $valid_url = VarnishDebug::is_url_valid( esc_url( $input ) );
380
+
381
+ switch ( $valid_url ) {
382
+ case 'empty':
383
+ case 'domain':
384
+ $set_message = __( 'You must provide a URL on your own domain to scan.', 'varnish-http-purge' );
385
+ break;
386
+ case 'invalid':
387
+ $set_message = __( 'You have entered an invalid URL address.', 'varnish-http-purge' );
388
+ break;
389
+ case 'valid':
390
+ $set_type = 'updated';
391
+ $set_message = __( 'URL Scanned.', 'varnish-http-purge' );
392
+ $output = esc_url( $input );
393
+ break;
394
+ default:
395
+ $set_message = __( 'An unknown error has occurred.', 'varnish-http-purge' );
396
+ break;
397
+ }
398
+ }
399
+
400
+ if ( isset( $set_message ) ) {
401
+ add_settings_error( 'vhp_varnish_url', 'varnish-url', $set_message, $set_type );
402
+ }
403
+ return $output;
404
+ }
405
+
406
+ /**
407
+ * Call settings page
408
+ *
409
+ * @since 4.0
410
+ */
411
+ public function settings_page() {
412
+ ?>
413
+ <div class="wrap">
414
+ <?php settings_errors(); ?>
415
+ <h1><?php esc_html_e( 'Varnish HTTP Purge Settings', 'varnish-http-purge' ); ?></h1>
416
+
417
+ <p><?php esc_html_e( 'Varnish HTTP Purge can empty the cache for different server based caching systems, including Varnish and nginx. For most users, there should be no configuration necessary as the plugin is intended to work silently, behind the scenes.', 'varnish-http-purge' ); ?></p>
418
+
419
+ <?php
420
+ if ( ! is_multisite() || current_user_can( 'manage_network' ) ) {
421
+ ?>
422
+ <form action="options.php" method="POST" >
423
+ <?php
424
+ settings_fields( 'vhp-settings-devmode' );
425
+ do_settings_sections( 'varnish-devmode-settings' );
426
+ submit_button( __( 'Save Settings', 'varnish-http-purge' ), 'primary' );
427
+ ?>
428
+ </form>
429
+
430
+ <form action="options.php" method="POST" >
431
+ <?php
432
+ settings_fields( 'vhp-settings-ip' );
433
+ do_settings_sections( 'varnish-ip-settings' );
434
+ submit_button( __( 'Save IP', 'varnish-http-purge' ), 'secondary' );
435
+ ?>
436
+ </form>
437
+ <?php
438
+ } else {
439
+ ?>
440
+ <p><?php esc_html_e( 'Your account does not have access to configure settings. Please contact your site administrator.', 'varnish-http-purge' ); ?></p>
441
+ <?php
442
+ }
443
+ ?>
444
+
445
+ </div>
446
+ <?php
447
+ }
448
+
449
+ /**
450
+ * Call the Check Caching
451
+ *
452
+ * @since 4.6.0
453
+ */
454
+ public function check_caching_page() {
455
+ ?>
456
+ <div class="wrap">
457
+
458
+ <?php settings_errors(); ?>
459
+ <h1><?php esc_html_e( 'Is Caching Working?', 'varnish-http-purge' ); ?></h1>
460
+
461
+ <form action="options.php" method="POST" >
462
+ <?php
463
+ settings_fields( 'varnish-http-purge-url' );
464
+ do_settings_sections( 'varnish-url-settings' );
465
+ submit_button( __( 'Check URL', 'varnish-http-purge' ), 'primary' );
466
+ ?>
467
+ </form>
468
+
469
+ </div>
470
+ <?php
471
+ }
472
+
473
+ }
474
+
475
+ $status = new VarnishStatus();
status.php DELETED
@@ -1,338 +0,0 @@
1
- <?php
2
- /**
3
- Copyright 2016-2018 Mika Epstein (email: ipstenu@halfelf.org)
4
-
5
- This file is part of Varnish HTTP Purge, a plugin for WordPress.
6
-
7
- Varnish HTTP Purge is free software: you can redistribute it and/or modify
8
- it under the terms of the Apache License 2.0 license.
9
-
10
- Varnish HTTP Purge is distributed in the hope that it will be useful,
11
- but WITHOUT ANY WARRANTY; without even the implied warranty of
12
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13
- */
14
-
15
- if ( !defined( 'ABSPATH' ) ) die();
16
-
17
- /**
18
- * Varnish Status Class
19
- *
20
- * @since 4.0
21
- */
22
-
23
- class VarnishStatus {
24
-
25
- /**
26
- * Construct
27
- * Fires when class is constructed, adds init hook
28
- *
29
- * @since 4.0
30
- */
31
- function __construct() {
32
- // Admin Init Hooks
33
- add_action( 'admin_init', array( &$this, 'admin_init' ) );
34
- // Admin Menu
35
- add_action( 'admin_menu', array( &$this, 'admin_menu' ) );
36
- }
37
-
38
- /**
39
- * Admin init Callback
40
- *
41
- * @since 4.0
42
- */
43
- function admin_init() {
44
- $this->register_settings_url();
45
- if ( !is_multisite() ) $this->register_settings_ip();
46
- }
47
-
48
- /**
49
- * Admin Menu Callback
50
- *
51
- * @since 4.0
52
- */
53
- function admin_menu() {
54
- add_management_page( __( 'Is Caching Working?', 'varnish-http-purge' ), __( 'Varnish Debugging', 'varnish-http-purge' ), 'manage_options', 'varnish-status', array( &$this, 'settings_page' ) );
55
- }
56
-
57
- /**
58
- * Register Admin Settings URL
59
- *
60
- * @since 4.0
61
- */
62
- function register_settings_url() {
63
- register_setting( 'varnish-http-purge-url', 'vhp_varnish_url', array( &$this, 'varnish_url_sanitize' ) );
64
- add_settings_section( 'varnish-url-settings-section', __( 'Check Caching Status', 'varnish-http-purge' ), array( &$this, 'options_callback_url'), 'varnish-url-settings' );
65
- add_settings_field( 'varnish_url', __( 'Check A URL On Your Site:', 'varnish-http-purge' ), array( &$this, 'varnish_url_callback' ), 'varnish-url-settings', 'varnish-url-settings-section' );
66
- }
67
-
68
- /**
69
- * Register Admin Settings IP
70
- *
71
- * @since 4.0.2
72
- */
73
- function register_settings_ip() {
74
- register_setting( 'varnish-http-purge-ip', 'vhp_varnish_ip', array( &$this, 'varnish_ip_sanitize' ) );
75
- add_settings_section( 'varnish-ip-settings-section', __( 'Configure Custom Varnish IP', 'varnish-http-purge' ), array( &$this, 'options_callback_ip'), 'varnish-ip-settings' );
76
- add_settings_field( 'varnish_ip', __( 'Set Varnish IP', 'varnish-http-purge' ), array( &$this, 'varnish_ip_callback' ), 'varnish-ip-settings', 'varnish-ip-settings-section' );
77
- }
78
-
79
- /**
80
- * Options Callback - IP Address
81
- *
82
- * @since 4.0
83
- */
84
- function options_callback_ip() {
85
- ?>
86
- <p><a name="#configure"></a><?php _e( 'The majority of users will never need to look down here. However there are cases when a custom Varnish IP Address will need to be set, in order to tell the plugin to empty the cache in a specific location. If you\'re using a CDN like Cloudflare or a Firewall Proxy like Sucuri, you will want to set this.', 'varnish-http-purge' ); ?></p>
87
- <p><?php _e( 'Your Varnish IP the IP address of the server where your caching service (i.e. Varnish or Nginx) is installed. Your Varnish IP must be one of the IPs used by your cache service. If you use multiple IPs, or if you\'ve customized your ACLs, you\'ll need to pick one that doesn\'t conflict with your other settings. For example, if you have Varnish listening on a public and private IP, pick the private. On the other hand, if you told Varnish to listen on 0.0.0.0 (i.e. "listen on every interface you can") you would need to check what IP you set your purge ACL to allow (commonly 127.0.0.1 aka localhost), and use that (i.e. 127.0.0.1).', 'varnish-http-purge' ); ?></p>
88
- <p><?php _e( 'If your webhost set the service up for you, as is the case with DreamPress or WP Engine, ask them for the specifics if they don\'t have it documented. I\'ve listed the ones I know about here, however you should still check with them if you\'re not sure.', 'varnish-http-purge' ); ?></p>
89
- <p><strong><?php _e( 'If you aren\'t sure what to do, contact your webhost or server admin before making any changes.', 'varnish-http-purge' ); ?></strong></p>
90
-
91
- <ul>
92
- <li><?php _e( 'DreamHost - Go into the Panel and click on the DNS settings for the domain. The entry for <em>resolve-to.domain</em> (if set) will be your cache server. If it\'s not set, then you don\'t need to worry about this at all. Example:', 'varnish-http-purge' ); ?> <code>resolve-to.www A 208.97.157.172</code></li>
93
- </ul>
94
- <?php
95
- }
96
-
97
- /**
98
- * Varnish IP Callback
99
- *
100
- * @since 4.0
101
- */
102
- function varnish_ip_callback() {
103
-
104
- $disabled = false;
105
-
106
- if ( VHP_VARNISH_IP != false ) {
107
- $disabled = true;
108
- $varniship = VHP_VARNISH_IP;
109
- } else {
110
- $varniship = get_option( 'vhp_varnish_ip' );
111
- }
112
-
113
- ?>
114
- <input type="text" id="vhp_varnish_ip" name="vhp_varnish_ip" value="<?php echo $varniship; ?>" size="25" <?php if ( $disabled == true ) { echo 'disabled'; } ?>/>
115
- <label for="vhp_varnish_ip">
116
- <?php
117
- if ( $disabled == true ) {
118
- _e( 'A Varnish IP has been defined in your wp-config, so it is not editable here.', 'varnish-http-purge' );
119
- } else {
120
- _e( 'Example:', 'varnish-http-purge' ); ?> <code>123.45.67.89</code><?php
121
- }
122
- ?>
123
- </label>
124
- <?php
125
- }
126
-
127
- /**
128
- * Options Callback - URL Scanner
129
- *
130
- * @since 4.0
131
- */
132
- function options_callback_url() {
133
-
134
- ?><p><?php _e( 'While it is impossible to detect all possible conflicts, this status page performs a check of the most common issues that prevents your site from caching properly. This feature is provided to help you in debugging any conflicts on your own. When filing an issue with your web-host, we recommend you include the output in your ticket.', 'varnish-http-purge' ); ?></p>
135
-
136
- <p><?php printf ( __( '<strong>This check uses <a href="%s">a remote service hosted on DreamObjects</a></strong>. The service used only for providing up to date compatibility checks on plugins and themes that may conflict with running a server based cache (such as Varnish or Nginx). No personally identifying information regarding persons running this check, nor the plugins and themes in use on this site will be transmitted. The bare minimum of usage information is collected, concerning only IPs and domains making requests of the service. If you do not wish to use this service, please do not use this debugging tool.', 'varnish-http-purge' ), 'https://varnish-http-purge.objects-us-east-1.dream.io/readme.txt' ); ?></p>
137
-
138
- <?php
139
-
140
- // If there's no post made, let's not...
141
- if ( !isset( $_REQUEST['settings-updated'] ) || !$_REQUEST['settings-updated'] ) return;
142
-
143
- // Set icons
144
- $icons = array (
145
- 'awesome' => '<span class="dashicons dashicons-heart" style="color:#008000;"></span>',
146
- 'good' => '<span class="dashicons dashicons-thumbs-up" style="color:#008000;"></span>',
147
- 'warning' => '<span class="dashicons dashicons-warning" style="color:#FF9933"></span>',
148
- 'awkward' => '<span class="dashicons dashicons-flag" style="color:#FF9933;">',
149
- 'bad' => '<span class="dashicons dashicons-thumbs-down" style="color:#990000;"></span>',
150
- );
151
-
152
- // Include the debug code
153
- include( 'debug.php' );
154
-
155
- // Get the base URL to start
156
- $url = esc_url( VarnishPurger::the_home_url() );
157
- $varnishurl = get_option( 'vhp_varnish_url', $url );
158
-
159
- // Get the response and headers
160
- $remote_get = VarnishDebug::remote_get( $varnishurl );
161
- $headers = wp_remote_retrieve_headers( $remote_get );
162
-
163
- // Preflight checklist
164
- $preflight = VarnishDebug::preflight( $remote_get );
165
-
166
- // Check for Remote IP
167
- $remote_ip = VarnishDebug::remote_ip( $headers );
168
-
169
- // Get the Varnish IP
170
- if ( VHP_VARNISH_IP != false ) {
171
- $varniship = VHP_VARNISH_IP;
172
- } else {
173
- $varniship = get_option('vhp_varnish_ip');
174
- }
175
- ?>
176
-
177
- <h4><?php printf( __( 'Results for %s', 'varnish-http-purge' ), $varnishurl ); ?></h4>
178
-
179
- <table class="wp-list-table widefat fixed posts">
180
- <?php
181
-
182
- // If we failed the preflight checks, we fail.
183
- if ( $preflight['preflight'] == false ) {
184
- ?><tr>
185
- <td width="40px"><?php echo $icons['bad']; ?></td>
186
- <td><?php echo $preflight['message']; ?></td>
187
- </tr><?php
188
- } else {
189
- // We passed the checks, let's get the data!
190
-
191
- $output = VarnishDebug::get_all_the_results( $headers, $remote_ip, $varniship );
192
-
193
- foreach ( $output as $item ) {
194
- if ( $item !== false && is_array( $item ) ) {
195
- ?><tr>
196
- <td width="40px"><?php echo $icons[ $item['icon'] ]; ?></td>
197
- <td><?php echo $item['message'] ?></td>
198
- </tr><?php
199
- }
200
- }
201
- }
202
- ?>
203
- </table>
204
-
205
- <?php
206
- if ( $preflight['preflight'] !== false ) {
207
- ?>
208
- <h4><?php _e( 'Technical Details', 'varnish-http-purge' ); ?></h4>
209
- <table class="wp-list-table widefat fixed posts">
210
- <?php
211
- if ( !empty( $headers[0] ) ) {
212
- echo '<tr><td width="200px">&nbsp;</td><td>' . $headers[0] . '</td></tr>';
213
- }
214
- foreach ( $headers as $header => $key ) {
215
- if ( $header !== '0' ) {
216
- if ( is_array( $key ) ) {
217
- $content = print_r( $key, true );
218
- } else {
219
- $content = wp_kses_post( $key );
220
- }
221
-
222
- echo '<tr><td width="200px" style="text-align:right;">' . $header . ':</td><td>' . $content . '</td></tr>';
223
- }
224
- }
225
- ?>
226
- </table>
227
- <?php
228
- }
229
- }
230
-
231
- /**
232
- * Varnish URL Callback
233
- *
234
- * @since 4.0
235
- */
236
- function varnish_url_callback() {
237
- $url = esc_url( VarnishPurger::the_home_url() );
238
- $varnishurl = get_option( 'vhp_varnish_url', $url );
239
- ?><input type="text" id="vhp_varnish_url" name="vhp_varnish_url" value="<?php echo $varnishurl; ?>" size="50" /><?php
240
- }
241
-
242
- /*
243
- * Call settings page
244
- *
245
- * @since 4.0
246
- */
247
- function settings_page() {
248
- ?>
249
- <div class="wrap">
250
-
251
- <h1><?php _e( 'Is Caching Working?', 'varnish-http-purge' ); ?></h1>
252
-
253
- <?php settings_errors(); ?>
254
-
255
- <form action="options.php" method="POST" ><?php
256
- settings_fields( 'varnish-http-purge-url' );
257
- do_settings_sections( 'varnish-url-settings' );
258
- submit_button( __( 'Check URL', 'varnish-http-purge' ), 'primary');
259
- ?></form>
260
-
261
- <form action="options.php" method="POST" ><?php
262
- // Only available if _not_ multisite
263
- if ( !is_multisite() ) {
264
- settings_fields( 'varnish-http-purge-ip' );
265
- do_settings_sections( 'varnish-ip-settings' );
266
- submit_button( __( 'Save IP', 'varnish-http-purge' ), 'secondary');
267
- }
268
- ?></form>
269
-
270
- </div>
271
- <?php
272
- }
273
-
274
- /**
275
- * Sanitization and validation for IP
276
- *
277
- * @param $input the input to be sanitized
278
- * @since 4.0
279
- */
280
- function varnish_ip_sanitize( $input ) {
281
-
282
- $output = '';
283
- $set_message = __( 'You have entered an invalid IP address.', 'varnish-http-purge' );
284
- $set_type = 'error';
285
-
286
- if ( empty($input) ) {
287
- return; // do nothing
288
- } elseif ( filter_var( $input, FILTER_VALIDATE_IP) ) {
289
- $set_message = 'IP Updated.';
290
- $set_type = 'updated';
291
- $output = filter_var( $input, FILTER_VALIDATE_IP);
292
- }
293
-
294
- add_settings_error( 'vhp_varnish_url', 'varnish-url', $set_message, $set_type );
295
- return $output;
296
- }
297
-
298
- /**
299
- * Sanitization and validation for URL
300
- *
301
- * @param $input the input to be sanitized
302
- * @since 4.0
303
- */
304
- function varnish_url_sanitize( $input ) {
305
-
306
- // Defaults
307
- $output = esc_url( VarnishPurger::the_home_url() );
308
- $set_type = 'error';
309
-
310
- if ( !empty( $input ) ) {
311
- $parsed_input = parse_url( $input );
312
- if ( empty( $parsed_input['scheme'] ) ) {
313
- $schema_input = 'http://';
314
- if ( is_ssl() ) $schema_input = 'https://';
315
- $input = $schema_input . ltrim( $input, '/' );
316
- }
317
- }
318
-
319
- if ( empty( $input ) ) {
320
- $set_message = __( 'You must enter a URL from your own domain to scan.', 'varnish-http-purge' );
321
- } elseif ( !filter_var( $input, FILTER_VALIDATE_URL) ) {
322
- $set_message = __( 'You have entered an invalid URL address.', 'varnish-http-purge' );
323
- } elseif ( parse_url( $output, PHP_URL_HOST ) !== parse_url( $input, PHP_URL_HOST ) ) {
324
- $set_message = __( 'You cannot scan URLs on other domains.', 'varnish-http-purge' );
325
- } else {
326
- $set_type = 'updated';
327
- $set_message = __( 'URL Scanned.', 'varnish-http-purge' );
328
- $output = filter_var( $input, FILTER_VALIDATE_URL);
329
- }
330
-
331
- if ( isset( $set_message ) ) add_settings_error( 'vhp_varnish_url', 'varnish-url', $set_message, $set_type );
332
- return $output;
333
- }
334
-
335
- }
336
-
337
-
338
- $status = new VarnishStatus();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
style.css CHANGED
@@ -1,18 +1,25 @@
1
  /* Add Orange Carrot Dashicon */
2
- #wpadminbar #wp-admin-bar-purge-varnish-cache .ab-icon:before {
3
- content: '\f511';
4
- top: 4px;
5
- /*color: #F56E28;*/
 
 
 
6
  }
7
 
8
  /* Add Orange Carrot to Button */
9
- span.dashicons.dashicons-carrot.varnish-http-purge {
10
- color: #F56E28;
11
  vertical-align: middle;
12
  }
13
 
14
  @media screen and (max-width: 782px) {
15
- #wpadminbar li#wp-admin-bar-purge-varnish-cache{
 
 
16
  display: block!important;
 
 
 
17
  }
18
  }
1
  /* Add Orange Carrot Dashicon */
2
+ #wpadminbar #wp-admin-bar-purge-varnish-cache .ab-icon {
3
+ float: left;
4
+ width: 26px;
5
+ height: 30px;
6
+ background-repeat: no-repeat;
7
+ background-position: 0 8px;
8
+ background-size: 20px;
9
  }
10
 
11
  /* Add Orange Carrot to Button */
12
+ span.dashicons.varnish-http-purge {
 
13
  vertical-align: middle;
14
  }
15
 
16
  @media screen and (max-width: 782px) {
17
+ #wpadminbar #wp-admin-bar-purge-varnish-cache .ab-icon,
18
+ #wpadminbar li#wp-admin-bar-purge-varnish-cache {
19
+ margin-left: 5px;
20
  display: block!important;
21
+ background-size: 36px;
22
+ height: 46px;
23
+ width: 52px;
24
  }
25
  }
uninstall.php CHANGED
@@ -1,21 +1,25 @@
1
  <?php
2
  /**
3
- Copyright 2016-2018 Mika Epstein (email: ipstenu@halfelf.org)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
 
5
- This file is part of Varnish HTTP Purge, a plugin for WordPress.
6
-
7
- Varnish HTTP Purge is free software: you can redistribute it and/or modify
8
- it under the terms of the Apache License 2.0 license.
9
-
10
- Varnish HTTP Purge is distributed in the hope that it will be useful,
11
- but WITHOUT ANY WARRANTY; without even the implied warranty of
12
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13
- */
14
-
15
- // This is the uninstall script.
16
-
17
- if( !defined( 'ABSPATH') && !defined('WP_UNINSTALL_PLUGIN') )
18
  exit();
 
19
 
20
- delete_site_option('vhp_varnish_url');
21
- delete_site_option('vhp_varnish_ip');
 
1
  <?php
2
  /**
3
+ * Uninstall
4
+ *
5
+ * @package varnish-http-purge
6
+ *
7
+ * Copyright 2016-2018 Mika Epstein (email: ipstenu@halfelf.org)
8
+ *
9
+ * This file is part of Varnish HTTP Purge, a plugin for WordPress.
10
+ *
11
+ * Varnish HTTP Purge is free software: you can redistribute it and/or modify
12
+ * it under the terms of the Apache License 2.0 license.
13
+ *
14
+ * Varnish HTTP Purge is distributed in the hope that it will be useful,
15
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17
+ */
18
 
19
+ if ( ! defined( 'ABSPATH' ) && ! defined( 'WP_UNINSTALL_PLUGIN' ) ) {
 
 
 
 
 
 
 
 
 
 
 
 
20
  exit();
21
+ }
22
 
23
+ delete_site_option( 'vhp_varnish_url' );
24
+ delete_site_option( 'vhp_varnish_ip' );
25
+ delete_site_option( 'vhp_varnish_devmode' );
varnish-http-purge.php CHANGED
@@ -1,37 +1,56 @@
1
  <?php
2
- /*
3
- Plugin Name: Varnish HTTP Purge
4
- Plugin URI: https://halfelf.org/plugins/varnish-http-purge/
5
- Description: Automatically empty cached pages when content on your site is modified.
6
- Version: 4.5.2
7
- Author: Mika Epstein
8
- Author URI: https://halfelf.org/
9
- License: http://www.apache.org/licenses/LICENSE-2.0
10
- Text Domain: varnish-http-purge
11
- Network: true
12
-
13
- Copyright 2013-2018: Mika A. Epstein (email: ipstenu@halfelf.org)
14
-
15
- Original Author: Leon Weidauer ( http:/www.lnwdr.de/ )
16
-
17
- This file is part of Varnish HTTP Purge, a plugin for WordPress.
18
-
19
- Varnish HTTP Purge is free software: you can redistribute it and/or modify
20
- it under the terms of the Apache License 2.0 license.
21
-
22
- Varnish HTTP Purge is distributed in the hope that it will be useful,
23
- but WITHOUT ANY WARRANTY; without even the implied warranty of
24
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
25
- */
26
 
27
  /**
28
  * Purge Varnish Class
29
  *
30
  * @since 2.0
31
  */
32
-
33
  class VarnishPurger {
34
- protected $purgeUrls = array();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
 
36
  /**
37
  * Init
@@ -39,11 +58,33 @@ class VarnishPurger {
39
  * @since 2.0
40
  * @access public
41
  */
42
- public function __construct( ) {
43
- defined( 'VHP_VARNISH_IP' ) || define( 'VHP_VARNISH_IP' , false );
44
- defined( 'VHP_DEBUG' ) || define( 'VHP_DEBUG', false );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
  add_action( 'init', array( &$this, 'init' ) );
46
  add_action( 'admin_init', array( &$this, 'admin_init' ) );
 
47
  }
48
 
49
  /**
@@ -53,21 +94,29 @@ class VarnishPurger {
53
  * @access public
54
  */
55
  public function admin_init() {
56
-
57
- // Add to 'right now'
58
  add_action( 'activity_box_end', array( $this, 'varnish_rightnow' ), 100 );
59
 
60
- // Failure: Pre WP 4.7
61
  if ( version_compare( get_bloginfo( 'version' ), '4.7', '<=' ) ) {
62
  deactivate_plugins( plugin_basename( __FILE__ ) );
63
- add_action( 'admin_notices' , array( $this, 'require_wp_version_notice'));
64
  return;
65
  }
66
 
67
- // Warning: No Pretty Permalinks!
68
- if ( '' == get_option( 'permalink_structure' ) && current_user_can( 'manage_options' ) ) {
69
- add_action( 'admin_notices' , array( $this, 'require_pretty_permalinks_notice' ) );
70
- return;
 
 
 
 
 
 
 
 
71
  }
72
  }
73
 
@@ -80,44 +129,59 @@ class VarnishPurger {
80
  public function init() {
81
  global $blog_id;
82
 
83
- // Cheap Dev Mode
84
- // If VHP_DEBUG is true, throw down a session to 'break' caching
85
- if ( VHP_DEBUG ) {
86
- @session_start();
 
 
 
 
 
 
 
 
 
 
87
  }
88
 
89
- // get my events
90
- $events = $this->getRegisterEvents();
91
- $noIDevents = $this->getNoIDEvents();
92
 
93
- // make sure we have events and they're in an array
94
- if ( !empty( $events ) && !empty( $noIDevents ) ) {
95
 
96
- // Force it to be an array, in case someone's stupid
97
- $events = (array) $events;
98
- $noIDevents = (array) $noIDevents;
99
 
100
- // Add the action for each event
101
- foreach ( $events as $event) {
102
- if ( in_array($event, $noIDevents ) ) {
103
- // These events have no post ID and, thus, will perform a full purge
104
- add_action( $event, array( $this, 'purgeNoID' ) );
105
  } else {
106
- add_action( $event, array( $this, 'purgePost' ), 10, 2 );
107
  }
108
  }
109
  }
110
-
111
- add_action( 'shutdown', array( $this, 'executePurge' ) );
112
 
113
- // Success: Admin notice when purging
114
- if (
115
- ( isset( $_GET['vhp_flush_all'] ) && check_admin_referer( 'vhp-flush-all' ) ) ||
 
116
  ( isset( $_GET['vhp_flush_do'] ) && check_admin_referer( 'vhp-flush-do' ) ) ) {
117
- add_action( 'admin_notices', array( $this, 'purgeMessage') );
 
 
 
 
 
 
118
  }
119
-
120
- // Add Admin Bar
121
  add_action( 'admin_bar_menu', array( $this, 'varnish_rightnow_adminbar' ), 100 );
122
  add_action( 'admin_enqueue_scripts', array( $this, 'custom_css' ) );
123
  add_action( 'wp_enqueue_scripts', array( $this, 'custom_css' ) );
@@ -127,10 +191,21 @@ class VarnishPurger {
127
  * Purge Message
128
  * Informs of a succcessful purge
129
  *
130
- * @since 2.0
131
  */
132
- function purgeMessage() {
133
- echo "<div id='message' class='notice notice-success fade is-dismissible'><p><strong>".__('Varnish cache emptied!', 'varnish-http-purge')."</strong></p></div>";
 
 
 
 
 
 
 
 
 
 
 
134
  }
135
 
136
  /**
@@ -139,8 +214,9 @@ class VarnishPurger {
139
  *
140
  * @since 2.0
141
  */
142
- function require_pretty_permalinks_notice() {
143
- echo "<div id='message' class='error'><p>" . sprintf( __( 'Varnish HTTP Purge requires you to use custom permalinks. Please go to the <a href="%1$s">Permalinks Options Page</a> to configure them.', 'varnish-http-purge' ), admin_url( 'options-permalink.php' ) ) . "</p></div>";
 
144
  }
145
 
146
  /**
@@ -149,8 +225,28 @@ class VarnishPurger {
149
  *
150
  * @since 4.1
151
  */
152
- function require_wp_version_notice() {
153
- echo "<div id='message' class='error'><p>" . sprintf( __( 'Varnish HTTP Purge requires WordPress 4.7 or greater. Please <a href="%1$s">upgrade WordPress</a>.', 'varnish-http-purge' ), admin_url( 'update-core.php' ) ) . "</p></div>";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
154
  }
155
 
156
  /**
@@ -161,88 +257,108 @@ class VarnishPurger {
161
  *
162
  * @since 4.0
163
  */
164
- static public function the_home_url() {
165
  $home_url = apply_filters( 'vhp_home_url', home_url() );
166
  return $home_url;
167
  }
168
 
169
  /**
170
  * Custom CSS to allow for coloring.
171
- *
172
  * @since 4.5.0
173
  */
174
- function custom_css() {
175
- wp_register_style( 'varnish_http_purge', plugins_url( 'style.css', __FILE__ ), false, '4.5.2' );
176
- wp_enqueue_style( 'varnish_http_purge' );
 
 
177
  }
178
 
179
  /**
180
  * Varnish Purge Button in the Admin Bar
181
  *
182
- * @since 2.0
 
 
183
  */
184
- function varnish_rightnow_adminbar( $admin_bar ) {
185
  global $wp;
186
 
187
- $can_purge = FALSE;
 
 
 
188
 
189
- if ( ( !is_admin() && get_post() !== false && current_user_can( 'edit_published_posts' ) ) || current_user_can( 'activate_plugins' ) ) {
190
- // Main Array
191
- $args = array(
192
  array(
193
  'id' => 'purge-varnish-cache',
194
- 'title' => '<span class="ab-icon"></span><span class="ab-label">' . __( 'Empty Cache', 'varnish-http-purge' ) . '</span>',
195
- 'meta' => array(
196
- 'class' => 'varnish-http-purge'
197
  ),
198
  ),
199
  );
200
- $can_purge = TRUE;
201
  }
202
 
203
- // Checking user permissions for who can and cannot use the all flush
204
  if (
205
- // SingleSite - admins can always purge
206
- ( !is_multisite() && current_user_can( 'activate_plugins' ) ) ||
207
- // Multisite - Network Admin can always purge
208
  current_user_can( 'manage_network' ) ||
209
- // Multisite - Site admins can purge UNLESS it's a subfolder install and we're on site #1
210
- ( is_multisite() && current_user_can( 'activate_plugins' ) && ( SUBDOMAIN_INSTALL || ( !SUBDOMAIN_INSTALL && ( BLOG_ID_CURRENT_SITE != $blog_id ) ) ) )
211
  ) {
212
 
213
  $args[] = array(
214
  'parent' => 'purge-varnish-cache',
215
  'id' => 'purge-varnish-cache-all',
216
- 'title' => __( 'Entire Cache (All Pages)', 'varnish-http-purge' ),
217
  'href' => wp_nonce_url( add_query_arg( 'vhp_flush_do', 'all' ), 'vhp-flush-do' ),
218
  'meta' => array(
219
- 'title' => __( 'Entire Cache (All Pages)', 'varnish-http-purge' ),
220
  ),
221
  );
222
- // If a memcached file is found, we can do this too:
 
223
  if ( file_exists( WP_CONTENT_DIR . '/object-cache.php' ) ) {
224
  $args[] = array(
225
  'parent' => 'purge-varnish-cache',
226
  'id' => 'purge-varnish-cache-db',
227
- 'title' => __( 'Database Cache', 'varnish-http-purge' ),
228
  'href' => wp_nonce_url( add_query_arg( 'vhp_flush_do', 'object' ), 'vhp-flush-do' ),
229
  'meta' => array(
230
- 'title' => __( 'Database Cache', 'varnish-http-purge' ),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
231
  ),
232
  );
233
  }
234
- }
235
 
236
- // If we're on a front end page and the current user can edit published posts, then they can do this:
237
- if ( ! is_admin() && get_post() !== false && current_user_can( 'edit_published_posts' ) ) {
238
- $page_url = esc_url( home_url( $wp->request ) );
239
- $args[] = array(
240
  'parent' => 'purge-varnish-cache',
241
- 'id' => 'purge-varnish-cache-this',
242
- 'title' => __( 'This Page\'s Cache', 'varnish-http-purge' ),
243
- 'href' => wp_nonce_url( add_query_arg( 'vhp_flush_do', $page_url . '/' ), 'vhp-flush-do' ),
244
  'meta' => array(
245
- 'title' => __( 'This Page\'s Cache', 'varnish-http-purge' ),
246
  ),
247
  );
248
  }
@@ -254,35 +370,67 @@ class VarnishPurger {
254
  }
255
  }
256
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
257
  /**
258
  * Varnish Right Now Information
259
  * This information is put on the Dashboard 'Right now' widget
260
  *
261
  * @since 1.0
262
  */
263
- function varnish_rightnow() {
264
  global $blog_id;
265
- $url = wp_nonce_url( add_query_arg( 'vhp_flush_do', 'all' ), 'vhp-flush-do' );
266
  $intro = sprintf( __( '<a href="%1$s">Varnish HTTP Purge</a> automatically deletes your cached posts when published or updated. When making major site changes, such as with a new theme, plugins, or widgets, you may need to manually empty the cache.', 'varnish-http-purge' ), 'http://wordpress.org/plugins/varnish-http-purge/' );
267
- $button = __( 'Press the button below to force it to empty your entire Varnish cache.', 'varnish-http-purge' );
268
- $button .= '</p><p><span class="button"><span class="dashicons dashicons-carrot varnish-http-purge"></span> <a href="'.$url.'"><strong>';
 
269
  $button .= __( 'Empty Cache', 'varnish-http-purge' );
270
  $button .= '</strong></a></span>';
271
- $nobutton = __( 'You do not have permission to empty the Varnish cache for the whole site. Please contact your administrator.', 'varnish-http-purge' );
272
 
273
  if (
274
- // SingleSite - admins can always purge
275
- ( !is_multisite() && current_user_can( 'activate_plugins' ) ) ||
276
- // Multisite - Network Admin can always purge
277
  current_user_can( 'manage_network' ) ||
278
- // Multisite - Site admins can purge UNLESS it's a subfolder install and we're on site #1
279
- ( is_multisite() && current_user_can( 'activate_plugins' ) && ( SUBDOMAIN_INSTALL || ( !SUBDOMAIN_INSTALL && ( BLOG_ID_CURRENT_SITE != $blog_id ) ) ) )
280
  ) {
281
- $text = $intro.' '.$button;
282
  } else {
283
- $text = $intro.' '.$nobutton;
284
  }
285
- echo "<p class='varnish-rightnow'>$text</p>\n";
286
  }
287
 
288
  /**
@@ -292,21 +440,21 @@ class VarnishPurger {
292
  * @since 1.0
293
  * @access protected
294
  */
295
- protected function getRegisterEvents() {
296
 
297
- // Define registered purge events
298
  $actions = array(
299
- 'switch_theme', // After a theme is changed
300
- 'autoptimize_action_cachepurged', // Compat with https://wordpress.org/plugins/autoptimize/
301
- 'save_post', // Save a post
302
- 'deleted_post', // Delete a post
303
- 'trashed_post', // Empty Trashed post
304
- 'edit_post', // Edit a post - includes leaving comments
305
- 'delete_attachment', // Delete an attachment - includes re-uploading
306
  );
307
 
308
- // send back the actions array, filtered
309
- // @param array $actions the actions that trigger the purge event
310
  return apply_filters( 'varnish_http_purge_events', $actions );
311
  }
312
 
@@ -317,52 +465,60 @@ class VarnishPurger {
317
  * @since 3.9
318
  * @access protected
319
  */
320
- protected function getNoIDEvents() {
321
 
322
- // Define registered purge events
323
  $actions = array(
324
- 'switch_theme', // After a theme is changed
325
- 'autoptimize_action_cachepurged,' // Compat with https://wordpress.org/plugins/autoptimize/
326
  );
327
 
328
- // send back the actions array, filtered
329
- // @param array $actions the actions that trigger the purge event
330
- // DEVELOPERS! USE THIS SPARINGLY! YOU'RE A GREAT BIG 💩 IF YOU USE IT FLAGRANTLY
331
- // Remember to add your action to this AND varnish_http_purge_events due to shenanigans
 
 
 
 
332
  return apply_filters( 'varnish_http_purge_events_full', $actions );
333
  }
334
 
335
  /**
336
  * Execute Purge
337
- * Run the purge command for the URLs. Calls $this->purgeUrl for each URL
338
  *
339
  * @since 1.0
340
  * @access protected
341
  */
342
- public function executePurge() {
343
- $purgeUrls = array_unique( $this->purgeUrls );
344
 
345
- if ( empty( $purgeUrls ) && isset( $_GET ) ) {
346
  if ( isset( $_GET['vhp_flush_all'] ) && check_admin_referer( 'vhp-flush-all' ) ) {
347
- // Flush Varnish Cache recursize
348
- $this->purgeUrl( $this->the_home_url() . '/?vhp-regex' );
349
  } elseif ( isset( $_GET['vhp_flush_do'] ) && check_admin_referer( 'vhp-flush-do' ) ) {
350
- if ( $_GET['vhp_flush_do'] == 'object' ) {
351
- // Flush Object Cache (with a double check)
352
- if ( file_exists( WP_CONTENT_DIR . '/object-cache.php' ) ) wp_cache_flush();
353
- } elseif ( $_GET['vhp_flush_do'] == 'all' ) {
354
- // Flush Varnish Cache recursize
355
- $this->purgeUrl( $this->the_home_url() . '/?vhp-regex' );
 
 
356
  } else {
357
- // Flush the URL we're on
358
- $p = parse_url( $_GET['vhp_flush_do'] );
359
- if ( !isset( $p['host'] ) ) return;
360
- $this->purgeUrl( $_GET['vhp_flush_do'] );
 
 
361
  }
362
  }
363
  } else {
364
- foreach( $purgeUrls as $url ) {
365
- $this->purgeUrl( $url );
366
  }
367
  }
368
  }
@@ -372,33 +528,35 @@ class VarnishPurger {
372
  * Parse the URL for proxy proxies
373
  *
374
  * @since 1.0
375
- * @param array $url the url to be purged
376
  * @access protected
377
  */
378
- public function purgeUrl( $url ) {
379
- $p = parse_url( $url );
380
-
381
- // Bail early if there's no host since some plugins are weird
382
- if ( !isset( $p['host'] ) ) return;
 
 
383
 
384
- // Determine if we're using regex to flush all pages or not
385
  $pregex = '';
386
  $x_purge_method = 'default';
387
 
388
- if ( isset( $p['query'] ) && ( $p['query'] == 'vhp-regex' ) ) {
389
  $pregex = '.*';
390
  $x_purge_method = 'regex';
391
  }
392
 
393
- // Build a varniship
394
- if ( VHP_VARNISH_IP != false ) {
395
  $varniship = VHP_VARNISH_IP;
396
  } else {
397
- $varniship = get_option( 'vhp_varnish_ip' );
398
  }
399
- $varniship = apply_filters( 'vhp_varnish_ip' , $varniship );
400
 
401
- // Determine the path
402
  $path = '';
403
  if ( isset( $p['path'] ) ) {
404
  $path = $p['path'];
@@ -414,16 +572,21 @@ class VarnishPurger {
414
  */
415
  $schema = apply_filters( 'varnish_http_purge_schema', 'http://' );
416
 
417
- // If we made varniship, let it sail
418
- if ( isset( $varniship ) && $varniship != null ) {
419
  $host = $varniship;
420
  } else {
421
  $host = $p['host'];
422
  }
423
 
424
- /*
425
  * Allow setting of ports in host name
426
  * Credit: davidbarratt - https://github.com/Ipstenu/varnish-http-purge/pull/38/
 
 
 
 
 
427
  * @since 4.4.0
428
  */
429
  $host_headers = $p['host'];
@@ -431,11 +594,11 @@ class VarnishPurger {
431
  $host_headers .= ':' . $p['port'];
432
  }
433
 
434
- // Create path to purge
435
- $purgeme = $schema.$host.$path.$pregex;
436
 
437
  // Check the queries...
438
- if ( !empty( $p['query'] ) && $p['query'] != 'vhp-regex' ) {
439
  $purgeme .= '?' . $p['query'];
440
  }
441
 
@@ -444,8 +607,14 @@ class VarnishPurger {
444
  *
445
  * @since 4.1
446
  */
447
- $headers = apply_filters( 'varnish_http_purge_headers', array( 'host' => $host_headers, 'X-Purge-Method' => $x_purge_method ) );
448
- $response = wp_remote_request( $purgeme, array( 'method' => 'PURGE', 'headers' => $headers ) );
 
 
 
 
 
 
449
 
450
  do_action( 'after_purge_url', $url, $purgeme, $response, $headers );
451
  }
@@ -454,20 +623,24 @@ class VarnishPurger {
454
  * Purge - No IDs
455
  * Flush the whole cache
456
  *
457
- * @since 3.9
458
  * @access public
 
 
 
459
  */
460
- public function purgeNoID( $postId ) {
461
  $listofurls = array();
462
 
463
  array_push( $listofurls, $this->the_home_url() . '/?vhp-regex' );
464
-
465
- // Now flush all the URLs we've collected provided the array isn't empty
466
- if ( !empty( $listofurls ) ) {
467
  foreach ( $listofurls as $url ) {
468
- array_push( $this->purgeUrls, $url ) ;
469
  }
470
  }
 
 
471
  }
472
 
473
  /**
@@ -476,14 +649,14 @@ class VarnishPurger {
476
  * Generates a list of URLs that should be purged, based on the post ID
477
  * passed through. Useful for when you're trying to get a post to flush
478
  * another post.
479
- *
480
  * @access public
481
- * @param mixed $postId
482
  * @return array()
483
  */
484
- public function generate_urls ( $postId ) {
485
- $this->purgePost( $postId );
486
- return $this->purgeUrls;
487
  }
488
 
489
  /**
@@ -491,173 +664,206 @@ class VarnishPurger {
491
  * Flush the post
492
  *
493
  * @since 1.0
494
- * @param array $postId the ID of the post to be purged
495
  * @access public
496
  */
497
- public function purgePost( $postId ) {
498
-
499
- // Future Me: You may need this if you figure out how to use an array
500
- // further down with versions of WP and their json versions.
501
- // global $wp_version;
502
-
503
- // If this is a valid post we want to purge the post,
504
- // the home page and any associated tags and categories
 
505
  $valid_post_status = array( 'publish', 'private', 'trash' );
506
- $this_post_status = get_post_status( $postId );
507
 
508
- // Not all post types are created equal
509
- $invalid_post_type = array( 'nav_menu_item', 'revision' );
510
  $noarchive_post_type = array( 'post', 'page' );
511
- $this_post_type = get_post_type( $postId );
512
-
513
- // Determine the route for the rest API
514
- // This will need to be revisted if WP updates the version.
515
- // Future me: Consider an array? 4.7-4.7.3 use v2, and then adapt from there?
516
- $rest_api_route = 'wp/v2';
517
-
518
- // array to collect all our URLs
 
 
519
  $listofurls = array();
520
 
521
- // Verify we have a permalink and that we're a valid post status and a not an invalid post type
522
- if( get_permalink( $postId ) == true && in_array( $this_post_status, $valid_post_status ) && !in_array( $this_post_type, $invalid_post_type ) ) {
523
 
524
- // Post URL
525
- array_push( $listofurls, get_permalink( $postId ) );
526
 
527
- // JSON API Permalink for the post based on type
528
- // We only want to do this if the rest_base exists
529
- // But we apparently have to force it for posts and pages (seriously?)
530
- $post_type_object = get_post_type_object( $postId );
531
- $rest_permalink = false;
 
 
532
  if ( isset( $post_type_object->rest_base ) ) {
533
- $rest_permalink = get_rest_url() . $rest_api_route . '/' . $post_type_object->rest_base . '/' . $postId . '/';
534
- } elseif ( $this_post_type == 'post' ) {
535
- $rest_permalink = get_rest_url() . $rest_api_route . '/posts/' . $postId . '/';
536
- } elseif ( $this_post_type == 'page' ) {
537
- $rest_permalink = get_rest_url() . $rest_api_route . '/pages/' . $postId . '/';
538
  }
539
 
540
- if ( $rest_permalink !== false ) array_push( $listofurls, $rest_permalink );
 
 
541
 
542
- // Add in AMP permalink if Automattic's AMP is installed
543
  if ( function_exists( 'amp_get_permalink' ) ) {
544
- array_push( $listofurls, amp_get_permalink( $postId ) );
545
  }
546
-
547
- // Regular AMP url for posts
548
- array_push( $listofurls, get_permalink( $postId ) . 'amp/' );
549
 
550
  // Also clean URL for trashed post.
551
- if ( $this_post_status == 'trash' ) {
552
- $trashpost = get_permalink( $postId );
553
  $trashpost = str_replace( '__trashed', '', $trashpost );
554
  array_push( $listofurls, $trashpost, $trashpost . 'feed/' );
555
  }
556
 
557
- // Category purge based on Donnacha's work in WP Super Cache
558
- $categories = get_the_category( $postId) ;
559
  if ( $categories ) {
560
  foreach ( $categories as $cat ) {
561
- $category_base = get_option( 'category_base');
562
- if ( $category_base == '' ) $category_base = '/category/';
563
- array_push( $listofurls,
 
 
564
  get_category_link( $cat->term_id ),
565
  get_rest_url() . $rest_api_route . '/categories/' . $cat->term_id . '/'
566
  );
567
  }
568
  }
569
- // Tag purge based on Donnacha's work in WP Super Cache
570
- $tags = get_the_tags( $postId );
571
  if ( $tags ) {
572
- $tag_base = get_option( 'tag_base' );
573
- if ( $tag_base == '' ) $tag_base = '/tag/';
 
 
574
  foreach ( $tags as $tag ) {
575
- array_push( $listofurls,
576
  get_tag_link( $tag->term_id ),
577
  get_rest_url() . $rest_api_route . $tag_base . $tag->term_id . '/'
578
  );
579
  }
580
  }
581
- // Custom Taxonomies
582
- // Only show if the taxonomy is public
583
- $taxonomies = get_post_taxonomies( $postId );
584
- if ( $taxonomies ) {
585
  foreach ( $taxonomies as $taxonomy ) {
586
- $features = (array) get_taxonomy( $taxonomy );
587
  if ( $features['public'] ) {
588
- $terms = wp_get_post_terms( $postId, $taxonomy );
589
  foreach ( $terms as $term ) {
590
- array_push( $listofurls,
591
  get_term_link( $term ),
592
  get_rest_url() . $rest_api_route . '/' . $term->taxonomy . '/' . $term->slug . '/'
593
  );
594
- }
595
  }
596
  }
597
  }
598
-
599
- // Author URL
600
- $author_id = get_post_field( 'post_author', $postId );
601
  array_push( $listofurls,
602
  get_author_posts_url( $author_id ),
603
  get_author_feed_link( $author_id ),
604
  get_rest_url() . $rest_api_route . '/users/' . $author_id . '/'
605
  );
606
 
607
- // Archives and their feeds
608
- if ( $this_post_type && !in_array( $this_post_type, $noarchive_post_type ) ) {
609
  array_push( $listofurls,
610
- get_post_type_archive_link( get_post_type( $postId ) ),
611
- get_post_type_archive_feed_link( get_post_type( $postId ) )
612
  // Need to add in JSON?
613
  );
614
  }
615
-
616
- // Feeds
617
  array_push( $listofurls,
618
  get_bloginfo_rss( 'rdf_url' ),
619
  get_bloginfo_rss( 'rss_url' ),
620
  get_bloginfo_rss( 'rss2_url' ),
621
  get_bloginfo_rss( 'atom_url' ),
622
  get_bloginfo_rss( 'comments_rss2_url' ),
623
- get_post_comments_feed_link( $postId )
624
  );
625
 
626
- // Home Pages and (if used) posts page
627
- array_push( $listofurls,
628
  get_rest_url(),
629
  $this->the_home_url() . '/'
630
- );
631
- if ( get_option( 'show_on_front' ) == 'page' ) {
632
- // Ensure we have a page_for_posts setting to avoid empty URL
633
- if ( get_option('page_for_posts') ) {
634
- array_push( $listofurls, get_permalink( get_option( 'page_for_posts' ) ) );
635
  }
636
  }
637
-
638
  } else {
639
  // We're not sure how we got here, but bail instead of processing anything else.
640
  return;
641
  }
642
-
643
- // Now flush all the URLs we've collected provided the array isn't empty
644
  // And make sure each URL only gets purged once, eh?
645
- if ( !empty( $listofurls ) ) {
646
  $purgeurls = array_unique( $listofurls, SORT_REGULAR );
647
  foreach ( $purgeurls as $url ) {
648
- array_push( $this->purgeUrls, $url ) ;
649
  }
650
  }
651
 
652
- // Filter to add or remove urls to the array of purged urls
653
- // @param array $purgeUrls the urls (paths) to be purged
654
- // @param int $postId the id of the new/edited post
655
- $this->purgeUrls = apply_filters( 'vhp_purge_urls', $this->purgeUrls, $postId );
 
 
656
  }
657
 
658
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
659
 
660
- $purger = new VarnishPurger();
661
 
662
  /**
663
  * Purge Varnish via WP-CLI
@@ -665,11 +871,15 @@ $purger = new VarnishPurger();
665
  * @since 3.8
666
  */
667
  if ( defined( 'WP_CLI' ) && WP_CLI ) {
668
- include( 'wp-cli.php' );
669
  }
670
 
671
- /* Varnish Status Page
672
- *
 
673
  * @since 4.0
674
  */
675
- include_once( 'status.php' );
 
 
 
1
  <?php
2
+ /**
3
+ * Plugin Name: Varnish HTTP Purge
4
+ * Plugin URI: https://halfelf.org/plugins/varnish-http-purge/
5
+ * Description: Automatically empty cached pages when content on your site is modified.
6
+ * Version: 4.6.0
7
+ * Author: Mika Epstein
8
+ * Author URI: https://halfelf.org/
9
+ * License: http://www.apache.org/licenses/LICENSE-2.0
10
+ * Text Domain: varnish-http-purge
11
+ * Network: true
12
+ *
13
+ * @package varnish-http-purge
14
+ *
15
+ * Copyright 2016-2018 Mika Epstein (email: ipstenu@halfelf.org)
16
+ *
17
+ * This file is part of Varnish HTTP Purge, a plugin for WordPress.
18
+ *
19
+ * Varnish HTTP Purge is free software: you can redistribute it and/or modify
20
+ * it under the terms of the Apache License 2.0 license.
21
+ *
22
+ * Varnish HTTP Purge is distributed in the hope that it will be useful,
23
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
24
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
25
+ */
26
 
27
  /**
28
  * Purge Varnish Class
29
  *
30
  * @since 2.0
31
  */
 
32
  class VarnishPurger {
33
+
34
+ /**
35
+ * List of URLs to be purged
36
+ *
37
+ * (default value: array())
38
+ *
39
+ * @var array
40
+ * @access protected
41
+ */
42
+ protected $purge_urls = array();
43
+
44
+ /**
45
+ * Devmode options
46
+ *
47
+ * (default value: array())
48
+ *
49
+ * @var array
50
+ * @access public
51
+ * @static
52
+ */
53
+ public static $devmode = array();
54
 
55
  /**
56
  * Init
58
  * @since 2.0
59
  * @access public
60
  */
61
+ public function __construct() {
62
+ defined( 'VHP_VARNISH_IP' ) || define( 'VHP_VARNISH_IP', false );
63
+ defined( 'VHP_DEVMODE' ) || define( 'VHP_DEVMODE', false );
64
+
65
+ // Development mode defaults to off.
66
+ self::$devmode = array(
67
+ 'active' => false,
68
+ 'expire' => current_time( 'timestamp' ),
69
+ );
70
+ if ( ! get_site_option( 'vhp_varnish_devmode' ) ) {
71
+ update_site_option( 'vhp_varnish_devmode', self::$devmode );
72
+ }
73
+
74
+ // Default URL is home.
75
+ if ( ! get_site_option( 'vhp_varnish_url' ) ) {
76
+ update_site_option( 'vhp_varnish_url', $this->the_home_url() );
77
+ }
78
+
79
+ // Default IP is nothing.
80
+ if ( ! get_site_option( 'vhp_varnish_ip' ) && ! VHP_VARNISH_IP ) {
81
+ update_site_option( 'vhp_varnish_ip', '' );
82
+ }
83
+
84
+ // Release the hounds!
85
  add_action( 'init', array( &$this, 'init' ) );
86
  add_action( 'admin_init', array( &$this, 'admin_init' ) );
87
+
88
  }
89
 
90
  /**
94
  * @access public
95
  */
96
  public function admin_init() {
97
+
98
+ // Add to 'right now'.
99
  add_action( 'activity_box_end', array( $this, 'varnish_rightnow' ), 100 );
100
 
101
+ // Failure: Pre WP 4.7.
102
  if ( version_compare( get_bloginfo( 'version' ), '4.7', '<=' ) ) {
103
  deactivate_plugins( plugin_basename( __FILE__ ) );
104
+ add_action( 'admin_notices', array( $this, 'require_wp_version_notice' ) );
105
  return;
106
  }
107
 
108
+ // Admin notices.
109
+ if ( current_user_can( 'manage_options' ) ) {
110
+
111
+ // Warning: Debug is active.
112
+ if ( VarnishDebug::devmode_check() ) {
113
+ add_action( 'admin_notices', array( $this, 'devmode_is_active_notice' ) );
114
+ }
115
+
116
+ // Warning: No Pretty Permalinks!
117
+ if ( '' === get_site_option( 'permalink_structure' ) ) {
118
+ add_action( 'admin_notices', array( $this, 'require_pretty_permalinks_notice' ) );
119
+ }
120
  }
121
  }
122
 
129
  public function init() {
130
  global $blog_id;
131
 
132
+ // If Dev Mode is true, kill caching.
133
+ if ( VarnishDebug::devmode_check() ) {
134
+ if ( ! is_admin() ) {
135
+ // Sessions to break PHP caching.
136
+ if ( ! is_user_logged_in() ) {
137
+ // @codingStandardsIgnoreStart
138
+ @session_start();
139
+ // @codingStandardsIgnoreEnd
140
+ }
141
+
142
+ // Add nocacche to CSS and JS.
143
+ add_filter( 'style_loader_src', array( 'VarnishDebug', 'nocache_cssjs' ), 10, 2 );
144
+ add_filter( 'script_loader_src', array( 'VarnishDebug', 'nocache_cssjs' ), 10, 2 );
145
+ }
146
  }
147
 
148
+ // get my events.
149
+ $events = $this->get_register_events();
150
+ $no_id_events = $this->get_no_id_events();
151
 
152
+ // make sure we have events and they're in an array.
153
+ if ( ! empty( $events ) && ! empty( $no_id_events ) ) {
154
 
155
+ // Force it to be an array, in case someone's stupid.
156
+ $events = (array) $events;
157
+ $no_id_events = (array) $no_id_events;
158
 
159
+ // Add the action for each event.
160
+ foreach ( $events as $event ) {
161
+ if ( in_array( $event, $no_id_events, true ) ) {
162
+ // These events have no post ID and, thus, will perform a full purge.
163
+ add_action( $event, array( $this, 'execute_purge_no_id' ) );
164
  } else {
165
+ add_action( $event, array( $this, 'purge_post' ), 10, 2 );
166
  }
167
  }
168
  }
 
 
169
 
170
+ add_action( 'shutdown', array( $this, 'execute_purge' ) );
171
+
172
+ // Success: Admin notice when purging.
173
+ if ( ( isset( $_GET['vhp_flush_all'] ) && check_admin_referer( 'vhp-flush-all' ) ) ||
174
  ( isset( $_GET['vhp_flush_do'] ) && check_admin_referer( 'vhp-flush-do' ) ) ) {
175
+ if ( 'devmode' === $_GET['vhp_flush_do'] ) {
176
+ $toggle = ( VarnishDebug::devmode_check() ) ? 'deactivate' : 'activate';
177
+ VarnishDebug::devmode_toggle( $toggle );
178
+ add_action( 'admin_notices', array( $this, 'admin_message_devmode' ) );
179
+ } else {
180
+ add_action( 'admin_notices', array( $this, 'admin_message_purge' ) );
181
+ }
182
  }
183
+
184
+ // Add Admin Bar.
185
  add_action( 'admin_bar_menu', array( $this, 'varnish_rightnow_adminbar' ), 100 );
186
  add_action( 'admin_enqueue_scripts', array( $this, 'custom_css' ) );
187
  add_action( 'wp_enqueue_scripts', array( $this, 'custom_css' ) );
191
  * Purge Message
192
  * Informs of a succcessful purge
193
  *
194
+ * @since 4.6
195
  */
196
+ public function admin_message_purge() {
197
+ echo '<div id="message" class="notice notice-success fade is-dismissible"><p><strong>' . esc_html__( 'Varnish cache emptied!', 'varnish-http-purge' ) . '</strong></p></div>';
198
+ }
199
+
200
+ /**
201
+ * Devmode Message
202
+ * Informs of a toggle in Devmode
203
+ *
204
+ * @since 4.6
205
+ */
206
+ public function admin_message_devmode() {
207
+ $message = ( VarnishDebug::devmode_check() ) ? __( 'Development Mode activated for the next 24 hours.', 'varnish-http-purge' ) : __( 'Development Mode deactivated.', 'varnish-http-purge' );
208
+ echo '<div id="message" class="notice notice-success fade is-dismissible"><p><strong>' . wp_kses_post( $message ) . '</strong></p></div>';
209
  }
210
 
211
  /**
214
  *
215
  * @since 2.0
216
  */
217
+ public function require_pretty_permalinks_notice() {
218
+ // translators: The URL should link to the permalinks page.
219
+ echo "<div id='message' class='error'><p>" . sprintf( esc_html__( 'Varnish HTTP Purge requires you to use custom permalinks. Please go to the <a href="%1$s">Permalinks Options Page</a> to configure them.', 'varnish-http-purge' ), esc_url( admin_url( 'options-permalink.php' ) ) ) . '</p></div>';
220
  }
221
 
222
  /**
225
  *
226
  * @since 4.1
227
  */
228
+ public function require_wp_version_notice() {
229
+ // translators: The URL should link to the update core page.
230
+ echo "<div id='message' class='error'><p>" . sprintf( esc_html__( 'Varnish HTTP Purge requires WordPress 4.7 or greater. Please <a href="%1$s">upgrade WordPress</a>.', 'varnish-http-purge' ), esc_url( admin_url( 'update-core.php' ) ) ) . '</p></div>';
231
+ }
232
+
233
+ /**
234
+ * Warning: Development Mode
235
+ * Checks if DevMode is active
236
+ *
237
+ * @since 4.6.0
238
+ */
239
+ public function devmode_is_active_notice() {
240
+ if ( VHP_DEVMODE ) {
241
+ $message = __( 'Varnish HTTP Purge Development Mode is active because it has been defined in wp-config.', 'varnish-http-purge' );
242
+ } else {
243
+ $devmode = get_site_option( 'vhp_varnish_devmode', self::$devmode );
244
+ $time = human_time_diff( current_time( 'timestamp' ), $devmode['expire'] );
245
+ // translators: %1$s is the time until dev mode expires.
246
+ // translators: %2$s is a link to the Varnish settings pages.
247
+ $message = sprintf( __( 'Varnish HTTP Purge Development Mode is active for the next %1$s. You can disable this at the <a href="%2$s">Varnish Settings Page</a>.', 'varnish-http-purge' ), $time, esc_url( admin_url( 'admin.php?page=varnish-page' ) ) );
248
+ }
249
+ echo '<div class="notice notice-warning"><p>' . wp_kses_post( $message ) . '</p></div>';
250
  }
251
 
252
  /**
257
  *
258
  * @since 4.0
259
  */
260
+ public static function the_home_url() {
261
  $home_url = apply_filters( 'vhp_home_url', home_url() );
262
  return $home_url;
263
  }
264
 
265
  /**
266
  * Custom CSS to allow for coloring.
267
+ *
268
  * @since 4.5.0
269
  */
270
+ public function custom_css() {
271
+ if ( is_user_logged_in() ) {
272
+ wp_register_style( 'varnish_http_purge', plugins_url( 'style.css', __FILE__ ), false, '4.6.0' );
273
+ wp_enqueue_style( 'varnish_http_purge' );
274
+ }
275
  }
276
 
277
  /**
278
  * Varnish Purge Button in the Admin Bar
279
  *
280
+ * @access public
281
+ * @param mixed $admin_bar - data passed back from admin bar.
282
+ * @return void
283
  */
284
+ public function varnish_rightnow_adminbar( $admin_bar ) {
285
  global $wp;
286
 
287
+ $can_purge = false;
288
+ $cache_active = ( VarnishDebug::devmode_check() ) ? __( 'Inactive', 'varnish-http-purge' ) : __( 'Active', 'varnish-http-purge' );
289
+ // translators: %s is the state of cache.
290
+ $cache_titled = sprintf( __( 'Cache (%s)', 'varnish-http-purge' ), $cache_active );
291
 
292
+ if ( ( ! is_admin() && get_post() !== false && current_user_can( 'edit_published_posts' ) ) || current_user_can( 'activate_plugins' ) ) {
293
+ // Main Array.
294
+ $args = array(
295
  array(
296
  'id' => 'purge-varnish-cache',
297
+ 'title' => '<span class="ab-icon" style="background-image: url(' . self::get_icon_svg() . ') !important;"></span><span class="ab-label">' . $cache_titled . '</span>',
298
+ 'meta' => array(
299
+ 'class' => 'varnish-http-purge',
300
  ),
301
  ),
302
  );
303
+ $can_purge = true;
304
  }
305
 
306
+ // Checking user permissions for who can and cannot use the all flush.
307
  if (
308
+ // SingleSite - admins can always purge.
309
+ ( ! is_multisite() && current_user_can( 'activate_plugins' ) ) ||
310
+ // Multisite - Network Admin can always purge.
311
  current_user_can( 'manage_network' ) ||
312
+ // Multisite - Site admins can purge UNLESS it's a subfolder install and we're on site #1.
313
+ ( is_multisite() && current_user_can( 'activate_plugins' ) && ( SUBDOMAIN_INSTALL || ( ! SUBDOMAIN_INSTALL && ( BLOG_ID_CURRENT_SITE !== $blog_id ) ) ) )
314
  ) {
315
 
316
  $args[] = array(
317
  'parent' => 'purge-varnish-cache',
318
  'id' => 'purge-varnish-cache-all',
319
+ 'title' => __( 'Purge Cache (All Pages)', 'varnish-http-purge' ),
320
  'href' => wp_nonce_url( add_query_arg( 'vhp_flush_do', 'all' ), 'vhp-flush-do' ),
321
  'meta' => array(
322
+ 'title' => __( 'Purge Cache (All Pages)', 'varnish-http-purge' ),
323
  ),
324
  );
325
+
326
+ // If a memcached file is found, we can do this too.
327
  if ( file_exists( WP_CONTENT_DIR . '/object-cache.php' ) ) {
328
  $args[] = array(
329
  'parent' => 'purge-varnish-cache',
330
  'id' => 'purge-varnish-cache-db',
331
+ 'title' => __( 'Purge Database Cache', 'varnish-http-purge' ),
332
  'href' => wp_nonce_url( add_query_arg( 'vhp_flush_do', 'object' ), 'vhp-flush-do' ),
333
  'meta' => array(
334
+ 'title' => __( 'Purge Database Cache', 'varnish-http-purge' ),
335
+ ),
336
+ );
337
+ }
338
+
339
+ // If we're on a front end page and the current user can edit published posts, then they can do this.
340
+ if ( ! is_admin() && get_post() !== false && current_user_can( 'edit_published_posts' ) ) {
341
+ $page_url = esc_url( home_url( $wp->request ) );
342
+ $args[] = array(
343
+ 'parent' => 'purge-varnish-cache',
344
+ 'id' => 'purge-varnish-cache-this',
345
+ 'title' => __( 'Purge Cache (This Page)', 'varnish-http-purge' ),
346
+ 'href' => wp_nonce_url( add_query_arg( 'vhp_flush_do', $page_url . '/' ), 'vhp-flush-do' ),
347
+ 'meta' => array(
348
+ 'title' => __( 'Purge Cache (This Page)', 'varnish-http-purge' ),
349
  ),
350
  );
351
  }
 
352
 
353
+ // Populate enable/disable cache button.
354
+ $purge_devmode_title = ( VarnishDebug::devmode_check() ) ? __( 'Restart Cache', 'varnish-http-purge' ) : __( 'Pause Cache (24h)', 'varnish-http-purge' );
355
+ $args[] = array(
 
356
  'parent' => 'purge-varnish-cache',
357
+ 'id' => 'purge-varnish-cache-devmode',
358
+ 'title' => $purge_devmode_title,
359
+ 'href' => wp_nonce_url( add_query_arg( 'vhp_flush_do', 'devmode' ), 'vhp-flush-do' ),
360
  'meta' => array(
361
+ 'title' => $purge_devmode_title,
362
  ),
363
  );
364
  }
370
  }
371
  }
372
 
373
+ /**
374
+ * Get the icon as SVG.
375
+ *
376
+ * Forked from Yoast SEO
377
+ *
378
+ * @access public
379
+ * @param bool $base64 (default: true) - Use SVG, true/false?
380
+ * @param string $icon_color - What color to use.
381
+ * @return string
382
+ */
383
+ public static function get_icon_svg( $base64 = true, $icon_color = false ) {
384
+ global $_wp_admin_css_colors;
385
+
386
+ $fill = ( false !== $icon_color ) ? sanitize_hex_color( $icon_color ) : '#82878c';
387
+
388
+ if ( is_admin() && false === $icon_color ) {
389
+ $admin_colors = json_decode( wp_json_encode( $_wp_admin_css_colors ), true );
390
+ $current_color = get_user_option( 'admin_color' );
391
+ $fill = $admin_colors[ $current_color ]['icon_colors']['base'];
392
+ }
393
+
394
+ // Flat
395
+ $svg = '<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="100%" height="100%" style="fill:' . $fill . '" viewBox="0 0 36.2 34.39" role="img" aria-hidden="true" focusable="false"><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><path fill="' . $fill . '" d="M24.41,0H4L0,18.39H12.16v2a2,2,0,0,0,4.08,0v-2H24.1a8.8,8.8,0,0,1,4.09-1Z"/><path fill="' . $fill . '" d="M21.5,20.4H18.24a4,4,0,0,1-8.08,0v0H.2v8.68H19.61a9.15,9.15,0,0,1-.41-2.68A9,9,0,0,1,21.5,20.4Z"/><path fill="' . $fill . '" d="M28.7,33.85a7,7,0,1,1,7-7A7,7,0,0,1,28.7,33.85Zm-1.61-5.36h5V25.28H30.31v-3H27.09Z"/><path fill="' . $fill . '" d="M28.7,20.46a6.43,6.43,0,1,1-6.43,6.43,6.43,6.43,0,0,1,6.43-6.43M26.56,29h6.09V24.74H30.84V21.8H26.56V29m2.14-9.64a7.5,7.5,0,1,0,7.5,7.5,7.51,7.51,0,0,0-7.5-7.5ZM27.63,28V22.87h2.14v2.95h1.81V28Z"/></g></g></svg>';
396
+
397
+ if ( $base64 ) {
398
+ return 'data:image/svg+xml;base64,' . base64_encode( $svg );
399
+ }
400
+
401
+ return $svg;
402
+ }
403
+
404
  /**
405
  * Varnish Right Now Information
406
  * This information is put on the Dashboard 'Right now' widget
407
  *
408
  * @since 1.0
409
  */
410
+ public function varnish_rightnow() {
411
  global $blog_id;
412
+ // translators: %1$s links to the plugin's page on WordPress.org.
413
  $intro = sprintf( __( '<a href="%1$s">Varnish HTTP Purge</a> automatically deletes your cached posts when published or updated. When making major site changes, such as with a new theme, plugins, or widgets, you may need to manually empty the cache.', 'varnish-http-purge' ), 'http://wordpress.org/plugins/varnish-http-purge/' );
414
+ $url = wp_nonce_url( add_query_arg( 'vhp_flush_do', 'all' ), 'vhp-flush-do' );
415
+ $button = __( 'Press the button below to force it to empty your entire Varnish cache.', 'varnish-http-purge' );
416
+ $button .= '</p><p><span class="button"><span class="dashicons varnish-http-purge" style="background-image: url(' . self::get_icon_svg( true, '#F56E28' ) . ') !important;"></span> <a href="' . $url . '"><strong>';
417
  $button .= __( 'Empty Cache', 'varnish-http-purge' );
418
  $button .= '</strong></a></span>';
419
+ $nobutton = __( 'You do not have permission to empty the Varnish cache for the whole site. Please contact your administrator.', 'varnish-http-purge' );
420
 
421
  if (
422
+ // SingleSite - admins can always purge.
423
+ ( ! is_multisite() && current_user_can( 'activate_plugins' ) ) ||
424
+ // Multisite - Network Admin can always purge.
425
  current_user_can( 'manage_network' ) ||
426
+ // Multisite - Site admins can purge UNLESS it's a subfolder install and we're on site #1.
427
+ ( is_multisite() && current_user_can( 'activate_plugins' ) && ( SUBDOMAIN_INSTALL || ( ! SUBDOMAIN_INSTALL && ( BLOG_ID_CURRENT_SITE !== $blog_id ) ) ) )
428
  ) {
429
+ $text = $intro . ' ' . $button;
430
  } else {
431
+ $text = $intro . ' ' . $nobutton;
432
  }
433
+ echo '<p class="varnish-rightnow">' . wp_kses_post( $text ) . '</p>';
434
  }
435
 
436
  /**
440
  * @since 1.0
441
  * @access protected
442
  */
443
+ protected function get_register_events() {
444
 
445
+ // Define registered purge events.
446
  $actions = array(
447
+ 'switch_theme', // After a theme is changed.
448
+ 'autoptimize_action_cachepurged', // Compat with https://wordpress.org/plugins/autoptimize/ plugin.
449
+ 'save_post', // Save a post.
450
+ 'deleted_post', // Delete a post.
451
+ 'trashed_post', // Empty Trashed post.
452
+ 'edit_post', // Edit a post - includes leaving comments.
453
+ 'delete_attachment', // Delete an attachment - includes re-uploading.
454
  );
455
 
456
+ // send back the actions array, filtered.
457
+ // @param array $actions the actions that trigger the purge event.
458
  return apply_filters( 'varnish_http_purge_events', $actions );
459
  }
460
 
465
  * @since 3.9
466
  * @access protected
467
  */
468
+ protected function get_no_id_events() {
469
 
470
+ // Define registered purge events.
471
  $actions = array(
472
+ 'switch_theme', // After a theme is changed.
473
+ 'autoptimize_action_cachepurged,', // Compat with https://wordpress.org/plugins/autoptimize/ plugin.
474
  );
475
 
476
+ /**
477
+ * Send back the actions array, filtered
478
+ *
479
+ * @param array $actions the actions that trigger the purge event
480
+ *
481
+ * DEVELOPERS! USE THIS SPARINGLY! YOU'RE A GREAT BIG 💩 IF YOU USE IT FLAGRANTLY
482
+ * Remember to add your action to this AND varnish_http_purge_events due to shenanigans
483
+ */
484
  return apply_filters( 'varnish_http_purge_events_full', $actions );
485
  }
486
 
487
  /**
488
  * Execute Purge
489
+ * Run the purge command for the URLs. Calls $this->purge_url for each URL
490
  *
491
  * @since 1.0
492
  * @access protected
493
  */
494
+ public function execute_purge() {
495
+ $purge_urls = array_unique( $this->purge_urls );
496
 
497
+ if ( empty( $purge_urls ) && isset( $_GET ) ) {
498
  if ( isset( $_GET['vhp_flush_all'] ) && check_admin_referer( 'vhp-flush-all' ) ) {
499
+ // Flush Varnish Cache recursize.
500
+ $this->purge_url( $this->the_home_url() . '/?vhp-regex' );
501
  } elseif ( isset( $_GET['vhp_flush_do'] ) && check_admin_referer( 'vhp-flush-do' ) ) {
502
+ if ( 'object' === $_GET['vhp_flush_do'] ) {
503
+ // Flush Object Cache (with a double check).
504
+ if ( file_exists( WP_CONTENT_DIR . '/object-cache.php' ) ) {
505
+ wp_cache_flush();
506
+ }
507
+ } elseif ( 'all' === $_GET['vhp_flush_do'] ) {
508
+ // Flush Varnish Cache recursize.
509
+ $this->purge_url( $this->the_home_url() . '/?vhp-regex' );
510
  } else {
511
+ // Flush the URL we're on.
512
+ $p = wp_parse_url( esc_url_raw( wp_unslash( $_GET['vhp_flush_do'] ) ) );
513
+ if ( ! isset( $p['host'] ) ) {
514
+ return;
515
+ }
516
+ $this->purge_url( esc_url_raw( wp_unslash( $_GET['vhp_flush_do'] ) ) );
517
  }
518
  }
519
  } else {
520
+ foreach ( $purge_urls as $url ) {
521
+ $this->purge_url( $url );
522
  }
523
  }
524
  }
528
  * Parse the URL for proxy proxies
529
  *
530
  * @since 1.0
531
+ * @param array $url - The url to be purged.
532
  * @access protected
533
  */
534
+ public static function purge_url( $url ) {
535
+ $p = wp_parse_url( wp_unslash( $url ) );
536
+
537
+ // Bail early if there's no host since some plugins are weird.
538
+ if ( ! isset( $p['host'] ) ) {
539
+ return;
540
+ }
541
 
542
+ // Determine if we're using regex to flush all pages or not.
543
  $pregex = '';
544
  $x_purge_method = 'default';
545
 
546
+ if ( isset( $p['query'] ) && ( 'vhp-regex' === $p['query'] ) ) {
547
  $pregex = '.*';
548
  $x_purge_method = 'regex';
549
  }
550
 
551
+ // Build a varniship.
552
+ if ( VHP_VARNISH_IP !== false ) {
553
  $varniship = VHP_VARNISH_IP;
554
  } else {
555
+ $varniship = get_site_option( 'vhp_varnish_ip' );
556
  }
557
+ $varniship = apply_filters( 'vhp_varnish_ip', $varniship );
558
 
559
+ // Determine the path.
560
  $path = '';
561
  if ( isset( $p['path'] ) ) {
562
  $path = $p['path'];
572
  */
573
  $schema = apply_filters( 'varnish_http_purge_schema', 'http://' );
574
 
575
+ // If we made varniship, let it sail.
576
+ if ( isset( $varniship ) && ! is_null( $varniship ) ) {
577
  $host = $varniship;
578
  } else {
579
  $host = $p['host'];
580
  }
581
 
582
+ /**
583
  * Allow setting of ports in host name
584
  * Credit: davidbarratt - https://github.com/Ipstenu/varnish-http-purge/pull/38/
585
+ *
586
+ * (default value: $p['host'])
587
+ *
588
+ * @var string
589
+ * @access public
590
  * @since 4.4.0
591
  */
592
  $host_headers = $p['host'];
594
  $host_headers .= ':' . $p['port'];
595
  }
596
 
597
+ // Create path to purge.
598
+ $purgeme = $schema . $host . $path . $pregex;
599
 
600
  // Check the queries...
601
+ if ( ! empty( $p['query'] ) && 'vhp-regex' !== $p['query'] ) {
602
  $purgeme .= '?' . $p['query'];
603
  }
604
 
607
  *
608
  * @since 4.1
609
  */
610
+ $headers = apply_filters( 'varnish_http_purge_headers', array(
611
+ 'host' => $host_headers,
612
+ 'X-Purge-Method' => $x_purge_method,
613
+ ) );
614
+ $response = wp_remote_request( $purgeme, array(
615
+ 'method' => 'PURGE',
616
+ 'headers' => $headers,
617
+ ) );
618
 
619
  do_action( 'after_purge_url', $url, $purgeme, $response, $headers );
620
  }
623
  * Purge - No IDs
624
  * Flush the whole cache
625
  *
 
626
  * @access public
627
+ * @param mixed $post_id - the post ID that triggered this (we don't use it yet).
628
+ * @return void
629
+ * @since 3.9
630
  */
631
+ public function execute_purge_no_id( $post_id ) {
632
  $listofurls = array();
633
 
634
  array_push( $listofurls, $this->the_home_url() . '/?vhp-regex' );
635
+
636
+ // Now flush all the URLs we've collected provided the array isn't empty.
637
+ if ( ! empty( $listofurls ) ) {
638
  foreach ( $listofurls as $url ) {
639
+ array_push( $this->purge_urls, $url );
640
  }
641
  }
642
+
643
+ do_action( 'after_full_purge' );
644
  }
645
 
646
  /**
649
  * Generates a list of URLs that should be purged, based on the post ID
650
  * passed through. Useful for when you're trying to get a post to flush
651
  * another post.
652
+ *
653
  * @access public
654
+ * @param mixed $post_id - The ID of the post to be purged.
655
  * @return array()
656
  */
657
+ public function generate_urls( $post_id ) {
658
+ $this->purge_post( $post_id );
659
+ return $this->purge_urls;
660
  }
661
 
662
  /**
664
  * Flush the post
665
  *
666
  * @since 1.0
667
+ * @param array $post_id - The ID of the post to be purged.
668
  * @access public
669
  */
670
+ public function purge_post( $post_id ) {
671
+
672
+ /**
673
+ * Future Me: You may need this if you figure out how to use an array
674
+ * further down with versions of WP and their json versions.
675
+ * Maybe use global $wp_version;
676
+ * If this is a valid post we want to purge the post,
677
+ * the home page and any associated tags and categories
678
+ */
679
  $valid_post_status = array( 'publish', 'private', 'trash' );
680
+ $this_post_status = get_post_status( $post_id );
681
 
682
+ // Not all post types are created equal.
683
+ $invalid_post_type = array( 'nav_menu_item', 'revision' );
684
  $noarchive_post_type = array( 'post', 'page' );
685
+ $this_post_type = get_post_type( $post_id );
686
+
687
+ /**
688
+ * Determine the route for the rest API
689
+ * This will need to be revisted if WP updates the version.
690
+ * Future me: Consider an array? 4.7-4.9 use v2, and then adapt from there?
691
+ */
692
+ $rest_api_route = 'wp/v2';
693
+
694
+ // array to collect all our URLs.
695
  $listofurls = array();
696
 
697
+ // Verify we have a permalink and that we're a valid post status and a not an invalid post type.
698
+ if ( true === get_permalink( $post_id ) && in_array( $this_post_status, $valid_post_status, true ) && ! in_array( $this_post_type, $invalid_post_type, true ) ) {
699
 
700
+ // Post URL.
701
+ array_push( $listofurls, get_permalink( $post_id ) );
702
 
703
+ /**
704
+ * JSON API Permalink for the post based on type
705
+ * We only want to do this if the rest_base exists
706
+ * But we apparently have to force it for posts and pages (seriously?)
707
+ */
708
+ $post_type_object = get_post_type_object( $post_id );
709
+ $rest_permalink = false;
710
  if ( isset( $post_type_object->rest_base ) ) {
711
+ $rest_permalink = get_rest_url() . $rest_api_route . '/' . $post_type_object->rest_base . '/' . $post_id . '/';
712
+ } elseif ( 'post' === $this_post_type ) {
713
+ $rest_permalink = get_rest_url() . $rest_api_route . '/posts/' . $post_id . '/';
714
+ } elseif ( 'page' === $this_post_type ) {
715
+ $rest_permalink = get_rest_url() . $rest_api_route . '/pages/' . $post_id . '/';
716
  }
717
 
718
+ if ( $rest_permalink ) {
719
+ array_push( $listofurls, $rest_permalink );
720
+ }
721
 
722
+ // Add in AMP permalink if Automattic's AMP is installed.
723
  if ( function_exists( 'amp_get_permalink' ) ) {
724
+ array_push( $listofurls, amp_get_permalink( $post_id ) );
725
  }
726
+
727
+ // Regular AMP url for posts.
728
+ array_push( $listofurls, get_permalink( $post_id ) . 'amp/' );
729
 
730
  // Also clean URL for trashed post.
731
+ if ( 'trash' === $this_post_status ) {
732
+ $trashpost = get_permalink( $post_id );
733
  $trashpost = str_replace( '__trashed', '', $trashpost );
734
  array_push( $listofurls, $trashpost, $trashpost . 'feed/' );
735
  }
736
 
737
+ // Category purge based on Donnacha's work in WP Super Cache.
738
+ $categories = get_the_category( $post_id );
739
  if ( $categories ) {
740
  foreach ( $categories as $cat ) {
741
+ $category_base = get_site_option( 'category_base' );
742
+ if ( '' === $category_base ) {
743
+ $category_base = '/category/';
744
+ }
745
+ array_push( $listofurls,
746
  get_category_link( $cat->term_id ),
747
  get_rest_url() . $rest_api_route . '/categories/' . $cat->term_id . '/'
748
  );
749
  }
750
  }
751
+ // Tag purge based on Donnacha's work in WP Super Cache.
752
+ $tags = get_the_tags( $post_id );
753
  if ( $tags ) {
754
+ $tag_base = get_site_option( 'tag_base' );
755
+ if ( '' === $tag_base ) {
756
+ $tag_base = '/tag/';
757
+ }
758
  foreach ( $tags as $tag ) {
759
+ array_push( $listofurls,
760
  get_tag_link( $tag->term_id ),
761
  get_rest_url() . $rest_api_route . $tag_base . $tag->term_id . '/'
762
  );
763
  }
764
  }
765
+ // Custom Taxonomies: Only show if the taxonomy is public.
766
+ $taxonomies = get_post_taxonomies( $post_id );
767
+ if ( $taxonomies ) {
 
768
  foreach ( $taxonomies as $taxonomy ) {
769
+ $features = (array) get_taxonomy( $taxonomy );
770
  if ( $features['public'] ) {
771
+ $terms = wp_get_post_terms( $post_id, $taxonomy );
772
  foreach ( $terms as $term ) {
773
+ array_push( $listofurls,
774
  get_term_link( $term ),
775
  get_rest_url() . $rest_api_route . '/' . $term->taxonomy . '/' . $term->slug . '/'
776
  );
777
+ }
778
  }
779
  }
780
  }
781
+
782
+ // Author URLs.
783
+ $author_id = get_post_field( 'post_author', $post_id );
784
  array_push( $listofurls,
785
  get_author_posts_url( $author_id ),
786
  get_author_feed_link( $author_id ),
787
  get_rest_url() . $rest_api_route . '/users/' . $author_id . '/'
788
  );
789
 
790
+ // Archives and their feeds.
791
+ if ( $this_post_type && ! in_array( $this_post_type, $noarchive_post_type, true ) ) {
792
  array_push( $listofurls,
793
+ get_post_type_archive_link( get_post_type( $post_id ) ),
794
+ get_post_type_archive_feed_link( get_post_type( $post_id ) )
795
  // Need to add in JSON?
796
  );
797
  }
798
+
799
+ // More feeds.
800
  array_push( $listofurls,
801
  get_bloginfo_rss( 'rdf_url' ),
802
  get_bloginfo_rss( 'rss_url' ),
803
  get_bloginfo_rss( 'rss2_url' ),
804
  get_bloginfo_rss( 'atom_url' ),
805
  get_bloginfo_rss( 'comments_rss2_url' ),
806
+ get_post_comments_feed_link( $post_id )
807
  );
808
 
809
+ // Home Pages and (if used) posts page.
810
+ array_push( $listofurls,
811
  get_rest_url(),
812
  $this->the_home_url() . '/'
813
+ );
814
+ if ( 'page' === get_site_option( 'show_on_front' ) ) {
815
+ // Ensure we have a page_for_posts setting to avoid empty URL.
816
+ if ( get_site_option( 'page_for_posts' ) ) {
817
+ array_push( $listofurls, get_permalink( get_site_option( 'page_for_posts' ) ) );
818
  }
819
  }
 
820
  } else {
821
  // We're not sure how we got here, but bail instead of processing anything else.
822
  return;
823
  }
824
+
825
+ // Now flush all the URLs we've collected provided the array isn't empty.
826
  // And make sure each URL only gets purged once, eh?
827
+ if ( ! empty( $listofurls ) ) {
828
  $purgeurls = array_unique( $listofurls, SORT_REGULAR );
829
  foreach ( $purgeurls as $url ) {
830
+ array_push( $this->purge_urls, $url );
831
  }
832
  }
833
 
834
+ /*
835
+ * Filter to add or remove urls to the array of purged urls
836
+ * @param array $purge_urls the urls (paths) to be purged
837
+ * @param int $post_id the id of the new/edited post
838
+ */
839
+ $this->purge_urls = apply_filters( 'vhp_purge_urls', $this->purge_urls, $post_id );
840
  }
841
 
842
+ // @codingStandardsIgnoreStart
843
+ /*
844
+ * These have all been name changed to proper names, but just in case...
845
+ */
846
+ public function getRegisterEvents() {
847
+ get_register_events();
848
+ }
849
+ public function getNoIDEvents() {
850
+ get_no_id_events();
851
+ }
852
+ public function executePurge() {
853
+ execute_purge();
854
+ }
855
+ public function purgeNoID( $post_id ) {
856
+ execute_purge_no_id( $post_id );
857
+ }
858
+ public function purgeURL( $url ) {
859
+ purge_url( $url );
860
+ }
861
+ public function purgePost( $post_id ) {
862
+ purge_post( $post_id );
863
+ }
864
+ // @codingStandardsIgnoreEnd
865
 
866
+ }
867
 
868
  /**
869
  * Purge Varnish via WP-CLI
871
  * @since 3.8
872
  */
873
  if ( defined( 'WP_CLI' ) && WP_CLI ) {
874
+ include 'wp-cli.php';
875
  }
876
 
877
+ /*
878
+ * Settings Pages
879
+ *
880
  * @since 4.0
881
  */
882
+ require_once 'settings.php';
883
+ require_once 'debug.php';
884
+
885
+ $purger = new VarnishPurger();
wp-cli.php CHANGED
@@ -1,7 +1,11 @@
1
  <?php
2
  /**
 
 
 
 
3
  Copyright 2015-2018 Mika Epstein (email: ipstenu@halfelf.org)
4
-
5
  This file is part of Varnish HTTP Purge, a plugin for WordPress.
6
 
7
  Varnish HTTP Purge is free software: you can redistribute it and/or modify
@@ -10,166 +14,303 @@
10
  Varnish HTTP Purge is distributed in the hope that it will be useful,
11
  but WITHOUT ANY WARRANTY; without even the implied warranty of
12
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13
- */
 
 
 
 
14
 
15
- if ( !defined( 'ABSPATH' ) ) die();
 
 
 
16
 
17
- // Bail if WP-CLI is not present
18
- if ( !defined( 'WP_CLI' ) ) return;
19
 
20
- /**
21
- * WP-CLI Commands
22
- */
23
-
24
- if ( !class_exists( 'WP_CLI_Varnish_Command' ) ) {
25
  class WP_CLI_Varnish_Command extends WP_CLI_Command {
26
-
 
 
 
 
 
 
 
 
 
27
  private $wildcard = false;
28
-
 
 
 
 
 
 
 
29
  public function __construct() {
30
  $this->varnish_purge = new VarnishPurger();
31
  }
32
-
33
  /**
34
  * Forces a full Varnish Purge of the entire site (provided
35
  * regex is supported). Alternately you can fluxh the cache
36
  * for specific pages or folders (using the --wildcard param)
37
- *
38
  * ## EXAMPLES
39
- *
40
- * wp varnish purge
41
  *
42
- * wp varnish purge http://example.com/wp-content/themes/twentyeleventy/style.css
43
  *
44
- * wp varnish purge http://example.com/wp-content/themes/ --wildcard
45
  *
 
46
  */
47
-
48
- function purge( $args, $assoc_args ) {
49
-
50
- $wp_version = get_bloginfo( 'version' );
51
  $cli_version = WP_CLI_VERSION;
52
-
53
- // Set the URL/path
54
- if ( !empty($args) ) { list( $url ) = $args; }
55
-
56
- // If wildcard is set, or the URL argument is empty
57
- // then treat this as a full purge
58
- $pregex = $wild = '';
59
- if ( isset( $assoc_args['wildcard'] ) || empty($url) ) {
 
60
  $pregex = '/?vhp-regex';
61
- $wild = ".*";
62
  }
63
-
64
- wp_create_nonce('vhp-flush-cli');
65
-
66
  // If the URL is not empty, sanitize. Else use home URL.
67
- if ( !empty( $url ) ) {
68
  $url = esc_url( $url );
69
-
70
- // If it's a regex, let's make sure we don't have //
71
- if ( isset( $assoc_args['wildcard'] ) ) $url = rtrim( $url, '/' );
 
 
72
  } else {
73
  $url = $this->varnish_purge->the_home_url();
74
  }
75
-
76
  if ( version_compare( $wp_version, '4.6', '>=' ) && ( version_compare( $cli_version, '0.25.0', '<' ) || version_compare( $cli_version, '0.25.0-alpha', 'eq' ) ) ) {
77
-
78
- WP_CLI::log( sprintf( 'This plugin does not work on WP 4.6 and up, unless WP-CLI is version 0.25.0 or greater. You\'re using WP-CLI %s and WordPress %s.', $cli_version, $wp_version ) );
79
- WP_CLI::log( 'To flush your cache, please run the following command:');
80
- WP_CLI::log( sprintf( '$ curl -X PURGE "%s"' , $url . $wild ) );
81
- WP_CLI::error( 'Varnish Cache must be purged manually.' );
 
 
82
  }
83
-
84
- $this->varnish_purge->purgeUrl( $url . $pregex );
85
-
86
- if ( WP_DEBUG == true ) {
87
- WP_CLI::log( sprintf( 'Flushing URL: %s with params: %s.', $url, $pregex ) );
 
 
88
  }
89
-
90
- WP_CLI::success( 'The Varnish cache was purged.' );
91
  }
92
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
93
  /**
94
- * Runs a debug check of the site to see if there are any known
95
  * issues that would stop Varnish from caching.
96
- *
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
97
  * ## EXAMPLES
98
- *
99
- * wp varnish debug
100
  *
101
- * wp varnish debug http://example.com/wp-content/themes/twentyeleventy/style.css
102
  *
 
103
  */
104
-
105
- function debug( $args, $assoc_args ) {
106
-
107
- // Set the URL/path
108
- if ( !empty($args) ) list( $url ) = $args;
109
-
110
- $default_url = esc_url( $this->varnish_purge->the_home_url() );
111
-
112
- if ( !empty( $url ) ) {
113
- $parsed_input = parse_url($url);
114
- if ( empty($parsed_input['scheme']) ) {
115
- $schema_input = 'http://';
116
- if ( is_ssl() ) $schema_input = 'https://';
117
- $url = $schema_input . ltrim($url, '/');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
118
  }
119
- } else {
120
- $url = $default_url;
 
 
 
 
 
 
 
 
 
121
  }
122
-
123
- if ( empty( $url ) || parse_url( $default_url, PHP_URL_HOST ) !== parse_url( $url, PHP_URL_HOST ) ) {
124
- WP_CLI::error( __( 'You must enter a URL from your own domain to scan.', 'varnish-http-purge' ) );
125
- } elseif ( !filter_var( $url, FILTER_VALIDATE_URL) ) {
126
- WP_CLI::error( __( 'You have entered an invalid URL address.', 'varnish-http-purge' ) );
127
- } else {
128
-
129
- // Include the debug code
130
- if ( !class_exists( 'VarnishDebug' ) ) include( 'debug.php' );
131
-
132
- $varnishurl = get_option( 'vhp_varnish_url', $url );
133
-
134
- // Get the response and headers
135
- $remote_get = VarnishDebug::remote_get( $varnishurl );
136
- $headers = wp_remote_retrieve_headers( $remote_get );
137
-
138
- // Preflight checklist
139
- $preflight = VarnishDebug::preflight( $remote_get );
140
-
141
- // Check for Remote IP
142
- $remote_ip = VarnishDebug::remote_ip( $headers );
143
-
144
- // Get the Varnish IP
145
- if ( VHP_VARNISH_IP != false ) {
146
- $varniship = VHP_VARNISH_IP;
147
- } else {
148
- $varniship = get_option('vhp_varnish_ip');
149
  }
 
 
150
 
151
- if ( $preflight['preflight'] == false ) {
152
- WP_CLI::error( $preflight['message'] );
153
- } else {
154
- $results = VarnishDebug::get_all_the_results( $headers, $remote_ip, $varniship );
155
-
156
- // Generate array
157
- foreach ( $results as $type => $content ) {
158
- $items[] = array(
159
- 'name' => $type,
160
- 'status' => ucwords( $content['icon'] ),
161
- 'message' => $content['message'],
162
- );
163
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
164
 
165
- $format = ( isset( $assoc_args['format'] ) )? $assoc_args['format'] : 'table';
 
 
 
166
 
167
- // Output the data
168
- WP_CLI\Utils\format_items( $format, $items, array( 'name', 'status', 'message' ) );
 
 
 
 
 
169
  }
 
 
 
 
 
170
  }
171
- }
172
  }
173
  }
174
 
175
- WP_CLI::add_command( 'varnish', 'WP_CLI_Varnish_Command' );
1
  <?php
2
  /**
3
+ WP-CLI code
4
+
5
+ @package varnish-http-purge
6
+
7
  Copyright 2015-2018 Mika Epstein (email: ipstenu@halfelf.org)
8
+
9
  This file is part of Varnish HTTP Purge, a plugin for WordPress.
10
 
11
  Varnish HTTP Purge is free software: you can redistribute it and/or modify
14
  Varnish HTTP Purge is distributed in the hope that it will be useful,
15
  but WITHOUT ANY WARRANTY; without even the implied warranty of
16
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17
+ */
18
+
19
+ if ( ! defined( 'ABSPATH' ) ) {
20
+ die();
21
+ }
22
 
23
+ // Bail if WP-CLI is not present.
24
+ if ( ! defined( 'WP_CLI' ) ) {
25
+ return;
26
+ }
27
 
28
+ if ( ! class_exists( 'WP_CLI_Varnish_Command' ) ) {
 
29
 
30
+ /**
31
+ * WP CLI Commands for Varnish.
32
+ *
33
+ * @extends WP_CLI_Command
34
+ */
35
  class WP_CLI_Varnish_Command extends WP_CLI_Command {
36
+
37
+
38
+ /**
39
+ * wildcard
40
+ *
41
+ * (default value: false)
42
+ *
43
+ * @var bool
44
+ * @access private
45
+ */
46
  private $wildcard = false;
47
+
48
+
49
+ /**
50
+ * __construct function.
51
+ *
52
+ * @access public
53
+ * @return void
54
+ */
55
  public function __construct() {
56
  $this->varnish_purge = new VarnishPurger();
57
  }
58
+
59
  /**
60
  * Forces a full Varnish Purge of the entire site (provided
61
  * regex is supported). Alternately you can fluxh the cache
62
  * for specific pages or folders (using the --wildcard param)
63
+ *
64
  * ## EXAMPLES
 
 
65
  *
66
+ * wp varnish purge
67
  *
68
+ * wp varnish purge http://example.com/wp-content/themes/twentyeleventy/style.css
69
  *
70
+ * wp varnish purge http://example.com/wp-content/themes/ --wildcard
71
  */
72
+ public function purge( $args, $assoc_args ) {
73
+
74
+ $wp_version = get_bloginfo( 'version' );
 
75
  $cli_version = WP_CLI_VERSION;
76
+
77
+ // Set the URL/path.
78
+ if ( ! empty( $args ) ) {
79
+ list( $url ) = $args; }
80
+
81
+ // If wildcard is set, or the URL argument is empty then treat this as a full purge.
82
+ $pregex = '';
83
+ $wild = '';
84
+ if ( isset( $assoc_args['wildcard'] ) || empty( $url ) ) {
85
  $pregex = '/?vhp-regex';
86
+ $wild = '.*';
87
  }
88
+
89
+ wp_create_nonce( 'vhp-flush-cli' );
90
+
91
  // If the URL is not empty, sanitize. Else use home URL.
92
+ if ( ! empty( $url ) ) {
93
  $url = esc_url( $url );
94
+
95
+ // If it's a regex, let's make sure we don't have a trailing slash.
96
+ if ( isset( $assoc_args['wildcard'] ) ) {
97
+ $url = rtrim( $url, '/' );
98
+ }
99
  } else {
100
  $url = $this->varnish_purge->the_home_url();
101
  }
102
+
103
  if ( version_compare( $wp_version, '4.6', '>=' ) && ( version_compare( $cli_version, '0.25.0', '<' ) || version_compare( $cli_version, '0.25.0-alpha', 'eq' ) ) ) {
104
+
105
+ // translators: %1$s is the version of WP-CLI.
106
+ // translators: %2$s is the version of WordPress.
107
+ WP_CLI::log( sprintf( __( 'This plugin does not work on WP 4.6 and up, unless WP-CLI is version 0.25.0 or greater. You\'re using WP-CLI %1$s and WordPress %2$s.', 'varnish-http-purge' ), $cli_version, $wp_version ) );
108
+ WP_CLI::log( __( 'To flush your cache, please run the following command:', 'varnish-http-purge' ) );
109
+ WP_CLI::log( sprintf( '$ curl -X PURGE "%s"', $url . $wild ) );
110
+ WP_CLI::error( __( 'Your cache must be purged manually.', 'varnish-http-purge' ) );
111
  }
112
+
113
+ $this->varnish_purge->purge_url( $url . $pregex );
114
+
115
+ if ( WP_DEBUG === true ) {
116
+ // translators: %1$s is the URL being flushed.
117
+ // translators: %2$s are the params being flushed.
118
+ WP_CLI::log( sprintf( __( 'Varnish HTTP Purge is flushing the URL %1$s with params %2$s.', 'varnish-http-purge' ), $url, $pregex ) );
119
  }
120
+
121
+ WP_CLI::success( __( 'Varnish HTTP Purge has flushed your cache.', 'varnish-http-purge' ) );
122
  }
123
+
124
+ /**
125
+ * Activate, deactivate, or toggle Development Mode.
126
+ *
127
+ * ## OPTIONS
128
+ *
129
+ * [<state>]
130
+ * : Change the state of Development Mode
131
+ * ---
132
+ * options:
133
+ * - activate
134
+ * - deactivate
135
+ * - toggle
136
+ * ---
137
+ *
138
+ * ## EXAMPLES
139
+ *
140
+ * wp varnish devmode activate
141
+ * wp varnish devmode deactivate
142
+ * wp varnish devmode toggle
143
+ */
144
+ public function devmode( $args, $assoc_args ) {
145
+
146
+ $valid_modes = array( 'activate', 'deactivate', 'toggle' );
147
+ $devmode = get_site_option( 'vhp_varnish_devmode', VarnishPurger::$devmode );
148
+
149
+ // Check for valid arguments.
150
+ if ( empty( $args[0] ) ) {
151
+ // No params, echo state.
152
+ $state = ( $devmode['active'] ) ? __( 'activated', 'varnish-http-purge' ) : __( 'deactivated', 'varnish-http-purge' );
153
+ // translators: %s is the state of dev mode.
154
+ WP_CLI::log( sprintf( __( 'Varnish HTTP Purge development mode is currently %s.', 'varnish-http-purge' ), $state ) );
155
+ } elseif ( ! in_array( $args[0], $valid_modes, true ) ) {
156
+ // Invalid Params, warn.
157
+ // translators: %s is the bad command.
158
+ WP_CLI::error( sprintf( __( '%s is not a valid subcommand for varnish development mode.', 'varnish-http-purge' ), sanitize_text_field( $args[0] ) ) );
159
+ } else {
160
+ // Run the toggle!
161
+ $result = VarnishDebug::devmode_toggle( sanitize_text_field( $args[0] ) );
162
+ $state = ( $result ) ? __( 'activated', 'varnish-http-purge' ) : __( 'deactivated', 'varnish-http-purge' );
163
+ // translators: %s is the state of dev mode.
164
+ WP_CLI::success( sprintf( __( 'Varnish HTTP Purge development mode has been %s.', 'varnish-http-purge' ), $state ) );
165
+ }
166
+ } // End devmode.
167
+
168
  /**
169
+ * Runs a debug check of the site to see if there are any known
170
  * issues that would stop Varnish from caching.
171
+ *
172
+ * ## OPTIONS
173
+ *
174
+ * [<url>]
175
+ * : Specify a URL for testing against. Default is the home URL.
176
+ *
177
+ * [--include-headers]
178
+ * : Include headers in debug check output.
179
+ *
180
+ * [--include-grep]
181
+ * : Also grep active theme and plugin directories for common issues.
182
+ *
183
+ * [--format=<format>]
184
+ * : Render output in a particular format.
185
+ * ---
186
+ * default: table
187
+ * options:
188
+ * - table
189
+ * - csv
190
+ * - json
191
+ * - yaml
192
+ * ---
193
+ *
194
  * ## EXAMPLES
 
 
195
  *
196
+ * wp varnish debug
197
  *
198
+ * wp varnish debug http://example.com/wp-content/themes/twentyeleventy/style.css
199
  */
200
+ public function debug( $args, $assoc_args ) {
201
+
202
+ // Set the URL/path.
203
+ if ( ! empty( $args ) ) {
204
+ list( $url ) = $args;
205
+ }
206
+
207
+ if ( empty( $url ) ) {
208
+ $url = esc_url( $this->varnish_purge->the_home_url() );
209
+ }
210
+
211
+ WP_CLI::log( __( 'Robots are scanning your site for possible issues with caching... ', 'varnish-http-purge' ) );
212
+
213
+ if ( WP_CLI\Utils\get_flag_value( $assoc_args, 'include-grep' ) ) {
214
+ $pattern = '(PHPSESSID|session_start|start_session|$cookie|setCookie)';
215
+ // translators: %s is the pattern string.
216
+ WP_CLI::log( sprintf( __( 'Grepping for: %s.', 'varnish-http-purge' ), $pattern ) );
217
+ WP_CLI::log( '' );
218
+ $paths = array(
219
+ get_template_directory(),
220
+ get_stylesheet_directory(),
221
+ );
222
+ foreach ( wp_get_active_and_valid_plugins() as $plugin_path ) {
223
+ // We don't care about our own plugin.
224
+ if ( false !== stripos( $plugin_path, 'varnish-http-purge/varnish-http-purge.php' ) ) {
225
+ continue;
226
+ }
227
+ $paths[] = dirname( $plugin_path );
228
  }
229
+ $paths = array_unique( $paths );
230
+ foreach ( $paths as $path ) {
231
+ $cmd = sprintf(
232
+ "grep -RE '%s' %s",
233
+ $pattern,
234
+ escapeshellarg( $path )
235
+ );
236
+ passthru( $cmd );
237
+ }
238
+ WP_CLI::log( '' );
239
+ WP_CLI::log( __( 'Grep complete. If no data was output, you\'re good!', 'varnish-http-purge' ) );
240
  }
241
+
242
+ // Include the debug code.
243
+ if ( ! class_exists( 'VarnishDebug' ) ) {
244
+ include 'debug.php';
245
+ }
246
+
247
+ // Validate the URL.
248
+ $valid_url = VarnishDebug::is_url_valid( $url );
249
+
250
+ if ( 'valid' !== $valid_url ) {
251
+ switch ( $valid_url ) {
252
+ case 'empty':
253
+ case 'domain':
254
+ WP_CLI::error( __( 'You must provide a URL on your own domain to scan.', 'varnish-http-purge' ) );
255
+ break;
256
+ case 'invalid':
257
+ WP_CLI::error( __( 'You have entered an invalid URL address.', 'varnish-http-purge' ) );
258
+ break;
259
+ default:
260
+ WP_CLI::error( __( 'An unknown error has occurred.', 'varnish-http-purge' ) );
261
+ break;
 
 
 
 
 
 
262
  }
263
+ }
264
+ $varnishurl = get_site_option( 'vhp_varnish_url', $url );
265
 
266
+ // Get the response and headers.
267
+ $remote_get = VarnishDebug::remote_get( $varnishurl );
268
+ $headers = wp_remote_retrieve_headers( $remote_get );
269
+
270
+ if ( WP_CLI\Utils\get_flag_value( $assoc_args, 'include-headers' ) ) {
271
+ WP_CLI::log( 'Headers:' );
272
+ foreach ( $headers as $key => $value ) {
273
+ if ( is_array( $value ) ) {
274
+ $value = implode( ', ', $value );
 
 
 
275
  }
276
+ WP_CLI::log( " - {$key}: {$value}" );
277
+ }
278
+ }
279
+
280
+ // Preflight checklist.
281
+ $preflight = VarnishDebug::preflight( $remote_get );
282
+
283
+ // Check for Remote IP.
284
+ $remote_ip = VarnishDebug::remote_ip( $headers );
285
+
286
+ // Get the Varnish IP.
287
+ if ( false !== VHP_VARNISH_IP ) {
288
+ $varniship = VHP_VARNISH_IP;
289
+ } else {
290
+ $varniship = get_site_option( 'vhp_varnish_ip' );
291
+ }
292
 
293
+ if ( false === $preflight['preflight'] ) {
294
+ WP_CLI::error( $preflight['message'] );
295
+ } else {
296
+ $results = VarnishDebug::get_all_the_results( $headers, $remote_ip, $varniship );
297
 
298
+ // Generate array.
299
+ foreach ( $results as $type => $content ) {
300
+ $items[] = array(
301
+ 'name' => $type,
302
+ 'status' => ucwords( $content['icon'] ),
303
+ 'message' => $content['message'],
304
+ );
305
  }
306
+
307
+ $format = ( isset( $assoc_args['format'] ) ) ? $assoc_args['format'] : 'table';
308
+
309
+ // Output the data.
310
+ WP_CLI\Utils\format_items( $format, $items, array( 'name', 'status', 'message' ) );
311
  }
312
+ } // End Debug.
313
  }
314
  }
315
 
316
+ WP_CLI::add_command( 'varnish', 'WP_CLI_Varnish_Command' );