Health Check - Version 1.2.4

Version Description

Download this release

Release Info

Developer Clorith
Plugin Icon 128x128 Health Check
Version 1.2.4
Comparing to
See all releases

Code changes from version 1.2.3 to 1.2.4

assets/css/health-check-troubleshooting-mode.css ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @media all and (min-width: 783px) {
2
+ #health-check-dashboard-widget {
3
+ margin-top: 3rem;
4
+ }
5
+ }
6
+
7
+ #health-check-dashboard-widget .welcome-panel-content {
8
+ max-width: initial;
9
+ }
10
+
11
+ #health-check-dashboard-widget .notices .no-notices p {
12
+ color: #bfc3c7;
13
+ font-size: 1.2rem;
14
+ }
15
+
16
+ #health-check-dashboard-widget .notices .notice {
17
+ margin-left: 0;
18
+ }
19
+
20
+ #health-check-dashboard-widget .notices .dismiss-notices {
21
+ float: right;
22
+ margin-right: 1rem;
23
+ }
24
+
25
+ #health-check-dashboard-widget .disable-troubleshooting-mode {
26
+ margin-bottom: 1rem;
27
+ }
28
+
29
+ @media all and (min-width: 960px) {
30
+ #health-check-dashboard-widget .disable-troubleshooting-mode {
31
+ position: absolute;
32
+ bottom: 1rem;
33
+ right: 1rem;
34
+ }
35
+ }
36
+
37
+ #health-check-dashboard-widget .toggle-visibility {
38
+ display: none;
39
+ }
40
+
41
+ #health-check-dashboard-widget .toggle-visibility.visible {
42
+ display: block;
43
+ }
44
+
45
+ #health-check-dashboard-widget .welcome-panel-column-container {
46
+ position: initial;
47
+ }
48
+
49
+ #health-check-dashboard-widget .welcome-panel-column-container .welcome-panel-column.is-standalone-button {
50
+ width: 100%;
51
+ text-align: right;
52
+ }
53
+
54
+ #health-check-dashboard-widget .welcome-panel-column-container .welcome-panel-column.is-standalone-button .disable-troubleshooting-mode {
55
+ position: relative;
56
+ }
57
+
58
+ #health-check-dashboard-widget .about-description {
59
+ margin: 1em 0;
60
+ }
61
+
62
+ #health-check-dashboard-widget .health-check-toggle-visibility {
63
+ position: relative;
64
+ padding-right: 1.5rem;
65
+ }
66
+
67
+ #health-check-dashboard-widget .health-check-toggle-visibility .icon {
68
+ border: solid #9e9e9e;
69
+ border-width: 0 2px 2px 0;
70
+ height: 0.3rem;
71
+ pointer-events: none;
72
+ position: absolute;
73
+ right: 0.5em;
74
+ top: 50%;
75
+ transform: translateY(-60%) rotate(45deg);
76
+ width: 0.3rem;
77
+ }
78
+
79
+ #health-check-dashboard-widget .health-check-toggle-visibility .icon.icon-up {
80
+ transform: translateY(-50%) rotate(-135deg);
81
+ top: 60%;
82
+ }
assets/javascript/health-check.js CHANGED
@@ -1,101 +1,102 @@
1
- jQuery( document ).ready(function( $ ) {
2
- $( '.health-check-accordion-trigger' ).click(function() {
3
- var isExpanded = ( 'true' === $( this ).attr( 'aria-expanded' ) );
4
-
5
- if ( isExpanded ) {
6
- $( this ).attr( 'aria-expanded', 'false' );
7
- $( '#' + $( this ).attr( 'aria-controls' ) ).attr( 'hidden', true );
8
- } else {
9
- $( this ).attr( 'aria-expanded', 'true' );
10
- $( '#' + $( this ).attr( 'aria-controls' ) ).attr( 'hidden', false );
11
- }
12
- });
13
-
14
- $( '.health-check-accordion' ).on( 'keyup', '.health-check-accordion-trigger', function( e ) {
15
- if ( '38' === e.keyCode.toString() ) {
16
- $( '.health-check-accordion-trigger', $( this ).closest( 'dt' ).prevAll( 'dt' ) ).focus();
17
- } else if ( '40' === e.keyCode.toString() ) {
18
- $( '.health-check-accordion-trigger', $( this ).closest( 'dt' ).nextAll( 'dt' ) ).focus();
19
- }
20
- });
21
- });
22
-
23
- /* global HealthCheck */
24
- jQuery( document ).ready(function( $ ) {
25
- $( '.health-check-copy-field' ).click(function( e ) {
26
- var $textarea = $( 'textarea', $( this ).closest( 'div' ) ),
27
- $button = $( this ),
28
- copied = false;
29
-
30
- e.preventDefault();
31
-
32
- $textarea.select();
33
-
34
- copied = document.execCommand( 'copy' );
35
- if ( copied ) {
36
- $button.text( HealthCheck.string.copied );
37
- }
38
- });
39
- });
40
-
41
- jQuery( document ).ready(function( $ ) {
42
- $( '.health-check-toc' ).click(function( e ) {
43
-
44
- // Remove the height of the admin bar, and an extra 10px for better positioning.
45
- var offset = $( $( this ).attr( 'href' ) ).offset().top - $( '#wpadminbar' ).height() - 10;
46
-
47
- e.preventDefault();
48
-
49
- $( 'html, body' ).animate({
50
- scrollTop: offset
51
- }, 1200 );
52
- });
53
- });
54
-
55
- /* global ajaxurl */
56
- jQuery( document ).ready(function( $ ) {
57
- function healthCheckFailureModal( markup, action, parent ) {
58
- $( '#dynamic-content' ).html( markup );
59
- $( '.health-check-modal' ).data( 'modal-action', action ).data( 'parent-field', parent ).show();
60
- }
61
-
62
- function healthCheckFailureModalClose( modal ) {
63
- modal.hide();
64
- }
65
-
66
- $( '.modal-close' ).click(function( e ) {
67
- e.preventDefault();
68
- healthCheckFailureModalClose( $( this ).closest( '.health-check-modal' ) );
69
- });
70
-
71
- $( '.health-check-modal' ).on( 'submit', 'form', function( e ) {
72
- var data = $( this ).serializeArray(),
73
- modal = $( this ).closest( '.health-check-modal' );
74
 
75
- e.preventDefault();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
76
 
77
- $.post(
78
- ajaxurl,
79
- data,
80
- function( response ) {
81
- if ( true === response.success ) {
82
- $( modal.data( 'parent-field' ) ).append( response.data.message );
83
- } else {
84
- healthCheckFailureModal( response.data.message, data.action, modal.data( 'parent-field' ) );
85
- }
86
- }
87
- );
 
 
88
 
89
- healthCheckFailureModalClose( modal );
90
- });
91
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
 
93
  /* global HealthCheck, ajaxurl, healthCheckFailureModal */
94
  jQuery( document ).ready(function( $ ) {
95
  function testDefaultTheme() {
96
  var $parent = $( '.individual-loopback-test-status', '#test-single-no-theme' ),
97
  data = {
98
- action: 'health-check-loopback-default-theme'
 
99
  };
100
 
101
  $.post(
@@ -125,8 +126,9 @@ jQuery( document ).ready(function( $ ) {
125
 
126
  $testLine = $testLines.first();
127
  data = {
128
- action: 'health-check-loopback-individual-plugins',
129
- plugin: $testLine.data( 'test-plugin' )
 
130
  };
131
 
132
  $parentField = $( '.individual-loopback-test-status', $testLine );
@@ -153,7 +155,8 @@ jQuery( document ).ready(function( $ ) {
153
  var $trigger = $( this ),
154
  $parent = $( this ).closest( 'td' ),
155
  data = {
156
- action: 'health-check-loopback-no-plugins'
 
157
  };
158
 
159
  e.preventDefault();
@@ -180,117 +183,121 @@ jQuery( document ).ready(function( $ ) {
180
  });
181
  });
182
 
183
- /* global ajaxurl */
184
- jQuery( document ).ready(function( $ ) {
185
- $( '.health-check-site-status-test' ).each( function() {
186
- var $check = $( this ),
187
- data = {
188
- action: 'health-check-site-status',
189
- feature: $( this ).data( 'site-status' )
190
- };
191
-
192
- $.post(
193
- ajaxurl,
194
- data,
195
- function( response ) {
196
- $check.html( response );
197
- }
198
- );
199
- });
200
- });
201
-
202
- /* global ajaxurl */
203
- jQuery( document ).ready(function( $ ) {
204
- $( '#health-check-file-integrity' ).submit( function( e ) {
205
- var data = {
206
- 'action': 'health-check-files-integrity-check'
207
- };
208
-
209
- e.preventDefault();
210
-
211
- $( '#tools-file-integrity-response-holder' ).html( '<span class="spinner"></span>' );
212
- $( '#tools-file-integrity-response-holder .spinner' ).addClass( 'is-active' );
213
-
214
- $.post(
215
- ajaxurl,
216
- data,
217
- function( response ) {
218
- $( '#tools-file-integrity-response-holder .spinner' ).removeClass( 'is-active' );
219
- $( '#tools-file-integrity-response-holder' ).parent().css( 'height', 'auto' );
220
- $( '#tools-file-integrity-response-holder' ).html( response.data.message );
221
- }
222
- );
223
- });
224
-
225
- $( '#tools-file-integrity-response-holder' ).on( 'click', 'a[href="#health-check-diff"]', function( e ) {
226
- var file = $( this ).data( 'file' ),
227
- data;
228
-
229
- e.preventDefault();
230
-
231
- $( '#health-check-diff-modal' ).toggle();
232
- $( '#health-check-diff-modal #health-check-diff-modal-content .spinner' ).addClass( 'is-active' );
233
-
234
- data = {
235
- 'action': 'health-check-view-file-diff',
236
- 'file': file
237
- };
238
-
239
- $.post(
240
- ajaxurl,
241
- data,
242
- function( response ) {
243
- $( '#health-check-diff-modal #health-check-diff-modal-diff' ).html( response.data.message );
244
- $( '#health-check-diff-modal #health-check-diff-modal-content h3' ).html( file );
245
- $( '#health-check-diff-modal #health-check-diff-modal-content .spinner' ).removeClass( 'is-active' );
246
- }
247
- );
248
- });
249
- });
250
-
251
- jQuery( document ).ready(function( $ ) {
252
- $( '#health-check-diff-modal' ).on( 'click', 'a[href="#health-check-diff-modal-close"]', function( e ) {
253
- e.preventDefault();
254
- $( '#health-check-diff-modal' ).toggle();
255
- $( '#health-check-diff-modal #health-check-diff-modal-diff' ).html( '' );
256
- $( '#health-check-diff-modal #health-check-diff-modal-content h3' ).html( '' );
257
- });
258
-
259
- $( document ).keyup(function( e ) {
260
- if ( 27 === e.which ) {
261
- $( '#health-check-diff-modal' ).css( 'display', 'none' );
262
- $( '#health-check-diff-modal #health-check-diff-modal-diff' ).html( '' );
263
- $( '#health-check-diff-modal #health-check-diff-modal-content h3' ).html( '' );
264
- }
265
- });
266
- });
267
-
268
- /* global ajaxurl */
269
- jQuery( document ).ready(function( $ ) {
270
- $( '#health-check-mail-check' ).submit( function( e ) {
271
- var email = $( '#health-check-mail-check #email' ).val(),
272
- emailMessage = $( '#health-check-mail-check #email_message' ).val(),
273
- data;
274
-
275
- e.preventDefault();
276
 
277
- $( '#tools-mail-check-response-holder' ).html( '<span class="spinner"></span>' );
278
- $( '#tools-mail-check-response-holder .spinner' ).addClass( 'is-active' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
279
 
280
- data = {
281
- 'action': 'health-check-mail-check',
282
- 'email': email,
283
- 'email_message': emailMessage
284
- };
 
 
 
 
 
 
 
 
 
 
 
285
 
286
- $.post(
287
- ajaxurl,
288
- data,
289
- function( response ) {
290
- $( '#tools-mail-check-response-holder .spinner' ).removeClass( 'is-active' );
291
- $( '#tools-mail-check-response-holder' ).parent().css( 'height', 'auto' );
292
- $( '#tools-mail-check-response-holder' ).html( response.data.message );
293
- }
294
- );
295
- });
296
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ jQuery( document ).ready(function( $ ) {
2
+ $( '.health-check-accordion-trigger' ).click(function() {
3
+ var isExpanded = ( 'true' === $( this ).attr( 'aria-expanded' ) );
4
+
5
+ if ( isExpanded ) {
6
+ $( this ).attr( 'aria-expanded', 'false' );
7
+ $( '#' + $( this ).attr( 'aria-controls' ) ).attr( 'hidden', true );
8
+ } else {
9
+ $( this ).attr( 'aria-expanded', 'true' );
10
+ $( '#' + $( this ).attr( 'aria-controls' ) ).attr( 'hidden', false );
11
+ }
12
+ });
13
+
14
+ $( '.health-check-accordion' ).on( 'keyup', '.health-check-accordion-trigger', function( e ) {
15
+ if ( '38' === e.keyCode.toString() ) {
16
+ $( '.health-check-accordion-trigger', $( this ).closest( 'dt' ).prevAll( 'dt' ) ).focus();
17
+ } else if ( '40' === e.keyCode.toString() ) {
18
+ $( '.health-check-accordion-trigger', $( this ).closest( 'dt' ).nextAll( 'dt' ) ).focus();
19
+ }
20
+ });
21
+ });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
 
23
+ /* global HealthCheck */
24
+ jQuery( document ).ready(function( $ ) {
25
+ $( '.health-check-copy-field' ).click(function( e ) {
26
+ var $textarea = $( 'textarea', $( this ).closest( 'div' ) ),
27
+ $button = $( this ),
28
+ copied = false;
29
+
30
+ e.preventDefault();
31
+
32
+ $textarea.select();
33
+
34
+ copied = document.execCommand( 'copy' );
35
+ if ( copied ) {
36
+ $button.text( HealthCheck.string.copied );
37
+ }
38
+ });
39
+ });
40
 
41
+ jQuery( document ).ready(function( $ ) {
42
+ $( '.health-check-toc' ).click(function( e ) {
43
+
44
+ // Remove the height of the admin bar, and an extra 10px for better positioning.
45
+ var offset = $( $( this ).attr( 'href' ) ).offset().top - $( '#wpadminbar' ).height() - 10;
46
+
47
+ e.preventDefault();
48
+
49
+ $( 'html, body' ).animate({
50
+ scrollTop: offset
51
+ }, 1200 );
52
+ });
53
+ });
54
 
55
+ /* global ajaxurl */
56
+ jQuery( document ).ready(function( $ ) {
57
+ function healthCheckFailureModal( markup, action, parent ) {
58
+ $( '#dynamic-content' ).html( markup );
59
+ $( '.health-check-modal' ).data( 'modal-action', action ).data( 'parent-field', parent ).show();
60
+ }
61
+
62
+ function healthCheckFailureModalClose( modal ) {
63
+ modal.hide();
64
+ }
65
+
66
+ $( '.modal-close' ).click(function( e ) {
67
+ e.preventDefault();
68
+ healthCheckFailureModalClose( $( this ).closest( '.health-check-modal' ) );
69
+ });
70
+
71
+ $( '.health-check-modal' ).on( 'submit', 'form', function( e ) {
72
+ var data = $( this ).serializeArray(),
73
+ modal = $( this ).closest( '.health-check-modal' );
74
+
75
+ e.preventDefault();
76
+
77
+ $.post(
78
+ ajaxurl,
79
+ data,
80
+ function( response ) {
81
+ if ( true === response.success ) {
82
+ $( modal.data( 'parent-field' ) ).append( response.data.message );
83
+ } else {
84
+ healthCheckFailureModal( response.data.message, data.action, modal.data( 'parent-field' ) );
85
+ }
86
+ }
87
+ );
88
+
89
+ healthCheckFailureModalClose( modal );
90
+ });
91
+ });
92
 
93
  /* global HealthCheck, ajaxurl, healthCheckFailureModal */
94
  jQuery( document ).ready(function( $ ) {
95
  function testDefaultTheme() {
96
  var $parent = $( '.individual-loopback-test-status', '#test-single-no-theme' ),
97
  data = {
98
+ 'action': 'health-check-loopback-default-theme',
99
+ '_wpnonce': HealthCheck.nonce.loopback_default_theme
100
  };
101
 
102
  $.post(
126
 
127
  $testLine = $testLines.first();
128
  data = {
129
+ 'action': 'health-check-loopback-individual-plugins',
130
+ 'plugin': $testLine.data( 'test-plugin' ),
131
+ '_wpnonce': HealthCheck.nonce.loopback_individual_plugins
132
  };
133
 
134
  $parentField = $( '.individual-loopback-test-status', $testLine );
155
  var $trigger = $( this ),
156
  $parent = $( this ).closest( 'td' ),
157
  data = {
158
+ 'action': 'health-check-loopback-no-plugins',
159
+ '_wpnonce': HealthCheck.nonce.loopback_no_plugins
160
  };
161
 
162
  e.preventDefault();
183
  });
184
  });
185
 
186
+ /* global ajaxurl, HealthCheck */
187
+ jQuery( document ).ready(function( $ ) {
188
+ $( '.health-check-site-status-test' ).each( function() {
189
+ var $check = $( this ),
190
+ data = {
191
+ 'action': 'health-check-site-status',
192
+ 'feature': $( this ).data( 'site-status' ),
193
+ '_wpnonce': HealthCheck.nonce.site_status
194
+ };
195
+
196
+ $.post(
197
+ ajaxurl,
198
+ data,
199
+ function( response ) {
200
+ $check.html( response );
201
+ }
202
+ );
203
+ });
204
+ });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
205
 
206
+ /* global ajaxurl, HealthCheck */
207
+ jQuery( document ).ready(function( $ ) {
208
+ $( '#health-check-file-integrity' ).submit( function( e ) {
209
+ var data = {
210
+ 'action': 'health-check-files-integrity-check',
211
+ '_wpnonce': HealthCheck.nonce.files_integrity_check
212
+ };
213
+
214
+ e.preventDefault();
215
+
216
+ $( '#tools-file-integrity-response-holder' ).html( '<span class="spinner"></span>' );
217
+ $( '#tools-file-integrity-response-holder .spinner' ).addClass( 'is-active' );
218
+
219
+ $.post(
220
+ ajaxurl,
221
+ data,
222
+ function( response ) {
223
+ $( '#tools-file-integrity-response-holder .spinner' ).removeClass( 'is-active' );
224
+ $( '#tools-file-integrity-response-holder' ).parent().css( 'height', 'auto' );
225
+ $( '#tools-file-integrity-response-holder' ).html( response.data.message );
226
+ }
227
+ );
228
+ });
229
+
230
+ $( '#tools-file-integrity-response-holder' ).on( 'click', 'a[href="#health-check-diff"]', function( e ) {
231
+ var file = $( this ).data( 'file' ),
232
+ data;
233
+
234
+ e.preventDefault();
235
+
236
+ $( '#health-check-diff-modal' ).toggle();
237
+ $( '#health-check-diff-modal #health-check-diff-modal-content .spinner' ).addClass( 'is-active' );
238
+
239
+ data = {
240
+ 'action': 'health-check-view-file-diff',
241
+ 'file': file,
242
+ '_wpnonce': HealthCheck.nonce.view_file_diff
243
+ };
244
+
245
+ $.post(
246
+ ajaxurl,
247
+ data,
248
+ function( response ) {
249
+ $( '#health-check-diff-modal #health-check-diff-modal-diff' ).html( response.data.message );
250
+ $( '#health-check-diff-modal #health-check-diff-modal-content h3' ).html( file );
251
+ $( '#health-check-diff-modal #health-check-diff-modal-content .spinner' ).removeClass( 'is-active' );
252
+ }
253
+ );
254
+ });
255
+ });
256
 
257
+ jQuery( document ).ready(function( $ ) {
258
+ $( '#health-check-diff-modal' ).on( 'click', 'a[href="#health-check-diff-modal-close"]', function( e ) {
259
+ e.preventDefault();
260
+ $( '#health-check-diff-modal' ).toggle();
261
+ $( '#health-check-diff-modal #health-check-diff-modal-diff' ).html( '' );
262
+ $( '#health-check-diff-modal #health-check-diff-modal-content h3' ).html( '' );
263
+ });
264
+
265
+ $( document ).keyup(function( e ) {
266
+ if ( 27 === e.which ) {
267
+ $( '#health-check-diff-modal' ).css( 'display', 'none' );
268
+ $( '#health-check-diff-modal #health-check-diff-modal-diff' ).html( '' );
269
+ $( '#health-check-diff-modal #health-check-diff-modal-content h3' ).html( '' );
270
+ }
271
+ });
272
+ });
273
 
274
+ /* global ajaxurl, HealthCheck */
275
+ jQuery( document ).ready(function( $ ) {
276
+ $( '#health-check-mail-check' ).submit( function( e ) {
277
+ var email = $( '#health-check-mail-check #email' ).val(),
278
+ emailMessage = $( '#health-check-mail-check #email_message' ).val(),
279
+ data;
280
+
281
+ e.preventDefault();
282
+
283
+ $( '#tools-mail-check-response-holder' ).html( '<span class="spinner"></span>' );
284
+ $( '#tools-mail-check-response-holder .spinner' ).addClass( 'is-active' );
285
+
286
+ data = {
287
+ 'action': 'health-check-mail-check',
288
+ 'email': email,
289
+ 'email_message': emailMessage,
290
+ '_wpnonce': HealthCheck.nonce.mail_check
291
+ };
292
+
293
+ $.post(
294
+ ajaxurl,
295
+ data,
296
+ function( response ) {
297
+ $( '#tools-mail-check-response-holder .spinner' ).removeClass( 'is-active' );
298
+ $( '#tools-mail-check-response-holder' ).parent().css( 'height', 'auto' );
299
+ $( '#tools-mail-check-response-holder' ).html( response.data.message );
300
+ }
301
+ );
302
+ });
303
+ });
assets/mu-plugin/health-check-troubleshooting-mode.php CHANGED
@@ -1,1088 +1,1038 @@
1
- <?php
2
- /*
3
- Plugin Name: Health Check Troubleshooting Mode
4
- Description: Conditionally disabled themes or plugins on your site for a given session, used to rule out conflicts during troubleshooting.
5
- Version: 1.5.0
6
- */
7
-
8
- if ( ! defined( 'ABSPATH' ) ) {
9
- die( 'We\'re sorry, but you can not directly access this file.' );
10
- }
11
-
12
- class Health_Check_Troubleshooting_MU {
13
- private $disable_hash = null;
14
- private $override_active = true;
15
- private $default_theme = true;
16
- private $active_plugins = array();
17
- private $allowed_plugins = array();
18
- private $current_theme;
19
- private $current_theme_details;
20
- private $self_fetching_theme = false;
21
-
22
- private $available_query_args = array(
23
- 'health-check-disable-plugins',
24
- 'health-check-disable-plugins-hash',
25
- 'health-check-disable-troubleshooting',
26
- 'health-check-change-active-theme',
27
- 'health-check-troubleshoot-enable-plugin',
28
- 'health-check-troubleshoot-disable-plugin',
29
- );
30
-
31
- private $default_themes = array(
32
- 'twentynineteen',
33
- 'twentyseventeen',
34
- 'twentysixteen',
35
- 'twentyfifteen',
36
- 'twentyfourteen',
37
- 'twentythirteen',
38
- 'twentytwelve',
39
- 'twentyeleven',
40
- 'twentyten',
41
- );
42
-
43
- /**
44
- * Health_Check_Troubleshooting_MU constructor.
45
- */
46
- public function __construct() {
47
- $this->init();
48
- }
49
-
50
- /**
51
- * Actually initiation of the plugin.
52
- *
53
- * @return void
54
- */
55
- public function init() {
56
- add_action( 'admin_bar_menu', array( $this, 'health_check_troubleshoot_menu_bar' ), 999 );
57
-
58
- add_filter( 'option_active_plugins', array( $this, 'health_check_loopback_test_disable_plugins' ) );
59
- add_filter( 'option_active_sitewide_plugins', array( $this, 'health_check_loopback_test_disable_plugins' ) );
60
-
61
- add_filter( 'pre_option_template', array( $this, 'health_check_troubleshoot_theme_template' ) );
62
- add_filter( 'pre_option_stylesheet', array( $this, 'health_check_troubleshoot_theme_stylesheet' ) );
63
-
64
- add_action( 'admin_notices', array( $this, 'prompt_install_default_theme' ) );
65
- add_filter( 'user_has_cap', array( $this, 'remove_plugin_theme_install' ) );
66
-
67
- add_action( 'plugin_action_links', array( $this, 'plugin_actions' ), 50, 4 );
68
-
69
- add_action( 'admin_notices', array( $this, 'display_dashboard_widget' ) );
70
- add_action( 'admin_head', array( $this, 'dashboard_widget_styles' ) );
71
- add_action( 'admin_footer', array( $this, 'dashboard_widget_scripts' ) );
72
-
73
- add_action( 'wp_logout', array( $this, 'health_check_troubleshooter_mode_logout' ) );
74
- add_action( 'init', array( $this, 'health_check_troubleshoot_get_captures' ) );
75
-
76
- /*
77
- * Plugin activations can be forced by other tools in things like themes, so let's
78
- * attempt to work around that by forcing plugin lists back and forth.
79
- *
80
- * This is not an ideal scenario, but one we must accept as reality.
81
- */
82
- add_action( 'activated_plugin', array( $this, 'plugin_activated' ) );
83
-
84
- $this->load_options();
85
- }
86
-
87
- /**
88
- * Set up the class variables based on option table entries.
89
- *
90
- * @return void
91
- */
92
- public function load_options() {
93
- $this->disable_hash = get_option( 'health-check-disable-plugin-hash', null );
94
- $this->allowed_plugins = get_option( 'health-check-allowed-plugins', array() );
95
- $this->default_theme = ( 'yes' === get_option( 'health-check-default-theme', 'yes' ) ? true : false );
96
- $this->active_plugins = $this->get_unfiltered_plugin_list();
97
- $this->current_theme = get_option( 'health-check-current-theme', false );
98
- }
99
-
100
- /**
101
- * Add a prompt to install a default theme.
102
- *
103
- * If no default theme exists, we can't reliably assert if an issue is
104
- * caused by the theme. In these cases we should provide an easy step
105
- * to get to, and install, one of the default themes.
106
- *
107
- * @return void
108
- */
109
- public function prompt_install_default_theme() {
110
- if ( ! $this->is_troubleshooting() || $this->has_default_theme() ) {
111
- return;
112
- }
113
-
114
- printf(
115
- '<div class="notice notice-warning dismissable"><p>%s</p><p><a href="%s" class="button button-primary">%s</a></p></div>',
116
- esc_html__( 'You don\'t have any of the default themes installed. A default theme helps you determine if your current theme is causing conflicts.', 'health-check' ),
117
- esc_url( admin_url( sprintf(
118
- 'theme-install.php?theme=%s',
119
- $this->default_themes[0]
120
- ) ) ),
121
- esc_html__( 'Install a default theme', 'health-check' )
122
- );
123
- }
124
-
125
- /**
126
- * Remove the `Add` option for plugins and themes.
127
- *
128
- * When troubleshooting, adding or changing themes and plugins can
129
- * lead to unexpected results. Remove these menu items to make it less
130
- * likely that a user breaks their site through these.
131
- *
132
- * @param array $caps Array containing the current users capabilities.
133
- *
134
- * @return array
135
- */
136
- public function remove_plugin_theme_install( $caps ) {
137
- if ( ! $this->is_troubleshooting() ) {
138
- return $caps;
139
- }
140
-
141
- $caps['switch_themes'] = false;
142
-
143
- /*
144
- * This is to early for `get_current_screen()`, so we have to do it the
145
- * old fashioned way with `$_SERVER`.
146
- */
147
- if ( 'plugin-install.php' === substr( $_SERVER['REQUEST_URI'], -18 ) ) {
148
- $caps['activate_plugins'] = false;
149
- }
150
-
151
- return $caps;
152
- }
153
-
154
- /**
155
- * Fire on plugin activation.
156
- *
157
- * When in Troubleshooting Mode, plugin activations
158
- * will clear out the DB entry for `active_plugins`, this is bad.
159
- *
160
- * We fix this by re-setting the DB entry if anything tries
161
- * to modify it during troubleshooting.
162
- *
163
- * @return void
164
- */
165
- public function plugin_activated() {
166
- if ( ! $this->is_troubleshooting() ) {
167
- return;
168
- }
169
-
170
- // Force the database entry for active plugins if someone tried changing plugins while in Troubleshooting Mode.
171
- update_option( 'active_plugins', $this->active_plugins );
172
- }
173
-
174
- /**
175
- * Modify plugin actions.
176
- *
177
- * While in Troubleshooting Mode, weird things will happen if you start
178
- * modifying your plugin list. Prevent this, but also add in the ability
179
- * to enable or disable a plugin during troubleshooting from this screen.
180
- *
181
- * @param $actions
182
- * @param $plugin_file
183
- * @param $plugin_data
184
- * @param $context
185
- *
186
- * @return array
187
- */
188
- public function plugin_actions( $actions, $plugin_file, $plugin_data, $context ) {
189
- if ( ! $this->is_troubleshooting() ) {
190
- return $actions;
191
- }
192
-
193
- if ( 'mustuse' === $context ) {
194
- return $actions;
195
- }
196
-
197
- /*
198
- * Disable all plugin actions when in Troubleshooting Mode.
199
- *
200
- * We intentionally remove all plugin actions to avoid accidental clicking, activating or deactivating plugins
201
- * while our plugin is altering plugin data may lead to unexpected behaviors, so to keep things sane we do
202
- * not allow users to perform any actions during this time.
203
- */
204
- $actions = array();
205
-
206
- // This isn't an active plugin, so does not apply to our troubleshooting scenarios.
207
- if ( ! in_array( $plugin_file, $this->active_plugins ) ) {
208
- return $actions;
209
- }
210
-
211
- // Set a slug if the plugin lives in the plugins directory root.
212
- if ( ! stristr( $plugin_file, '/' ) ) {
213
- $plugin_data['slug'] = $plugin_file;
214
- }
215
-
216
- $plugin_slug = ( isset( $plugin_data['slug'] ) ? $plugin_data['slug'] : sanitize_title( $plugin_data['Name'] ) );
217
-
218
- if ( in_array( $plugin_slug, $this->allowed_plugins ) ) {
219
- $actions['troubleshoot-disable'] = sprintf(
220
- '<a href="%s">%s</a>',
221
- esc_url( add_query_arg( array(
222
- 'health-check-troubleshoot-disable-plugin' => $plugin_slug,
223
- ), admin_url( 'plugins.php' ) ) ),
224
- esc_html__( 'Disable while troubleshooting', 'health-check' )
225
- );
226
- } else {
227
- $actions['troubleshoot-disable'] = sprintf(
228
- '<a href="%s">%s</a>',
229
- esc_url( add_query_arg( array(
230
- 'health-check-troubleshoot-enable-plugin' => $plugin_slug,
231
- ), admin_url( 'plugins.php' ) ) ),
232
- esc_html__( 'Enable while troubleshooting', 'health-check' )
233
- );
234
- }
235
-
236
- return $actions;
237
- }
238
-
239
- /**
240
- * Get the actual list of active plugins.
241
- *
242
- * When in Troubleshooting Mode we override the list of plugins,
243
- * this function lets us grab the active plugins list without
244
- * any interference.
245
- *
246
- * @return array Array of active plugins.
247
- */
248
- public function get_unfiltered_plugin_list() {
249
- $this->override_active = false;
250
- $all_plugins = get_option( 'active_plugins' );
251
- $this->override_active = true;
252
-
253
- return $all_plugins;
254
- }
255
-
256
- /**
257
- * Check if the user is currently in Troubleshooting Mode or not.
258
- *
259
- * @return bool
260
- */
261
- public function is_troubleshooting() {
262
- // Check if a session cookie to disable plugins has been set.
263
- if ( isset( $_COOKIE['health-check-disable-plugins'] ) ) {
264
- $_GET['health-check-disable-plugin-hash'] = $_COOKIE['health-check-disable-plugins'];
265
- }
266
-
267
- // If the disable hash isn't set, no need to interact with things.
268
- if ( ! isset( $_GET['health-check-disable-plugin-hash'] ) ) {
269
- return false;
270
- }
271
-
272
- if ( empty( $this->disable_hash ) ) {
273
- return false;
274
- }
275
-
276
- // If the plugin hash is not valid, we also break out
277
- if ( $this->disable_hash !== $_GET['health-check-disable-plugin-hash'] ) {
278
- return false;
279
- }
280
-
281
- return true;
282
- }
283
-
284
- /**
285
- * Filter the plugins that are activated in WordPress.
286
- *
287
- * @param array $plugins An array of plugins marked as active.
288
- *
289
- * @return array
290
- */
291
- function health_check_loopback_test_disable_plugins( $plugins ) {
292
- if ( ! $this->is_troubleshooting() || ! $this->override_active ) {
293
- return $plugins;
294
- }
295
-
296
- // If we've received a comma-separated list of allowed plugins, we'll add them to the array of allowed plugins.
297
- if ( isset( $_GET['health-check-allowed-plugins'] ) ) {
298
- $this->allowed_plugins = explode( ',', $_GET['health-check-allowed-plugins'] );
299
- }
300
-
301
- foreach ( $plugins as $plugin_no => $plugin_path ) {
302
- // Split up the plugin path, [0] is the slug and [1] holds the primary plugin file.
303
- $plugin_parts = explode( '/', $plugin_path );
304
-
305
- // We may want to allow individual, or groups of plugins, so introduce a skip-mechanic for those scenarios.
306
- if ( in_array( $plugin_parts[0], $this->allowed_plugins ) ) {
307
- continue;
308
- }
309
-
310
- // Remove the reference to this plugin.
311
- unset( $plugins[ $plugin_no ] );
312
- }
313
-
314
- // Return a possibly modified list of activated plugins.
315
- return $plugins;
316
- }
317
-
318
- /**
319
- * Check if a default theme exists.
320
- *
321
- * If a default theme exists, return the most recent one, if not return `false`.
322
- *
323
- * @return bool|string
324
- */
325
- function has_default_theme() {
326
- foreach ( $this->default_themes as $default_theme ) {
327
- if ( $this->theme_exists( $default_theme ) ) {
328
- return $default_theme;
329
- }
330
- }
331
-
332
- return false;
333
- }
334
-
335
- /**
336
- * Check if a theme exists by looking for the slug.
337
- *
338
- * @param string $theme_slug
339
- *
340
- * @return bool
341
- */
342
- function theme_exists( $theme_slug ) {
343
- return is_dir( WP_CONTENT_DIR . '/themes/' . $theme_slug );
344
- }
345
-
346
- /**
347
- * Check if theme overrides are active.
348
- *
349
- * @return bool
350
- */
351
- function override_theme() {
352
- if ( ! $this->is_troubleshooting() ) {
353
- return false;
354
- }
355
-
356
- return true;
357
- }
358
-
359
- /**
360
- * Override the default theme.
361
- *
362
- * Attempt to set one of the default themes, or a theme of the users choosing, as the active one
363
- * during Troubleshooting Mode.
364
- *
365
- * @param $default
366
- *
367
- * @return bool|string
368
- */
369
- function health_check_troubleshoot_theme_stylesheet( $default ) {
370
- if ( $this->self_fetching_theme ) {
371
- return $default;
372
- }
373
-
374
- if ( ! $this->override_theme() ) {
375
- return $default;
376
- }
377
-
378
- if ( empty( $this->current_theme_details ) ) {
379
- $this->self_fetching_theme = true;
380
- $this->current_theme_details = wp_get_theme( $this->current_theme );
381
- $this->self_fetching_theme = false;
382
- }
383
-
384
- // If no theme has been chosen, start off by troubleshooting as a default theme if one exists.
385
- $default_theme = $this->has_default_theme();
386
- if ( false === $this->current_theme ) {
387
- if ( $default_theme ) {
388
- return $default_theme;
389
- }
390
- }
391
-
392
- return $this->current_theme;
393
- }
394
-
395
- /**
396
- * Override the default parent theme.
397
- *
398
- * If this is a child theme, override the parent and provide our users chosen themes parent instead.
399
- *
400
- * @param $default
401
- *
402
- * @return bool|string
403
- */
404
- function health_check_troubleshoot_theme_template( $default ) {
405
- if ( $this->self_fetching_theme ) {
406
- return $default;
407
- }
408
-
409
- if ( ! $this->override_theme() ) {
410
- return $default;
411
- }
412
-
413
- if ( empty( $this->current_theme_details ) ) {
414
- $this->self_fetching_theme = true;
415
- $this->current_theme_details = wp_get_theme( $this->current_theme );
416
- $this->self_fetching_theme = false;
417
- }
418
-
419
- // If no theme has been chosen, start off by troubleshooting as a default theme if one exists.
420
- $default_theme = $this->has_default_theme();
421
- if ( false === $this->current_theme ) {
422
- if ( $default_theme ) {
423
- return $default_theme;
424
- }
425
- }
426
-
427
- if ( $this->current_theme_details->parent() ) {
428
- return $this->current_theme_details->get_template();
429
- }
430
-
431
- return $this->current_theme;
432
- }
433
-
434
- /**
435
- * Disable Troubleshooting Mode on logout.
436
- *
437
- * If logged in, disable the Troubleshooting Mode when the logout
438
- * event is fired, this ensures we start with a clean slate on
439
- * the next login.
440
- *
441
- * @return void
442
- */
443
- function health_check_troubleshooter_mode_logout() {
444
- if ( ! $this->is_troubleshooting() ) {
445
- return;
446
- }
447
-
448
- if ( isset( $_COOKIE['health-check-disable-plugins'] ) ) {
449
- $this->disable_troubleshooting_mode();
450
- }
451
- }
452
-
453
- function disable_troubleshooting_mode() {
454
- unset( $_COOKIE['health-check-disable-plugins'] );
455
- setcookie( 'health-check-disable-plugins', null, 0, COOKIEPATH, COOKIE_DOMAIN );
456
- delete_option( 'health-check-allowed-plugins' );
457
- delete_option( 'health-check-default-theme' );
458
- delete_option( 'health-check-current-theme' );
459
-
460
- delete_option( 'health-check-backup-plugin-list' );
461
- }
462
-
463
- /**
464
- * Catch query arguments.
465
- *
466
- * When in Troubleshooting Mode, look for various GET variables that trigger
467
- * various plugin actions.
468
- *
469
- * @return void
470
- */
471
- function health_check_troubleshoot_get_captures() {
472
- if ( ! $this->is_troubleshooting() ) {
473
- return;
474
- }
475
-
476
- // Disable Troubleshooting Mode.
477
- if ( isset( $_GET['health-check-disable-troubleshooting'] ) ) {
478
- $this->disable_troubleshooting_mode();
479
-
480
- wp_redirect( remove_query_arg( $this->available_query_args ) );
481
- die();
482
- }
483
-
484
- // Dismiss notices.
485
- if ( isset( $_GET['health-check-dismiss-notices'] ) && $this->is_troubleshooting() && is_admin() ) {
486
- update_option( 'health-check-dashboard-notices', array() );
487
-
488
- wp_redirect( admin_url() );
489
- die();
490
- }
491
-
492
- // Enable an individual plugin.
493
- if ( isset( $_GET['health-check-troubleshoot-enable-plugin'] ) ) {
494
- $old_allowed_plugins = $this->allowed_plugins;
495
-
496
- $this->allowed_plugins[ $_GET['health-check-troubleshoot-enable-plugin'] ] = $_GET['health-check-troubleshoot-enable-plugin'];
497
-
498
- update_option( 'health-check-allowed-plugins', $this->allowed_plugins );
499
-
500
- if ( ! $this->test_site_state() ) {
501
- $this->allowed_plugins = $old_allowed_plugins;
502
- update_option( 'health-check-allowed-plugins', $old_allowed_plugins );
503
-
504
- $this->add_dashboard_notice(
505
- sprintf(
506
- // translators: %s: The plugin slug that was enabled.
507
- __( 'When enabling the plugin, %s, a site failure occurred. Because of this the change was automatically reverted.', 'health-check' ),
508
- $_GET['health-check-troubleshoot-enable-plugin']
509
- ),
510
- 'warning'
511
- );
512
- }
513
-
514
- wp_redirect( remove_query_arg( $this->available_query_args ) );
515
- die();
516
- }
517
-
518
- // Disable an individual plugin.
519
- if ( isset( $_GET['health-check-troubleshoot-disable-plugin'] ) ) {
520
- $old_allowed_plugins = $this->allowed_plugins;
521
-
522
- unset( $this->allowed_plugins[ $_GET['health-check-troubleshoot-disable-plugin'] ] );
523
-
524
- update_option( 'health-check-allowed-plugins', $this->allowed_plugins );
525
-
526
- if ( ! $this->test_site_state() ) {
527
- $this->allowed_plugins = $old_allowed_plugins;
528
- update_option( 'health-check-allowed-plugins', $old_allowed_plugins );
529
-
530
- $this->add_dashboard_notice(
531
- sprintf(
532
- // translators: %s: The plugin slug that was disabled.
533
- __( 'When disabling the plugin, %s, a site failure occurred. Because of this the change was automatically reverted.', 'health-check' ),
534
- $_GET['health-check-troubleshoot-enable-plugin']
535
- ),
536
- 'warning'
537
- );
538
- }
539
-
540
- wp_redirect( remove_query_arg( $this->available_query_args ) );
541
- die();
542
- }
543
-
544
- // Change the active theme for this session.
545
- if ( isset( $_GET['health-check-change-active-theme'] ) ) {
546
- $old_theme = get_option( 'health-check-current-theme' );
547
-
548
- update_option( 'health-check-current-theme', $_GET['health-check-change-active-theme'] );
549
-
550
- if ( ! $this->test_site_state() ) {
551
- update_option( 'health-check-current-theme', $old_theme );
552
-
553
- $this->add_dashboard_notice(
554
- sprintf(
555
- // translators: %s: The theme slug that was switched to.
556
- __( 'When switching the active theme to %s, a site failure occurred. Because of this we reverted the theme to the one you used previously.', 'health-check' ),
557
- $_GET['health-check-change-active-theme']
558
- ),
559
- 'warning'
560
- );
561
- }
562
-
563
- wp_redirect( remove_query_arg( $this->available_query_args ) );
564
- die();
565
- }
566
- }
567
-
568
- private function add_dashboard_notice( $message, $severity = 'notice' ) {
569
- $notices = get_option( 'health-check-dashboard-notices', array() );
570
-
571
- $notices[] = array(
572
- 'severity' => $severity,
573
- 'message' => $message,
574
- 'time' => date( 'Y-m-d H:i' ),
575
- );
576
-
577
- update_option( 'health-check-dashboard-notices', $notices );
578
- }
579
-
580
- /**
581
- * Extend the admin bar.
582
- *
583
- * When in Troubleshooting Mode, introduce a new element to the admin bar to show
584
- * enabled and disabled plugins (if conditions are met), switch between themes
585
- * and disable Troubleshooting Mode altogether.
586
- *
587
- * @param WP_Admin_Bar $wp_menu
588
- *
589
- * @return void
590
- */
591
- function health_check_troubleshoot_menu_bar( $wp_menu ) {
592
- if ( ! $this->is_troubleshooting() ) {
593
- return;
594
- }
595
-
596
- // We need some admin functions to make this a better user experience, so include that file.
597
- if ( ! is_admin() ) {
598
- require_once( trailingslashit( ABSPATH ) . 'wp-admin/includes/plugin.php' );
599
- }
600
-
601
- // Ensure the theme functions are available to us on every page.
602
- include_once( trailingslashit( ABSPATH ) . 'wp-admin/includes/theme.php' );
603
-
604
- // Add top-level menu item.
605
- $wp_menu->add_menu( array(
606
- 'id' => 'health-check',
607
- 'title' => esc_html__( 'Troubleshooting Mode', 'health-check' ),
608
- ) );
609
-
610
- // Add a link to manage plugins if there are more than 20 set to be active.
611
- if ( count( $this->active_plugins ) > 20 ) {
612
- $wp_menu->add_node( array(
613
- 'id' => 'health-check-plugins',
614
- 'title' => esc_html__( 'Manage active plugins', 'health-check' ),
615
- 'parent' => 'health-check',
616
- 'href' => admin_url( 'plugins.php' ),
617
- ) );
618
- } else {
619
- $wp_menu->add_node( array(
620
- 'id' => 'health-check-plugins',
621
- 'title' => esc_html__( 'Plugins', 'health-check' ),
622
- 'parent' => 'health-check',
623
- ) );
624
-
625
- $wp_menu->add_group( array(
626
- 'id' => 'health-check-plugins-enabled',
627
- 'parent' => 'health-check-plugins',
628
- ) );
629
- $wp_menu->add_group( array(
630
- 'id' => 'health-check-plugins-disabled',
631
- 'parent' => 'health-check-plugins',
632
- ) );
633
-
634
- foreach ( $this->active_plugins as $single_plugin ) {
635
- $plugin_slug = explode( '/', $single_plugin );
636
- $plugin_slug = $plugin_slug[0];
637
-
638
- $plugin_data = get_plugin_data( trailingslashit( WP_PLUGIN_DIR ) . $single_plugin );
639
-
640
- $enabled = true;
641
-
642
- if ( in_array( $plugin_slug, $this->allowed_plugins ) ) {
643
- $label = sprintf(
644
- // Translators: %s: Plugin slug.
645
- esc_html__( 'Disable %s', 'health-check' ),
646
- sprintf(
647
- '<strong>%s</strong>',
648
- $plugin_data['Name']
649
- )
650
- );
651
- $url = add_query_arg( array(
652
- 'health-check-troubleshoot-disable-plugin' => $plugin_slug,
653
- ) );
654
- } else {
655
- $enabled = false;
656
- $label = sprintf(
657
- // Translators: %s: Plugin slug.
658
- esc_html__( 'Enable %s', 'health-check' ),
659
- sprintf(
660
- '<strong>%s</strong>',
661
- $plugin_data['Name']
662
- )
663
- );
664
- $url = add_query_arg( array(
665
- 'health-check-troubleshoot-enable-plugin' => $plugin_slug,
666
- ) );
667
- }
668
-
669
- $wp_menu->add_node( array(
670
- 'id' => sprintf(
671
- 'health-check-plugin-%s',
672
- $plugin_slug
673
- ),
674
- 'title' => $label,
675
- 'parent' => ( $enabled ? 'health-check-plugins-enabled' : 'health-check-plugins-disabled' ),
676
- 'href' => $url,
677
- ) );
678
- }
679
- }
680
-
681
- $wp_menu->add_node( array(
682
- 'id' => 'health-check-theme',
683
- 'title' => esc_html__( 'Themes', 'health-check' ),
684
- 'parent' => 'health-check',
685
- ) );
686
-
687
- $themes = wp_prepare_themes_for_js();
688
-
689
- foreach ( $themes as $theme ) {
690
- $node = array(
691
- 'id' => sprintf(
692
- 'health-check-theme-%s',
693
- sanitize_title( $theme['id'] )
694
- ),
695
- 'title' => sprintf(
696
- '%s %s',
697
- // translators: Prefix for the active theme in a listing.
698
- ( $theme['active'] ? esc_html__( 'Active:', 'health-check' ) : '' ),
699
- $theme['name']
700
- ),
701
- 'parent' => 'health-check-theme',
702
- );
703
-
704
- if ( ! $theme['active'] ) {
705
- $node['href'] = add_query_arg( array(
706
- 'health-check-change-active-theme' => $theme['id'],
707
- ) );
708
- }
709
-
710
- $wp_menu->add_node( $node );
711
- }
712
-
713
- // Add a link to disable Troubleshooting Mode.
714
- $wp_menu->add_node( array(
715
- 'id' => 'health-check-disable',
716
- 'title' => esc_html__( 'Disable Troubleshooting Mode', 'health-check' ),
717
- 'parent' => 'health-check',
718
- 'href' => add_query_arg( array(
719
- 'health-check-disable-troubleshooting' => true,
720
- ) ),
721
- ) );
722
- }
723
-
724
- public function test_site_state() {
725
-
726
- // Make sure the Health_Check_Loopback class is available to us, in case the primary plugin is disabled.
727
- if ( ! method_exists( 'Health_Check_Loopback', 'can_perform_loopback' ) ) {
728
- $plugin_file = trailingslashit( WP_PLUGIN_DIR ) . 'health-check/includes/class-health-check-loopback.php';
729
-
730
- // Make sure the file exists, in case someone deleted the plugin manually, we don't want any errors.
731
- if ( ! file_exists( $plugin_file ) ) {
732
-
733
- // If the plugin files are inaccessible, we can't guarantee for the state of the site, so the default is a bad response.
734
- return false;
735
- }
736
-
737
- require_once( $plugin_file );
738
- }
739
-
740
- $loopback_state = Health_Check_Loopback::can_perform_loopback();
741
-
742
- if ( 'good' !== $loopback_state->status ) {
743
- return false;
744
- }
745
-
746
- return true;
747
- }
748
-
749
- public function dashboard_widget_styles() {
750
- if ( ! $this->is_troubleshooting() ) {
751
- return;
752
- }
753
-
754
- // Check that it's the dashboard page, we don't want to disturb any other pages.
755
- $screen = get_current_screen();
756
- if ( 'dashboard' !== $screen->id && 'plugins' !== $screen->id ) {
757
- return;
758
- }
759
- ?>
760
- <style type="text/css">
761
- @media all and (min-width: 783px) {
762
- #health-check-dashboard-widget {
763
- margin-top: 3rem;
764
- }
765
- }
766
-
767
- #health-check-dashboard-widget .welcome-panel-content {
768
- max-width: initial;
769
- }
770
-
771
- #health-check-dashboard-widget .notices .no-notices p {
772
- color: #bfc3c7;
773
- font-size: 1.2rem;
774
- }
775
- #health-check-dashboard-widget .notices .notice {
776
- margin-left: 0;
777
- }
778
- #health-check-dashboard-widget .notices .dismiss-notices {
779
- float: right;
780
- margin-right: 1rem;
781
- }
782
-
783
- #health-check-dashboard-widget .disable-troubleshooting-mode {
784
- margin-bottom: 1rem;
785
- }
786
- @media all and (min-width: 960px) {
787
- #health-check-dashboard-widget .disable-troubleshooting-mode {
788
- position: absolute;
789
- bottom: 1rem;
790
- right: 1rem;
791
- }
792
- }
793
-
794
- #health-check-dashboard-widget .toggle-visibility {
795
- display: none;
796
- }
797
- #health-check-dashboard-widget .toggle-visibility.visible {
798
- display: block;
799
- }
800
-
801
- #health-check-dashboard-widget .welcome-panel-column-container {
802
- position: initial;
803
- }
804
-
805
- #health-check-dashboard-widget .welcome-panel-column.is-standalone-button {
806
- width: 100%;
807
- text-align: right;
808
- }
809
- #health-check-dashboard-widget .welcome-panel-column.is-standalone-button .disable-troubleshooting-mode {
810
- position: relative;
811
- }
812
- </style>
813
- <?php
814
- }
815
-
816
- public function dashboard_widget_scripts() {
817
- if ( ! $this->is_troubleshooting() ) {
818
- return;
819
- }
820
-
821
- // Check that it's the dashboard page, we don't want to disturb any other pages.
822
- $screen = get_current_screen();
823
- if ( 'dashboard' !== $screen->id && 'plugins' !== $screen->id ) {
824
- return;
825
- }
826
- ?>
827
- <script type="text/javascript">
828
- jQuery( document ).ready(function( $ ) {
829
- $( '.health-check-toggle-visibility' ).click(function( e ) {
830
- var $elements = $( '.toggle-visibility', $( '#' + $ ( this ).data( 'element' ) ) );
831
-
832
- if ( $elements.is( ':visible' ) ) {
833
- $elements.attr( 'aria-hidden', 'true' ).toggle();
834
- } else {
835
- $elements.attr( 'aria-hidden', 'false' ).toggle();
836
- }
837
- });
838
- });
839
- </script>
840
- <?php
841
- }
842
-
843
- public function display_dashboard_widget() {
844
- if ( ! $this->is_troubleshooting() ) {
845
- return;
846
- }
847
-
848
- // Check that it's the dashboard page, we don't want to disturb any other pages.
849
- $screen = get_current_screen();
850
- if ( 'dashboard' !== $screen->id && 'plugins' !== $screen->id ) {
851
- return;
852
- }
853
-
854
- $notices = get_option( 'health-check-dashboard-notices', array() );
855
- ?>
856
- <div class="wrap">
857
- <div id="health-check-dashboard-widget" class="welcome-panel">
858
- <div class="welcome-panel-content">
859
- <h2>
860
- <?php esc_html_e( 'Health Check &mdash; Troubleshooting Mode', 'health-check' ); ?>
861
- </h2>
862
-
863
- <p class="about-description">
864
- <?php esc_html_e( 'Your site is currently in Troubleshooting Mode. This has no effect on your site visitors, they will continue to view your site as usual, but for you it will look as if you had just installed WordPress for the first time.', 'health-check' ); ?>
865
- </p>
866
-
867
- <p class="about-description">
868
- <?php esc_html_e( 'Here you can enable individual plugins or themes, helping you to find out what might be causing strange behaviors on your site. Do note that any changes you make to settings will be kept when you disable Troubleshooting Mode.', 'health-check' ); ?>
869
- </p>
870
-
871
- <div class="notices">
872
- <h3>
873
- <span class="dashicons dashicons-flag"></span>
874
- <?php esc_html_e( 'Notices', 'health-check' ); ?>
875
- </h3>
876
-
877
- <?php if ( empty( $notices ) && 'plugins' !== $screen->id ) : ?>
878
- <div class="no-notices">
879
- <p>
880
- <?php esc_html_e( 'There are no notices to show.', 'health-check' ); ?>
881
- </p>
882
- </div>
883
- <?php endif; ?>
884
-
885
- <?php if ( 'plugins' === $screen->id ) : ?>
886
- <div class="notice notice-warning inline">
887
- <p>
888
- <?php esc_html_e( 'Plugin actions, such as activating and deactivating, are not available while in Troubleshooting Mode.', 'health-check' ); ?>
889
- </p>
890
- </div>
891
- <?php endif; ?>
892
-
893
- <?php
894
- foreach ( $notices as $notice ) {
895
- printf(
896
- '<div class="notice notice-%s inline"><p>%s</p></div>',
897
- esc_attr( $notice['severity'] ),
898
- esc_html( $notice['message'] )
899
- );
900
- }
901
- ?>
902
-
903
- <?php
904
- if ( ! empty( $notices ) ) {
905
- printf(
906
- '<a href="%s" class="dismiss-notices">%s</a>',
907
- esc_url( add_query_arg( array(
908
- 'health-check-dismiss-notices' => true,
909
- ) ) ),
910
- esc_html__( 'Dismiss notices', 'health-check' )
911
- );
912
- }
913
- ?>
914
- </div>
915
-
916
- <div class="welcome-panel-column-container">
917
- <div class="welcome-panel-column">
918
- <?php if ( 'plugins' !== $screen->id ) : ?>
919
- <h3>
920
- <span class="dashicons dashicons-admin-plugins"></span>
921
- <?php esc_html_e( 'Available Plugins', 'health-check' ); ?>
922
- </h3>
923
-
924
- <ul id="health-check-plugins">
925
- <?php
926
- $active_plugins = array();
927
- $inactive_plugins = array();
928
-
929
- foreach ( $this->active_plugins as $count => $single_plugin ) {
930
- $plugin_slug = explode( '/', $single_plugin );
931
- $plugin_slug = $plugin_slug[0];
932
-
933
- $plugin_is_visible = true;
934
- if ( $count >= 5 ) {
935
- $plugin_is_visible = false;
936
- }
937
-
938
- $plugin_data = get_plugin_data( trailingslashit( WP_PLUGIN_DIR ) . $single_plugin );
939
-
940
- $actions = array();
941
-
942
- if ( in_array( $plugin_slug, $this->allowed_plugins ) ) {
943
- $actions[] = sprintf(
944
- '<a href="%s" aria-label="%s">%s</a>',
945
- esc_url( add_query_arg( array(
946
- 'health-check-troubleshoot-disable-plugin' => $plugin_slug,
947
- ) ) ),
948
- esc_attr(
949
- sprintf(
950
- // translators: %s: Plugin name.
951
- __( 'Disable the plugin, %s, while troubleshooting.', 'health-check' ),
952
- $plugin_data['Name']
953
- )
954
- ),
955
- esc_html__( 'Disable', 'health-check' )
956
- );
957
- } else {
958
- $actions[] = sprintf(
959
- '<a href="%s" aria-label="%s">%s</a>',
960
- esc_url( add_query_arg( array(
961
- 'health-check-troubleshoot-enable-plugin' => $plugin_slug,
962
- ) ) ),
963
- esc_attr(
964
- sprintf(
965
- // translators: %s: Plugin name.
966
- __( 'Enable the plugin, %s, while troubleshooting.', 'health-check' ),
967
- $plugin_data['Name']
968
- )
969
- ),
970
- esc_html__( 'Enable', 'health-check' )
971
- );
972
- }
973
-
974
- printf(
975
- '<li class="%s" aria-hidden="%s">%s - %s</li>',
976
- ( ! $plugin_is_visible ? 'toggle-visibility' : '' ),
977
- ( ! $plugin_is_visible ? 'true' : 'false' ),
978
- esc_html( $plugin_data['Name'] ),
979
- implode( ' | ', $actions )
980
- );
981
- }
982
- ?>
983
- </ul>
984
-
985
- <?php if ( count( $this->active_plugins ) > 5 ) : ?>
986
- <p>
987
- <button type="button" class="button button-link health-check-toggle-visibility toggle-visibility visible" aria-hidden="false" data-element="health-check-plugins">
988
- <?php esc_html_e( 'Show all plugins', 'health-check' ); ?>
989
- </button>
990
-
991
- <button type="button" class="button button-link health-check-toggle-visibility toggle-visibility" aria-hidden="true" data-element="health-check-plugins">
992
- <?php esc_html_e( 'Show fewer plugins', 'health-check' ); ?>
993
- </button>
994
- </p>
995
- <?php endif; ?>
996
- <?php endif; ?>
997
- </div>
998
-
999
- <div class="welcome-panel-column">
1000
- <?php if ( 'plugins' !== $screen->id ) : ?>
1001
- <h3>
1002
- <span class="dashicons dashicons-admin-appearance"></span>
1003
- <?php esc_html_e( 'Available Themes', 'health-check' ); ?>
1004
- </h3>
1005
-
1006
- <ul id="health-check-themes">
1007
- <?php
1008
- $themes = wp_prepare_themes_for_js();
1009
-
1010
- foreach ( $themes as $count => $theme ) {
1011
- $active = $theme['active'];
1012
-
1013
- $theme_is_visible = true;
1014
- if ( $count >= 5 ) {
1015
- $theme_is_visible = false;
1016
- }
1017
-
1018
- $actions = sprintf(
1019
- '<a href="%s" aria-label="%s">%s</a>',
1020
- esc_url( add_query_arg( array(
1021
- 'health-check-change-active-theme' => $theme['id'],
1022
- ) ) ),
1023
- esc_attr(
1024
- sprintf(
1025
- // translators: %s: Theme name.
1026
- __( 'Switch the active theme to %s', 'health-check' ),
1027
- $theme['name']
1028
- )
1029
- ),
1030
- esc_html__( 'Switch to this theme', 'health-check' )
1031
- );
1032
-
1033
- $plugin_label = sprintf(
1034
- '%s %s',
1035
- // translators: Prefix for the active theme in a listing.
1036
- ( $theme['active'] ? esc_html__( 'Active:', 'health-check' ) : '' ),
1037
- $theme['name']
1038
- );
1039
-
1040
- if ( ! $theme['active'] ) {
1041
- $plugin_label .= ' - ' . $actions;
1042
- }
1043
-
1044
- printf(
1045
- '<li class="%s" aria-hidden="%s">%s</li>',
1046
- ( $theme_is_visible ? '' : 'toggle-visibility' ),
1047
- ( $theme_is_visible ? 'false' : 'true' ),
1048
- $plugin_label
1049
- );
1050
- }
1051
- ?>
1052
- </ul>
1053
-
1054
- <?php if ( count( $themes ) > 5 ) : ?>
1055
- <p>
1056
- <button type="button" class="button button-link health-check-toggle-visibility toggle-visibility visible" aria-hidden="false" data-element="health-check-themes">
1057
- <?php esc_html_e( 'Show all themes', 'health-check' ); ?>
1058
- </button>
1059
-
1060
- <button type="button" class="button button-link health-check-toggle-visibility toggle-visibility" aria-hidden="true">
1061
- <?php esc_html_e( 'Show fewer themes', 'health-check' ); ?>
1062
- </button>
1063
- </p>
1064
- <?php endif; ?>
1065
- <?php endif; ?>
1066
- </div>
1067
-
1068
- <div class="welcome-panel-column <?php echo ( 'plugins' === $screen->id ? 'is-standalone-button' : '' ); ?>">
1069
- <?php
1070
- printf(
1071
- '<a href="%s" class="button button-primary button-hero disable-troubleshooting-mode">%s</a>',
1072
- esc_url( add_query_arg( array(
1073
- 'health-check-disable-troubleshooting' => true,
1074
- ) ) ),
1075
- esc_html__( 'Disable Troubleshooting Mode', 'health-check' )
1076
- );
1077
- ?>
1078
- </div>
1079
- </div>
1080
- </div>
1081
- </div>
1082
- </div>
1083
- <?php
1084
- }
1085
-
1086
- }
1087
-
1088
- new Health_Check_Troubleshooting_MU();
1
+ <?php
2
+ /*
3
+ Plugin Name: Health Check Troubleshooting Mode
4
+ Description: Conditionally disabled themes or plugins on your site for a given session, used to rule out conflicts during troubleshooting.
5
+ Version: 1.5.1
6
+ */
7
+
8
+ if ( ! defined( 'ABSPATH' ) ) {
9
+ die( 'We\'re sorry, but you can not directly access this file.' );
10
+ }
11
+
12
+ // Set the MU plugin version.
13
+ define( 'HEALTH_CHECK_TROUBLESHOOTING_MODE_PLUGIN_VERSION', '1.5.1' );
14
+
15
+ class Health_Check_Troubleshooting_MU {
16
+ private $disable_hash = null;
17
+ private $override_active = true;
18
+ private $default_theme = true;
19
+ private $active_plugins = array();
20
+ private $allowed_plugins = array();
21
+ private $current_theme;
22
+ private $current_theme_details;
23
+ private $self_fetching_theme = false;
24
+
25
+ private $available_query_args = array(
26
+ 'health-check-disable-plugins',
27
+ 'health-check-disable-plugins-hash',
28
+ 'health-check-disable-troubleshooting',
29
+ 'health-check-change-active-theme',
30
+ 'health-check-troubleshoot-enable-plugin',
31
+ 'health-check-troubleshoot-disable-plugin',
32
+ );
33
+
34
+ private $default_themes = array(
35
+ 'twentynineteen',
36
+ 'twentyseventeen',
37
+ 'twentysixteen',
38
+ 'twentyfifteen',
39
+ 'twentyfourteen',
40
+ 'twentythirteen',
41
+ 'twentytwelve',
42
+ 'twentyeleven',
43
+ 'twentyten',
44
+ );
45
+
46
+ /**
47
+ * Health_Check_Troubleshooting_MU constructor.
48
+ */
49
+ public function __construct() {
50
+ $this->init();
51
+ }
52
+
53
+ /**
54
+ * Actually initiation of the plugin.
55
+ *
56
+ * @return void
57
+ */
58
+ public function init() {
59
+ add_action( 'admin_bar_menu', array( $this, 'health_check_troubleshoot_menu_bar' ), 999 );
60
+
61
+ add_filter( 'option_active_plugins', array( $this, 'health_check_loopback_test_disable_plugins' ) );
62
+ add_filter( 'option_active_sitewide_plugins', array( $this, 'health_check_loopback_test_disable_plugins' ) );
63
+
64
+ add_filter( 'pre_option_template', array( $this, 'health_check_troubleshoot_theme_template' ) );
65
+ add_filter( 'pre_option_stylesheet', array( $this, 'health_check_troubleshoot_theme_stylesheet' ) );
66
+
67
+ add_action( 'admin_notices', array( $this, 'prompt_install_default_theme' ) );
68
+ add_filter( 'user_has_cap', array( $this, 'remove_plugin_theme_install' ) );
69
+
70
+ add_action( 'plugin_action_links', array( $this, 'plugin_actions' ), 50, 4 );
71
+
72
+ add_action( 'admin_notices', array( $this, 'display_dashboard_widget' ) );
73
+ add_action( 'admin_footer', array( $this, 'dashboard_widget_scripts' ) );
74
+
75
+ add_action( 'wp_logout', array( $this, 'health_check_troubleshooter_mode_logout' ) );
76
+ add_action( 'init', array( $this, 'health_check_troubleshoot_get_captures' ) );
77
+
78
+ add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_styles' ) );
79
+
80
+ /*
81
+ * Plugin activations can be forced by other tools in things like themes, so let's
82
+ * attempt to work around that by forcing plugin lists back and forth.
83
+ *
84
+ * This is not an ideal scenario, but one we must accept as reality.
85
+ */
86
+ add_action( 'activated_plugin', array( $this, 'plugin_activated' ) );
87
+
88
+ $this->load_options();
89
+ }
90
+
91
+ /**
92
+ * Set up the class variables based on option table entries.
93
+ *
94
+ * @return void
95
+ */
96
+ public function load_options() {
97
+ $this->disable_hash = get_option( 'health-check-disable-plugin-hash', null );
98
+ $this->allowed_plugins = get_option( 'health-check-allowed-plugins', array() );
99
+ $this->default_theme = ( 'yes' === get_option( 'health-check-default-theme', 'yes' ) ? true : false );
100
+ $this->active_plugins = $this->get_unfiltered_plugin_list();
101
+ $this->current_theme = get_option( 'health-check-current-theme', false );
102
+ }
103
+
104
+ /**
105
+ * Enqueue styles used by the MU plugin if applicable.
106
+ *
107
+ * @return void
108
+ */
109
+ public function enqueue_styles() {
110
+ if ( ! $this->is_troubleshooting() || ! is_admin() ) {
111
+ return;
112
+ }
113
+
114
+ wp_enqueue_style( 'health-check-troubleshooting-mode', plugins_url( '/health-check/assets/css/health-check-troubleshooting-mode.css' ), array(), HEALTH_CHECK_TROUBLESHOOTING_MODE_PLUGIN_VERSION );
115
+ }
116
+
117
+ /**
118
+ * Add a prompt to install a default theme.
119
+ *
120
+ * If no default theme exists, we can't reliably assert if an issue is
121
+ * caused by the theme. In these cases we should provide an easy step
122
+ * to get to, and install, one of the default themes.
123
+ *
124
+ * @return void
125
+ */
126
+ public function prompt_install_default_theme() {
127
+ if ( ! $this->is_troubleshooting() || $this->has_default_theme() ) {
128
+ return;
129
+ }
130
+
131
+ printf(
132
+ '<div class="notice notice-warning dismissable"><p>%s</p><p><a href="%s" class="button button-primary">%s</a></p></div>',
133
+ esc_html__( 'You don\'t have any of the default themes installed. A default theme helps you determine if your current theme is causing conflicts.', 'health-check' ),
134
+ esc_url( admin_url( sprintf(
135
+ 'theme-install.php?theme=%s',
136
+ $this->default_themes[0]
137
+ ) ) ),
138
+ esc_html__( 'Install a default theme', 'health-check' )
139
+ );
140
+ }
141
+
142
+ /**
143
+ * Remove the `Add` option for plugins and themes.
144
+ *
145
+ * When troubleshooting, adding or changing themes and plugins can
146
+ * lead to unexpected results. Remove these menu items to make it less
147
+ * likely that a user breaks their site through these.
148
+ *
149
+ * @param array $caps Array containing the current users capabilities.
150
+ *
151
+ * @return array
152
+ */
153
+ public function remove_plugin_theme_install( $caps ) {
154
+ if ( ! $this->is_troubleshooting() ) {
155
+ return $caps;
156
+ }
157
+
158
+ $caps['switch_themes'] = false;
159
+
160
+ /*
161
+ * This is to early for `get_current_screen()`, so we have to do it the
162
+ * old fashioned way with `$_SERVER`.
163
+ */
164
+ if ( 'plugin-install.php' === substr( $_SERVER['REQUEST_URI'], -18 ) ) {
165
+ $caps['activate_plugins'] = false;
166
+ }
167
+
168
+ return $caps;
169
+ }
170
+
171
+ /**
172
+ * Fire on plugin activation.
173
+ *
174
+ * When in Troubleshooting Mode, plugin activations
175
+ * will clear out the DB entry for `active_plugins`, this is bad.
176
+ *
177
+ * We fix this by re-setting the DB entry if anything tries
178
+ * to modify it during troubleshooting.
179
+ *
180
+ * @return void
181
+ */
182
+ public function plugin_activated() {
183
+ if ( ! $this->is_troubleshooting() ) {
184
+ return;
185
+ }
186
+
187
+ // Force the database entry for active plugins if someone tried changing plugins while in Troubleshooting Mode.
188
+ update_option( 'active_plugins', $this->active_plugins );
189
+ }
190
+
191
+ /**
192
+ * Modify plugin actions.
193
+ *
194
+ * While in Troubleshooting Mode, weird things will happen if you start
195
+ * modifying your plugin list. Prevent this, but also add in the ability
196
+ * to enable or disable a plugin during troubleshooting from this screen.
197
+ *
198
+ * @param $actions
199
+ * @param $plugin_file
200
+ * @param $plugin_data
201
+ * @param $context
202
+ *
203
+ * @return array
204
+ */
205
+ public function plugin_actions( $actions, $plugin_file, $plugin_data, $context ) {
206
+ if ( ! $this->is_troubleshooting() ) {
207
+ return $actions;
208
+ }
209
+
210
+ if ( 'mustuse' === $context ) {
211
+ return $actions;
212
+ }
213
+
214
+ /*
215
+ * Disable all plugin actions when in Troubleshooting Mode.
216
+ *
217
+ * We intentionally remove all plugin actions to avoid accidental clicking, activating or deactivating plugins
218
+ * while our plugin is altering plugin data may lead to unexpected behaviors, so to keep things sane we do
219
+ * not allow users to perform any actions during this time.
220
+ */
221
+ $actions = array();
222
+
223
+ // This isn't an active plugin, so does not apply to our troubleshooting scenarios.
224
+ if ( ! in_array( $plugin_file, $this->active_plugins ) ) {
225
+ return $actions;
226
+ }
227
+
228
+ // Set a slug if the plugin lives in the plugins directory root.
229
+ if ( ! stristr( $plugin_file, '/' ) ) {
230
+ $plugin_data['slug'] = $plugin_file;
231
+ }
232
+
233
+ $plugin_slug = ( isset( $plugin_data['slug'] ) ? $plugin_data['slug'] : sanitize_title( $plugin_data['Name'] ) );
234
+
235
+ if ( in_array( $plugin_slug, $this->allowed_plugins ) ) {
236
+ $actions['troubleshoot-disable'] = sprintf(
237
+ '<a href="%s">%s</a>',
238
+ esc_url( add_query_arg( array(
239
+ 'health-check-troubleshoot-disable-plugin' => $plugin_slug,
240
+ ), admin_url( 'plugins.php' ) ) ),
241
+ esc_html__( 'Disable while troubleshooting', 'health-check' )
242
+ );
243
+ } else {
244
+ $actions['troubleshoot-disable'] = sprintf(
245
+ '<a href="%s">%s</a>',
246
+ esc_url( add_query_arg( array(
247
+ 'health-check-troubleshoot-enable-plugin' => $plugin_slug,
248
+ ), admin_url( 'plugins.php' ) ) ),
249
+ esc_html__( 'Enable while troubleshooting', 'health-check' )
250
+ );
251
+ }
252
+
253
+ return $actions;
254
+ }
255
+
256
+ /**
257
+ * Get the actual list of active plugins.
258
+ *
259
+ * When in Troubleshooting Mode we override the list of plugins,
260
+ * this function lets us grab the active plugins list without
261
+ * any interference.
262
+ *
263
+ * @return array Array of active plugins.
264
+ */
265
+ public function get_unfiltered_plugin_list() {
266
+ $this->override_active = false;
267
+ $all_plugins = get_option( 'active_plugins' );
268
+ $this->override_active = true;
269
+
270
+ return $all_plugins;
271
+ }
272
+
273
+ /**
274
+ * Check if the user is currently in Troubleshooting Mode or not.
275
+ *
276
+ * @return bool
277
+ */
278
+ public function is_troubleshooting() {
279
+ // Check if a session cookie to disable plugins has been set.
280
+ if ( isset( $_COOKIE['health-check-disable-plugins'] ) ) {
281
+ $_GET['health-check-disable-plugin-hash'] = $_COOKIE['health-check-disable-plugins'] . md5( $_SERVER['REMOTE_ADDR'] );
282
+ }
283
+
284
+ // If the disable hash isn't set, no need to interact with things.
285
+ if ( ! isset( $_GET['health-check-disable-plugin-hash'] ) ) {
286
+ return false;
287
+ }
288
+
289
+ if ( empty( $this->disable_hash ) ) {
290
+ return false;
291
+ }
292
+
293
+ // If the plugin hash is not valid, we also break out
294
+ if ( $this->disable_hash !== $_GET['health-check-disable-plugin-hash'] ) {
295
+ return false;
296
+ }
297
+
298
+ return true;
299
+ }
300
+
301
+ /**
302
+ * Filter the plugins that are activated in WordPress.
303
+ *
304
+ * @param array $plugins An array of plugins marked as active.
305
+ *
306
+ * @return array
307
+ */
308
+ function health_check_loopback_test_disable_plugins( $plugins ) {
309
+ if ( ! $this->is_troubleshooting() || ! $this->override_active ) {
310
+ return $plugins;
311
+ }
312
+
313
+ // If we've received a comma-separated list of allowed plugins, we'll add them to the array of allowed plugins.
314
+ if ( isset( $_GET['health-check-allowed-plugins'] ) ) {
315
+ $this->allowed_plugins = explode( ',', $_GET['health-check-allowed-plugins'] );
316
+ }
317
+
318
+ foreach ( $plugins as $plugin_no => $plugin_path ) {
319
+ // Split up the plugin path, [0] is the slug and [1] holds the primary plugin file.
320
+ $plugin_parts = explode( '/', $plugin_path );
321
+
322
+ // We may want to allow individual, or groups of plugins, so introduce a skip-mechanic for those scenarios.
323
+ if ( in_array( $plugin_parts[0], $this->allowed_plugins ) ) {
324
+ continue;
325
+ }
326
+
327
+ // Remove the reference to this plugin.
328
+ unset( $plugins[ $plugin_no ] );
329
+ }
330
+
331
+ // Return a possibly modified list of activated plugins.
332
+ return $plugins;
333
+ }
334
+
335
+ /**
336
+ * Check if a default theme exists.
337
+ *
338
+ * If a default theme exists, return the most recent one, if not return `false`.
339
+ *
340
+ * @return bool|string
341
+ */
342
+ function has_default_theme() {
343
+ foreach ( $this->default_themes as $default_theme ) {
344
+ if ( $this->theme_exists( $default_theme ) ) {
345
+ return $default_theme;
346
+ }
347
+ }
348
+
349
+ return false;
350
+ }
351
+
352
+ /**
353
+ * Check if a theme exists by looking for the slug.
354
+ *
355
+ * @param string $theme_slug
356
+ *
357
+ * @return bool
358
+ */
359
+ function theme_exists( $theme_slug ) {
360
+ return is_dir( WP_CONTENT_DIR . '/themes/' . $theme_slug );
361
+ }
362
+
363
+ /**
364
+ * Check if theme overrides are active.
365
+ *
366
+ * @return bool
367
+ */
368
+ function override_theme() {
369
+ if ( ! $this->is_troubleshooting() ) {
370
+ return false;
371
+ }
372
+
373
+ return true;
374
+ }
375
+
376
+ /**
377
+ * Override the default theme.
378
+ *
379
+ * Attempt to set one of the default themes, or a theme of the users choosing, as the active one
380
+ * during Troubleshooting Mode.
381
+ *
382
+ * @param $default
383
+ *
384
+ * @return bool|string
385
+ */
386
+ function health_check_troubleshoot_theme_stylesheet( $default ) {
387
+ if ( $this->self_fetching_theme ) {
388
+ return $default;
389
+ }
390
+
391
+ if ( ! $this->override_theme() ) {
392
+ return $default;
393
+ }
394
+
395
+ if ( empty( $this->current_theme_details ) ) {
396
+ $this->self_fetching_theme = true;
397
+ $this->current_theme_details = wp_get_theme( $this->current_theme );
398
+ $this->self_fetching_theme = false;
399
+ }
400
+
401
+ // If no theme has been chosen, start off by troubleshooting as a default theme if one exists.
402
+ $default_theme = $this->has_default_theme();
403
+ if ( false === $this->current_theme ) {
404
+ if ( $default_theme ) {
405
+ return $default_theme;
406
+ }
407
+ }
408
+
409
+ return $this->current_theme;
410
+ }
411
+
412
+ /**
413
+ * Override the default parent theme.
414
+ *
415
+ * If this is a child theme, override the parent and provide our users chosen themes parent instead.
416
+ *
417
+ * @param $default
418
+ *
419
+ * @return bool|string
420
+ */
421
+ function health_check_troubleshoot_theme_template( $default ) {
422
+ if ( $this->self_fetching_theme ) {
423
+ return $default;
424
+ }
425
+
426
+ if ( ! $this->override_theme() ) {
427
+ return $default;
428
+ }
429
+
430
+ if ( empty( $this->current_theme_details ) ) {
431
+ $this->self_fetching_theme = true;
432
+ $this->current_theme_details = wp_get_theme( $this->current_theme );
433
+ $this->self_fetching_theme = false;
434
+ }
435
+
436
+ // If no theme has been chosen, start off by troubleshooting as a default theme if one exists.
437
+ $default_theme = $this->has_default_theme();
438
+ if ( false === $this->current_theme ) {
439
+ if ( $default_theme ) {
440
+ return $default_theme;
441
+ }
442
+ }
443
+
444
+ if ( $this->current_theme_details->parent() ) {
445
+ return $this->current_theme_details->get_template();
446
+ }
447
+
448
+ return $this->current_theme;
449
+ }
450
+
451
+ /**
452
+ * Disable Troubleshooting Mode on logout.
453
+ *
454
+ * If logged in, disable the Troubleshooting Mode when the logout
455
+ * event is fired, this ensures we start with a clean slate on
456
+ * the next login.
457
+ *
458
+ * @return void
459
+ */
460
+ function health_check_troubleshooter_mode_logout() {
461
+ if ( ! $this->is_troubleshooting() ) {
462
+ return;
463
+ }
464
+
465
+ if ( isset( $_COOKIE['health-check-disable-plugins'] ) ) {
466
+ $this->disable_troubleshooting_mode();
467
+ }
468
+ }
469
+
470
+ function disable_troubleshooting_mode() {
471
+ unset( $_COOKIE['health-check-disable-plugins'] );
472
+ setcookie( 'health-check-disable-plugins', null, 0, COOKIEPATH, COOKIE_DOMAIN );
473
+ delete_option( 'health-check-allowed-plugins' );
474
+ delete_option( 'health-check-default-theme' );
475
+ delete_option( 'health-check-current-theme' );
476
+
477
+ delete_option( 'health-check-backup-plugin-list' );
478
+ }
479
+
480
+ /**
481
+ * Catch query arguments.
482
+ *
483
+ * When in Troubleshooting Mode, look for various GET variables that trigger
484
+ * various plugin actions.
485
+ *
486
+ * @return void
487
+ */
488
+ function health_check_troubleshoot_get_captures() {
489
+ if ( ! $this->is_troubleshooting() ) {
490
+ return;
491
+ }
492
+
493
+ // Disable Troubleshooting Mode.
494
+ if ( isset( $_GET['health-check-disable-troubleshooting'] ) ) {
495
+ $this->disable_troubleshooting_mode();
496
+
497
+ wp_redirect( remove_query_arg( $this->available_query_args ) );
498
+ die();
499
+ }
500
+
501
+ // Dismiss notices.
502
+ if ( isset( $_GET['health-check-dismiss-notices'] ) && $this->is_troubleshooting() && is_admin() ) {
503
+ update_option( 'health-check-dashboard-notices', array() );
504
+
505
+ wp_redirect( admin_url() );
506
+ die();
507
+ }
508
+
509
+ // Enable an individual plugin.
510
+ if ( isset( $_GET['health-check-troubleshoot-enable-plugin'] ) ) {
511
+ $old_allowed_plugins = $this->allowed_plugins;
512
+
513
+ $this->allowed_plugins[ $_GET['health-check-troubleshoot-enable-plugin'] ] = $_GET['health-check-troubleshoot-enable-plugin'];
514
+
515
+ update_option( 'health-check-allowed-plugins', $this->allowed_plugins );
516
+
517
+ if ( ! $this->test_site_state() ) {
518
+ $this->allowed_plugins = $old_allowed_plugins;
519
+ update_option( 'health-check-allowed-plugins', $old_allowed_plugins );
520
+
521
+ $this->add_dashboard_notice(
522
+ sprintf(
523
+ // translators: %s: The plugin slug that was enabled.
524
+ __( 'When enabling the plugin, %s, a site failure occurred. Because of this the change was automatically reverted.', 'health-check' ),
525
+ $_GET['health-check-troubleshoot-enable-plugin']
526
+ ),
527
+ 'warning'
528
+ );
529
+ }
530
+
531
+ wp_redirect( remove_query_arg( $this->available_query_args ) );
532
+ die();
533
+ }
534
+
535
+ // Disable an individual plugin.
536
+ if ( isset( $_GET['health-check-troubleshoot-disable-plugin'] ) ) {
537
+ $old_allowed_plugins = $this->allowed_plugins;
538
+
539
+ unset( $this->allowed_plugins[ $_GET['health-check-troubleshoot-disable-plugin'] ] );
540
+
541
+ update_option( 'health-check-allowed-plugins', $this->allowed_plugins );
542
+
543
+ if ( ! $this->test_site_state() ) {
544
+ $this->allowed_plugins = $old_allowed_plugins;
545
+ update_option( 'health-check-allowed-plugins', $old_allowed_plugins );
546
+
547
+ $this->add_dashboard_notice(
548
+ sprintf(
549
+ // translators: %s: The plugin slug that was disabled.
550
+ __( 'When disabling the plugin, %s, a site failure occurred. Because of this the change was automatically reverted.', 'health-check' ),
551
+ $_GET['health-check-troubleshoot-disable-plugin']
552
+ ),
553
+ 'warning'
554
+ );
555
+ }
556
+
557
+ wp_redirect( remove_query_arg( $this->available_query_args ) );
558
+ die();
559
+ }
560
+
561
+ // Change the active theme for this session.
562
+ if ( isset( $_GET['health-check-change-active-theme'] ) ) {
563
+ $old_theme = get_option( 'health-check-current-theme' );
564
+
565
+ update_option( 'health-check-current-theme', $_GET['health-check-change-active-theme'] );
566
+
567
+ if ( ! $this->test_site_state() ) {
568
+ update_option( 'health-check-current-theme', $old_theme );
569
+
570
+ $this->add_dashboard_notice(
571
+ sprintf(
572
+ // translators: %s: The theme slug that was switched to.
573
+ __( 'When switching the active theme to %s, a site failure occurred. Because of this we reverted the theme to the one you used previously.', 'health-check' ),
574
+ $_GET['health-check-change-active-theme']
575
+ ),
576
+ 'warning'
577
+ );
578
+ }
579
+
580
+ wp_redirect( remove_query_arg( $this->available_query_args ) );
581
+ die();
582
+ }
583
+ }
584
+
585
+ private function add_dashboard_notice( $message, $severity = 'notice' ) {
586
+ $notices = get_option( 'health-check-dashboard-notices', array() );
587
+
588
+ $notices[] = array(
589
+ 'severity' => $severity,
590
+ 'message' => $message,
591
+ 'time' => date( 'Y-m-d H:i' ),
592
+ );
593
+
594
+ update_option( 'health-check-dashboard-notices', $notices );
595
+ }
596
+
597
+ /**
598
+ * Extend the admin bar.
599
+ *
600
+ * When in Troubleshooting Mode, introduce a new element to the admin bar to show
601
+ * enabled and disabled plugins (if conditions are met), switch between themes
602
+ * and disable Troubleshooting Mode altogether.
603
+ *
604
+ * @param WP_Admin_Bar $wp_menu
605
+ *
606
+ * @return void
607
+ */
608
+ function health_check_troubleshoot_menu_bar( $wp_menu ) {
609
+ if ( ! $this->is_troubleshooting() ) {
610
+ return;
611
+ }
612
+
613
+ // We need some admin functions to make this a better user experience, so include that file.
614
+ if ( ! is_admin() ) {
615
+ require_once( trailingslashit( ABSPATH ) . 'wp-admin/includes/plugin.php' );
616
+ }
617
+
618
+ // Ensure the theme functions are available to us on every page.
619
+ include_once( trailingslashit( ABSPATH ) . 'wp-admin/includes/theme.php' );
620
+
621
+ // Add top-level menu item.
622
+ $wp_menu->add_menu( array(
623
+ 'id' => 'health-check',
624
+ 'title' => esc_html__( 'Troubleshooting Mode', 'health-check' ),
625
+ ) );
626
+
627
+ // Add a link to manage plugins if there are more than 20 set to be active.
628
+ if ( count( $this->active_plugins ) > 20 ) {
629
+ $wp_menu->add_node( array(
630
+ 'id' => 'health-check-plugins',
631
+ 'title' => esc_html__( 'Manage active plugins', 'health-check' ),
632
+ 'parent' => 'health-check',
633
+ 'href' => admin_url( 'plugins.php' ),
634
+ ) );
635
+ } else {
636
+ $wp_menu->add_node( array(
637
+ 'id' => 'health-check-plugins',
638
+ 'title' => esc_html__( 'Plugins', 'health-check' ),
639
+ 'parent' => 'health-check',
640
+ ) );
641
+
642
+ $wp_menu->add_group( array(
643
+ 'id' => 'health-check-plugins-enabled',
644
+ 'parent' => 'health-check-plugins',
645
+ ) );
646
+ $wp_menu->add_group( array(
647
+ 'id' => 'health-check-plugins-disabled',
648
+ 'parent' => 'health-check-plugins',
649
+ ) );
650
+
651
+ foreach ( $this->active_plugins as $single_plugin ) {
652
+ $plugin_slug = explode( '/', $single_plugin );
653
+ $plugin_slug = $plugin_slug[0];
654
+
655
+ $plugin_data = get_plugin_data( trailingslashit( WP_PLUGIN_DIR ) . $single_plugin );
656
+
657
+ $enabled = true;
658
+
659
+ if ( in_array( $plugin_slug, $this->allowed_plugins ) ) {
660
+ $label = sprintf(
661
+ // Translators: %s: Plugin slug.
662
+ esc_html__( 'Disable %s', 'health-check' ),
663
+ sprintf(
664
+ '<strong>%s</strong>',
665
+ $plugin_data['Name']
666
+ )
667
+ );
668
+ $url = add_query_arg( array(
669
+ 'health-check-troubleshoot-disable-plugin' => $plugin_slug,
670
+ ) );
671
+ } else {
672
+ $enabled = false;
673
+ $label = sprintf(
674
+ // Translators: %s: Plugin slug.
675
+ esc_html__( 'Enable %s', 'health-check' ),
676
+ sprintf(
677
+ '<strong>%s</strong>',
678
+ $plugin_data['Name']
679
+ )
680
+ );
681
+ $url = add_query_arg( array(
682
+ 'health-check-troubleshoot-enable-plugin' => $plugin_slug,
683
+ ) );
684
+ }
685
+
686
+ $wp_menu->add_node( array(
687
+ 'id' => sprintf(
688
+ 'health-check-plugin-%s',
689
+ $plugin_slug
690
+ ),
691
+ 'title' => $label,
692
+ 'parent' => ( $enabled ? 'health-check-plugins-enabled' : 'health-check-plugins-disabled' ),
693
+ 'href' => $url,
694
+ ) );
695
+ }
696
+ }
697
+
698
+ $wp_menu->add_node( array(
699
+ 'id' => 'health-check-theme',
700
+ 'title' => esc_html__( 'Themes', 'health-check' ),
701
+ 'parent' => 'health-check',
702
+ ) );
703
+
704
+ $themes = wp_prepare_themes_for_js();
705
+
706
+ foreach ( $themes as $theme ) {
707
+ $node = array(
708
+ 'id' => sprintf(
709
+ 'health-check-theme-%s',
710
+ sanitize_title( $theme['id'] )
711
+ ),
712
+ 'title' => sprintf(
713
+ '%s %s',
714
+ // translators: Prefix for the active theme in a listing.
715
+ ( $theme['active'] ? esc_html__( 'Active:', 'health-check' ) : '' ),
716
+ $theme['name']
717
+ ),
718
+ 'parent' => 'health-check-theme',
719
+ );
720
+
721
+ if ( ! $theme['active'] ) {
722
+ $node['href'] = add_query_arg( array(
723
+ 'health-check-change-active-theme' => $theme['id'],
724
+ ) );
725
+ }
726
+
727
+ $wp_menu->add_node( $node );
728
+ }
729
+
730
+ // Add a link to disable Troubleshooting Mode.
731
+ $wp_menu->add_node( array(
732
+ 'id' => 'health-check-disable',
733
+ 'title' => esc_html__( 'Disable Troubleshooting Mode', 'health-check' ),
734
+ 'parent' => 'health-check',
735
+ 'href' => add_query_arg( array(
736
+ 'health-check-disable-troubleshooting' => true,
737
+ ) ),
738
+ ) );
739
+ }
740
+
741
+ public function test_site_state() {
742
+
743
+ // Make sure the Health_Check_Loopback class is available to us, in case the primary plugin is disabled.
744
+ if ( ! method_exists( 'Health_Check_Loopback', 'can_perform_loopback' ) ) {
745
+ $plugin_file = trailingslashit( WP_PLUGIN_DIR ) . 'health-check/includes/class-health-check-loopback.php';
746
+
747
+ // Make sure the file exists, in case someone deleted the plugin manually, we don't want any errors.
748
+ if ( ! file_exists( $plugin_file ) ) {
749
+
750
+ // If the plugin files are inaccessible, we can't guarantee for the state of the site, so the default is a bad response.
751
+ return false;
752
+ }
753
+
754
+ require_once( $plugin_file );
755
+ }
756
+
757
+ $loopback_state = Health_Check_Loopback::can_perform_loopback();
758
+
759
+ if ( 'good' !== $loopback_state->status ) {
760
+ return false;
761
+ }
762
+
763
+ return true;
764
+ }
765
+
766
+ public function dashboard_widget_scripts() {
767
+ if ( ! $this->is_troubleshooting() ) {
768
+ return;
769
+ }
770
+
771
+ // Check that it's the dashboard page, we don't want to disturb any other pages.
772
+ $screen = get_current_screen();
773
+ if ( 'dashboard' !== $screen->id && 'plugins' !== $screen->id ) {
774
+ return;
775
+ }
776
+ ?>
777
+ <script type="text/javascript">
778
+ jQuery( document ).ready(function( $ ) {
779
+ $( '.health-check-toggle-visibility' ).click(function() {
780
+ var $elements = $( '.toggle-visibility', $( '#' + $ ( this ).data( 'element' ) ).closest( '.welcome-panel-column' ) );
781
+
782
+ if ( $elements.is( ':visible' ) ) {
783
+ $elements.attr( 'aria-hidden', 'false' ).toggle();
784
+ } else {
785
+ $elements.attr( 'aria-hidden', 'true' ).toggle();
786
+ }
787
+ });
788
+ });
789
+ </script>
790
+ <?php
791
+ }
792
+
793
+ public function display_dashboard_widget() {
794
+ if ( ! $this->is_troubleshooting() ) {
795
+ return;
796
+ }
797
+
798
+ // Check that it's the dashboard page, we don't want to disturb any other pages.
799
+ $screen = get_current_screen();
800
+ if ( 'dashboard' !== $screen->id && 'plugins' !== $screen->id ) {
801
+ return;
802
+ }
803
+
804
+ $notices = get_option( 'health-check-dashboard-notices', array() );
805
+ ?>
806
+ <div class="wrap">
807
+ <div id="health-check-dashboard-widget" class="welcome-panel">
808
+ <div class="welcome-panel-content">
809
+ <h2>
810
+ <?php esc_html_e( 'Health Check &mdash; Troubleshooting Mode', 'health-check' ); ?>
811
+ </h2>
812
+
813
+ <p class="about-description">
814
+ <?php _e( 'Your site is currently in Troubleshooting Mode. This has <strong>no effect on your site visitors</strong>, they will continue to view your site as usual, but for you it will look as if you had just installed WordPress for the first time.', 'health-check' ); ?>
815
+ </p>
816
+
817
+ <p class="about-description">
818
+ <?php _e( 'Here you can enable individual plugins or themes, helping you to find out what might be causing strange behaviors on your site. Do note that <strong>any changes you make to settings will be kept</strong> when you disable Troubleshooting Mode.', 'health-check' ); ?>
819
+ </p>
820
+
821
+ <div class="notices">
822
+ <h3>
823
+ <span class="dashicons dashicons-flag"></span>
824
+ <?php esc_html_e( 'Notices', 'health-check' ); ?>
825
+ </h3>
826
+
827
+ <?php if ( empty( $notices ) && 'plugins' !== $screen->id ) : ?>
828
+ <div class="no-notices">
829
+ <p>
830
+ <?php esc_html_e( 'There are no notices to show.', 'health-check' ); ?>
831
+ </p>
832
+ </div>
833
+ <?php endif; ?>
834
+
835
+ <?php if ( 'plugins' === $screen->id ) : ?>
836
+ <div class="notice notice-warning inline">
837
+ <p>
838
+ <?php esc_html_e( 'Plugin actions, such as activating and deactivating, are not available while in Troubleshooting Mode.', 'health-check' ); ?>
839
+ </p>
840
+ </div>
841
+ <?php endif; ?>
842
+
843
+ <?php
844
+ foreach ( $notices as $notice ) {
845
+ printf(
846
+ '<div class="notice notice-%s inline"><p>%s</p></div>',
847
+ esc_attr( $notice['severity'] ),
848
+ esc_html( $notice['message'] )
849
+ );
850
+ }
851
+ ?>
852
+
853
+ <?php
854
+ if ( ! empty( $notices ) ) {
855
+ printf(
856
+ '<a href="%s" class="dismiss-notices">%s</a>',
857
+ esc_url( add_query_arg( array(
858
+ 'health-check-dismiss-notices' => true,
859
+ ) ) ),
860
+ esc_html__( 'Dismiss notices', 'health-check' )
861
+ );
862
+ }
863
+ ?>
864
+ </div>
865
+
866
+ <div class="welcome-panel-column-container">
867
+ <div class="welcome-panel-column">
868
+ <?php if ( 'plugins' !== $screen->id ) : ?>
869
+ <h3>
870
+ <span class="dashicons dashicons-admin-plugins"></span>
871
+ <?php esc_html_e( 'Available Plugins', 'health-check' ); ?>
872
+ </h3>
873
+
874
+ <ul id="health-check-plugins">
875
+ <?php
876
+ $active_plugins = array();
877
+ $inactive_plugins = array();
878
+
879
+ foreach ( $this->active_plugins as $count => $single_plugin ) {
880
+ $plugin_slug = explode( '/', $single_plugin );
881
+ $plugin_slug = $plugin_slug[0];
882
+
883
+ $plugin_is_visible = true;
884
+ if ( $count >= 5 ) {
885
+ $plugin_is_visible = false;
886
+ }
887
+
888
+ $plugin_data = get_plugin_data( trailingslashit( WP_PLUGIN_DIR ) . $single_plugin );
889
+
890
+ $actions = array();
891
+
892
+ if ( in_array( $plugin_slug, $this->allowed_plugins ) ) {
893
+ $actions[] = sprintf(
894
+ '<a href="%s" aria-label="%s">%s</a>',
895
+ esc_url( add_query_arg( array(
896
+ 'health-check-troubleshoot-disable-plugin' => $plugin_slug,
897
+ ) ) ),
898
+ esc_attr(
899
+ sprintf(
900
+ // translators: %s: Plugin name.
901
+ __( 'Disable the plugin, %s, while troubleshooting.', 'health-check' ),
902
+ $plugin_data['Name']
903
+ )
904
+ ),
905
+ esc_html__( 'Disable', 'health-check' )
906
+ );
907
+ } else {
908
+ $actions[] = sprintf(
909
+ '<a href="%s" aria-label="%s">%s</a>',
910
+ esc_url( add_query_arg( array(
911
+ 'health-check-troubleshoot-enable-plugin' => $plugin_slug,
912
+ ) ) ),
913
+ esc_attr(
914
+ sprintf(
915
+ // translators: %s: Plugin name.
916
+ __( 'Enable the plugin, %s, while troubleshooting.', 'health-check' ),
917
+ $plugin_data['Name']
918
+ )
919
+ ),
920
+ esc_html__( 'Enable', 'health-check' )
921
+ );
922
+ }
923
+
924
+ printf(
925
+ '<li class="%s" aria-hidden="%s">%s - %s</li>',
926
+ ( ! $plugin_is_visible ? 'toggle-visibility' : '' ),
927
+ ( ! $plugin_is_visible ? 'true' : 'false' ),
928
+ esc_html( $plugin_data['Name'] ),
929
+ implode( ' | ', $actions )
930
+ );
931
+ }
932
+ ?>
933
+ </ul>
934
+
935
+ <?php if ( count( $this->active_plugins ) > 5 ) : ?>
936
+ <p>
937
+ <button type="button" class="button button-link health-check-toggle-visibility toggle-visibility visible" aria-hidden="false" data-element="health-check-plugins">
938
+ <?php esc_html_e( 'Show all plugins', 'health-check' ); ?> <span class="icon"></span>
939
+ </button>
940
+
941
+ <button type="button" class="button button-link health-check-toggle-visibility toggle-visibility" aria-hidden="true" data-element="health-check-plugins">
942
+ <?php esc_html_e( 'Show fewer plugins', 'health-check' ); ?> <span class="icon icon-up"></span>
943
+ </button>
944
+ </p>
945
+ <?php endif; ?>
946
+ <?php endif; ?>
947
+ </div>
948
+
949
+ <div class="welcome-panel-column">
950
+ <?php if ( 'plugins' !== $screen->id ) : ?>
951
+ <h3>
952
+ <span class="dashicons dashicons-admin-appearance"></span>
953
+ <?php esc_html_e( 'Available Themes', 'health-check' ); ?>
954
+ </h3>
955
+
956
+ <ul id="health-check-themes">
957
+ <?php
958
+ $themes = wp_prepare_themes_for_js();
959
+
960
+ foreach ( $themes as $count => $theme ) {
961
+ $active = $theme['active'];
962
+
963
+ $theme_is_visible = true;
964
+ if ( $count >= 5 ) {
965
+ $theme_is_visible = false;
966
+ }
967
+
968
+ $actions = sprintf(
969
+ '<a href="%s" aria-label="%s">%s</a>',
970
+ esc_url( add_query_arg( array(
971
+ 'health-check-change-active-theme' => $theme['id'],
972
+ ) ) ),
973
+ esc_attr(
974
+ sprintf(
975
+ // translators: %s: Theme name.
976
+ __( 'Switch the active theme to %s', 'health-check' ),
977
+ $theme['name']
978
+ )
979
+ ),
980
+ esc_html__( 'Switch to this theme', 'health-check' )
981
+ );
982
+
983
+ $plugin_label = sprintf(
984
+ '%s %s',
985
+ // translators: Prefix for the active theme in a listing.
986
+ ( $theme['active'] ? esc_html__( 'Active:', 'health-check' ) : '' ),
987
+ $theme['name']
988
+ );
989
+
990
+ if ( ! $theme['active'] ) {
991
+ $plugin_label .= ' - ' . $actions;
992
+ }
993
+
994
+ printf(
995
+ '<li class="%s" aria-hidden="%s">%s</li>',
996
+ ( $theme_is_visible ? '' : 'toggle-visibility' ),
997
+ ( $theme_is_visible ? 'false' : 'true' ),
998
+ $plugin_label
999
+ );
1000
+ }
1001
+ ?>
1002
+ </ul>
1003
+
1004
+ <?php if ( count( $themes ) > 5 ) : ?>
1005
+ <p>
1006
+ <button type="button" class="button button-link health-check-toggle-visibility toggle-visibility visible" aria-hidden="false" data-element="health-check-themes">
1007
+ <?php esc_html_e( 'Show all themes', 'health-check' ); ?> <span class="icon"></span>
1008
+ </button>
1009
+
1010
+ <button type="button" class="button button-link health-check-toggle-visibility toggle-visibility" aria-hidden="true" data-element="health-check-themes">
1011
+ <?php esc_html_e( 'Show fewer themes', 'health-check' ); ?> <span class="icon icon-up"></span>
1012
+ </button>
1013
+ </p>
1014
+ <?php endif; ?>
1015
+ <?php endif; ?>
1016
+ </div>
1017
+
1018
+ <div class="welcome-panel-column <?php echo ( 'plugins' === $screen->id ? 'is-standalone-button' : '' ); ?>">
1019
+ <?php
1020
+ printf(
1021
+ '<a href="%s" class="button button-primary button-hero disable-troubleshooting-mode">%s</a>',
1022
+ esc_url( add_query_arg( array(
1023
+ 'health-check-disable-troubleshooting' => true,
1024
+ ) ) ),
1025
+ esc_html__( 'Disable Troubleshooting Mode', 'health-check' )
1026
+ );
1027
+ ?>
1028
+ </div>
1029
+ </div>
1030
+ </div>
1031
+ </div>
1032
+ </div>
1033
+ <?php
1034
+ }
1035
+
1036
+ }
1037
+
1038
+ new Health_Check_Troubleshooting_MU();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
health-check.php CHANGED
@@ -1,64 +1,65 @@
1
- <?php
2
- /**
3
- * Plugins primary file, in charge of including all other dependencies.
4
- *
5
- * @package Health Check
6
- *
7
- * @wordpress-plugin
8
- * Plugin Name: Health Check & Troubleshooting
9
- * Plugin URI: http://wordpress.org/plugins/health-check/
10
- * Description: Checks the health of your WordPress install.
11
- * Author: The WordPress.org community
12
- * Version: 1.2.3
13
- * Author URI: http://wordpress.org/plugins/health-check/
14
- * Text Domain: health-check
15
- */
16
-
17
- // Check that the file is nto accessed directly.
18
- if ( ! defined( 'ABSPATH' ) ) {
19
- die( 'We\'re sorry, but you can not directly access this file.' );
20
- }
21
-
22
- // Set the minimum PHP version WordPress supports.
23
- define( 'HEALTH_CHECK_PHP_MIN_VERSION', '5.2.4' );
24
-
25
- // Set the lowest PHP version still receiving security updates.
26
- define( 'HEALTH_CHECK_PHP_SUPPORTED_VERSION', '5.6' );
27
-
28
- // Set the PHP version WordPress recommends.
29
- define( 'HEALTH_CHECK_PHP_REC_VERSION', '7.2' );
30
-
31
- // Set the minimum MySQL version WordPress supports.
32
- define( 'HEALTH_CHECK_MYSQL_MIN_VERSION', '5.0' );
33
-
34
- // Set the MySQL version WordPress recommends.
35
- define( 'HEALTH_CHECK_MYSQL_REC_VERSION', '5.6' );
36
-
37
- // Set the plugin version.
38
- define( 'HEALTH_CHECK_PLUGIN_VERSION', '1.2.3' );
39
-
40
- // Set the absolute path for the plugin.
41
- define( 'HEALTH_CHECK_PLUGIN_DIRECTORY', plugin_dir_path( __FILE__ ) );
42
-
43
- // Set the plugin URL root.
44
- define( 'HEALTH_CHECK_PLUGIN_URL', plugins_url( '/', __FILE__ ) );
45
-
46
- // Set the current cURL version.
47
- define( 'HEALTH_CHECK_CURL_VERSION', '7.58' );
48
-
49
- // Set the minimum cURL version that we've tested that core works with.
50
- define( 'HEALTH_CHECK_CURL_MIN_VERSION', '7.38' );
51
-
52
- // Include class-files used by our plugin.
53
- require_once( dirname( __FILE__ ) . '/includes/class-health-check.php' );
54
- require_once( dirname( __FILE__ ) . '/includes/class-health-check-auto-updates.php' );
55
- require_once( dirname( __FILE__ ) . '/includes/class-health-check-wp-cron.php' );
56
- require_once( dirname( __FILE__ ) . '/includes/class-health-check-debug-data.php' );
57
- require_once( dirname( __FILE__ ) . '/includes/class-health-check-loopback.php' );
58
- require_once( dirname( __FILE__ ) . '/includes/class-health-check-troubleshoot.php' );
59
- require_once( dirname( __FILE__ ) . '/includes/class-health-check-files-integrity.php' );
60
- require_once( dirname( __FILE__ ) . '/includes/class-health-check-mail-check.php' );
61
- require_once( dirname( __FILE__ ) . '/includes/class-health-check-site-status.php' );
62
-
63
- // Initialize our plugin.
64
- new Health_Check();
 
1
+ <?php
2
+ /**
3
+ * Plugins primary file, in charge of including all other dependencies.
4
+ *
5
+ * @package Health Check
6
+ *
7
+ * @wordpress-plugin
8
+ * Plugin Name: Health Check & Troubleshooting
9
+ * Plugin URI: https://wordpress.org/plugins/health-check/
10
+ * Description: Checks the health of your WordPress install.
11
+ * Author: The WordPress.org community
12
+ * Version: 1.2.4
13
+ * Author URI: https://wordpress.org/plugins/health-check/
14
+ * Text Domain: health-check
15
+ */
16
+
17
+ // Check that the file is nto accessed directly.
18
+ if ( ! defined( 'ABSPATH' ) ) {
19
+ die( 'We\'re sorry, but you can not directly access this file.' );
20
+ }
21
+
22
+ // Set the minimum PHP version WordPress supports.
23
+ define( 'HEALTH_CHECK_PHP_MIN_VERSION', '5.2.4' );
24
+
25
+ // Set the lowest PHP version still receiving security updates.
26
+ define( 'HEALTH_CHECK_PHP_SUPPORTED_VERSION', '5.6' );
27
+
28
+ // Set the PHP version WordPress recommends.
29
+ define( 'HEALTH_CHECK_PHP_REC_VERSION', '7.2' );
30
+
31
+ // Set the minimum MySQL version WordPress supports.
32
+ define( 'HEALTH_CHECK_MYSQL_MIN_VERSION', '5.0' );
33
+
34
+ // Set the MySQL version WordPress recommends.
35
+ define( 'HEALTH_CHECK_MYSQL_REC_VERSION', '5.6' );
36
+
37
+ // Set the plugin version.
38
+ define( 'HEALTH_CHECK_PLUGIN_VERSION', '1.2.4' );
39
+
40
+ // Set the absolute path for the plugin.
41
+ define( 'HEALTH_CHECK_PLUGIN_DIRECTORY', plugin_dir_path( __FILE__ ) );
42
+
43
+ // Set the plugin URL root.
44
+ define( 'HEALTH_CHECK_PLUGIN_URL', plugins_url( '/', __FILE__ ) );
45
+
46
+ // Set the current cURL version.
47
+ define( 'HEALTH_CHECK_CURL_VERSION', '7.58' );
48
+
49
+ // Set the minimum cURL version that we've tested that core works with.
50
+ define( 'HEALTH_CHECK_CURL_MIN_VERSION', '7.38' );
51
+
52
+ // Include class-files used by our plugin.
53
+ require_once( dirname( __FILE__ ) . '/includes/class-health-check.php' );
54
+ require_once( dirname( __FILE__ ) . '/includes/class-health-check-auto-updates.php' );
55
+ require_once( dirname( __FILE__ ) . '/includes/class-health-check-wp-cron.php' );
56
+ require_once( dirname( __FILE__ ) . '/includes/class-health-check-debug-data.php' );
57
+ require_once( dirname( __FILE__ ) . '/includes/class-health-check-loopback.php' );
58
+ require_once( dirname( __FILE__ ) . '/includes/class-health-check-troubleshoot.php' );
59
+ require_once( dirname( __FILE__ ) . '/includes/class-health-check-files-integrity.php' );
60
+ require_once( dirname( __FILE__ ) . '/includes/class-health-check-mail-check.php' );
61
+ require_once( dirname( __FILE__ ) . '/includes/class-health-check-site-status.php' );
62
+ require_once( dirname( __FILE__ ) . '/includes/class-health-check-updates.php' );
63
+
64
+ // Initialize our plugin.
65
+ new Health_Check();
includes/class-health-check-auto-updates.php CHANGED
@@ -1,531 +1,531 @@
1
- <?php
2
- /**
3
- * Class for testing automatic updates in the WordPress code.
4
- *
5
- * @package Health Check
6
- */
7
-
8
- /**
9
- * Class Health_Check_Auto_Updates
10
- */
11
- class Health_Check_Auto_Updates {
12
- /**
13
- * Health_Check_Auto_Updates constructor.
14
- *
15
- * @uses Health_Check::init()
16
- *
17
- * @return void
18
- */
19
- public function __construct() {
20
- $this->init();
21
- }
22
-
23
- /**
24
- * Initiate the plugin class.
25
- *
26
- * @return void
27
- */
28
- public function init() {
29
- include_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
30
- }
31
-
32
- /**
33
- * Run tests to determine if auto-updates can run.
34
- *
35
- * @uses get_class_methods()
36
- * @uses substr()
37
- * @uses call_user_func()
38
- *
39
- * @return array
40
- */
41
- public function run_tests() {
42
- $tests = array();
43
-
44
- foreach ( get_class_methods( $this ) as $method ) {
45
- if ( 'test_' !== substr( $method, 0, 5 ) ) {
46
- continue;
47
- }
48
-
49
- $result = call_user_func( array( $this, $method ) );
50
-
51
- if ( false === $result || null === $result ) {
52
- continue;
53
- }
54
-
55
- $result = (object) $result;
56
-
57
- if ( empty( $result->severity ) ) {
58
- $result->severity = 'warning';
59
- }
60
-
61
- $tests[ $method ] = $result;
62
- }
63
-
64
- return $tests;
65
- }
66
-
67
- /**
68
- * Test if file modifications are possible.
69
- *
70
- * @uses defined()
71
- * @uses sprintf()
72
- * @uses esc_html__()
73
- *
74
- * @return array
75
- */
76
- function test_constant_FILE_MODS() {
77
- if ( defined( 'DISALLOW_FILE_MODS' ) && DISALLOW_FILE_MODS ) {
78
- return array(
79
- 'desc' => sprintf(
80
- /* translators: %s: Name of the constant used. */
81
- esc_html__( 'The %s constant is defined and enabled.', 'health-check' ),
82
- '<code>DISALLOW_FILE_MODS</code>'
83
- ),
84
- 'severity' => 'fail',
85
- );
86
- }
87
- }
88
-
89
- /**
90
- * Check if automatic updates are disabled with a constant.
91
- *
92
- * @uses defined()
93
- * @uses sprintf()
94
- * @uses esc_html__()
95
- *
96
- * @return array
97
- */
98
- function test_constant_AUTOMATIC_UPDATER_DISABLED() {
99
- if ( defined( 'AUTOMATIC_UPDATER_DISABLED' ) && AUTOMATIC_UPDATER_DISABLED ) {
100
- return array(
101
- 'desc' => sprintf(
102
- /* translators: %s: Name of the constant used. */
103
- esc_html__( 'The %s constant is defined and enabled.', 'health-check' ),
104
- '<code>AUTOMATIC_UPDATER_DISABLED</code>'
105
- ),
106
- 'severity' => 'fail',
107
- );
108
- }
109
- }
110
-
111
- /**
112
- * Check if automatic core updates are disabled with a constant.
113
- *
114
- * @uses defined()
115
- * @uses sprintf()
116
- * @uses esc_html__()
117
- *
118
- * @return array
119
- */
120
- function test_constant_WP_AUTO_UPDATE_CORE() {
121
- if ( defined( 'WP_AUTO_UPDATE_CORE' ) && false === WP_AUTO_UPDATE_CORE ) {
122
- return array(
123
- 'desc' => sprintf(
124
- /* translators: %s: Name of the constant used. */
125
- esc_html__( 'The %s constant is defined and enabled.', 'health-check' ),
126
- '<code>WP_AUTO_UPDATE_CORE</code>'
127
- ),
128
- 'severity' => 'fail',
129
- );
130
- }
131
- }
132
-
133
- /**
134
- * Check if updates are intercepted by a filter.
135
- *
136
- * @uses has_filter()
137
- * @uses sprintf()
138
- * @uses esc_html__()
139
- *
140
- * @return array
141
- */
142
- function test_wp_version_check_attached() {
143
- $cookies = wp_unslash( $_COOKIE );
144
- $timeout = 10;
145
- $headers = array(
146
- 'Cache-Control' => 'no-cache',
147
- );
148
-
149
- // Include Basic auth in loopback requests.
150
- if ( isset( $_SERVER['PHP_AUTH_USER'] ) && isset( $_SERVER['PHP_AUTH_PW'] ) ) {
151
- $headers['Authorization'] = 'Basic ' . base64_encode( wp_unslash( $_SERVER['PHP_AUTH_USER'] ) . ':' . wp_unslash( $_SERVER['PHP_AUTH_PW'] ) );
152
- }
153
-
154
- $url = add_query_arg( array(
155
- 'health-check-test-wp_version_check' => true,
156
- ), admin_url() );
157
-
158
- $test = wp_remote_get( $url, compact( 'cookies', 'headers', 'timeout' ) );
159
-
160
- $response = wp_remote_retrieve_body( $test );
161
-
162
- if ( 'yes' !== $response ) {
163
- return array(
164
- 'desc' => sprintf(
165
- /* translators: %s: Name of the filter used. */
166
- esc_html__( 'A plugin has prevented updates by disabling %s.', 'health-check' ),
167
- '<code>wp_version_check()</code>'
168
- ),
169
- 'severity' => 'fail',
170
- );
171
- }
172
- }
173
-
174
- /**
175
- * Check if automatic updates are disabled by a filter.
176
- *
177
- * @uses apply_filters()
178
- * @uses sprintf()
179
- * @uses esc_html__()
180
- *
181
- * @return array
182
- */
183
- function test_filters_automatic_updater_disabled() {
184
- if ( apply_filters( 'automatic_updater_disabled', false ) ) {
185
- return array(
186
- 'desc' => sprintf(
187
- /* translators: %s: Name of the filter used. */
188
- esc_html__( 'The %s filter is enabled.', 'health-check' ),
189
- '<code>automatic_updater_disabled</code>'
190
- ),
191
- 'severity' => 'fail',
192
- );
193
- }
194
- }
195
-
196
- /**
197
- * Check if automatic updates have tried to run, but failed, previously.
198
- *
199
- * @uses get_site_option()
200
- * @uses esc_html__()
201
- * @uses sprintf()
202
- *
203
- * @return array|bool
204
- */
205
- function test_if_failed_update() {
206
- $failed = get_site_option( 'auto_core_update_failed' );
207
-
208
- if ( ! $failed ) {
209
- return false;
210
- }
211
-
212
- if ( ! empty( $failed['critical'] ) ) {
213
- $desc = esc_html__( 'A previous automatic background update ended with a critical failure, so updates are now disabled.', 'health-check' );
214
- $desc .= ' ' . esc_html__( 'You would have received an email because of this.', 'health-check' );
215
- $desc .= ' ' . esc_html__( "When you've been able to update using the \"Update Now\" button on Dashboard > Updates, we'll clear this error for future update attempts.", 'health-check' );
216
- $desc .= ' ' . sprintf(
217
- /* translators: %s: Code of error shown. */
218
- esc_html__( 'The error code was %s.', 'health-check' ),
219
- '<code>' . $failed['error_code'] . '</code>'
220
- );
221
- return array(
222
- 'desc' => $desc,
223
- 'severity' => 'warning',
224
- );
225
- }
226
-
227
- $desc = esc_html__( 'A previous automatic background update could not occur.', 'health-check' );
228
- if ( empty( $failed['retry'] ) ) {
229
- $desc .= ' ' . esc_html__( 'You would have received an email because of this.', 'health-check' );
230
- }
231
-
232
- $desc .= ' ' . esc_html__( "We'll try again with the next release.", 'health-check' );
233
- $desc .= ' ' . sprintf(
234
- /* translators: %s: Code of error shown. */
235
- esc_html__( 'The error code was %s.', 'health-check' ),
236
- '<code>' . $failed['error_code'] . '</code>'
237
- );
238
- return array(
239
- 'desc' => $desc,
240
- 'severity' => 'warning',
241
- );
242
- }
243
-
244
- /**
245
- * Check if WordPress is controlled by a VCS (Git, Subversion etc).
246
- *
247
- * @uses dirname()
248
- * @uses array_unique()
249
- * @uses is_dir()
250
- * @uses rtrim()
251
- * @uses apply_filters()
252
- * @uses sprintf()
253
- * @uses esc_html__()
254
- *
255
- * @param string $context The path to check from.
256
- *
257
- * @return array
258
- */
259
- function _test_is_vcs_checkout( $context ) {
260
- $context_dirs = array( ABSPATH );
261
- $vcs_dirs = array( '.svn', '.git', '.hg', '.bzr' );
262
- $check_dirs = array();
263
-
264
- foreach ( $context_dirs as $context_dir ) {
265
- // Walk up from $context_dir to the root.
266
- do {
267
- $check_dirs[] = $context_dir;
268
-
269
- // Once we've hit '/' or 'C:\', we need to stop. dirname will keep returning the input here.
270
- if ( dirname( $context_dir ) == $context_dir ) {
271
- break;
272
- }
273
-
274
- // Continue one level at a time.
275
- } while ( $context_dir = dirname( $context_dir ) );
276
- }
277
-
278
- $check_dirs = array_unique( $check_dirs );
279
-
280
- // Search all directories we've found for evidence of version control.
281
- foreach ( $vcs_dirs as $vcs_dir ) {
282
- foreach ( $check_dirs as $check_dir ) {
283
- // phpcs:ignore
284
- if ( $checkout = @is_dir( rtrim( $check_dir, '\\/' ) . "/$vcs_dir" ) ) {
285
- break 2;
286
- }
287
- }
288
- }
289
-
290
- if ( $checkout && ! apply_filters( 'automatic_updates_is_vcs_checkout', true, $context ) ) {
291
- return array(
292
- 'desc' => sprintf(
293
- // translators: %1$s: Folder name. %2$s: Version control directory. %3$s: Filter name.
294
- esc_html__( 'The folder %1$s was detected as being under version control (%2$s), but the %3$s filter is allowing updates.', 'health-check' ),
295
- '<code>' . $check_dir . '</code>',
296
- "<code>$vcs_dir</code>",
297
- '<code>automatic_updates_is_vcs_checkout</code>'
298
- ),
299
- 'severity' => 'info',
300
- );
301
- }
302
-
303
- if ( $checkout ) {
304
- return array(
305
- 'desc' => sprintf(
306
- // translators: %1$s: Folder name. %2$s: Version control directory.
307
- esc_html__( 'The folder %1$s was detected as being under version control (%2$s).', 'health-check' ),
308
- '<code>' . $check_dir . '</code>',
309
- "<code>$vcs_dir</code>"
310
- ),
311
- 'severity' => 'fail',
312
- );
313
- }
314
-
315
- return array(
316
- 'desc' => esc_html__( 'No version control systems were detected.', 'health-check' ),
317
- 'severity' => 'pass',
318
- );
319
- }
320
-
321
- /**
322
- * Check if the absolute path is under Version Control.
323
- *
324
- * @uses Health_Check_Auto_Updates::_test_is_vcs_checkout()
325
- *
326
- * @return array
327
- */
328
- function test_vcs_ABSPATH() {
329
- $result = $this->_test_is_vcs_checkout( ABSPATH );
330
- return $result;
331
- }
332
-
333
- /**
334
- * Check if we can access files without providing credentials.
335
- *
336
- * @uses Automatic_Upgrader_Skin
337
- * @uses Automatic_Upgrader_Skin::request_filesystem_credentials()
338
- * @uses esc_html__()
339
- *
340
- * @return array
341
- */
342
- function test_check_wp_filesystem_method() {
343
- $skin = new Automatic_Upgrader_Skin;
344
- $success = $skin->request_filesystem_credentials( false, ABSPATH );
345
-
346
- if ( ! $success ) {
347
- $desc = esc_html__( 'Your installation of WordPress prompts for FTP credentials to perform updates.', 'health-check' );
348
- $desc .= ' ' . esc_html__( '(Your site is performing updates over FTP due to file ownership. Talk to your hosting company.)', 'health-check' );
349
-
350
- return array(
351
- 'desc' => $desc,
352
- 'severity' => 'fail',
353
- );
354
- }
355
-
356
- return array(
357
- 'desc' => esc_html__( "Your installation of WordPress doesn't require FTP credentials to perform updates.", 'health-check' ),
358
- 'severity' => 'pass',
359
- );
360
- }
361
-
362
- /**
363
- * Check if core files are writeable by the web user/group.
364
- *
365
- * @global $wp_filesystem
366
- *
367
- * @uses Automatic_Upgrader_Skin
368
- * @uses Automatic_Upgrader_Skin::request_filesystem_credentials()
369
- * @uses WP_Filesystem
370
- * @uses WP_Filesystem::method
371
- * @uses get_core_checksums()
372
- * @uses strpos()
373
- * @uses sprintf()
374
- * @uses esc_html__()
375
- * @uses array_keys()
376
- * @uses substr()
377
- * @uses file_exists()
378
- * @uses is_writable()
379
- * @uses count()
380
- * @uses array_slice()
381
- * @uses implode()
382
- *
383
- * @return array|bool
384
- */
385
- function test_all_files_writable() {
386
- global $wp_filesystem;
387
- include ABSPATH . WPINC . '/version.php'; // $wp_version; // x.y.z
388
-
389
- $skin = new Automatic_Upgrader_Skin;
390
- $success = $skin->request_filesystem_credentials( false, ABSPATH );
391
-
392
- if ( ! $success ) {
393
- return false;
394
- }
395
-
396
- WP_Filesystem();
397
-
398
- if ( 'direct' != $wp_filesystem->method ) {
399
- return false;
400
- }
401
-
402
- $checksums = get_core_checksums( $wp_version, 'en_US' );
403
- $dev = ( false !== strpos( $wp_version, '-' ) );
404
- // Get the last stable version's files and test against that
405
- if ( ! $checksums && $dev ) {
406
- $checksums = get_core_checksums( (float) $wp_version - 0.1, 'en_US' );
407
- }
408
-
409
- // There aren't always checksums for development releases, so just skip the test if we still can't find any
410
- if ( ! $checksums && $dev ) {
411
- return false;
412
- }
413
-
414
- if ( ! $checksums ) {
415
- $desc = sprintf(
416
- // translators: %s: WordPress version
417
- esc_html__( "Couldn't retrieve a list of the checksums for WordPress %s.", 'health-check' ),
418
- $wp_version
419
- );
420
- $desc .= ' ' . esc_html__( 'This could mean that connections are failing to WordPress.org.', 'health-check' );
421
- return array(
422
- 'desc' => $desc,
423
- 'severity' => 'warning',
424
- );
425
- }
426
-
427
- $unwritable_files = array();
428
- foreach ( array_keys( $checksums ) as $file ) {
429
- if ( 'wp-content' == substr( $file, 0, 10 ) ) {
430
- continue;
431
- }
432
- if ( ! file_exists( ABSPATH . '/' . $file ) ) {
433
- continue;
434
- }
435
- if ( ! is_writable( ABSPATH . '/' . $file ) ) {
436
- $unwritable_files[] = $file;
437
- }
438
- }
439
-
440
- if ( $unwritable_files ) {
441
- if ( count( $unwritable_files ) > 20 ) {
442
- $unwritable_files = array_slice( $unwritable_files, 0, 20 );
443
- $unwritable_files[] = '...';
444
- }
445
- return array(
446
- 'desc' => esc_html__( 'Some files are not writable by WordPress:', 'health-check' ) . ' <ul><li>' . implode( '</li><li>', $unwritable_files ) . '</li></ul>',
447
- 'severity' => 'fail',
448
- );
449
- } else {
450
- return array(
451
- 'desc' => esc_html__( 'All of your WordPress files are writable.', 'health-check' ),
452
- 'severity' => 'pass',
453
- );
454
- }
455
- }
456
-
457
- /**
458
- * Check if the install is using a development branch and can use nightly packages.
459
- *
460
- * @uses strpos()
461
- * @uses defined()
462
- * @uses sprintf()
463
- * @uses esc_html__()
464
- * @uses apply_filters()
465
- *
466
- * @return array|bool
467
- */
468
- function test_accepts_dev_updates() {
469
- include ABSPATH . WPINC . '/version.php'; // $wp_version; // x.y.z
470
- // Only for dev versions
471
- if ( false === strpos( $wp_version, '-' ) ) {
472
- return false;
473
- }
474
-
475
- if ( defined( 'WP_AUTO_UPDATE_CORE' ) && ( 'minor' === WP_AUTO_UPDATE_CORE || false === WP_AUTO_UPDATE_CORE ) ) {
476
- return array(
477
- 'desc' => sprintf(
478
- /* translators: %s: Name of the constant used. */
479
- esc_html__( 'WordPress development updates are blocked by the %s constant.', 'health-check' ),
480
- '<code>WP_AUTO_UPDATE_CORE</code>'
481
- ),
482
- 'severity' => 'fail',
483
- );
484
- }
485
-
486
- if ( ! apply_filters( 'allow_dev_auto_core_updates', $wp_version ) ) {
487
- return array(
488
- 'desc' => sprintf(
489
- /* translators: %s: Name of the filter used. */
490
- esc_html__( 'WordPress development updates are blocked by the %s filter.', 'health-check' ),
491
- '<code>allow_dev_auto_core_updates</code>'
492
- ),
493
- 'severity' => 'fail',
494
- );
495
- }
496
- }
497
-
498
- /**
499
- * Check if the site supports automatic minor updates.
500
- *
501
- * @uses defined()
502
- * @uses sprintf()
503
- * @uses esc_html__()
504
- * @uses apply_filters()
505
- *
506
- * @return array
507
- */
508
- function test_accepts_minor_updates() {
509
- if ( defined( 'WP_AUTO_UPDATE_CORE' ) && false === WP_AUTO_UPDATE_CORE ) {
510
- return array(
511
- 'desc' => sprintf(
512
- /* translators: %s: Name of the constant used. */
513
- esc_html__( 'WordPress security and maintenance releases are blocked by %s.', 'health-check' ),
514
- "<code>define( 'WP_AUTO_UPDATE_CORE', false );</code>"
515
- ),
516
- 'severity' => 'fail',
517
- );
518
- }
519
-
520
- if ( ! apply_filters( 'allow_minor_auto_core_updates', true ) ) {
521
- return array(
522
- 'desc' => sprintf(
523
- /* translators: %s: Name of the filter used. */
524
- esc_html__( 'WordPress security and maintenance releases are blocked by the %s filter.', 'health-check' ),
525
- '<code>allow_minor_auto_core_updates</code>'
526
- ),
527
- 'severity' => 'fail',
528
- );
529
- }
530
- }
531
- }
1
+ <?php
2
+ /**
3
+ * Class for testing automatic updates in the WordPress code.
4
+ *
5
+ * @package Health Check
6
+ */
7
+
8
+ /**
9
+ * Class Health_Check_Auto_Updates
10
+ */
11
+ class Health_Check_Auto_Updates {
12
+ /**
13
+ * Health_Check_Auto_Updates constructor.
14
+ *
15
+ * @uses Health_Check::init()
16
+ *
17
+ * @return void
18
+ */
19
+ public function __construct() {
20
+ $this->init();
21
+ }
22
+
23
+ /**
24
+ * Initiate the plugin class.
25
+ *
26
+ * @return void
27
+ */
28
+ public function init() {
29
+ include_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
30
+ }
31
+
32
+ /**
33
+ * Run tests to determine if auto-updates can run.
34
+ *
35
+ * @uses get_class_methods()
36
+ * @uses substr()
37
+ * @uses call_user_func()
38
+ *
39
+ * @return array
40
+ */
41
+ public function run_tests() {
42
+ $tests = array();
43
+
44
+ foreach ( get_class_methods( $this ) as $method ) {
45
+ if ( 'test_' !== substr( $method, 0, 5 ) ) {
46
+ continue;
47
+ }
48
+
49
+ $result = call_user_func( array( $this, $method ) );
50
+
51
+ if ( false === $result || null === $result ) {
52
+ continue;
53
+ }
54
+
55
+ $result = (object) $result;
56
+
57
+ if ( empty( $result->severity ) ) {
58
+ $result->severity = 'warning';
59
+ }
60
+
61
+ $tests[ $method ] = $result;
62
+ }
63
+
64
+ return $tests;
65
+ }
66
+
67
+ /**
68
+ * Test if file modifications are possible.
69
+ *
70
+ * @uses defined()
71
+ * @uses sprintf()
72
+ * @uses esc_html__()
73
+ *
74
+ * @return array
75
+ */
76
+ function test_constant_FILE_MODS() {
77
+ if ( defined( 'DISALLOW_FILE_MODS' ) && DISALLOW_FILE_MODS ) {
78
+ return array(
79
+ 'desc' => sprintf(
80
+ /* translators: %s: Name of the constant used. */
81
+ esc_html__( 'The %s constant is defined and enabled.', 'health-check' ),
82
+ '<code>DISALLOW_FILE_MODS</code>'
83
+ ),
84
+ 'severity' => 'fail',
85
+ );
86
+ }
87
+ }
88
+
89
+ /**
90
+ * Check if automatic updates are disabled with a constant.
91
+ *
92
+ * @uses defined()
93
+ * @uses sprintf()
94
+ * @uses esc_html__()
95
+ *
96
+ * @return array
97
+ */
98
+ function test_constant_AUTOMATIC_UPDATER_DISABLED() {
99
+ if ( defined( 'AUTOMATIC_UPDATER_DISABLED' ) && AUTOMATIC_UPDATER_DISABLED ) {
100
+ return array(
101
+ 'desc' => sprintf(
102
+ /* translators: %s: Name of the constant used. */
103
+ esc_html__( 'The %s constant is defined and enabled.', 'health-check' ),
104
+ '<code>AUTOMATIC_UPDATER_DISABLED</code>'
105
+ ),
106
+ 'severity' => 'fail',
107
+ );
108
+ }
109
+ }
110
+
111
+ /**
112
+ * Check if automatic core updates are disabled with a constant.
113
+ *
114
+ * @uses defined()
115
+ * @uses sprintf()
116
+ * @uses esc_html__()
117
+ *
118
+ * @return array
119
+ */
120
+ function test_constant_WP_AUTO_UPDATE_CORE() {
121
+ if ( defined( 'WP_AUTO_UPDATE_CORE' ) && false === WP_AUTO_UPDATE_CORE ) {
122
+ return array(
123
+ 'desc' => sprintf(
124
+ /* translators: %s: Name of the constant used. */
125
+ esc_html__( 'The %s constant is defined and enabled.', 'health-check' ),
126
+ '<code>WP_AUTO_UPDATE_CORE</code>'
127
+ ),
128
+ 'severity' => 'fail',
129
+ );
130
+ }
131
+ }
132
+
133
+ /**
134
+ * Check if updates are intercepted by a filter.
135
+ *
136
+ * @uses has_filter()
137
+ * @uses sprintf()
138
+ * @uses esc_html__()
139
+ *
140
+ * @return array
141
+ */
142
+ function test_wp_version_check_attached() {
143
+ $cookies = wp_unslash( $_COOKIE );
144
+ $timeout = 10;
145
+ $headers = array(
146
+ 'Cache-Control' => 'no-cache',
147
+ );
148
+
149
+ // Include Basic auth in loopback requests.
150
+ if ( isset( $_SERVER['PHP_AUTH_USER'] ) && isset( $_SERVER['PHP_AUTH_PW'] ) ) {
151
+ $headers['Authorization'] = 'Basic ' . base64_encode( wp_unslash( $_SERVER['PHP_AUTH_USER'] ) . ':' . wp_unslash( $_SERVER['PHP_AUTH_PW'] ) );
152
+ }
153
+
154
+ $url = add_query_arg( array(
155
+ 'health-check-test-wp_version_check' => true,
156
+ ), admin_url() );
157
+
158
+ $test = wp_remote_get( $url, compact( 'cookies', 'headers', 'timeout' ) );
159
+
160
+ $response = wp_remote_retrieve_body( $test );
161
+
162
+ if ( 'yes' !== $response ) {
163
+ return array(
164
+ 'desc' => sprintf(
165
+ /* translators: %s: Name of the filter used. */
166
+ esc_html__( 'A plugin has prevented updates by disabling %s.', 'health-check' ),
167
+ '<code>wp_version_check()</code>'
168
+ ),
169
+ 'severity' => 'fail',
170
+ );
171
+ }
172
+ }
173
+
174
+ /**
175
+ * Check if automatic updates are disabled by a filter.
176
+ *
177
+ * @uses apply_filters()
178
+ * @uses sprintf()
179
+ * @uses esc_html__()
180
+ *
181
+ * @return array
182
+ */
183
+ function test_filters_automatic_updater_disabled() {
184
+ if ( apply_filters( 'automatic_updater_disabled', false ) ) {
185
+ return array(
186
+ 'desc' => sprintf(
187
+ /* translators: %s: Name of the filter used. */
188
+ esc_html__( 'The %s filter is enabled.', 'health-check' ),
189
+ '<code>automatic_updater_disabled</code>'
190
+ ),
191
+ 'severity' => 'fail',
192
+ );
193
+ }
194
+ }
195
+
196
+ /**
197
+ * Check if automatic updates have tried to run, but failed, previously.
198
+ *
199
+ * @uses get_site_option()
200
+ * @uses esc_html__()
201
+ * @uses sprintf()
202
+ *
203
+ * @return array|bool
204
+ */
205
+ function test_if_failed_update() {
206
+ $failed = get_site_option( 'auto_core_update_failed' );
207
+
208
+ if ( ! $failed ) {
209
+ return false;
210
+ }
211
+
212
+ if ( ! empty( $failed['critical'] ) ) {
213
+ $desc = esc_html__( 'A previous automatic background update ended with a critical failure, so updates are now disabled.', 'health-check' );
214
+ $desc .= ' ' . esc_html__( 'You would have received an email because of this.', 'health-check' );
215
+ $desc .= ' ' . esc_html__( "When you've been able to update using the \"Update Now\" button on Dashboard > Updates, we'll clear this error for future update attempts.", 'health-check' );
216
+ $desc .= ' ' . sprintf(
217
+ /* translators: %s: Code of error shown. */
218
+ esc_html__( 'The error code was %s.', 'health-check' ),
219
+ '<code>' . $failed['error_code'] . '</code>'
220
+ );
221
+ return array(
222
+ 'desc' => $desc,
223
+ 'severity' => 'warning',
224
+ );
225
+ }
226
+
227
+ $desc = esc_html__( 'A previous automatic background update could not occur.', 'health-check' );
228
+ if ( empty( $failed['retry'] ) ) {
229
+ $desc .= ' ' . esc_html__( 'You would have received an email because of this.', 'health-check' );
230
+ }
231
+
232
+ $desc .= ' ' . esc_html__( "We'll try again with the next release.", 'health-check' );
233
+ $desc .= ' ' . sprintf(
234
+ /* translators: %s: Code of error shown. */
235
+ esc_html__( 'The error code was %s.', 'health-check' ),
236
+ '<code>' . $failed['error_code'] . '</code>'
237
+ );
238
+ return array(
239
+ 'desc' => $desc,
240
+ 'severity' => 'warning',
241
+ );
242
+ }
243
+
244
+ /**
245
+ * Check if WordPress is controlled by a VCS (Git, Subversion etc).
246
+ *
247
+ * @uses dirname()
248
+ * @uses array_unique()
249
+ * @uses is_dir()
250
+ * @uses rtrim()
251
+ * @uses apply_filters()
252
+ * @uses sprintf()
253
+ * @uses esc_html__()
254
+ *
255
+ * @param string $context The path to check from.
256
+ *
257
+ * @return array
258
+ */
259
+ function _test_is_vcs_checkout( $context ) {
260
+ $context_dirs = array( ABSPATH );
261
+ $vcs_dirs = array( '.svn', '.git', '.hg', '.bzr' );
262
+ $check_dirs = array();
263
+
264
+ foreach ( $context_dirs as $context_dir ) {
265
+ // Walk up from $context_dir to the root.
266
+ do {
267
+ $check_dirs[] = $context_dir;
268
+
269
+ // Once we've hit '/' or 'C:\', we need to stop. dirname will keep returning the input here.
270
+ if ( dirname( $context_dir ) == $context_dir ) {
271
+ break;
272
+ }
273
+
274
+ // Continue one level at a time.
275
+ } while ( $context_dir = dirname( $context_dir ) );
276
+ }
277
+
278
+ $check_dirs = array_unique( $check_dirs );
279
+
280
+ // Search all directories we've found for evidence of version control.
281
+ foreach ( $vcs_dirs as $vcs_dir ) {
282
+ foreach ( $check_dirs as $check_dir ) {
283
+ // phpcs:ignore
284
+ if ( $checkout = @is_dir( rtrim( $check_dir, '\\/' ) . "/$vcs_dir" ) ) {
285
+ break 2;
286
+ }
287
+ }
288
+ }
289
+
290
+ if ( $checkout && ! apply_filters( 'automatic_updates_is_vcs_checkout', true, $context ) ) {
291
+ return array(
292
+ 'desc' => sprintf(
293
+ // translators: %1$s: Folder name. %2$s: Version control directory. %3$s: Filter name.
294
+ esc_html__( 'The folder %1$s was detected as being under version control (%2$s), but the %3$s filter is allowing updates.', 'health-check' ),
295
+ '<code>' . $check_dir . '</code>',
296
+ "<code>$vcs_dir</code>",
297
+ '<code>automatic_updates_is_vcs_checkout</code>'
298
+ ),
299
+ 'severity' => 'info',
300
+ );
301
+ }
302
+
303
+ if ( $checkout ) {
304
+ return array(
305
+ 'desc' => sprintf(
306
+ // translators: %1$s: Folder name. %2$s: Version control directory.
307
+ esc_html__( 'The folder %1$s was detected as being under version control (%2$s).', 'health-check' ),
308
+ '<code>' . $check_dir . '</code>',
309
+ "<code>$vcs_dir</code>"
310
+ ),
311
+ 'severity' => 'fail',
312
+ );
313
+ }
314
+
315
+ return array(
316
+ 'desc' => esc_html__( 'No version control systems were detected.', 'health-check' ),
317
+ 'severity' => 'pass',
318
+ );
319
+ }
320
+
321
+ /**
322
+ * Check if the absolute path is under Version Control.
323
+ *
324
+ * @uses Health_Check_Auto_Updates::_test_is_vcs_checkout()
325
+ *
326
+ * @return array
327
+ */
328
+ function test_vcs_ABSPATH() {
329
+ $result = $this->_test_is_vcs_checkout( ABSPATH );
330
+ return $result;
331
+ }
332
+
333
+ /**
334
+ * Check if we can access files without providing credentials.
335
+ *
336
+ * @uses Automatic_Upgrader_Skin
337
+ * @uses Automatic_Upgrader_Skin::request_filesystem_credentials()
338
+ * @uses esc_html__()
339
+ *
340
+ * @return array
341
+ */
342
+ function test_check_wp_filesystem_method() {
343
+ $skin = new Automatic_Upgrader_Skin;
344
+ $success = $skin->request_filesystem_credentials( false, ABSPATH );
345
+
346
+ if ( ! $success ) {
347
+ $desc = esc_html__( 'Your installation of WordPress prompts for FTP credentials to perform updates.', 'health-check' );
348
+ $desc .= ' ' . esc_html__( '(Your site is performing updates over FTP due to file ownership. Talk to your hosting company.)', 'health-check' );
349
+
350
+ return array(
351
+ 'desc' => $desc,
352
+ 'severity' => 'fail',
353
+ );
354
+ }
355
+
356
+ return array(
357
+ 'desc' => esc_html__( "Your installation of WordPress doesn't require FTP credentials to perform updates.", 'health-check' ),
358
+ 'severity' => 'pass',
359
+ );
360
+ }
361
+
362
+ /**
363
+ * Check if core files are writeable by the web user/group.
364
+ *
365
+ * @global $wp_filesystem
366
+ *
367
+ * @uses Automatic_Upgrader_Skin
368
+ * @uses Automatic_Upgrader_Skin::request_filesystem_credentials()
369
+ * @uses WP_Filesystem
370
+ * @uses WP_Filesystem::method
371
+ * @uses get_core_checksums()
372
+ * @uses strpos()
373
+ * @uses sprintf()
374
+ * @uses esc_html__()
375
+ * @uses array_keys()
376
+ * @uses substr()
377
+ * @uses file_exists()
378
+ * @uses is_writable()
379
+ * @uses count()
380
+ * @uses array_slice()
381
+ * @uses implode()
382
+ *
383
+ * @return array|bool
384
+ */
385
+ function test_all_files_writable() {
386
+ global $wp_filesystem;
387
+ include ABSPATH . WPINC . '/version.php'; // $wp_version; // x.y.z
388
+
389
+ $skin = new Automatic_Upgrader_Skin;
390
+ $success = $skin->request_filesystem_credentials( false, ABSPATH );
391
+
392
+ if ( ! $success ) {
393
+ return false;
394
+ }
395
+
396
+ WP_Filesystem();
397
+
398
+ if ( 'direct' != $wp_filesystem->method ) {
399
+ return false;
400
+ }
401
+
402
+ $checksums = get_core_checksums( $wp_version, 'en_US' );
403
+ $dev = ( false !== strpos( $wp_version, '-' ) );
404
+ // Get the last stable version's files and test against that
405
+ if ( ! $checksums && $dev ) {
406
+ $checksums = get_core_checksums( (float) $wp_version - 0.1, 'en_US' );
407
+ }
408
+
409
+ // There aren't always checksums for development releases, so just skip the test if we still can't find any
410
+ if ( ! $checksums && $dev ) {
411
+ return false;
412
+ }
413
+
414
+ if ( ! $checksums ) {
415
+ $desc = sprintf(
416
+ // translators: %s: WordPress version
417
+ esc_html__( "Couldn't retrieve a list of the checksums for WordPress %s.", 'health-check' ),
418
+ $wp_version
419
+ );
420
+ $desc .= ' ' . esc_html__( 'This could mean that connections are failing to WordPress.org.', 'health-check' );
421
+ return array(
422
+ 'desc' => $desc,
423
+ 'severity' => 'warning',
424
+ );
425
+ }
426
+
427
+ $unwritable_files = array();
428
+ foreach ( array_keys( $checksums ) as $file ) {
429
+ if ( 'wp-content' == substr( $file, 0, 10 ) ) {
430
+ continue;
431
+ }
432
+ if ( ! file_exists( ABSPATH . '/' . $file ) ) {
433
+ continue;
434
+ }
435
+ if ( ! is_writable( ABSPATH . '/' . $file ) ) {
436
+ $unwritable_files[] = $file;
437
+ }
438
+ }
439
+
440
+ if ( $unwritable_files ) {
441
+ if ( count( $unwritable_files ) > 20 ) {
442
+ $unwritable_files = array_slice( $unwritable_files, 0, 20 );
443
+ $unwritable_files[] = '...';
444
+ }
445
+ return array(
446
+ 'desc' => esc_html__( 'Some files are not writable by WordPress:', 'health-check' ) . ' <ul><li>' . implode( '</li><li>', $unwritable_files ) . '</li></ul>',
447
+ 'severity' => 'fail',
448
+ );
449
+ } else {
450
+ return array(
451
+ 'desc' => esc_html__( 'All of your WordPress files are writable.', 'health-check' ),
452
+ 'severity' => 'pass',
453
+ );
454
+ }
455
+ }
456
+
457
+ /**
458
+ * Check if the install is using a development branch and can use nightly packages.
459
+ *
460
+ * @uses strpos()
461
+ * @uses defined()
462
+ * @uses sprintf()
463
+ * @uses esc_html__()
464
+ * @uses apply_filters()
465
+ *
466
+ * @return array|bool
467
+ */
468
+ function test_accepts_dev_updates() {
469
+ include ABSPATH . WPINC . '/version.php'; // $wp_version; // x.y.z
470
+ // Only for dev versions
471
+ if ( false === strpos( $wp_version, '-' ) ) {
472
+ return false;
473
+ }
474
+
475
+ if ( defined( 'WP_AUTO_UPDATE_CORE' ) && ( 'minor' === WP_AUTO_UPDATE_CORE || false === WP_AUTO_UPDATE_CORE ) ) {
476
+ return array(
477
+ 'desc' => sprintf(
478
+ /* translators: %s: Name of the constant used. */
479
+ esc_html__( 'WordPress development updates are blocked by the %s constant.', 'health-check' ),
480
+ '<code>WP_AUTO_UPDATE_CORE</code>'
481
+ ),
482
+ 'severity' => 'fail',
483
+ );
484
+ }
485
+
486
+ if ( ! apply_filters( 'allow_dev_auto_core_updates', $wp_version ) ) {
487
+ return array(
488
+ 'desc' => sprintf(
489
+ /* translators: %s: Name of the filter used. */
490
+ esc_html__( 'WordPress development updates are blocked by the %s filter.', 'health-check' ),
491
+ '<code>allow_dev_auto_core_updates</code>'
492
+ ),
493
+ 'severity' => 'fail',
494
+ );
495
+ }
496
+ }
497
+
498
+ /**
499
+ * Check if the site supports automatic minor updates.
500
+ *
501
+ * @uses defined()
502
+ * @uses sprintf()
503
+ * @uses esc_html__()
504
+ * @uses apply_filters()
505
+ *
506
+ * @return array
507
+ */
508
+ function test_accepts_minor_updates() {
509
+ if ( defined( 'WP_AUTO_UPDATE_CORE' ) && false === WP_AUTO_UPDATE_CORE ) {
510
+ return array(
511
+ 'desc' => sprintf(
512
+ /* translators: %s: Name of the constant used. */
513
+ esc_html__( 'WordPress security and maintenance releases are blocked by %s.', 'health-check' ),
514
+ "<code>define( 'WP_AUTO_UPDATE_CORE', false );</code>"
515
+ ),
516
+ 'severity' => 'fail',
517
+ );
518
+ }
519
+
520
+ if ( ! apply_filters( 'allow_minor_auto_core_updates', true ) ) {
521
+ return array(
522
+ 'desc' => sprintf(
523
+ /* translators: %s: Name of the filter used. */
524
+ esc_html__( 'WordPress security and maintenance releases are blocked by the %s filter.', 'health-check' ),
525
+ '<code>allow_minor_auto_core_updates</code>'
526
+ ),
527
+ 'severity' => 'fail',
528
+ );
529
+ }
530
+ }
531
+ }
includes/class-health-check-debug-data.php CHANGED
@@ -1,843 +1,899 @@
1
- <?php
2
- /**
3
- * Class for providing debug data based on a users WordPress environment.
4
- *
5
- * @package Health Check
6
- */
7
-
8
- /**
9
- * Class Health_Check_Debug_Data
10
- */
11
- class Health_Check_Debug_Data {
12
-
13
- /**
14
- * Calls all core funtions to check for updates
15
- *
16
- * @uses wp_version_check()
17
- * @uses wp_update_plugins()
18
- * @uses wp_update_themes()
19
- *
20
- * @return void
21
- */
22
- static function check_for_updates() {
23
-
24
- wp_version_check();
25
- wp_update_plugins();
26
- wp_update_themes();
27
-
28
- }
29
-
30
- static function debug_data( $locale = null ) {
31
- if ( ! empty( $locale ) ) {
32
- // Change the language used for translations
33
- if ( function_exists( 'switch_to_locale' ) ) {
34
- $original_locale = get_locale();
35
- $switched_locale = switch_to_locale( $locale );
36
- }
37
- }
38
- global $wpdb;
39
-
40
- $upload_dir = wp_upload_dir();
41
- if ( file_exists( ABSPATH . 'wp-config.php' ) ) {
42
- $wp_config_path = ABSPATH . 'wp-config.php';
43
- // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
44
- } elseif ( @file_exists( dirname( ABSPATH ) . '/wp-config.php' ) && ! @file_exists( dirname( ABSPATH ) . '/wp-settings.php' ) ) {
45
- $wp_config_path = dirname( ABSPATH ) . '/wp-config.php';
46
- }
47
-
48
- $core_current_version = get_bloginfo( 'version' );
49
- $core_updates = get_core_updates();
50
- $core_update_needed = '';
51
-
52
- foreach ( $core_updates as $core => $update ) {
53
- if ( 'upgrade' === $update->response ) {
54
- // translators: %s: Latest WordPress version number.
55
- $core_update_needed = ' ' . sprintf( __( '( Latest version: %s )', 'health-check' ), $update->version );
56
- } else {
57
- $core_update_needed = '';
58
- }
59
- }
60
-
61
- $info = array(
62
- 'wp-core' => array(
63
- 'label' => __( 'WordPress', 'health-check' ),
64
- 'fields' => array(
65
- array(
66
- 'label' => __( 'Version', 'health-check' ),
67
- 'value' => $core_current_version . $core_update_needed,
68
- ),
69
- array(
70
- 'label' => __( 'Language', 'health-check' ),
71
- 'value' => ( ! empty( $locale ) ? $original_locale : get_locale() ),
72
- ),
73
- array(
74
- 'label' => __( 'Home URL', 'health-check' ),
75
- 'value' => get_bloginfo( 'url' ),
76
- 'private' => true,
77
- ),
78
- array(
79
- 'label' => __( 'Site URL', 'health-check' ),
80
- 'value' => get_bloginfo( 'wpurl' ),
81
- 'private' => true,
82
- ),
83
- array(
84
- 'label' => __( 'Permalink structure', 'health-check' ),
85
- 'value' => get_option( 'permalink_structure' ),
86
- ),
87
- array(
88
- 'label' => __( 'Is this site using HTTPS?', 'health-check' ),
89
- 'value' => ( is_ssl() ? __( 'Yes', 'health-check' ) : __( 'No', 'health-check' ) ),
90
- ),
91
- array(
92
- 'label' => __( 'Can anyone register on this site?', 'health-check' ),
93
- 'value' => ( get_option( 'users_can_register' ) ? __( 'Yes', 'health-check' ) : __( 'No', 'health-check' ) ),
94
- ),
95
- array(
96
- 'label' => __( 'Default comment status', 'health-check' ),
97
- 'value' => get_option( 'default_comment_status' ),
98
- ),
99
- array(
100
- 'label' => __( 'Is this a multisite?', 'health-check' ),
101
- 'value' => ( is_multisite() ? __( 'Yes', 'health-check' ) : __( 'No', 'health-check' ) ),
102
- ),
103
- ),
104
- ),
105
- 'wp-install-size' => array(
106
- 'label' => __( 'Installation size', 'health-check' ),
107
- 'fields' => array(),
108
- ),
109
- 'wp-dropins' => array(
110
- 'label' => __( 'Drop-ins', 'health-check' ),
111
- 'description' => __( 'Drop-ins are single files that replace or enhance WordPress features in ways that are not possible for traditional plugins', 'health-check' ),
112
- 'fields' => array(),
113
- ),
114
- 'wp-active-theme' => array(
115
- 'label' => __( 'Active Theme', 'health-check' ),
116
- 'fields' => array(),
117
- ),
118
- 'wp-themes' => array(
119
- 'label' => __( 'Other themes', 'health-check' ),
120
- 'show_count' => true,
121
- 'fields' => array(),
122
- ),
123
- 'wp-mu-plugins' => array(
124
- 'label' => __( 'Must Use Plugins', 'health-check' ),
125
- 'show_count' => true,
126
- 'fields' => array(),
127
- ),
128
- 'wp-plugins-active' => array(
129
- 'label' => __( 'Active Plugins', 'health-check' ),
130
- 'show_count' => true,
131
- 'fields' => array(),
132
- ),
133
- 'wp-plugins-inactive' => array(
134
- 'label' => __( 'Inactive Plugins', 'health-check' ),
135
- 'show_count' => true,
136
- 'fields' => array(),
137
- ),
138
- 'wp-media' => array(
139
- 'label' => __( 'Media handling', 'health-check' ),
140
- 'fields' => array(),
141
- ),
142
- 'wp-server' => array(
143
- 'label' => __( 'Server', 'health-check' ),
144
- 'description' => __( 'The options shown below relate to your server setup. If changes are required, you may need your web host\'s assistance.', 'health-check' ),
145
- 'fields' => array(),
146
- ),
147
- 'wp-database' => array(
148
- 'label' => __( 'Database', 'health-check' ),
149
- 'fields' => array(),
150
- ),
151
- 'wp-constants' => array(
152
- 'label' => __( 'WordPress Constants', 'health-check' ),
153
- 'description' => __( 'These values represent values set in your websites code which affect WordPress in various ways that may be of importance when seeking help with your site.', 'health-check' ),
154
- 'fields' => array(
155
- array(
156
- 'label' => 'ABSPATH',
157
- 'value' => ( ! defined( 'ABSPATH' ) ? __( 'Undefined', 'health-check' ) : ABSPATH ),
158
- ),
159
- array(
160
- 'label' => 'WP_HOME',
161
- 'value' => ( ! defined( 'WP_HOME' ) ? __( 'Undefined', 'health-check' ) : WP_HOME ),
162
- ),
163
- array(
164
- 'label' => 'WP_SITEURL',
165
- 'value' => ( ! defined( 'WP_SITEURL' ) ? __( 'Undefined', 'health-check' ) : WP_SITEURL ),
166
- ),
167
- array(
168
- 'label' => 'WP_DEBUG',
169
- 'value' => ( ! defined( 'WP_DEBUG' ) ? __( 'Undefined', 'health-check' ) : ( WP_DEBUG ? __( 'Enabled', 'health-check' ) : __( 'Disabled', 'health-check' ) ) ),
170
- ),
171
- array(
172
- 'label' => 'WP_MAX_MEMORY_LIMIT',
173
- 'value' => ( ! defined( 'WP_MAX_MEMORY_LIMIT' ) ? __( 'Undefined', 'health-check' ) : WP_MAX_MEMORY_LIMIT ),
174
- ),
175
- array(
176
- 'label' => 'WP_DEBUG_DISPLAY',
177
- 'value' => ( ! defined( 'WP_DEBUG_DISPLAY' ) ? __( 'Undefined', 'health-check' ) : ( WP_DEBUG_DISPLAY ? __( 'Enabled', 'health-check' ) : __( 'Disabled', 'health-check' ) ) ),
178
- ),
179
- array(
180
- 'label' => 'WP_DEBUG_LOG',
181
- 'value' => ( ! defined( 'WP_DEBUG_LOG' ) ? __( 'Undefined', 'health-check' ) : ( WP_DEBUG_LOG ? __( 'Enabled', 'health-check' ) : __( 'Disabled', 'health-check' ) ) ),
182
- ),
183
- array(
184
- 'label' => 'SCRIPT_DEBUG',
185
- 'value' => ( ! defined( 'SCRIPT_DEBUG' ) ? __( 'Undefined', 'health-check' ) : ( SCRIPT_DEBUG ? __( 'Enabled', 'health-check' ) : __( 'Disabled', 'health-check' ) ) ),
186
- ),
187
- array(
188
- 'label' => 'WP_CACHE',
189
- 'value' => ( ! defined( 'WP_CACHE' ) ? __( 'Undefined', 'health-check' ) : ( WP_CACHE ? __( 'Enabled', 'health-check' ) : __( 'Disabled', 'health-check' ) ) ),
190
- ),
191
- array(
192
- 'label' => 'CONCATENATE_SCRIPTS',
193
- 'value' => ( ! defined( 'CONCATENATE_SCRIPTS' ) ? __( 'Undefined', 'health-check' ) : ( CONCATENATE_SCRIPTS ? __( 'Enabled', 'health-check' ) : __( 'Disabled', 'health-check' ) ) ),
194
- ),
195
- array(
196
- 'label' => 'COMPRESS_SCRIPTS',
197
- 'value' => ( ! defined( 'COMPRESS_SCRIPTS' ) ? __( 'Undefined', 'health-check' ) : ( COMPRESS_SCRIPTS ? __( 'Enabled', 'health-check' ) : __( 'Disabled', 'health-check' ) ) ),
198
- ),
199
- array(
200
- 'label' => 'COMPRESS_CSS',
201
- 'value' => ( ! defined( 'COMPRESS_CSS' ) ? __( 'Undefined', 'health-check' ) : ( COMPRESS_CSS ? __( 'Enabled', 'health-check' ) : __( 'Disabled', 'health-check' ) ) ),
202
- ),
203
- array(
204
- 'label' => 'WP_LOCAL_DEV',
205
- 'value' => ( ! defined( 'WP_LOCAL_DEV' ) ? __( 'Undefined', 'health-check' ) : ( WP_LOCAL_DEV ? __( 'Enabled', 'health-check' ) : __( 'Disabled', 'health-check' ) ) ),
206
- ),
207
- ),
208
- ),
209
- 'wp-filesystem' => array(
210
- 'label' => __( 'Filesystem Permissions', 'health-check' ),
211
- 'description' => __( 'The status of various locations WordPress needs to write files in various scenarios.', 'health-check' ),
212
- 'fields' => array(
213
- array(
214
- 'label' => __( 'The main WordPress directory', 'health-check' ),
215
- 'value' => ( wp_is_writable( ABSPATH ) ? __( 'Writable', 'health-check' ) : __( 'Not writable', 'health-check' ) ),
216
- ),
217
- array(
218
- 'label' => __( 'The wp-content directory', 'health-check' ),
219
- 'value' => ( wp_is_writable( WP_CONTENT_DIR ) ? __( 'Writable', 'health-check' ) : __( 'Not writable', 'health-check' ) ),
220
- ),
221
- array(
222
- 'label' => __( 'The uploads directory', 'health-check' ),
223
- 'value' => ( wp_is_writable( $upload_dir['basedir'] ) ? __( 'Writable', 'health-check' ) : __( 'Not writable', 'health-check' ) ),
224
- ),
225
- array(
226
- 'label' => __( 'The plugins directory', 'health-check' ),
227
- 'value' => ( wp_is_writable( WP_PLUGIN_DIR ) ? __( 'Writable', 'health-check' ) : __( 'Not writable', 'health-check' ) ),
228
- ),
229
- array(
230
- 'label' => __( 'The themes directory', 'health-check' ),
231
- 'value' => ( wp_is_writable( get_template_directory() . '/..' ) ? __( 'Writable', 'health-check' ) : __( 'Not writable', 'health-check' ) ),
232
- ),
233
- ),
234
- ),
235
- );
236
-
237
- if ( is_multisite() ) {
238
- $network_query = new WP_Network_Query();
239
- $network_ids = $network_query->query( array(
240
- 'fields' => 'ids',
241
- 'number' => 100,
242
- 'no_found_rows' => false,
243
- ) );
244
-
245
- $site_count = 0;
246
- foreach ( $network_ids as $network_id ) {
247
- $site_count += get_blog_count( $network_id );
248
- }
249
-
250
- $info['wp-core']['fields'][] = array(
251
- 'label' => __( 'User Count', 'health-check' ),
252
- 'value' => get_user_count(),
253
- );
254
- $info['wp-core']['fields'][] = array(
255
- 'label' => __( 'Site Count', 'health-check' ),
256
- 'value' => $site_count,
257
- );
258
- $info['wp-core']['fields'][] = array(
259
- 'label' => __( 'Network Count', 'health-check' ),
260
- 'value' => $network_query->found_networks,
261
- );
262
- } else {
263
- $user_count = count_users();
264
-
265
- $info['wp-core']['fields'][] = array(
266
- 'label' => __( 'User Count', 'health-check' ),
267
- 'value' => $user_count['total_users'],
268
- );
269
- }
270
-
271
- // WordPress features requiring processing.
272
- $wp_dotorg = wp_remote_get( 'https://wordpress.org', array(
273
- 'timeout' => 10,
274
- ) );
275
- if ( ! is_wp_error( $wp_dotorg ) ) {
276
- $info['wp-core']['fields'][] = array(
277
- 'label' => __( 'Communication with WordPress.org', 'health-check' ),
278
- 'value' => sprintf(
279
- __( 'WordPress.org is reachable', 'health-check' )
280
- ),
281
- );
282
- } else {
283
- $info['wp-core']['fields'][] = array(
284
- 'label' => __( 'Communication with WordPress.org', 'health-check' ),
285
- 'value' => sprintf(
286
- // translators: %1$s: The IP address WordPress.org resolves to. %2$s: The error returned by the lookup.
287
- __( 'Unable to reach WordPress.org at %1$s: %2$s', 'health-check' ),
288
- gethostbyname( 'wordpress.org' ),
289
- $wp_dotorg->get_error_message()
290
- ),
291
- );
292
- }
293
-
294
- $loopback = Health_Check_Loopback::can_perform_loopback();
295
- $info['wp-core']['fields'][] = array(
296
- 'label' => __( 'Create loopback requests', 'health-check' ),
297
- 'value' => $loopback->message,
298
- );
299
-
300
- // Get drop-ins.
301
- $dropins = get_dropins();
302
- $dropin_description = _get_dropins();
303
- foreach ( $dropins as $dropin_key => $dropin ) {
304
- $info['wp-dropins']['fields'][] = array(
305
- 'label' => $dropin_key,
306
- 'value' => $dropin_description[ $dropin_key ][0],
307
- );
308
- }
309
-
310
- // Populate the media fields.
311
- $info['wp-media']['fields'][] = array(
312
- 'label' => __( 'Active editor', 'health-check' ),
313
- 'value' => _wp_image_editor_choose(),
314
- );
315
-
316
- // Get ImageMagic information, if available.
317
- if ( class_exists( 'Imagick' ) ) {
318
- // Save the Imagick instance for later use.
319
- $imagick = new Imagick();
320
- $imagick_version = $imagick->getVersion();
321
- } else {
322
- $imagick_version = 'Imagick not available';
323
- }
324
- $info['wp-media']['fields'][] = array(
325
- 'label' => __( 'Imagick Module Version', 'health-check' ),
326
- 'value' => ( is_array( $imagick_version ) ? $imagick_version['versionNumber'] : $imagick_version ),
327
- );
328
- $info['wp-media']['fields'][] = array(
329
- 'label' => __( 'ImageMagick Version', 'health-check' ),
330
- 'value' => ( is_array( $imagick_version ) ? $imagick_version['versionString'] : $imagick_version ),
331
- );
332
-
333
- // If Imagick is used as our editor, provide some more information about its limitations.
334
- if ( 'WP_Image_Editor_Imagick' === _wp_image_editor_choose() && isset( $imagick ) && $imagick instanceof Imagick ) {
335
- $limits = array(
336
- 'area' => ( defined( 'imagick::RESOURCETYPE_AREA' ) ? size_format( $imagick->getResourceLimit( imagick::RESOURCETYPE_AREA ) ) : 'Not Available' ),
337
- 'disk' => ( defined( 'imagick::RESOURCETYPE_DISK' ) ? $imagick->getResourceLimit( imagick::RESOURCETYPE_DISK ) : 'Not Available' ),
338
- 'file' => ( defined( 'imagick::RESOURCETYPE_FILE' ) ? $imagick->getResourceLimit( imagick::RESOURCETYPE_FILE ) : 'Not Available' ),
339
- 'map' => ( defined( 'imagick::RESOURCETYPE_MAP' ) ? size_format( $imagick->getResourceLimit( imagick::RESOURCETYPE_MAP ) ) : 'Not Available' ),
340
- 'memory' => ( defined( 'imagick::RESOURCETYPE_MEMORY' ) ? size_format( $imagick->getResourceLimit( imagick::RESOURCETYPE_MEMORY ) ) : 'Not Available' ),
341
- 'thread' => ( defined( 'imagick::RESOURCETYPE_THREAD' ) ? $imagick->getResourceLimit( imagick::RESOURCETYPE_THREAD ) : 'Not Available' ),
342
- );
343
-
344
- $info['wp-media']['fields'][] = array(
345
- 'label' => __( 'Imagick Resource Limits', 'health-check' ),
346
- 'value' => $limits,
347
- );
348
- }
349
-
350
- // Get GD information, if available.
351
- if ( function_exists( 'gd_info' ) ) {
352
- $gd = gd_info();
353
- } else {
354
- $gd = false;
355
- }
356
- $info['wp-media']['fields'][] = array(
357
- 'label' => __( 'GD Version', 'health-check' ),
358
- 'value' => ( is_array( $gd ) ? $gd['GD Version'] : __( 'GD not available', 'health-check' ) ),
359
- );
360
-
361
- // Get Ghostscript information, if available.
362
- if ( function_exists( 'exec' ) ) {
363
- $gs = exec( 'gs --version' );
364
- $gs = ( ! empty( $gs ) ? $gs : __( 'Not available', 'health-check' ) );
365
- } else {
366
- $gs = __( 'Unable to determine if Ghostscript is installed', 'health-check' );
367
- }
368
- $info['wp-media']['fields'][] = array(
369
- 'label' => __( 'Ghostscript Version', 'health-check' ),
370
- 'value' => $gs,
371
- );
372
-
373
- // Populate the server debug fields.
374
- $info['wp-server']['fields'][] = array(
375
- 'label' => __( 'Server architecture', 'health-check' ),
376
- 'value' => ( ! function_exists( 'php_uname' ) ? __( 'Unable to determine server architecture', 'health-check' ) : sprintf( '%s %s %s', php_uname( 's' ), php_uname( 'r' ), php_uname( 'm' ) ) ),
377
- );
378
- $info['wp-server']['fields'][] = array(
379
- 'label' => __( 'PHP Version', 'health-check' ),
380
- 'value' => ( ! function_exists( 'phpversion' ) ? __( 'Unable to determine PHP version', 'health-check' ) : sprintf(
381
- '%s %s',
382
- phpversion(),
383
- ( 64 === PHP_INT_SIZE * 8 ? __( '(Supports 64bit values)', 'health-check' ) : '' )
384
- )
385
- ),
386
- );
387
- $info['wp-server']['fields'][] = array(
388
- 'label' => __( 'PHP SAPI', 'health-check' ),
389
- 'value' => ( ! function_exists( 'php_sapi_name' ) ? __( 'Unable to determine PHP SAPI', 'health-check' ) : php_sapi_name() ),
390
- );
391
-
392
- if ( ! function_exists( 'ini_get' ) ) {
393
- $info['wp-server']['fields'][] = array(
394
- 'label' => __( 'Server settings', 'health-check' ),
395
- 'value' => __( 'Unable to determine some settings as the ini_get() function has been disabled', 'health-check' ),
396
- );
397
- } else {
398
- $info['wp-server']['fields'][] = array(
399
- 'label' => __( 'PHP max input variables', 'health-check' ),
400
- 'value' => ini_get( 'max_input_vars' ),
401
- );
402
- $info['wp-server']['fields'][] = array(
403
- 'label' => __( 'PHP time limit', 'health-check' ),
404
- 'value' => ini_get( 'max_execution_time' ),
405
- );
406
- $info['wp-server']['fields'][] = array(
407
- 'label' => __( 'PHP memory limit', 'health-check' ),
408
- 'value' => ini_get( 'memory_limit' ),
409
- );
410
- $info['wp-server']['fields'][] = array(
411
- 'label' => __( 'Max input time', 'health-check' ),
412
- 'value' => ini_get( 'max_input_time' ),
413
- );
414
- $info['wp-server']['fields'][] = array(
415
- 'label' => __( 'Upload max filesize', 'health-check' ),
416
- 'value' => ini_get( 'upload_max_filesize' ),
417
- );
418
- $info['wp-server']['fields'][] = array(
419
- 'label' => __( 'PHP post max size', 'health-check' ),
420
- 'value' => ini_get( 'post_max_size' ),
421
- );
422
- }
423
-
424
- if ( function_exists( 'curl_version' ) ) {
425
- $curl = curl_version();
426
- $info['wp-server']['fields'][] = array(
427
- 'label' => __( 'cURL Version', 'health-check' ),
428
- 'value' => sprintf( '%s %s', $curl['version'], $curl['ssl_version'] ),
429
- );
430
- } else {
431
- $info['wp-server']['fields'][] = array(
432
- 'label' => __( 'cURL Version', 'health-check' ),
433
- 'value' => __( 'Your server does not support cURL', 'health-check' ),
434
- );
435
- }
436
-
437
- $info['wp-server']['fields'][] = array(
438
- 'label' => __( 'SUHOSIN installed', 'health-check' ),
439
- 'value' => ( ( extension_loaded( 'suhosin' ) || ( defined( 'SUHOSIN_PATCH' ) && constant( 'SUHOSIN_PATCH' ) ) ) ? __( 'Yes', 'health-check' ) : __( 'No', 'health-check' ) ),
440
- );
441
-
442
- $info['wp-server']['fields'][] = array(
443
- 'label' => __( 'Is the Imagick library available', 'health-check' ),
444
- 'value' => ( extension_loaded( 'imagick' ) ? __( 'Yes', 'health-check' ) : __( 'No', 'health-check' ) ),
445
- );
446
-
447
- // Check if a .htaccess file exists.
448
- if ( is_file( ABSPATH . '/.htaccess' ) ) {
449
- // If the file exists, grab the content of it.
450
- $htaccess_content = file_get_contents( ABSPATH . '/.htaccess' );
451
-
452
- // Filter away the core WordPress rules.
453
- $filtered_htaccess_content = trim( preg_replace( '/\# BEGIN WordPress[\s\S]+?# END WordPress/si', '', $htaccess_content ) );
454
-
455
- $info['wp-server']['fields'][] = array(
456
- 'label' => __( 'htaccess rules', 'health-check' ),
457
- 'value' => ( ! empty( $filtered_htaccess_content ) ? __( 'Custom rules have been added to your htaccess file', 'health-check' ) : __( 'Your htaccess file only contains core WordPress features', 'health-check' ) ),
458
- );
459
- }
460
-
461
- // Populate the database debug fields.
462
- if ( is_resource( $wpdb->dbh ) ) {
463
- // Old mysql extension.
464
- $extension = 'mysql';
465
- } elseif ( is_object( $wpdb->dbh ) ) {
466
- // mysqli or PDO.
467
- $extension = get_class( $wpdb->dbh );
468
- } else {
469
- // Unknown sql extension.
470
- $extension = null;
471
- }
472
-
473
- if ( method_exists( $wpdb, 'db_version' ) ) {
474
- if ( $wpdb->use_mysqli ) {
475
- // phpcs:ignore WordPress.DB.RestrictedFunctions.mysql_mysqli_get_server_info
476
- $server = mysqli_get_server_info( $wpdb->dbh );
477
- } else {
478
- // phpcs:ignore WordPress.DB.RestrictedFunctions.mysql_mysql_get_server_info
479
- $server = mysql_get_server_info( $wpdb->dbh );
480
- }
481
- } else {
482
- $server = null;
483
- }
484
-
485
- if ( isset( $wpdb->use_mysqli ) && $wpdb->use_mysqli ) {
486
- $client_version = $wpdb->dbh->client_info;
487
- } else {
488
- // phpcs:ignore WordPress.DB.RestrictedFunctions.mysql_mysql_get_client_info
489
- if ( preg_match( '|[0-9]{1,2}\.[0-9]{1,2}\.[0-9]{1,2}|', mysql_get_client_info(), $matches ) ) {
490
- $client_version = $matches[0];
491
- } else {
492
- $client_version = null;
493
- }
494
- }
495
-
496
- $info['wp-database']['fields'][] = array(
497
- 'label' => __( 'Extension', 'health-check' ),
498
- 'value' => $extension,
499
- );
500
- $info['wp-database']['fields'][] = array(
501
- 'label' => __( 'Server version', 'health-check' ),
502
- 'value' => $server,
503
- );
504
- $info['wp-database']['fields'][] = array(
505
- 'label' => __( 'Client version', 'health-check' ),
506
- 'value' => $client_version,
507
- );
508
- $info['wp-database']['fields'][] = array(
509
- 'label' => __( 'Database user', 'health-check' ),
510
- 'value' => $wpdb->dbuser,
511
- 'private' => true,
512
- );
513
- $info['wp-database']['fields'][] = array(
514
- 'label' => __( 'Database host', 'health-check' ),
515
- 'value' => $wpdb->dbhost,
516
- 'private' => true,
517
- );
518
- $info['wp-database']['fields'][] = array(
519
- 'label' => __( 'Database name', 'health-check' ),
520
- 'value' => $wpdb->dbname,
521
- 'private' => true,
522
- );
523
- $info['wp-database']['fields'][] = array(
524
- 'label' => __( 'Database prefix', 'health-check' ),
525
- 'value' => $wpdb->prefix,
526
- );
527
-
528
- // List must use plugins if there are any.
529
- $mu_plugins = get_mu_plugins();
530
-
531
- foreach ( $mu_plugins as $plugin_path => $plugin ) {
532
- $plugin_version = $plugin['Version'];
533
- $plugin_author = $plugin['Author'];
534
-
535
- $plugin_version_string = __( 'No version or author information available', 'health-check' );
536
-
537
- if ( ! empty( $plugin_version ) && ! empty( $plugin_author ) ) {
538
- // translators: %1$s: Plugin version number. %2$s: Plugin author name.
539
- $plugin_version_string = sprintf( __( 'Version %1$s by %2$s', 'health-check' ), $plugin_version, $plugin_author );
540
- }
541
- if ( empty( $plugin_version ) && ! empty( $plugin_author ) ) {
542
- // translators: %s: Plugin author name.
543
- $plugin_version_string = sprintf( __( 'By %s', 'health-check' ), $plugin_author );
544
- }
545
- if ( ! empty( $plugin_version ) && empty( $plugin_author ) ) {
546
- // translators: %s: Plugin version number.
547
- $plugin_version_string = sprintf( __( 'Version %s', 'health-check' ), $plugin_version );
548
- }
549
-
550
- $info['wp-mu-plugins']['fields'][] = array(
551
- 'label' => $plugin['Name'],
552
- 'value' => $plugin_version_string,
553
- );
554
- }
555
-
556
- // List all available plugins.
557
- $plugins = get_plugins();
558
- $plugin_updates = get_plugin_updates();
559
-
560
- foreach ( $plugins as $plugin_path => $plugin ) {
561
- $plugin_part = ( is_plugin_active( $plugin_path ) ) ? 'wp-plugins-active' : 'wp-plugins-inactive';
562
-
563
- $plugin_version = $plugin['Version'];
564
- $plugin_author = $plugin['Author'];
565
-
566
- $plugin_version_string = __( 'No version or author information available', 'health-check' );
567
-
568
- if ( ! empty( $plugin_version ) && ! empty( $plugin_author ) ) {
569
- // translators: %1$s: Plugin version number. %2$s: Plugin author name.
570
- $plugin_version_string = sprintf( __( 'Version %1$s by %2$s', 'health-check' ), $plugin_version, $plugin_author );
571
- }
572
- if ( empty( $plugin_version ) && ! empty( $plugin_author ) ) {
573
- // translators: %s: Plugin author name.
574
- $plugin_version_string = sprintf( __( 'By %s', 'health-check' ), $plugin_author );
575
- }
576
- if ( ! empty( $plugin_version ) && empty( $plugin_author ) ) {
577
- // translators: %s: Plugin version number.
578
- $plugin_version_string = sprintf( __( 'Version %s', 'health-check' ), $plugin_version );
579
- }
580
-
581
- if ( array_key_exists( $plugin_path, $plugin_updates ) ) {
582
- // translators: %s: Latest plugin version number.
583
- $plugin_update_needed = ' ' . sprintf( __( '( Latest version: %s )', 'health-check' ), $plugin_updates[ $plugin_path ]->update->new_version );
584
- } else {
585
- $plugin_update_needed = '';
586
- }
587
-
588
- $info[ $plugin_part ]['fields'][] = array(
589
- 'label' => $plugin['Name'],
590
- 'value' => $plugin_version_string . $plugin_update_needed,
591
- );
592
- }
593
-
594
- // Populate the section for the currently active theme.
595
- global $_wp_theme_features;
596
- $theme_features = array();
597
- if ( ! empty( $_wp_theme_features ) ) {
598
- foreach ( $_wp_theme_features as $feature => $options ) {
599
- $theme_features[] = $feature;
600
- }
601
- }
602
-
603
- $active_theme = wp_get_theme();
604
- $theme_updates = get_theme_updates();
605
-
606
- if ( array_key_exists( $active_theme->stylesheet, $theme_updates ) ) {
607
- // translators: %s: Latest theme version number.
608
- $theme_update_needed_active = ' ' . sprintf( __( '( Latest version: %s )', 'health-check' ), $theme_updates[ $active_theme->stylesheet ]->update['new_version'] );
609
- } else {
610
- $theme_update_needed_active = '';
611
- }
612
-
613
- $info['wp-active-theme']['fields'] = array(
614
- array(
615
- 'label' => __( 'Name', 'health-check' ),
616
- // phpcs:ignore WordPress.NamingConventions.ValidVariableName.NotSnakeCaseMemberVar
617
- 'value' => $active_theme->Name,
618
- ),
619
- array(
620
- 'label' => __( 'Version', 'health-check' ),
621
- // phpcs:ignore WordPress.NamingConventions.ValidVariableName.NotSnakeCaseMemberVar
622
- 'value' => $active_theme->Version . $theme_update_needed_active,
623
- ),
624
- array(
625
- 'label' => __( 'Author', 'health-check' ),
626
- // phpcs:ignore WordPress.NamingConventions.ValidVariableName.NotSnakeCaseMemberVar
627
- 'value' => wp_kses( $active_theme->Author, array() ),
628
- ),
629
- array(
630
- 'label' => __( 'Author website', 'health-check' ),
631
- 'value' => ( $active_theme->offsetGet( 'Author URI' ) ? $active_theme->offsetGet( 'Author URI' ) : __( 'Undefined', 'health-check' ) ),
632
- ),
633
- array(
634
- 'label' => __( 'Parent theme', 'health-check' ),
635
- 'value' => ( $active_theme->parent_theme ? $active_theme->parent_theme : __( 'Not a child theme', 'health-check' ) ),
636
- ),
637
- array(
638
- 'label' => __( 'Supported theme features', 'health-check' ),
639
- 'value' => implode( ', ', $theme_features ),
640
- ),
641
- );
642
-
643
- // Populate a list of all themes available in the install.
644
- $all_themes = wp_get_themes();
645
-
646
- foreach ( $all_themes as $theme_slug => $theme ) {
647
- // Ignore the currently active theme from the list of all themes.
648
- if ( $active_theme->stylesheet == $theme_slug ) {
649
- continue;
650
- }
651
- // phpcs:ignore WordPress.NamingConventions.ValidVariableName.NotSnakeCaseMemberVar
652
- $theme_version = $theme->Version;
653
- // phpcs:ignore WordPress.NamingConventions.ValidVariableName.NotSnakeCaseMemberVar
654
- $theme_author = $theme->Author;
655
-
656
- $theme_version_string = __( 'No version or author information available', 'health-check' );
657
-
658
- if ( ! empty( $theme_version ) && ! empty( $theme_author ) ) {
659
- // translators: %1$s: Theme version number. %2$s: Theme author name.
660
- $theme_version_string = sprintf( __( 'Version %1$s by %2$s', 'health-check' ), $theme_version, wp_kses( $theme_author, array() ) );
661
- }
662
- if ( empty( $theme_version ) && ! empty( $theme_author ) ) {
663
- // translators: %s: Theme author name.
664
- $theme_version_string = sprintf( __( 'By %s', 'health-check' ), wp_kses( $theme_author, array() ) );
665
- }
666
- if ( ! empty( $theme_version ) && empty( $theme_author ) ) {
667
- // translators: %s: Theme version number.
668
- $theme_version_string = sprintf( __( 'Version %s', 'health-check' ), $theme_version );
669
- }
670
-
671
- if ( array_key_exists( $theme_slug, $theme_updates ) ) {
672
- // translators: %s: Latest theme version number.
673
- $theme_update_needed = ' ' . sprintf( __( '( Latest version: %s )', 'health-check' ), $theme_updates[ $theme_slug ]->update['new_version'] );
674
- } else {
675
- $theme_update_needed = '';
676
- }
677
-
678
- $info['wp-themes']['fields'][] = array(
679
- 'label' => sprintf(
680
- // translators: %1$s: Theme name. %2$s: Theme slug.
681
- __( '%1$s (%2$s)', 'health-check' ),
682
- // phpcs:ignore WordPress.NamingConventions.ValidVariableName.NotSnakeCaseMemberVar
683
- $theme->Name,
684
- $theme_slug
685
- ),
686
- 'value' => $theme_version_string . $theme_update_needed,
687
- );
688
- }
689
-
690
- // Add more filesystem checks
691
- if ( defined( 'WPMU_PLUGIN_DIR' ) && is_dir( WPMU_PLUGIN_DIR ) ) {
692
- $info['wp-filesystem']['fields'][] = array(
693
- 'label' => __( 'The Must Use Plugins directory', 'health-check' ),
694
- 'value' => ( wp_is_writable( WPMU_PLUGIN_DIR ) ? __( 'Writable', 'health-check' ) : __( 'Not writable', 'health-check' ) ),
695
- );
696
- }
697
-
698
- $info['wp-install-size']['fields'] = Health_Check_Debug_Data::get_installation_size();
699
-
700
- /**
701
- * Add or modify new debug sections.
702
- *
703
- * Plugin or themes may wish to introduce their own debug information without creating additional admin pages for this
704
- * kind of information as it is rarely needed, they can then utilize this filter to introduce their own sections.
705
- *
706
- * This filter intentionally does not include the fields introduced by core as those should always be un-modified
707
- * and reliable for support related scenarios, take note that the core fields will take priority if a filtered value
708
- * is trying to use the same array keys.
709
- *
710
- * Array keys added by core are all prefixed with `wp-`, plugins and themes are encouraged to use their own slug as
711
- * a prefix, both for consistency as well as avoiding key collisions.
712
- *
713
- * @since 4.9.0
714
- *
715
- * @param array $args {
716
- * The debug information to be added to the core information page.
717
- *
718
- * @type string $label The title for this section of the debug output.
719
- * @type string $description Optional. A description for your information section which may contain basic HTML
720
- * markup: `em`, `strong` and `a` for linking to documentation or putting emphasis.
721
- * @type boolean $show_count Optional. If set to `true` the amount of fields will be included in the title for
722
- * this section.
723
- * @type boolean $private Optional. If set to `true` the section and all associated fields will be excluded
724
- * from the copy-paste text area.
725
- * @type array $fields {
726
- * An associative array containing the data to be displayed.
727
- *
728
- * @type string $label The label for this piece of information.
729
- * @type string $value The output that is of interest for this field.
730
- * @type boolean $private Optional. If set to `true` the field will not be included in the copy-paste text area
731
- * on top of the page, allowing you to show, for example, API keys here.
732
- * }
733
- * }
734
- */
735
- $external_info = apply_filters( 'debug_information', array() );
736
-
737
- // Merge the core and external debug fields.
738
- $info = array_replace_recursive( $info, array_replace_recursive( $external_info, $info ) );
739
-
740
- if ( ! empty( $locale ) ) {
741
- // Change the language used for translations
742
- if ( function_exists( 'restore_previous_locale' ) && $switched_locale ) {
743
- restore_previous_locale();
744
- }
745
- }
746
-
747
- return $info;
748
- }
749
-
750
- public static function get_installation_size() {
751
- $uploads_dir = wp_upload_dir();
752
-
753
- $sizes = array(
754
- 'wp' => array(
755
- 'path' => ABSPATH,
756
- 'size' => 0,
757
- ),
758
- 'themes' => array(
759
- 'path' => trailingslashit( get_theme_root() ),
760
- 'size' => 0,
761
- ),
762
- 'plugins' => array(
763
- 'path' => WP_PLUGIN_DIR,
764
- 'size' => 0,
765
- ),
766
- 'uploads' => array(
767
- 'path' => $uploads_dir['basedir'],
768
- 'size' => 0,
769
- ),
770
- );
771
-
772
- $inaccurate = false;
773
-
774
- foreach ( $sizes as $size => $attributes ) {
775
- try {
776
- $sizes[ $size ]['size'] = Health_Check_Debug_Data::get_directory_size( $attributes['path'] );
777
- } catch ( Exception $e ) {
778
- $inaccurate = true;
779
- }
780
- }
781
-
782
- $size_db = Health_Check_Debug_Data::get_database_size();
783
-
784
- $size_total = $sizes['wp']['size'] + $size_db;
785
-
786
- $result = array(
787
- array(
788
- 'label' => __( 'Uploads Directory', 'health-check' ),
789
- 'value' => size_format( $sizes['uploads']['size'], 2 ),
790
- ),
791
- array(
792
- 'label' => __( 'Themes Directory', 'health-check' ),
793
- 'value' => size_format( $sizes['themes']['size'], 2 ),
794
- ),
795
- array(
796
- 'label' => __( 'Plugins Directory', 'health-check' ),
797
- 'value' => size_format( $sizes['plugins']['size'], 2 ),
798
- ),
799
- array(
800
- 'label' => __( 'Database size', 'health-check' ),
801
- 'value' => size_format( $size_db, 2 ),
802
- ),
803
- array(
804
- 'label' => __( 'Whole WordPress Directory', 'health-check' ),
805
- 'value' => size_format( $sizes['wp']['size'], 2 ),
806
- ),
807
- array(
808
- 'label' => __( 'Total installation size', 'health-check' ),
809
- 'value' => sprintf(
810
- '%s%s',
811
- size_format( $size_total, 2 ),
812
- ( false === $inaccurate ? '' : __( '- Some errors, likely caused by invalid permissions, were encountered when determining the size of your installation. This means the values represented may be inaccurate.', 'health-check' ) )
813
- ),
814
- ),
815
- );
816
-
817
- return $result;
818
- }
819
-
820
- public static function get_directory_size( $path ) {
821
- $size = 0;
822
-
823
- foreach ( new RecursiveIteratorIterator( new RecursiveDirectoryIterator( $path ) ) as $file ) {
824
- $size += $file->getSize();
825
- }
826
-
827
- return $size;
828
- }
829
-
830
- public static function get_database_size() {
831
- global $wpdb;
832
- $size = 0;
833
- $rows = $wpdb->get_results( 'SHOW TABLE STATUS', ARRAY_A );
834
-
835
- if ( $wpdb->num_rows > 0 ) {
836
- foreach ( $rows as $row ) {
837
- $size += $row['Data_length'] + $row['Index_length'];
838
- }
839
- }
840
-
841
- return $size;
842
- }
843
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Class for providing debug data based on a users WordPress environment.
4
+ *
5
+ * @package Health Check
6
+ */
7
+
8
+ /**
9
+ * Class Health_Check_Debug_Data
10
+ */
11
+ class Health_Check_Debug_Data {
12
+
13
+ /**
14
+ * Calls all core funtions to check for updates
15
+ *
16
+ * @uses wp_version_check()
17
+ * @uses wp_update_plugins()
18
+ * @uses wp_update_themes()
19
+ *
20
+ * @return void
21
+ */
22
+ static function check_for_updates() {
23
+
24
+ wp_version_check();
25
+ wp_update_plugins();
26
+ wp_update_themes();
27
+
28
+ }
29
+
30
+ static function debug_data( $locale = null ) {
31
+ if ( ! empty( $locale ) ) {
32
+ // Change the language used for translations
33
+ if ( function_exists( 'switch_to_locale' ) ) {
34
+ $original_locale = get_locale();
35
+ $switched_locale = switch_to_locale( $locale );
36
+ }
37
+ }
38
+ global $wpdb;
39
+
40
+ $upload_dir = wp_upload_dir();
41
+ if ( file_exists( ABSPATH . 'wp-config.php' ) ) {
42
+ $wp_config_path = ABSPATH . 'wp-config.php';
43
+ // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
44
+ } elseif ( @file_exists( dirname( ABSPATH ) . '/wp-config.php' ) && ! @file_exists( dirname( ABSPATH ) . '/wp-settings.php' ) ) {
45
+ $wp_config_path = dirname( ABSPATH ) . '/wp-config.php';
46
+ }
47
+
48
+ $core_current_version = get_bloginfo( 'version' );
49
+ $core_updates = get_core_updates();
50
+ $core_update_needed = '';
51
+
52
+ foreach ( $core_updates as $core => $update ) {
53
+ if ( 'upgrade' === $update->response ) {
54
+ // translators: %s: Latest WordPress version number.
55
+ $core_update_needed = ' ' . sprintf( __( '( Latest version: %s )', 'health-check' ), $update->version );
56
+ } else {
57
+ $core_update_needed = '';
58
+ }
59
+ }
60
+
61
+ $info = array(
62
+ 'wp-core' => array(
63
+ 'label' => __( 'WordPress', 'health-check' ),
64
+ 'fields' => array(
65
+ array(
66
+ 'label' => __( 'Version', 'health-check' ),
67
+ 'value' => $core_current_version . $core_update_needed,
68
+ ),
69
+ array(
70
+ 'label' => __( 'Language', 'health-check' ),
71
+ 'value' => ( ! empty( $locale ) ? $original_locale : get_locale() ),
72
+ ),
73
+ array(
74
+ 'label' => __( 'Home URL', 'health-check' ),
75
+ 'value' => get_bloginfo( 'url' ),
76
+ 'private' => true,
77
+ ),
78
+ array(
79
+ 'label' => __( 'Site URL', 'health-check' ),
80
+ 'value' => get_bloginfo( 'wpurl' ),
81
+ 'private' => true,
82
+ ),
83
+ array(
84
+ 'label' => __( 'Permalink structure', 'health-check' ),
85
+ 'value' => get_option( 'permalink_structure' ),
86
+ ),
87
+ array(
88
+ 'label' => __( 'Is this site using HTTPS?', 'health-check' ),
89
+ 'value' => ( is_ssl() ? __( 'Yes', 'health-check' ) : __( 'No', 'health-check' ) ),
90
+ ),
91
+ array(
92
+ 'label' => __( 'Can anyone register on this site?', 'health-check' ),
93
+ 'value' => ( get_option( 'users_can_register' ) ? __( 'Yes', 'health-check' ) : __( 'No', 'health-check' ) ),
94
+ ),
95
+ array(
96
+ 'label' => __( 'Default comment status', 'health-check' ),
97
+ 'value' => get_option( 'default_comment_status' ),
98
+ ),
99
+ array(
100
+ 'label' => __( 'Is this a multisite?', 'health-check' ),
101
+ 'value' => ( is_multisite() ? __( 'Yes', 'health-check' ) : __( 'No', 'health-check' ) ),
102
+ ),
103
+ ),
104
+ ),
105
+ 'wp-install-size' => array(
106
+ 'label' => __( 'Installation size', 'health-check' ),
107
+ 'fields' => array(),
108
+ ),
109
+ 'wp-dropins' => array(
110
+ 'label' => __( 'Drop-ins', 'health-check' ),
111
+ 'description' => __( 'Drop-ins are single files that replace or enhance WordPress features in ways that are not possible for traditional plugins', 'health-check' ),
112
+ 'fields' => array(),
113
+ ),
114
+ 'wp-active-theme' => array(
115
+ 'label' => __( 'Active Theme', 'health-check' ),
116
+ 'fields' => array(),
117
+ ),
118
+ 'wp-themes' => array(
119
+ 'label' => __( 'Other themes', 'health-check' ),
120
+ 'show_count' => true,
121
+ 'fields' => array(),
122
+ ),
123
+ 'wp-mu-plugins' => array(
124
+ 'label' => __( 'Must Use Plugins', 'health-check' ),
125
+ 'show_count' => true,
126
+ 'fields' => array(),
127
+ ),
128
+ 'wp-plugins-active' => array(
129
+ 'label' => __( 'Active Plugins', 'health-check' ),
130
+ 'show_count' => true,
131
+ 'fields' => array(),
132
+ ),
133
+ 'wp-plugins-inactive' => array(
134
+ 'label' => __( 'Inactive Plugins', 'health-check' ),
135
+ 'show_count' => true,
136
+ 'fields' => array(),
137
+ ),
138
+ 'wp-media' => array(
139
+ 'label' => __( 'Media handling', 'health-check' ),
140
+ 'fields' => array(),
141
+ ),
142
+ 'wp-server' => array(
143
+ 'label' => __( 'Server', 'health-check' ),
144
+ 'description' => __( 'The options shown below relate to your server setup. If changes are required, you may need your web host\'s assistance.', 'health-check' ),
145
+ 'fields' => array(),
146
+ ),
147
+ 'wp-database' => array(
148
+ 'label' => __( 'Database', 'health-check' ),
149
+ 'fields' => array(),
150
+ ),
151
+ 'wp-constants' => array(
152
+ 'label' => __( 'WordPress Constants', 'health-check' ),
153
+ 'description' => __( 'These values represent values set in your websites code which affect WordPress in various ways that may be of importance when seeking help with your site.', 'health-check' ),
154
+ 'fields' => array(
155
+ array(
156
+ 'label' => 'ABSPATH',
157
+ 'value' => ( ! defined( 'ABSPATH' ) ? __( 'Undefined', 'health-check' ) : ABSPATH ),
158
+ ),
159
+ array(
160
+ 'label' => 'WP_HOME',
161
+ 'value' => ( ! defined( 'WP_HOME' ) ? __( 'Undefined', 'health-check' ) : WP_HOME ),
162
+ ),
163
+ array(
164
+ 'label' => 'WP_SITEURL',
165
+ 'value' => ( ! defined( 'WP_SITEURL' ) ? __( 'Undefined', 'health-check' ) : WP_SITEURL ),
166
+ ),
167
+ array(
168
+ 'label' => 'WP_DEBUG',
169
+ 'value' => ( ! defined( 'WP_DEBUG' ) ? __( 'Undefined', 'health-check' ) : ( WP_DEBUG ? __( 'Enabled', 'health-check' ) : __( 'Disabled', 'health-check' ) ) ),
170
+ ),
171
+ array(
172
+ 'label' => 'WP_MAX_MEMORY_LIMIT',
173
+ 'value' => ( ! defined( 'WP_MAX_MEMORY_LIMIT' ) ? __( 'Undefined', 'health-check' ) : WP_MAX_MEMORY_LIMIT ),
174
+ ),
175
+ array(
176
+ 'label' => 'WP_DEBUG_DISPLAY',
177
+ 'value' => ( ! defined( 'WP_DEBUG_DISPLAY' ) ? __( 'Undefined', 'health-check' ) : ( WP_DEBUG_DISPLAY ? __( 'Enabled', 'health-check' ) : __( 'Disabled', 'health-check' ) ) ),
178
+ ),
179
+ array(
180
+ 'label' => 'WP_DEBUG_LOG',
181
+ 'value' => ( ! defined( 'WP_DEBUG_LOG' ) ? __( 'Undefined', 'health-check' ) : ( WP_DEBUG_LOG ? __( 'Enabled', 'health-check' ) : __( 'Disabled', 'health-check' ) ) ),
182
+ ),
183
+ array(
184
+ 'label' => 'SCRIPT_DEBUG',
185
+ 'value' => ( ! defined( 'SCRIPT_DEBUG' ) ? __( 'Undefined', 'health-check' ) : ( SCRIPT_DEBUG ? __( 'Enabled', 'health-check' ) : __( 'Disabled', 'health-check' ) ) ),
186
+ ),
187
+ array(
188
+ 'label' => 'WP_CACHE',
189
+ 'value' => ( ! defined( 'WP_CACHE' ) ? __( 'Undefined', 'health-check' ) : ( WP_CACHE ? __( 'Enabled', 'health-check' ) : __( 'Disabled', 'health-check' ) ) ),
190
+ ),
191
+ array(
192
+ 'label' => 'CONCATENATE_SCRIPTS',
193
+ 'value' => ( ! defined( 'CONCATENATE_SCRIPTS' ) ? __( 'Undefined', 'health-check' ) : ( CONCATENATE_SCRIPTS ? __( 'Enabled', 'health-check' ) : __( 'Disabled', 'health-check' ) ) ),
194
+ ),
195
+ array(
196
+ 'label' => 'COMPRESS_SCRIPTS',
197
+ 'value' => ( ! defined( 'COMPRESS_SCRIPTS' ) ? __( 'Undefined', 'health-check' ) : ( COMPRESS_SCRIPTS ? __( 'Enabled', 'health-check' ) : __( 'Disabled', 'health-check' ) ) ),
198
+ ),
199
+ array(
200
+ 'label' => 'COMPRESS_CSS',
201
+ 'value' => ( ! defined( 'COMPRESS_CSS' ) ? __( 'Undefined', 'health-check' ) : ( COMPRESS_CSS ? __( 'Enabled', 'health-check' ) : __( 'Disabled', 'health-check' ) ) ),
202
+ ),
203
+ array(
204
+ 'label' => 'WP_LOCAL_DEV',
205
+ 'value' => ( ! defined( 'WP_LOCAL_DEV' ) ? __( 'Undefined', 'health-check' ) : ( WP_LOCAL_DEV ? __( 'Enabled', 'health-check' ) : __( 'Disabled', 'health-check' ) ) ),
206
+ ),
207
+ ),
208
+ ),
209
+ 'wp-filesystem' => array(
210
+ 'label' => __( 'Filesystem Permissions', 'health-check' ),
211
+ 'description' => __( 'The status of various locations WordPress needs to write files in various scenarios.', 'health-check' ),
212
+ 'fields' => array(
213
+ array(
214
+ 'label' => __( 'The main WordPress directory', 'health-check' ),
215
+ 'value' => ( wp_is_writable( ABSPATH ) ? __( 'Writable', 'health-check' ) : __( 'Not writable', 'health-check' ) ),
216
+ ),
217
+ array(
218
+ 'label' => __( 'The wp-content directory', 'health-check' ),
219
+ 'value' => ( wp_is_writable( WP_CONTENT_DIR ) ? __( 'Writable', 'health-check' ) : __( 'Not writable', 'health-check' ) ),
220
+ ),
221
+ array(
222
+ 'label' => __( 'The uploads directory', 'health-check' ),
223
+ 'value' => ( wp_is_writable( $upload_dir['basedir'] ) ? __( 'Writable', 'health-check' ) : __( 'Not writable', 'health-check' ) ),
224
+ ),
225
+ array(
226
+ 'label' => __( 'The plugins directory', 'health-check' ),
227
+ 'value' => ( wp_is_writable( WP_PLUGIN_DIR ) ? __( 'Writable', 'health-check' ) : __( 'Not writable', 'health-check' ) ),
228
+ ),
229
+ array(
230
+ 'label' => __( 'The themes directory', 'health-check' ),
231
+ 'value' => ( wp_is_writable( get_template_directory() . '/..' ) ? __( 'Writable', 'health-check' ) : __( 'Not writable', 'health-check' ) ),
232
+ ),
233
+ ),
234
+ ),
235
+ );
236
+
237
+ if ( is_multisite() ) {
238
+ $network_query = new WP_Network_Query();
239
+ $network_ids = $network_query->query( array(
240
+ 'fields' => 'ids',
241
+ 'number' => 100,
242
+ 'no_found_rows' => false,
243
+ ) );
244
+
245
+ $site_count = 0;
246
+ foreach ( $network_ids as $network_id ) {
247
+ $site_count += get_blog_count( $network_id );
248
+ }
249
+
250
+ $info['wp-core']['fields'][] = array(
251
+ 'label' => __( 'User Count', 'health-check' ),
252
+ 'value' => get_user_count(),
253
+ );
254
+ $info['wp-core']['fields'][] = array(
255
+ 'label' => __( 'Site Count', 'health-check' ),
256
+ 'value' => $site_count,
257
+ );
258
+ $info['wp-core']['fields'][] = array(
259
+ 'label' => __( 'Network Count', 'health-check' ),
260
+ 'value' => $network_query->found_networks,
261
+ );
262
+ } else {
263
+ $user_count = count_users();
264
+
265
+ $info['wp-core']['fields'][] = array(
266
+ 'label' => __( 'User Count', 'health-check' ),
267
+ 'value' => $user_count['total_users'],
268
+ );
269
+ }
270
+
271
+ // WordPress features requiring processing.
272
+ $wp_dotorg = wp_remote_get( 'https://wordpress.org', array(
273
+ 'timeout' => 10,
274
+ ) );
275
+ if ( ! is_wp_error( $wp_dotorg ) ) {
276
+ $info['wp-core']['fields'][] = array(
277
+ 'label' => __( 'Communication with WordPress.org', 'health-check' ),
278
+ 'value' => sprintf(
279
+ __( 'WordPress.org is reachable', 'health-check' )
280
+ ),
281
+ );
282
+ } else {
283
+ $info['wp-core']['fields'][] = array(
284
+ 'label' => __( 'Communication with WordPress.org', 'health-check' ),
285
+ 'value' => sprintf(
286
+ // translators: %1$s: The IP address WordPress.org resolves to. %2$s: The error returned by the lookup.
287
+ __( 'Unable to reach WordPress.org at %1$s: %2$s', 'health-check' ),
288
+ gethostbyname( 'wordpress.org' ),
289
+ $wp_dotorg->get_error_message()
290
+ ),
291
+ );
292
+ }
293
+
294
+ $loopback = Health_Check_Loopback::can_perform_loopback();
295
+ $info['wp-core']['fields'][] = array(
296
+ 'label' => __( 'Create loopback requests', 'health-check' ),
297
+ 'value' => $loopback->message,
298
+ );
299
+
300
+ // Get drop-ins.
301
+ $dropins = get_dropins();
302
+ $dropin_description = _get_dropins();
303
+ foreach ( $dropins as $dropin_key => $dropin ) {
304
+ $info['wp-dropins']['fields'][] = array(
305
+ 'label' => $dropin_key,
306
+ 'value' => $dropin_description[ $dropin_key ][0],
307
+ );
308
+ }
309
+
310
+ // Populate the media fields.
311
+ $info['wp-media']['fields'][] = array(
312
+ 'label' => __( 'Active editor', 'health-check' ),
313
+ 'value' => _wp_image_editor_choose(),
314
+ );
315
+
316
+ // Get ImageMagic information, if available.
317
+ if ( class_exists( 'Imagick' ) ) {
318
+ // Save the Imagick instance for later use.
319
+ $imagick = new Imagick();
320
+ $imagick_version = $imagick->getVersion();
321
+ } else {
322
+ $imagick_version = 'Imagick not available';
323
+ }
324
+ $info['wp-media']['fields'][] = array(
325
+ 'label' => __( 'Imagick Module Version', 'health-check' ),
326
+ 'value' => ( is_array( $imagick_version ) ? $imagick_version['versionNumber'] : $imagick_version ),
327
+ );
328
+ $info['wp-media']['fields'][] = array(
329
+ 'label' => __( 'ImageMagick Version', 'health-check' ),
330
+ 'value' => ( is_array( $imagick_version ) ? $imagick_version['versionString'] : $imagick_version ),
331
+ );
332
+
333
+ // If Imagick is used as our editor, provide some more information about its limitations.
334
+ if ( 'WP_Image_Editor_Imagick' === _wp_image_editor_choose() && isset( $imagick ) && $imagick instanceof Imagick ) {
335
+ $limits = array(
336
+ 'area' => ( defined( 'imagick::RESOURCETYPE_AREA' ) ? size_format( $imagick->getResourceLimit( imagick::RESOURCETYPE_AREA ) ) : 'Not Available' ),
337
+ 'disk' => ( defined( 'imagick::RESOURCETYPE_DISK' ) ? $imagick->getResourceLimit( imagick::RESOURCETYPE_DISK ) : 'Not Available' ),
338
+ 'file' => ( defined( 'imagick::RESOURCETYPE_FILE' ) ? $imagick->getResourceLimit( imagick::RESOURCETYPE_FILE ) : 'Not Available' ),
339
+ 'map' => ( defined( 'imagick::RESOURCETYPE_MAP' ) ? size_format( $imagick->getResourceLimit( imagick::RESOURCETYPE_MAP ) ) : 'Not Available' ),
340
+ 'memory' => ( defined( 'imagick::RESOURCETYPE_MEMORY' ) ? size_format( $imagick->getResourceLimit( imagick::RESOURCETYPE_MEMORY ) ) : 'Not Available' ),
341
+ 'thread' => ( defined( 'imagick::RESOURCETYPE_THREAD' ) ? $imagick->getResourceLimit( imagick::RESOURCETYPE_THREAD ) : 'Not Available' ),
342
+ );
343
+
344
+ $info['wp-media']['fields'][] = array(
345
+ 'label' => __( 'Imagick Resource Limits', 'health-check' ),
346
+ 'value' => $limits,
347
+ );
348
+ }
349
+
350
+ // Get GD information, if available.
351
+ if ( function_exists( 'gd_info' ) ) {
352
+ $gd = gd_info();
353
+ } else {
354
+ $gd = false;
355
+ }
356
+ $info['wp-media']['fields'][] = array(
357
+ 'label' => __( 'GD Version', 'health-check' ),
358
+ 'value' => ( is_array( $gd ) ? $gd['GD Version'] : __( 'GD not available', 'health-check' ) ),
359
+ );
360
+
361
+ // Get Ghostscript information, if available.
362
+ if ( function_exists( 'exec' ) ) {
363
+ $gs = exec( 'gs --version' );
364
+ $gs = ( ! empty( $gs ) ? $gs : __( 'Not available', 'health-check' ) );
365
+ } else {
366
+ $gs = __( 'Unable to determine if Ghostscript is installed', 'health-check' );
367
+ }
368
+ $info['wp-media']['fields'][] = array(
369
+ 'label' => __( 'Ghostscript Version', 'health-check' ),
370
+ 'value' => $gs,
371
+ );
372
+
373
+ // Populate the server debug fields.
374
+ $info['wp-server']['fields'][] = array(
375
+ 'label' => __( 'Server architecture', 'health-check' ),
376
+ 'value' => ( ! function_exists( 'php_uname' ) ? __( 'Unable to determine server architecture', 'health-check' ) : sprintf( '%s %s %s', php_uname( 's' ), php_uname( 'r' ), php_uname( 'm' ) ) ),
377
+ );
378
+ $info['wp-server']['fields'][] = array(
379
+ 'label' => __( 'Web Server Software', 'health-check' ),
380
+ 'value' => ( isset( $_SERVER['SERVER_SOFTWARE'] ) ? $_SERVER['SERVER_SOFTWARE'] : __( 'Unable to determine what web server software is used', 'health-check' ) ),
381
+ );
382
+ $info['wp-server']['fields'][] = array(
383
+ 'label' => __( 'PHP Version', 'health-check' ),
384
+ 'value' => ( ! function_exists( 'phpversion' ) ? __( 'Unable to determine PHP version', 'health-check' ) : sprintf(
385
+ '%s %s',
386
+ phpversion(),
387
+ ( 64 === PHP_INT_SIZE * 8 ? __( '(Supports 64bit values)', 'health-check' ) : __( '(Does not support 64bit values)', 'health-check' ) )
388
+ )
389
+ ),
390
+ );
391
+ $info['wp-server']['fields'][] = array(
392
+ 'label' => __( 'PHP SAPI', 'health-check' ),
393
+ 'value' => ( ! function_exists( 'php_sapi_name' ) ? __( 'Unable to determine PHP SAPI', 'health-check' ) : php_sapi_name() ),
394
+ );
395
+
396
+ if ( ! function_exists( 'ini_get' ) ) {
397
+ $info['wp-server']['fields'][] = array(
398
+ 'label' => __( 'Server settings', 'health-check' ),
399
+ 'value' => __( 'Unable to determine some settings as the ini_get() function has been disabled', 'health-check' ),
400
+ );
401
+ } else {
402
+ $info['wp-server']['fields'][] = array(
403
+ 'label' => __( 'PHP max input variables', 'health-check' ),
404
+ 'value' => ini_get( 'max_input_vars' ),
405
+ );
406
+ $info['wp-server']['fields'][] = array(
407
+ 'label' => __( 'PHP time limit', 'health-check' ),
408
+ 'value' => ini_get( 'max_execution_time' ),
409
+ );
410
+ $info['wp-server']['fields'][] = array(
411
+ 'label' => __( 'PHP memory limit', 'health-check' ),
412
+ 'value' => ini_get( 'memory_limit' ),
413
+ );
414
+ $info['wp-server']['fields'][] = array(
415
+ 'label' => __( 'Max input time', 'health-check' ),
416
+ 'value' => ini_get( 'max_input_time' ),
417
+ );
418
+ $info['wp-server']['fields'][] = array(
419
+ 'label' => __( 'Upload max filesize', 'health-check' ),
420
+ 'value' => ini_get( 'upload_max_filesize' ),
421
+ );
422
+ $info['wp-server']['fields'][] = array(
423
+ 'label' => __( 'PHP post max size', 'health-check' ),
424
+ 'value' => ini_get( 'post_max_size' ),
425
+ );
426
+ }
427
+
428
+ if ( function_exists( 'curl_version' ) ) {
429
+ $curl = curl_version();
430
+ $info['wp-server']['fields'][] = array(
431
+ 'label' => __( 'cURL Version', 'health-check' ),
432
+ 'value' => sprintf( '%s %s', $curl['version'], $curl['ssl_version'] ),
433
+ );
434
+ } else {
435
+ $info['wp-server']['fields'][] = array(
436
+ 'label' => __( 'cURL Version', 'health-check' ),
437
+ 'value' => __( 'Your server does not support cURL', 'health-check' ),
438
+ );
439
+ }
440
+
441
+ $info['wp-server']['fields'][] = array(
442
+ 'label' => __( 'SUHOSIN installed', 'health-check' ),
443
+ 'value' => ( ( extension_loaded( 'suhosin' ) || ( defined( 'SUHOSIN_PATCH' ) && constant( 'SUHOSIN_PATCH' ) ) ) ? __( 'Yes', 'health-check' ) : __( 'No', 'health-check' ) ),
444
+ );
445
+
446
+ $info['wp-server']['fields'][] = array(
447
+ 'label' => __( 'Is the Imagick library available', 'health-check' ),
448
+ 'value' => ( extension_loaded( 'imagick' ) ? __( 'Yes', 'health-check' ) : __( 'No', 'health-check' ) ),
449
+ );
450
+
451
+ // Check if a .htaccess file exists.
452
+ if ( is_file( ABSPATH . '/.htaccess' ) ) {
453
+ // If the file exists, grab the content of it.
454
+ $htaccess_content = file_get_contents( ABSPATH . '/.htaccess' );
455
+
456
+ // Filter away the core WordPress rules.
457
+ $filtered_htaccess_content = trim( preg_replace( '/\# BEGIN WordPress[\s\S]+?# END WordPress/si', '', $htaccess_content ) );
458
+
459
+ $info['wp-server']['fields'][] = array(
460
+ 'label' => __( 'htaccess rules', 'health-check' ),
461
+ 'value' => ( ! empty( $filtered_htaccess_content ) ? __( 'Custom rules have been added to your htaccess file', 'health-check' ) : __( 'Your htaccess file only contains core WordPress features', 'health-check' ) ),
462
+ );
463
+ }
464
+
465
+ // Populate the database debug fields.
466
+ if ( is_resource( $wpdb->dbh ) ) {
467
+ // Old mysql extension.
468
+ $extension = 'mysql';
469
+ } elseif ( is_object( $wpdb->dbh ) ) {
470
+ // mysqli or PDO.
471
+ $extension = get_class( $wpdb->dbh );
472
+ } else {
473
+ // Unknown sql extension.
474
+ $extension = null;
475
+ }
476
+
477
+ if ( method_exists( $wpdb, 'db_version' ) ) {
478
+ if ( $wpdb->use_mysqli ) {
479
+ // phpcs:ignore WordPress.DB.RestrictedFunctions.mysql_mysqli_get_server_info
480
+ $server = mysqli_get_server_info( $wpdb->dbh );
481
+ } else {
482
+ // phpcs:ignore WordPress.DB.RestrictedFunctions.mysql_mysql_get_server_info
483
+ $server = mysql_get_server_info( $wpdb->dbh );
484
+ }
485
+ } else {
486
+ $server = null;
487
+ }
488
+
489
+ if ( isset( $wpdb->use_mysqli ) && $wpdb->use_mysqli ) {
490
+ $client_version = $wpdb->dbh->client_info;
491
+ } else {
492
+ // phpcs:ignore WordPress.DB.RestrictedFunctions.mysql_mysql_get_client_info
493
+ if ( preg_match( '|[0-9]{1,2}\.[0-9]{1,2}\.[0-9]{1,2}|', mysql_get_client_info(), $matches ) ) {
494
+ $client_version = $matches[0];
495
+ } else {
496
+ $client_version = null;
497
+ }
498
+ }
499
+
500
+ $info['wp-database']['fields'][] = array(
501
+ 'label' => __( 'Extension', 'health-check' ),
502
+ 'value' => $extension,
503
+ );
504
+ $info['wp-database']['fields'][] = array(
505
+ 'label' => __( 'Server version', 'health-check' ),
506
+ 'value' => $server,
507
+ );
508
+ $info['wp-database']['fields'][] = array(
509
+ 'label' => __( 'Client version', 'health-check' ),
510
+ 'value' => $client_version,
511
+ );
512
+ $info['wp-database']['fields'][] = array(
513
+ 'label' => __( 'Database user', 'health-check' ),
514
+ 'value' => $wpdb->dbuser,
515
+ 'private' => true,
516
+ );
517
+ $info['wp-database']['fields'][] = array(
518
+ 'label' => __( 'Database host', 'health-check' ),
519
+ 'value' => $wpdb->dbhost,
520
+ 'private' => true,
521
+ );
522
+ $info['wp-database']['fields'][] = array(
523
+ 'label' => __( 'Database name', 'health-check' ),
524
+ 'value' => $wpdb->dbname,
525
+ 'private' => true,
526
+ );
527
+ $info['wp-database']['fields'][] = array(
528
+ 'label' => __( 'Database prefix', 'health-check' ),
529
+ 'value' => $wpdb->prefix,
530
+ );
531
+
532
+ // List must use plugins if there are any.
533
+ $mu_plugins = get_mu_plugins();
534
+
535
+ foreach ( $mu_plugins as $plugin_path => $plugin ) {
536
+ $plugin_version = $plugin['Version'];
537
+ $plugin_author = $plugin['Author'];
538
+
539
+ $plugin_version_string = __( 'No version or author information available', 'health-check' );
540
+
541
+ if ( ! empty( $plugin_version ) && ! empty( $plugin_author ) ) {
542
+ // translators: %1$s: Plugin version number. %2$s: Plugin author name.
543
+ $plugin_version_string = sprintf( __( 'Version %1$s by %2$s', 'health-check' ), $plugin_version, $plugin_author );
544
+ }
545
+ if ( empty( $plugin_version ) && ! empty( $plugin_author ) ) {
546
+ // translators: %s: Plugin author name.
547
+ $plugin_version_string = sprintf( __( 'By %s', 'health-check' ), $plugin_author );
548
+ }
549
+ if ( ! empty( $plugin_version ) && empty( $plugin_author ) ) {
550
+ // translators: %s: Plugin version number.
551
+ $plugin_version_string = sprintf( __( 'Version %s', 'health-check' ), $plugin_version );
552
+ }
553
+
554
+ $info['wp-mu-plugins']['fields'][] = array(
555
+ 'label' => $plugin['Name'],
556
+ 'value' => $plugin_version_string,
557
+ );
558
+ }
559
+
560
+ // List all available plugins.
561
+ $plugins = get_plugins();
562
+ $plugin_updates = get_plugin_updates();
563
+
564
+ foreach ( $plugins as $plugin_path => $plugin ) {
565
+ $plugin_part = ( is_plugin_active( $plugin_path ) ) ? 'wp-plugins-active' : 'wp-plugins-inactive';
566
+
567
+ $plugin_version = $plugin['Version'];
568
+ $plugin_author = $plugin['Author'];
569
+
570
+ $plugin_version_string = __( 'No version or author information available', 'health-check' );
571
+
572
+ if ( ! empty( $plugin_version ) && ! empty( $plugin_author ) ) {
573
+ // translators: %1$s: Plugin version number. %2$s: Plugin author name.
574
+ $plugin_version_string = sprintf( __( 'Version %1$s by %2$s', 'health-check' ), $plugin_version, $plugin_author );
575
+ }
576
+ if ( empty( $plugin_version ) && ! empty( $plugin_author ) ) {
577
+ // translators: %s: Plugin author name.
578
+ $plugin_version_string = sprintf( __( 'By %s', 'health-check' ), $plugin_author );
579
+ }
580
+ if ( ! empty( $plugin_version ) && empty( $plugin_author ) ) {
581
+ // translators: %s: Plugin version number.
582
+ $plugin_version_string = sprintf( __( 'Version %s', 'health-check' ), $plugin_version );
583
+ }
584
+
585
+ if ( array_key_exists( $plugin_path, $plugin_updates ) ) {
586
+ // translators: %s: Latest plugin version number.
587
+ $plugin_update_needed = ' ' . sprintf( __( '( Latest version: %s )', 'health-check' ), $plugin_updates[ $plugin_path ]->update->new_version );
588
+ } else {
589
+ $plugin_update_needed = '';
590
+ }
591
+
592
+ $info[ $plugin_part ]['fields'][] = array(
593
+ 'label' => $plugin['Name'],
594
+ 'value' => $plugin_version_string . $plugin_update_needed,
595
+ );
596
+ }
597
+
598
+ // Populate the section for the currently active theme.
599
+ global $_wp_theme_features;
600
+ $theme_features = array();
601
+ if ( ! empty( $_wp_theme_features ) ) {
602
+ foreach ( $_wp_theme_features as $feature => $options ) {
603
+ $theme_features[] = $feature;
604
+ }
605
+ }
606
+
607
+ $active_theme = wp_get_theme();
608
+ $theme_updates = get_theme_updates();
609
+
610
+ if ( array_key_exists( $active_theme->stylesheet, $theme_updates ) ) {
611
+ // translators: %s: Latest theme version number.
612
+ $theme_update_needed_active = ' ' . sprintf( __( '( Latest version: %s )', 'health-check' ), $theme_updates[ $active_theme->stylesheet ]->update['new_version'] );
613
+ } else {
614
+ $theme_update_needed_active = '';
615
+ }
616
+
617
+ $info['wp-active-theme']['fields'] = array(
618
+ array(
619
+ 'label' => __( 'Name', 'health-check' ),
620
+ // phpcs:ignore WordPress.NamingConventions.ValidVariableName.NotSnakeCaseMemberVar
621
+ 'value' => $active_theme->Name,
622
+ ),
623
+ array(
624
+ 'label' => __( 'Version', 'health-check' ),
625
+ // phpcs:ignore WordPress.NamingConventions.ValidVariableName.NotSnakeCaseMemberVar
626
+ 'value' => $active_theme->Version . $theme_update_needed_active,
627
+ ),
628
+ array(
629
+ 'label' => __( 'Author', 'health-check' ),
630
+ // phpcs:ignore WordPress.NamingConventions.ValidVariableName.NotSnakeCaseMemberVar
631
+ 'value' => wp_kses( $active_theme->Author, array() ),
632
+ ),
633
+ array(
634
+ 'label' => __( 'Author website', 'health-check' ),
635
+ 'value' => ( $active_theme->offsetGet( 'Author URI' ) ? $active_theme->offsetGet( 'Author URI' ) : __( 'Undefined', 'health-check' ) ),
636
+ ),
637
+ array(
638
+ 'label' => __( 'Parent theme', 'health-check' ),
639
+ 'value' => ( $active_theme->parent_theme ? $active_theme->parent_theme : __( 'Not a child theme', 'health-check' ) ),
640
+ ),
641
+ array(
642
+ 'label' => __( 'Supported theme features', 'health-check' ),
643
+ 'value' => implode( ', ', $theme_features ),
644
+ ),
645
+ );
646
+
647
+ // Populate a list of all themes available in the install.
648
+ $all_themes = wp_get_themes();
649
+
650
+ foreach ( $all_themes as $theme_slug => $theme ) {
651
+ // Ignore the currently active theme from the list of all themes.
652
+ if ( $active_theme->stylesheet == $theme_slug ) {
653
+ continue;
654
+ }
655
+ // phpcs:ignore WordPress.NamingConventions.ValidVariableName.NotSnakeCaseMemberVar
656
+ $theme_version = $theme->Version;
657
+ // phpcs:ignore WordPress.NamingConventions.ValidVariableName.NotSnakeCaseMemberVar
658
+ $theme_author = $theme->Author;
659
+
660
+ $theme_version_string = __( 'No version or author information available', 'health-check' );
661
+
662
+ if ( ! empty( $theme_version ) && ! empty( $theme_author ) ) {
663
+ // translators: %1$s: Theme version number. %2$s: Theme author name.
664
+ $theme_version_string = sprintf( __( 'Version %1$s by %2$s', 'health-check' ), $theme_version, wp_kses( $theme_author, array() ) );
665
+ }
666
+ if ( empty( $theme_version ) && ! empty( $theme_author ) ) {
667
+ // translators: %s: Theme author name.
668
+ $theme_version_string = sprintf( __( 'By %s', 'health-check' ), wp_kses( $theme_author, array() ) );
669
+ }
670
+ if ( ! empty( $theme_version ) && empty( $theme_author ) ) {
671
+ // translators: %s: Theme version number.
672
+ $theme_version_string = sprintf( __( 'Version %s', 'health-check' ), $theme_version );
673
+ }
674
+
675
+ if ( array_key_exists( $theme_slug, $theme_updates ) ) {
676
+ // translators: %s: Latest theme version number.
677
+ $theme_update_needed = ' ' . sprintf( __( '( Latest version: %s )', 'health-check' ), $theme_updates[ $theme_slug ]->update['new_version'] );
678
+ } else {
679
+ $theme_update_needed = '';
680
+ }
681
+
682
+ $info['wp-themes']['fields'][] = array(
683
+ 'label' => sprintf(
684
+ // translators: %1$s: Theme name. %2$s: Theme slug.
685
+ __( '%1$s (%2$s)', 'health-check' ),
686
+ // phpcs:ignore WordPress.NamingConventions.ValidVariableName.NotSnakeCaseMemberVar
687
+ $theme->Name,
688
+ $theme_slug
689
+ ),
690
+ 'value' => $theme_version_string . $theme_update_needed,
691
+ );
692
+ }
693
+
694
+ // Add more filesystem checks
695
+ if ( defined( 'WPMU_PLUGIN_DIR' ) && is_dir( WPMU_PLUGIN_DIR ) ) {
696
+ $info['wp-filesystem']['fields'][] = array(
697
+ 'label' => __( 'The Must Use Plugins directory', 'health-check' ),
698
+ 'value' => ( wp_is_writable( WPMU_PLUGIN_DIR ) ? __( 'Writable', 'health-check' ) : __( 'Not writable', 'health-check' ) ),
699
+ );
700
+ }
701
+
702
+ $info['wp-install-size']['fields'] = Health_Check_Debug_Data::get_installation_size();
703
+
704
+ /**
705
+ * Add or modify new debug sections.
706
+ *
707
+ * Plugin or themes may wish to introduce their own debug information without creating additional admin pages for this
708
+ * kind of information as it is rarely needed, they can then utilize this filter to introduce their own sections.
709
+ *
710
+ * This filter intentionally does not include the fields introduced by core as those should always be un-modified
711
+ * and reliable for support related scenarios, take note that the core fields will take priority if a filtered value
712
+ * is trying to use the same array keys.
713
+ *
714
+ * Array keys added by core are all prefixed with `wp-`, plugins and themes are encouraged to use their own slug as
715
+ * a prefix, both for consistency as well as avoiding key collisions.
716
+ *
717
+ * @since 4.9.0
718
+ *
719
+ * @param array $args {
720
+ * The debug information to be added to the core information page.
721
+ *
722
+ * @type string $label The title for this section of the debug output.
723
+ * @type string $description Optional. A description for your information section which may contain basic HTML
724
+ * markup: `em`, `strong` and `a` for linking to documentation or putting emphasis.
725
+ * @type boolean $show_count Optional. If set to `true` the amount of fields will be included in the title for
726
+ * this section.
727
+ * @type boolean $private Optional. If set to `true` the section and all associated fields will be excluded
728
+ * from the copy-paste text area.
729
+ * @type array $fields {
730
+ * An associative array containing the data to be displayed.
731
+ *
732
+ * @type string $label The label for this piece of information.
733
+ * @type string $value The output that is of interest for this field.
734
+ * @type boolean $private Optional. If set to `true` the field will not be included in the copy-paste text area
735
+ * on top of the page, allowing you to show, for example, API keys here.
736
+ * }
737
+ * }
738
+ */
739
+ $external_info = apply_filters( 'debug_information', array() );
740
+
741
+ // Merge the core and external debug fields.
742
+ $info = array_replace_recursive( $info, array_replace_recursive( $external_info, $info ) );
743
+
744
+ if ( ! empty( $locale ) ) {
745
+ // Change the language used for translations
746
+ if ( function_exists( 'restore_previous_locale' ) && $switched_locale ) {
747
+ restore_previous_locale();
748
+ }
749
+ }
750
+
751
+ return $info;
752
+ }
753
+
754
+ /**
755
+ * Print the formatted variation of the information gathered for debugging, in a manner
756
+ * suitable for a text area that can be instantly copied to a forum or support ticket.
757
+ *
758
+ * @param array $info_array
759
+ *
760
+ * @return void
761
+ */
762
+ public static function textarea_format( $info_array ) {
763
+ echo "`\n";
764
+
765
+ foreach ( $info_array as $section => $details ) {
766
+ // Skip this section if there are no fields, or the section has been declared as private.
767
+ if ( empty( $details['fields'] ) || ( isset( $details['private'] ) && $details['private'] ) ) {
768
+ continue;
769
+ }
770
+
771
+ printf(
772
+ "### %s%s ###\n\n",
773
+ $details['label'],
774
+ ( isset( $details['show_count'] ) && $details['show_count'] ? sprintf( ' (%d)', count( $details['fields'] ) ) : '' )
775
+ );
776
+
777
+ foreach ( $details['fields'] as $field ) {
778
+ if ( isset( $field['private'] ) && true === $field['private'] ) {
779
+ continue;
780
+ }
781
+
782
+ $values = $field['value'];
783
+ if ( is_array( $field['value'] ) ) {
784
+ $values = '';
785
+
786
+ foreach ( $field['value'] as $name => $value ) {
787
+ $values .= sprintf(
788
+ "\n\t%s: %s",
789
+ $name,
790
+ $value
791
+ );
792
+ }
793
+ }
794
+
795
+ printf(
796
+ "%s: %s\n",
797
+ $field['label'],
798
+ $values
799
+ );
800
+ }
801
+ echo "\n";
802
+ }
803
+ echo '`';
804
+ }
805
+
806
+ public static function get_installation_size() {
807
+ $uploads_dir = wp_upload_dir();
808
+
809
+ $sizes = array(
810
+ 'wp' => array(
811
+ 'path' => ABSPATH,
812
+ 'size' => 0,
813
+ ),
814
+ 'themes' => array(
815
+ 'path' => trailingslashit( get_theme_root() ),
816
+ 'size' => 0,
817
+ ),
818
+ 'plugins' => array(
819
+ 'path' => WP_PLUGIN_DIR,
820
+ 'size' => 0,
821
+ ),
822
+ 'uploads' => array(
823
+ 'path' => $uploads_dir['basedir'],
824
+ 'size' => 0,
825
+ ),
826
+ );
827
+
828
+ $inaccurate = false;
829
+
830
+ foreach ( $sizes as $size => $attributes ) {
831
+ try {
832
+ $sizes[ $size ]['size'] = Health_Check_Debug_Data::get_directory_size( $attributes['path'] );
833
+ } catch ( Exception $e ) {
834
+ $inaccurate = true;
835
+ }
836
+ }
837
+
838
+ $size_db = Health_Check_Debug_Data::get_database_size();
839
+
840
+ $size_total = $sizes['wp']['size'] + $size_db;
841
+
842
+ $result = array(
843
+ array(
844
+ 'label' => __( 'Uploads Directory', 'health-check' ),
845
+ 'value' => size_format( $sizes['uploads']['size'], 2 ),
846
+ ),
847
+ array(
848
+ 'label' => __( 'Themes Directory', 'health-check' ),
849
+ 'value' => size_format( $sizes['themes']['size'], 2 ),
850
+ ),
851
+ array(
852
+ 'label' => __( 'Plugins Directory', 'health-check' ),
853
+ 'value' => size_format( $sizes['plugins']['size'], 2 ),
854
+ ),
855
+ array(
856
+ 'label' => __( 'Database size', 'health-check' ),
857
+ 'value' => size_format( $size_db, 2 ),
858
+ ),
859
+ array(
860
+ 'label' => __( 'Whole WordPress Directory', 'health-check' ),
861
+ 'value' => size_format( $sizes['wp']['size'], 2 ),
862
+ ),
863
+ array(
864
+ 'label' => __( 'Total installation size', 'health-check' ),
865
+ 'value' => sprintf(
866
+ '%s%s',
867
+ size_format( $size_total, 2 ),
868
+ ( false === $inaccurate ? '' : __( '- Some errors, likely caused by invalid permissions, were encountered when determining the size of your installation. This means the values represented may be inaccurate.', 'health-check' ) )
869
+ ),
870
+ ),
871
+ );
872
+
873
+ return $result;
874
+ }
875
+
876
+ public static function get_directory_size( $path ) {
877
+ $size = 0;
878
+
879
+ foreach ( new RecursiveIteratorIterator( new RecursiveDirectoryIterator( $path ) ) as $file ) {
880
+ $size += $file->getSize();
881
+ }
882
+
883
+ return $size;
884
+ }
885
+
886
+ public static function get_database_size() {
887
+ global $wpdb;
888
+ $size = 0;
889
+ $rows = $wpdb->get_results( 'SHOW TABLE STATUS', ARRAY_A );
890
+
891
+ if ( $wpdb->num_rows > 0 ) {
892
+ foreach ( $rows as $row ) {
893
+ $size += $row['Data_length'] + $row['Index_length'];
894
+ }
895
+ }
896
+
897
+ return $size;
898
+ }
899
+ }
includes/class-health-check-files-integrity.php CHANGED
@@ -1,224 +1,236 @@
1
- <?php
2
-
3
- /**
4
- * Check all core files against the checksums provided by WordPress API.
5
- *
6
- * @package Health Check
7
- */
8
-
9
- /**
10
- * Class Files_Integrity
11
- */
12
- class Health_Check_Files_Integrity {
13
-
14
- /**
15
- * Gathers checksums from WordPress API and cross checks the core files in the current installation.
16
- *
17
- * @return void
18
- */
19
- static function run_files_integrity_check() {
20
-
21
- $checksums = Health_Check_Files_Integrity::call_checksum_api();
22
-
23
- $files = Health_Check_Files_Integrity::parse_checksum_results( $checksums );
24
-
25
- Health_Check_Files_Integrity::create_the_response( $files );
26
-
27
- }
28
-
29
- /**
30
- * Calls the WordPress API on the checksums endpoint
31
- *
32
- * @uses get_bloginfo()
33
- * @uses get_locale()
34
- * @uses ABSPATH
35
- * @uses wp_remote_get()
36
- * @uses get_bloginfo()
37
- * @uses strpos()
38
- * @uses unset()
39
- *
40
- * @return array
41
- */
42
- static function call_checksum_api() {
43
- // Setup variables.
44
- $wpversion = get_bloginfo( 'version' );
45
- $wplocale = get_locale();
46
-
47
- // Setup API Call.
48
- $checksumapi = wp_remote_get( 'https://api.wordpress.org/core/checksums/1.0/?version=' . $wpversion . '&locale=' . $wplocale, array( 'timeout' => 10000 ) );
49
-
50
- // Encode the API response body.
51
- $checksumapibody = json_decode( wp_remote_retrieve_body( $checksumapi ), true );
52
-
53
- // Remove the wp-content/ files from checking
54
- foreach ( $checksumapibody['checksums'] as $file => $checksum ) {
55
- if ( false !== strpos( $file, 'wp-content/' ) ) {
56
- unset( $checksumapibody['checksums'][ $file ] );
57
- }
58
- }
59
-
60
- return $checksumapibody;
61
- }
62
-
63
- /**
64
- * Parses the results from the WordPress API call
65
- *
66
- * @uses file_exists()
67
- * @uses md5_file()
68
- * @uses ABSPATH
69
- *
70
- * @param array $checksums
71
- *
72
- * @return array
73
- */
74
- static function parse_checksum_results( $checksums ) {
75
- $filepath = ABSPATH;
76
- $files = array();
77
- // Parse the results.
78
- foreach ( $checksums['checksums'] as $file => $checksum ) {
79
- // Check the files.
80
- if ( file_exists( $filepath . $file ) && md5_file( $filepath . $file ) !== $checksum ) {
81
- $reason = esc_html__( 'Content changed', 'health-check' ) . ' <a href="#health-check-diff" data-file="' . $file . '">' . esc_html__( '(View Diff)', 'health-check' ) . '</a>';
82
- array_push( $files, array( $file, $reason ) );
83
- } elseif ( ! file_exists( $filepath . $file ) ) {
84
- $reason = esc_html__( 'File not found', 'health-check' );
85
- array_push( $files, array( $file, $reason ) );
86
- }
87
- }
88
- return $files;
89
- }
90
-
91
- /**
92
- * Generates the response
93
- *
94
- * @uses wp_send_json_success()
95
- * @uses wp_die()
96
- * @uses ABSPATH
97
- *
98
- * @param null|array $files
99
- *
100
- * @return void
101
- */
102
- static function create_the_response( $files ) {
103
- $filepath = ABSPATH;
104
- $output = '';
105
-
106
- if ( empty( $files ) ) {
107
- $output .= '<div class="notice notice-success inline"><p>';
108
- $output .= esc_html__( 'All files passed the check. Everything seems to be ok!', 'health-check' );
109
- $output .= '</p></div>';
110
- } else {
111
- $output .= '<div class="notice notice-error inline"><p>';
112
- $output .= esc_html__( 'It appears as if some files may have been modified.', 'health-check' );
113
- $output .= '<br>' . esc_html__( 'One possible reason for this may be that your installation contains translated versions. An easy way to clear this is to reinstall WordPress. Don\'t worry. This will only affect WordPress\' own files, not your themes, plugins or uploaded media.', 'health-check' );
114
- $output .= '</p></div><table class="widefat striped file-integrity-table"><thead><tr><th>';
115
- $output .= esc_html__( 'Status', 'health-check' );
116
- $output .= '</th><th>';
117
- $output .= esc_html__( 'File', 'health-check' );
118
- $output .= '</th><th>';
119
- $output .= esc_html__( 'Reason', 'health-check' );
120
- $output .= '</th></tr></thead><tfoot><tr><td>';
121
- $output .= esc_html__( 'Status', 'health-check' );
122
- $output .= '</td><td>';
123
- $output .= esc_html__( 'File', 'health-check' );
124
- $output .= '</td><td>';
125
- $output .= esc_html__( 'Reason', 'health-check' );
126
- $output .= '</td></tr></tfoot><tbody>';
127
- foreach ( $files as $tampered ) {
128
- $output .= '<tr>';
129
- $output .= '<td><span class="error"></span></td>';
130
- $output .= '<td>' . $filepath . $tampered[0] . '</td>';
131
- $output .= '<td>' . $tampered[1] . '</td>';
132
- $output .= '</tr>';
133
- }
134
- $output .= '</tbody>';
135
- $output .= '</table>';
136
- }
137
-
138
- $response = array(
139
- 'message' => $output,
140
- );
141
-
142
- wp_send_json_success( $response );
143
-
144
- wp_die();
145
- }
146
-
147
- /**
148
- * Generates Diff view
149
- *
150
- * @uses get_bloginfo()
151
- * @uses wp_remote_get()
152
- * @uses wp_remote_retrieve_body()
153
- * @uses wp_send_json_success()
154
- * @uses wp_die()
155
- * @uses ABSPATH
156
- * @uses FILE_USE_INCLUDE_PATH
157
- * @uses wp_text_diff()
158
- *
159
- *
160
- * @return void
161
- */
162
- static function view_file_diff() {
163
- $filepath = ABSPATH;
164
- $file = $_POST['file'];
165
- $wpversion = get_bloginfo( 'version' );
166
- $local_file_body = file_get_contents( $filepath . $file, FILE_USE_INCLUDE_PATH );
167
- $remote_file = wp_remote_get( 'https://core.svn.wordpress.org/tags/' . $wpversion . '/' . $file );
168
- $remote_file_body = wp_remote_retrieve_body( $remote_file );
169
- $diff_args = array(
170
- 'show_split_view' => true,
171
- );
172
-
173
- $output = '<table class="diff"><thead><tr class="diff-sub-title"><th>';
174
- $output .= esc_html__( 'Original', 'health-check' );
175
- $output .= '</th><th>';
176
- $output .= esc_html__( 'Modified', 'health-check' );
177
- $output .= '</th></tr></table>';
178
- $output .= wp_text_diff( $remote_file_body, $local_file_body, $diff_args );
179
- $response = array(
180
- 'message' => $output,
181
- );
182
-
183
- wp_send_json_success( $response );
184
-
185
- wp_die();
186
- }
187
-
188
- /**
189
- * Add the Files integrity checker to the tools tab.
190
- *
191
- * @param array $tabs
192
- *
193
- * return array
194
- */
195
- static function tools_tab( $tabs ) {
196
- ob_start();
197
- ?>
198
-
199
- <div>
200
- <p>
201
- <?php _e( 'The File Integrity checks all the core files with the <code>checksums</code> provided by the WordPress API to see if they are intact. If there are changes you will be able to make a Diff between the files hosted on WordPress.org and your installation to see what has been changed.', 'health-check' ); ?>
202
- </p>
203
- <form action="#" id="health-check-file-integrity" method="POST">
204
- <p>
205
- <input type="submit" class="button button-primary" value="<?php esc_html_e( 'Check the Files Integrity', 'health-check' ); ?>">
206
- </p>
207
- </form>
208
-
209
- <div id="tools-file-integrity-response-holder">
210
- <span class="spinner"></span>
211
- </div>
212
- </div>
213
-
214
- <?php
215
- $tab_content = ob_get_clean();
216
-
217
- $tabs[] = array(
218
- 'label' => esc_html__( 'File Integrity', 'health-check' ),
219
- 'content' => $tab_content,
220
- );
221
-
222
- return $tabs;
223
- }
224
- }
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Check all core files against the checksums provided by WordPress API.
5
+ *
6
+ * @package Health Check
7
+ */
8
+
9
+ /**
10
+ * Class Files_Integrity
11
+ */
12
+ class Health_Check_Files_Integrity {
13
+
14
+ /**
15
+ * Gathers checksums from WordPress API and cross checks the core files in the current installation.
16
+ *
17
+ * @return void
18
+ */
19
+ static function run_files_integrity_check() {
20
+ check_ajax_referer( 'health-check-files-integrity-check' );
21
+
22
+ $checksums = Health_Check_Files_Integrity::call_checksum_api();
23
+
24
+ $files = Health_Check_Files_Integrity::parse_checksum_results( $checksums );
25
+
26
+ Health_Check_Files_Integrity::create_the_response( $files );
27
+
28
+ }
29
+
30
+ /**
31
+ * Calls the WordPress API on the checksums endpoint
32
+ *
33
+ * @uses get_bloginfo()
34
+ * @uses get_locale()
35
+ * @uses ABSPATH
36
+ * @uses wp_remote_get()
37
+ * @uses get_bloginfo()
38
+ * @uses strpos()
39
+ * @uses unset()
40
+ *
41
+ * @return array
42
+ */
43
+ static function call_checksum_api() {
44
+ // Setup variables.
45
+ $wpversion = get_bloginfo( 'version' );
46
+ $wplocale = get_locale();
47
+
48
+ // Setup API Call.
49
+ $checksumapi = wp_remote_get( 'https://api.wordpress.org/core/checksums/1.0/?version=' . $wpversion . '&locale=' . $wplocale, array( 'timeout' => 10000 ) );
50
+
51
+ // Encode the API response body.
52
+ $checksumapibody = json_decode( wp_remote_retrieve_body( $checksumapi ), true );
53
+
54
+ // Remove the wp-content/ files from checking
55
+ foreach ( $checksumapibody['checksums'] as $file => $checksum ) {
56
+ if ( false !== strpos( $file, 'wp-content/' ) ) {
57
+ unset( $checksumapibody['checksums'][ $file ] );
58
+ }
59
+ }
60
+
61
+ return $checksumapibody;
62
+ }
63
+
64
+ /**
65
+ * Parses the results from the WordPress API call
66
+ *
67
+ * @uses file_exists()
68
+ * @uses md5_file()
69
+ * @uses ABSPATH
70
+ *
71
+ * @param array $checksums
72
+ *
73
+ * @return array
74
+ */
75
+ static function parse_checksum_results( $checksums ) {
76
+ $filepath = ABSPATH;
77
+ $files = array();
78
+ // Parse the results.
79
+ foreach ( $checksums['checksums'] as $file => $checksum ) {
80
+ // Check the files.
81
+ if ( file_exists( $filepath . $file ) && md5_file( $filepath . $file ) !== $checksum ) {
82
+ $reason = esc_html__( 'Content changed', 'health-check' ) . ' <a href="#health-check-diff" data-file="' . $file . '">' . esc_html__( '(View Diff)', 'health-check' ) . '</a>';
83
+ array_push( $files, array( $file, $reason ) );
84
+ } elseif ( ! file_exists( $filepath . $file ) ) {
85
+ $reason = esc_html__( 'File not found', 'health-check' );
86
+ array_push( $files, array( $file, $reason ) );
87
+ }
88
+ }
89
+ return $files;
90
+ }
91
+
92
+ /**
93
+ * Generates the response
94
+ *
95
+ * @uses wp_send_json_success()
96
+ * @uses wp_die()
97
+ * @uses ABSPATH
98
+ *
99
+ * @param null|array $files
100
+ *
101
+ * @return void
102
+ */
103
+ static function create_the_response( $files ) {
104
+ $filepath = ABSPATH;
105
+ $output = '';
106
+
107
+ if ( empty( $files ) ) {
108
+ $output .= '<div class="notice notice-success inline"><p>';
109
+ $output .= esc_html__( 'All files passed the check. Everything seems to be ok!', 'health-check' );
110
+ $output .= '</p></div>';
111
+ } else {
112
+ $output .= '<div class="notice notice-error inline"><p>';
113
+ $output .= esc_html__( 'It appears as if some files may have been modified.', 'health-check' );
114
+ $output .= '<br>' . esc_html__( 'One possible reason for this may be that your installation contains translated versions. An easy way to clear this is to reinstall WordPress. Don\'t worry. This will only affect WordPress\' own files, not your themes, plugins or uploaded media.', 'health-check' );
115
+ $output .= '</p></div><table class="widefat striped file-integrity-table"><thead><tr><th>';
116
+ $output .= esc_html__( 'Status', 'health-check' );
117
+ $output .= '</th><th>';
118
+ $output .= esc_html__( 'File', 'health-check' );
119
+ $output .= '</th><th>';
120
+ $output .= esc_html__( 'Reason', 'health-check' );
121
+ $output .= '</th></tr></thead><tfoot><tr><td>';
122
+ $output .= esc_html__( 'Status', 'health-check' );
123
+ $output .= '</td><td>';
124
+ $output .= esc_html__( 'File', 'health-check' );
125
+ $output .= '</td><td>';
126
+ $output .= esc_html__( 'Reason', 'health-check' );
127
+ $output .= '</td></tr></tfoot><tbody>';
128
+ foreach ( $files as $tampered ) {
129
+ $output .= '<tr>';
130
+ $output .= '<td><span class="error"></span></td>';
131
+ $output .= '<td>' . $filepath . $tampered[0] . '</td>';
132
+ $output .= '<td>' . $tampered[1] . '</td>';
133
+ $output .= '</tr>';
134
+ }
135
+ $output .= '</tbody>';
136
+ $output .= '</table>';
137
+ }
138
+
139
+ $response = array(
140
+ 'message' => $output,
141
+ );
142
+
143
+ wp_send_json_success( $response );
144
+
145
+ wp_die();
146
+ }
147
+
148
+ /**
149
+ * Generates Diff view
150
+ *
151
+ * @uses get_bloginfo()
152
+ * @uses wp_remote_get()
153
+ * @uses wp_remote_retrieve_body()
154
+ * @uses wp_send_json_success()
155
+ * @uses wp_die()
156
+ * @uses ABSPATH
157
+ * @uses FILE_USE_INCLUDE_PATH
158
+ * @uses wp_text_diff()
159
+ *
160
+ *
161
+ * @return void
162
+ */
163
+ static function view_file_diff() {
164
+ check_ajax_referer( 'health-check-view-file-diff' );
165
+
166
+ if ( ! current_user_can( 'manage_options' ) ) {
167
+ wp_send_json_error();
168
+ }
169
+
170
+ $filepath = ABSPATH;
171
+ $file = $_POST['file'];
172
+ $wpversion = get_bloginfo( 'version' );
173
+
174
+ if ( 0 !== validate_file( $filepath . $file ) ) {
175
+ wp_send_json_error();
176
+ }
177
+
178
+ $local_file_body = file_get_contents( $filepath . $file, FILE_USE_INCLUDE_PATH );
179
+ $remote_file = wp_remote_get( 'https://core.svn.wordpress.org/tags/' . $wpversion . '/' . $file );
180
+ $remote_file_body = wp_remote_retrieve_body( $remote_file );
181
+ $diff_args = array(
182
+ 'show_split_view' => true,
183
+ );
184
+
185
+ $output = '<table class="diff"><thead><tr class="diff-sub-title"><th>';
186
+ $output .= esc_html__( 'Original', 'health-check' );
187
+ $output .= '</th><th>';
188
+ $output .= esc_html__( 'Modified', 'health-check' );
189
+ $output .= '</th></tr></table>';
190
+ $output .= wp_text_diff( $remote_file_body, $local_file_body, $diff_args );
191
+ $response = array(
192
+ 'message' => $output,
193
+ );
194
+
195
+ wp_send_json_success( $response );
196
+
197
+ wp_die();
198
+ }
199
+
200
+ /**
201
+ * Add the Files integrity checker to the tools tab.
202
+ *
203
+ * @param array $tabs
204
+ *
205
+ * @return array
206
+ */
207
+ static function tools_tab( $tabs ) {
208
+ ob_start();
209
+ ?>
210
+
211
+ <div>
212
+ <p>
213
+ <?php _e( 'The File Integrity checks all the core files with the <code>checksums</code> provided by the WordPress API to see if they are intact. If there are changes you will be able to make a Diff between the files hosted on WordPress.org and your installation to see what has been changed.', 'health-check' ); ?>
214
+ </p>
215
+ <form action="#" id="health-check-file-integrity" method="POST">
216
+ <p>
217
+ <input type="submit" class="button button-primary" value="<?php esc_html_e( 'Check the Files Integrity', 'health-check' ); ?>">
218
+ </p>
219
+ </form>
220
+
221
+ <div id="tools-file-integrity-response-holder">
222
+ <span class="spinner"></span>
223
+ </div>
224
+ </div>
225
+
226
+ <?php
227
+ $tab_content = ob_get_clean();
228
+
229
+ $tabs[] = array(
230
+ 'label' => esc_html__( 'File Integrity', 'health-check' ),
231
+ 'content' => $tab_content,
232
+ );
233
+
234
+ return $tabs;
235
+ }
236
+ }
includes/class-health-check-loopback.php CHANGED
@@ -1,323 +1,341 @@
1
- <?php
2
- /**
3
- * Tests to determine if the WordPress loopbacks are able to run unhindered.
4
- *
5
- * @package Health Check
6
- */
7
-
8
- /**
9
- * Class Health_Check_Loopback
10
- */
11
- class Health_Check_Loopback {
12
- /**
13
- * Run a loopback test on our site.
14
- *
15
- * @uses wp_unslash()
16
- * @uses base64_encode()
17
- * @uses admin_url()
18
- * @uses add_query_arg()
19
- * @uses is_array()
20
- * @uses implode()
21
- * @uses wp_remote_get()
22
- * @uses compact()
23
- * @uses is_wp_error()
24
- * @uses wp_remote_retrieve_response_code()
25
- * @uses sprintf()
26
- *
27
- * @param null|string $disable_plugin_hash Optional. A hash to send with our request to disable any plugins.
28
- * @param null|string|array $allowed_plugins Optional. A string or array of approved plugin slugs that can run even when we globally ignore plugins.
29
- *
30
- * @return object
31
- */
32
- static function can_perform_loopback( $disable_plugin_hash = null, $allowed_plugins = null ) {
33
- $cookies = wp_unslash( $_COOKIE );
34
- $timeout = 10;
35
- $headers = array(
36
- 'Cache-Control' => 'no-cache',
37
- );
38
-
39
- // Include Basic auth in loopback requests.
40
- if ( isset( $_SERVER['PHP_AUTH_USER'] ) && isset( $_SERVER['PHP_AUTH_PW'] ) ) {
41
- $headers['Authorization'] = 'Basic ' . base64_encode( wp_unslash( $_SERVER['PHP_AUTH_USER'] ) . ':' . wp_unslash( $_SERVER['PHP_AUTH_PW'] ) );
42
- }
43
-
44
- $url = admin_url();
45
-
46
- if ( ! empty( $disable_plugin_hash ) ) {
47
- $url = add_query_arg( array(
48
- 'health-check-disable-plugin-hash' => $disable_plugin_hash,
49
- ), $url );
50
- }
51
- if ( ! empty( $allowed_plugins ) ) {
52
- if ( ! is_array( $allowed_plugins ) ) {
53
- $allowed_plugins = (array) $allowed_plugins;
54
- }
55
-
56
- $url = add_query_arg(
57
- array(
58
- 'health-check-allowed-plugins' => implode( ',', $allowed_plugins ),
59
- ),
60
- $url
61
- );
62
- }
63
-
64
- $r = wp_remote_get( $url, compact( 'cookies', 'headers', 'timeout' ) );
65
-
66
- if ( is_wp_error( $r ) ) {
67
- return (object) array(
68
- 'status' => 'error',
69
- 'message' => sprintf(
70
- '%s<br>%s',
71
- esc_html__( 'The loopback request to your site failed, this may prevent WP_Cron from working, along with theme and plugin editors.', 'health-check' ),
72
- sprintf(
73
- /* translators: %1$d: The HTTP response code. %2$s: The error message returned. */
74
- esc_html__( 'Error encountered: (%1$d) %2$s', 'health-check' ),
75
- wp_remote_retrieve_response_code( $r ),
76
- $r->get_error_message()
77
- )
78
- ),
79
- );
80
- }
81
-
82
- if ( 200 !== wp_remote_retrieve_response_code( $r ) ) {
83
- return (object) array(
84
- 'status' => 'warning',
85
- 'message' => sprintf(
86
- /* translators: %d: The HTTP response code returned. */
87
- esc_html__( 'The loopback request returned an unexpected status code, %d, this may affect tools such as WP_Cron, or theme and plugin editors.', 'health-check' ),
88
- wp_remote_retrieve_response_code( $r )
89
- ),
90
- );
91
- }
92
-
93
- return (object) array(
94
- 'status' => 'good',
95
- 'message' => __( 'The loopback request to your site completed successfully.', 'health-check' ),
96
- );
97
- }
98
-
99
- /**
100
- * Perform the loopback check, but ensure no plugins are enabled when we do so.
101
- *
102
- * @uses ob_start()
103
- * @uses Health_Check_Troubleshoot::mu_plugin_exists()
104
- * @uses Health_Check::get_filesystem_credentials()
105
- * @uses Health_Check_Troubleshoot::setup_must_use_plugin()
106
- * @uses Health_Check_Troubleshoot::maybe_update_must_use_plugin()
107
- * @uses ob_get_clean()
108
- * @uses wp_send_json_error()
109
- * @uses md5()
110
- * @uses rand()
111
- * @uses update_option()
112
- * @uses Health_Check_Loopback::can_perform_loopback()
113
- * @uses sprintf()
114
- * @uses esc_attr()
115
- * @uses esc_html__()
116
- * @uses esc_html()
117
- * @uses wp_send_json_success()
118
- *
119
- * @return void
120
- */
121
- static function loopback_no_plugins() {
122
- ob_start();
123
-
124
- $needs_creds = false;
125
-
126
- if ( ! Health_Check_Troubleshoot::mu_plugin_exists() ) {
127
- if ( ! Health_Check::get_filesystem_credentials() ) {
128
- $needs_creds = true;
129
- } else {
130
- $check_output = Health_Check_Troubleshoot::setup_must_use_plugin();
131
- if ( false === $check_output ) {
132
- $needs_creds = true;
133
- }
134
- }
135
- } else {
136
- if ( ! Health_Check_Troubleshoot::maybe_update_must_use_plugin() ) {
137
- $needs_creds = true;
138
- }
139
- }
140
-
141
- $result = ob_get_clean();
142
-
143
- if ( $needs_creds ) {
144
- wp_send_json_error( $result );
145
- die();
146
- }
147
-
148
- $loopback_hash = md5( rand() );
149
- update_option( 'health-check-disable-plugin-hash', $loopback_hash );
150
- update_option( 'health-check-default-theme', 'yes' );
151
-
152
- $no_plugin_test = Health_Check_Loopback::can_perform_loopback( $loopback_hash );
153
-
154
- $message = sprintf(
155
- '<br><span class="%s"></span> %s: %s',
156
- esc_attr( $no_plugin_test->status ),
157
- esc_html__( 'Result from testing without any plugins active and a default theme', 'health-check' ),
158
- $no_plugin_test->message
159
- );
160
-
161
- if ( 'error' !== $no_plugin_test->status ) {
162
- $plugins = wp_get_active_and_valid_plugins();
163
- $theme = wp_get_theme();
164
-
165
- $message .= '<table id="loopback-individual-plugins-list">';
166
-
167
- foreach ( $plugins as $single_plugin ) {
168
- $plugin = get_plugin_data( $single_plugin );
169
-
170
- $message .= sprintf(
171
- '<tr data-test-plugin="%s" class="not-tested"><td>%s</td><td class="individual-loopback-test-status">%s</td></tr>',
172
- esc_attr( plugin_basename( $single_plugin ) ),
173
- esc_html( $plugin['Name'] ),
174
- esc_html__( 'Waiting...', 'health-check' )
175
- );
176
- }
177
-
178
- $message .= sprintf(
179
- '<tr id="test-single-no-theme"><td>%s</td><td class="individual-loopback-test-status">%s</td></tr>',
180
- sprintf(
181
- // translators: %s: The active theme name.
182
- esc_html__( 'Active theme: %s', 'health-check' ),
183
- $theme->name
184
- ),
185
- esc_html__( 'Waiting...', 'health-check' )
186
- );
187
-
188
- $message .= '</table>';
189
-
190
- $message .= '<br><button type="button" id="loopback-individual-plugins" class="button button-primary">Test individual plugins</button>';
191
- }
192
-
193
- $response = array(
194
- 'message' => $message,
195
- );
196
-
197
- delete_option( 'health-check-default-theme' );
198
-
199
- wp_send_json_success( $response );
200
-
201
- die();
202
- }
203
-
204
- /**
205
- * Test individual plugins for loopback compatibility issues.
206
- *
207
- * This function will perform the loopback check, without any plugins, then conditionally enables one plugin at a time.
208
- *
209
- * @uses ob_start()
210
- * @uses Health_Check_Troubleshoot::mu_plugin_exists()
211
- * @uses Health_Check::get_filesystem_credentials()
212
- * @uses Health_Check_Troubleshoot::setup_must_use_plugin()
213
- * @uses ob_get_clean()
214
- * @uses wp_send_json_error()
215
- * @uses delete_option()
216
- * @uses get_option()
217
- * @uses md5()
218
- * @uses rand()
219
- * @uses update_option()
220
- * @uses explode()
221
- * @uses Health_Check_Loopback::can_perform_loopback()
222
- * @uses sprintf()
223
- * @uses esc_attr()
224
- * @uses esc_html__()
225
- * @uses esc_html()
226
- * @uses wp_send_json_success()
227
- *
228
- * @return void
229
- */
230
- static function loopback_test_individual_plugins() {
231
- ob_start();
232
-
233
- $needs_creds = false;
234
-
235
- if ( ! Health_Check_Troubleshoot::mu_plugin_exists() ) {
236
- if ( ! Health_Check::get_filesystem_credentials() ) {
237
- $needs_creds = true;
238
- } else {
239
- Health_Check_Troubleshoot::setup_must_use_plugin();
240
- }
241
- }
242
-
243
- $result = ob_get_clean();
244
-
245
- if ( $needs_creds ) {
246
- wp_send_json_error( $result );
247
- die();
248
- }
249
-
250
- delete_option( 'health-check-disable-plugin-hash' );
251
-
252
- $loopback_hash = md5( rand() );
253
- update_option( 'health-check-disable-plugin-hash', $loopback_hash );
254
-
255
- $plugin_slug = explode( '/', $_POST['plugin'] );
256
- $plugin_slug = $plugin_slug[0];
257
-
258
- $single_test = Health_Check_Loopback::can_perform_loopback( $loopback_hash, $plugin_slug );
259
-
260
- $message = sprintf(
261
- '<span class="%s"></span> %s',
262
- esc_attr( $single_test->status ),
263
- $single_test->message
264
- );
265
-
266
- $response = array(
267
- 'message' => $message,
268
- );
269
-
270
- wp_send_json_success( $response );
271
-
272
- die();
273
- }
274
-
275
- static function loopback_test_default_theme() {
276
- ob_start();
277
-
278
- $needs_creds = false;
279
-
280
- if ( ! Health_Check_Troubleshoot::mu_plugin_exists() ) {
281
- if ( ! Health_Check::get_filesystem_credentials() ) {
282
- $needs_creds = true;
283
- } else {
284
- Health_Check_Troubleshoot::setup_must_use_plugin();
285
- }
286
- }
287
-
288
- $result = ob_get_clean();
289
-
290
- if ( $needs_creds ) {
291
- wp_send_json_error( $result );
292
- die();
293
- }
294
-
295
- delete_option( 'health-check-disable-plugin-hash' );
296
-
297
- $loopback_hash = md5( rand() );
298
- update_option( 'health-check-disable-plugin-hash', $loopback_hash );
299
-
300
- $message = '';
301
-
302
- // Test without a theme active.
303
- update_option( 'health-check-default-theme', 'yes' );
304
-
305
- $theme_test = Health_Check_Loopback::can_perform_loopback( $loopback_hash, '' );
306
-
307
- $message .= sprintf(
308
- '<span class="%s"></span> %s',
309
- esc_attr( $theme_test->status ),
310
- $theme_test->message
311
- );
312
-
313
- delete_option( 'health-check-default-theme' );
314
-
315
- $response = array(
316
- 'message' => $message,
317
- );
318
-
319
- wp_send_json_success( $response );
320
-
321
- die();
322
- }
323
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Tests to determine if the WordPress loopbacks are able to run unhindered.
4
+ *
5
+ * @package Health Check
6
+ */
7
+
8
+ /**
9
+ * Class Health_Check_Loopback
10
+ */
11
+ class Health_Check_Loopback {
12
+ /**
13
+ * Run a loopback test on our site.
14
+ *
15
+ * @uses wp_unslash()
16
+ * @uses base64_encode()
17
+ * @uses admin_url()
18
+ * @uses add_query_arg()
19
+ * @uses is_array()
20
+ * @uses implode()
21
+ * @uses wp_remote_get()
22
+ * @uses compact()
23
+ * @uses is_wp_error()
24
+ * @uses wp_remote_retrieve_response_code()
25
+ * @uses sprintf()
26
+ *
27
+ * @param null|string $disable_plugin_hash Optional. A hash to send with our request to disable any plugins.
28
+ * @param null|string|array $allowed_plugins Optional. A string or array of approved plugin slugs that can run even when we globally ignore plugins.
29
+ *
30
+ * @return object
31
+ */
32
+ static function can_perform_loopback( $disable_plugin_hash = null, $allowed_plugins = null ) {
33
+ $cookies = wp_unslash( $_COOKIE );
34
+ $timeout = 10;
35
+ $headers = array(
36
+ 'Cache-Control' => 'no-cache',
37
+ );
38
+
39
+ // Include Basic auth in loopback requests.
40
+ if ( isset( $_SERVER['PHP_AUTH_USER'] ) && isset( $_SERVER['PHP_AUTH_PW'] ) ) {
41
+ $headers['Authorization'] = 'Basic ' . base64_encode( wp_unslash( $_SERVER['PHP_AUTH_USER'] ) . ':' . wp_unslash( $_SERVER['PHP_AUTH_PW'] ) );
42
+ }
43
+
44
+ $url = admin_url();
45
+
46
+ if ( ! empty( $disable_plugin_hash ) ) {
47
+ $url = add_query_arg( array(
48
+ 'health-check-disable-plugin-hash' => $disable_plugin_hash,
49
+ ), $url );
50
+ }
51
+ if ( ! empty( $allowed_plugins ) ) {
52
+ if ( ! is_array( $allowed_plugins ) ) {
53
+ $allowed_plugins = (array) $allowed_plugins;
54
+ }
55
+
56
+ $url = add_query_arg(
57
+ array(
58
+ 'health-check-allowed-plugins' => implode( ',', $allowed_plugins ),
59
+ ),
60
+ $url
61
+ );
62
+ }
63
+
64
+ $r = wp_remote_get( $url, compact( 'cookies', 'headers', 'timeout' ) );
65
+
66
+ if ( is_wp_error( $r ) ) {
67
+ return (object) array(
68
+ 'status' => 'error',
69
+ 'message' => sprintf(
70
+ '%s<br>%s',
71
+ esc_html__( 'The loopback request to your site failed, this may prevent WP_Cron from working, along with theme and plugin editors.', 'health-check' ),
72
+ sprintf(
73
+ /* translators: %1$d: The HTTP response code. %2$s: The error message returned. */
74
+ esc_html__( 'Error encountered: (%1$d) %2$s', 'health-check' ),
75
+ wp_remote_retrieve_response_code( $r ),
76
+ $r->get_error_message()
77
+ )
78
+ ),
79
+ );
80
+ }
81
+
82
+ if ( 200 !== wp_remote_retrieve_response_code( $r ) ) {
83
+ return (object) array(
84
+ 'status' => 'warning',
85
+ 'message' => sprintf(
86
+ /* translators: %d: The HTTP response code returned. */
87
+ esc_html__( 'The loopback request returned an unexpected status code, %d, this may affect tools such as WP_Cron, or theme and plugin editors.', 'health-check' ),
88
+ wp_remote_retrieve_response_code( $r )
89
+ ),
90
+ );
91
+ }
92
+
93
+ return (object) array(
94
+ 'status' => 'good',
95
+ 'message' => __( 'The loopback request to your site completed successfully.', 'health-check' ),
96
+ );
97
+ }
98
+
99
+ /**
100
+ * Perform the loopback check, but ensure no plugins are enabled when we do so.
101
+ *
102
+ * @uses ob_start()
103
+ * @uses Health_Check_Troubleshoot::mu_plugin_exists()
104
+ * @uses Health_Check::get_filesystem_credentials()
105
+ * @uses Health_Check_Troubleshoot::setup_must_use_plugin()
106
+ * @uses Health_Check_Troubleshoot::maybe_update_must_use_plugin()
107
+ * @uses ob_get_clean()
108
+ * @uses wp_send_json_error()
109
+ * @uses md5()
110
+ * @uses rand()
111
+ * @uses update_option()
112
+ * @uses Health_Check_Loopback::can_perform_loopback()
113
+ * @uses sprintf()
114
+ * @uses esc_attr()
115
+ * @uses esc_html__()
116
+ * @uses esc_html()
117
+ * @uses wp_send_json_success()
118
+ *
119
+ * @return void
120
+ */
121
+ static function loopback_no_plugins() {
122
+ check_ajax_referer( 'health-check-loopback-no-plugins' );
123
+
124
+ if ( ! current_user_can( 'manage_options' ) ) {
125
+ wp_send_json_error();
126
+ }
127
+
128
+ ob_start();
129
+
130
+ $needs_creds = false;
131
+
132
+ if ( ! Health_Check_Troubleshoot::mu_plugin_exists() ) {
133
+ if ( ! Health_Check::get_filesystem_credentials() ) {
134
+ $needs_creds = true;
135
+ } else {
136
+ $check_output = Health_Check_Troubleshoot::setup_must_use_plugin();
137
+ if ( false === $check_output ) {
138
+ $needs_creds = true;
139
+ }
140
+ }
141
+ } else {
142
+ if ( ! Health_Check_Troubleshoot::maybe_update_must_use_plugin() ) {
143
+ $needs_creds = true;
144
+ }
145
+ }
146
+
147
+ $result = ob_get_clean();
148
+
149
+ if ( $needs_creds ) {
150
+ wp_send_json_error( $result );
151
+ die();
152
+ }
153
+
154
+ $loopback_hash = md5( rand() );
155
+ update_option( 'health-check-disable-plugin-hash', $loopback_hash );
156
+ update_option( 'health-check-default-theme', 'yes' );
157
+
158
+ $no_plugin_test = Health_Check_Loopback::can_perform_loopback( $loopback_hash );
159
+
160
+ $message = sprintf(
161
+ '<br><span class="%s"></span> %s: %s',
162
+ esc_attr( $no_plugin_test->status ),
163
+ esc_html__( 'Result from testing without any plugins active and a default theme', 'health-check' ),
164
+ $no_plugin_test->message
165
+ );
166
+
167
+ if ( 'error' !== $no_plugin_test->status ) {
168
+ $plugins = wp_get_active_and_valid_plugins();
169
+ $theme = wp_get_theme();
170
+
171
+ $message .= '<table id="loopback-individual-plugins-list">';
172
+
173
+ foreach ( $plugins as $single_plugin ) {
174
+ $plugin = get_plugin_data( $single_plugin );
175
+
176
+ $message .= sprintf(
177
+ '<tr data-test-plugin="%s" class="not-tested"><td>%s</td><td class="individual-loopback-test-status">%s</td></tr>',
178
+ esc_attr( plugin_basename( $single_plugin ) ),
179
+ esc_html( $plugin['Name'] ),
180
+ esc_html__( 'Waiting...', 'health-check' )
181
+ );
182
+ }
183
+
184
+ $message .= sprintf(
185
+ '<tr id="test-single-no-theme"><td>%s</td><td class="individual-loopback-test-status">%s</td></tr>',
186
+ sprintf(
187
+ // translators: %s: The active theme name.
188
+ esc_html__( 'Active theme: %s', 'health-check' ),
189
+ $theme->name
190
+ ),
191
+ esc_html__( 'Waiting...', 'health-check' )
192
+ );
193
+
194
+ $message .= '</table>';
195
+
196
+ $message .= '<br><button type="button" id="loopback-individual-plugins" class="button button-primary">Test individual plugins</button>';
197
+ }
198
+
199
+ $response = array(
200
+ 'message' => $message,
201
+ );
202
+
203
+ delete_option( 'health-check-default-theme' );
204
+
205
+ wp_send_json_success( $response );
206
+
207
+ die();
208
+ }
209
+
210
+ /**
211
+ * Test individual plugins for loopback compatibility issues.
212
+ *
213
+ * This function will perform the loopback check, without any plugins, then conditionally enables one plugin at a time.
214
+ *
215
+ * @uses ob_start()
216
+ * @uses Health_Check_Troubleshoot::mu_plugin_exists()
217
+ * @uses Health_Check::get_filesystem_credentials()
218
+ * @uses Health_Check_Troubleshoot::setup_must_use_plugin()
219
+ * @uses ob_get_clean()
220
+ * @uses wp_send_json_error()
221
+ * @uses delete_option()
222
+ * @uses get_option()
223
+ * @uses md5()
224
+ * @uses rand()
225
+ * @uses update_option()
226
+ * @uses explode()
227
+ * @uses Health_Check_Loopback::can_perform_loopback()
228
+ * @uses sprintf()
229
+ * @uses esc_attr()
230
+ * @uses esc_html__()
231
+ * @uses esc_html()
232
+ * @uses wp_send_json_success()
233
+ *
234
+ * @return void
235
+ */
236
+ static function loopback_test_individual_plugins() {
237
+ check_ajax_referer( 'health-check-loopback-individual-plugins' );
238
+
239
+ if ( ! current_user_can( 'manage_options' ) ) {
240
+ wp_send_json_error();
241
+ }
242
+
243
+ ob_start();
244
+
245
+ $needs_creds = false;
246
+
247
+ if ( ! Health_Check_Troubleshoot::mu_plugin_exists() ) {
248
+ if ( ! Health_Check::get_filesystem_credentials() ) {
249
+ $needs_creds = true;
250
+ } else {
251
+ Health_Check_Troubleshoot::setup_must_use_plugin();
252
+ }
253
+ }
254
+
255
+ $result = ob_get_clean();
256
+
257
+ if ( $needs_creds ) {
258
+ wp_send_json_error( $result );
259
+ die();
260
+ }
261
+
262
+ delete_option( 'health-check-disable-plugin-hash' );
263
+
264
+ $loopback_hash = md5( rand() );
265
+ update_option( 'health-check-disable-plugin-hash', $loopback_hash );
266
+
267
+ $plugin_slug = explode( '/', $_POST['plugin'] );
268
+ $plugin_slug = $plugin_slug[0];
269
+
270
+ $single_test = Health_Check_Loopback::can_perform_loopback( $loopback_hash, $plugin_slug );
271
+
272
+ $message = sprintf(
273
+ '<span class="%s"></span> %s',
274
+ esc_attr( $single_test->status ),
275
+ $single_test->message
276
+ );
277
+
278
+ $response = array(
279
+ 'message' => $message,
280
+ );
281
+
282
+ wp_send_json_success( $response );
283
+
284
+ die();
285
+ }
286
+
287
+ static function loopback_test_default_theme() {
288
+ check_ajax_referer( 'health-check-loopback-default-theme' );
289
+
290
+ if ( ! current_user_can( 'manage_options' ) ) {
291
+ wp_send_json_error();
292
+ }
293
+
294
+ ob_start();
295
+
296
+ $needs_creds = false;
297
+
298
+ if ( ! Health_Check_Troubleshoot::mu_plugin_exists() ) {
299
+ if ( ! Health_Check::get_filesystem_credentials() ) {
300
+ $needs_creds = true;
301
+ } else {
302
+ Health_Check_Troubleshoot::setup_must_use_plugin();
303
+ }
304
+ }
305
+
306
+ $result = ob_get_clean();
307
+
308
+ if ( $needs_creds ) {
309
+ wp_send_json_error( $result );
310
+ die();
311
+ }
312
+
313
+ delete_option( 'health-check-disable-plugin-hash' );
314
+
315
+ $loopback_hash = md5( rand() );
316
+ update_option( 'health-check-disable-plugin-hash', $loopback_hash );
317
+
318
+ $message = '';
319
+
320
+ // Test without a theme active.
321
+ update_option( 'health-check-default-theme', 'yes' );
322
+
323
+ $theme_test = Health_Check_Loopback::can_perform_loopback( $loopback_hash, '' );
324
+
325
+ $message .= sprintf(
326
+ '<span class="%s"></span> %s',
327
+ esc_attr( $theme_test->status ),
328
+ $theme_test->message
329
+ );
330
+
331
+ delete_option( 'health-check-default-theme' );
332
+
333
+ $response = array(
334
+ 'message' => $message,
335
+ );
336
+
337
+ wp_send_json_success( $response );
338
+
339
+ die();
340
+ }
341
+ }
includes/class-health-check-mail-check.php CHANGED
@@ -1,122 +1,136 @@
1
- <?php
2
-
3
- /**
4
- * Checks if wp_mail() works.
5
- *
6
- * @package Health Check
7
- */
8
-
9
- /**
10
- * Class Mail Check
11
- */
12
- class Health_Check_Mail_Check {
13
-
14
- /**
15
- * Checks if wp_mail() works.
16
- *
17
- * @uses sanitize_email()
18
- * @uses wp_mail()
19
- * @uses wp_send_json_success()
20
- * @uses wp_die()
21
- *
22
- * @return void
23
- */
24
- static function run_mail_check() {
25
- $output = '';
26
- $sendmail = false;
27
- $email = sanitize_email( $_POST['email'] );
28
- $email_message = sanitize_text_field( $_POST['email_message'] );
29
- $wp_address = get_bloginfo( 'url' );
30
- $wp_name = get_bloginfo( 'name' );
31
- $date = date( 'F j, Y' );
32
- $time = date( 'g:i a' );
33
-
34
- // translators: %s: website url.
35
- $email_subject = sprintf( esc_html__( 'Health Check – Test Message from %s', 'health-check' ), $wp_address );
36
-
37
- $email_body = sprintf(
38
- // translators: %1$s: website name. %2$s: website url. %3$s: The date the message was sent. %4$s: The time the message was sent. %5$s: Additional custom message from the administrator.
39
- __( 'Hi! This test message was sent by the Health Check plugin from %1$s (%2$s) on %3$s at %4$s. Since you’re reading this, it obviously works. Additional message from admin: %5$s', 'health-check' ),
40
- $wp_name,
41
- $wp_address,
42
- $date,
43
- $time,
44
- $email_message
45
- );
46
-
47
- $sendmail = wp_mail( $email, $email_subject, $email_body );
48
-
49
- if ( ! empty( $sendmail ) ) {
50
- $output .= '<div class="notice notice-success inline"><p>';
51
- $output .= __( 'We have just sent an e-mail using <code>wp_mail()</code> and it seems to work. Please check your inbox and spam folder to see if you received it.', 'health-check' );
52
- $output .= '</p></div>';
53
- } else {
54
- $output .= '<div class="notice notice-error inline"><p>';
55
- $output .= esc_html__( 'It seems there was a problem sending the e-mail.', 'health-check' );
56
- $output .= '</p></div>';
57
- }
58
-
59
- $response = array(
60
- 'message' => $output,
61
- );
62
-
63
- wp_send_json_success( $response );
64
-
65
- wp_die();
66
-
67
- }
68
-
69
- /**
70
- * Add the Mail Checker to the tools tab.
71
- *
72
- * @param array $tabs
73
- *
74
- * return array
75
- */
76
- public static function tools_tab( $tabs ) {
77
- ob_start();
78
- ?>
79
-
80
- <div>
81
- <p>
82
- <?php _e( 'The Mail Check will invoke the <code>wp_mail()</code> function and check if it succeeds. We will use the E-mail address you have set up, but you can change it below if you like.', 'health-check' ); ?>
83
- </p>
84
- <form action="#" id="health-check-mail-check" method="POST">
85
- <table class="widefat tools-email-table">
86
- <tr>
87
- <td>
88
- <p>
89
- <?php
90
- $current_user = wp_get_current_user();
91
- ?>
92
- <label for="email"><?php _e( 'E-mail', 'health-check' ); ?></label>
93
- <input type="text" name="email" id="email" value="<?php echo $current_user->user_email; ?>">
94
- </p>
95
- </td>
96
- <td>
97
- <p>
98
- <label for="email_message"><?php _e( 'Additional message', 'health-check' ); ?></label>
99
- <input type="text" name="email_message" id="email_message" value="">
100
- </p>
101
- </td>
102
- </tr>
103
- </table>
104
- <input type="submit" class="button button-primary" value="<?php esc_html_e( 'Send test mail', 'health-check' ); ?>">
105
- </form>
106
-
107
- <div id="tools-mail-check-response-holder">
108
- <span class="spinner"></span>
109
- </div>
110
- </div>
111
-
112
- <?php
113
- $tab_content = ob_get_clean();
114
-
115
- $tabs[] = array(
116
- 'label' => esc_html__( 'Mail Check', 'health-check' ),
117
- 'content' => $tab_content,
118
- );
119
-
120
- return $tabs;
121
- }
122
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Checks if wp_mail() works.
5
+ *
6
+ * @package Health Check
7
+ */
8
+
9
+ /**
10
+ * Class Mail Check
11
+ */
12
+ class Health_Check_Mail_Check {
13
+
14
+ /**
15
+ * Checks if wp_mail() works.
16
+ *
17
+ * @uses sanitize_email()
18
+ * @uses wp_mail()
19
+ * @uses wp_send_json_success()
20
+ * @uses wp_die()
21
+ *
22
+ * @return void
23
+ */
24
+ static function run_mail_check() {
25
+ check_ajax_referer( 'health-check-mail-check' );
26
+
27
+ if ( ! current_user_can( 'manage_options' ) ) {
28
+ wp_send_json_error();
29
+ }
30
+
31
+ $output = '';
32
+ $sendmail = false;
33
+ $email = sanitize_email( $_POST['email'] );
34
+ $email_message = sanitize_text_field( $_POST['email_message'] );
35
+ $wp_address = get_bloginfo( 'url' );
36
+ $wp_name = get_bloginfo( 'name' );
37
+ $date = date( 'F j, Y' );
38
+ $time = date( 'g:i a' );
39
+
40
+ // translators: %s: website url.
41
+ $email_subject = sprintf( esc_html__( 'Health Check – Test Message from %s', 'health-check' ), $wp_address );
42
+
43
+ $email_body = sprintf(
44
+ // translators: %1$s: website name. %2$s: website url. %3$s: The date the message was sent. %4$s: The time the message was sent.
45
+ __( 'Hi! This test message was sent by the Health Check plugin from %1$s (%2$s) on %3$s at %4$s. Since you’re reading this, it obviously works.', 'health-check' ),
46
+ $wp_name,
47
+ $wp_address,
48
+ $date,
49
+ $time,
50
+ $email_message
51
+ );
52
+
53
+ if ( ! empty( $email_message ) ) {
54
+ $email_body .= "\n\n" . sprintf(
55
+ // translators: %s: The custom message that may be included with the email.
56
+ __( 'Additional message from admin: %s', 'health-check' ),
57
+ $email_message
58
+ );
59
+ }
60
+
61
+ $sendmail = wp_mail( $email, $email_subject, $email_body );
62
+
63
+ if ( ! empty( $sendmail ) ) {
64
+ $output .= '<div class="notice notice-success inline"><p>';
65
+ $output .= __( 'We have just sent an e-mail using <code>wp_mail()</code> and it seems to work. Please check your inbox and spam folder to see if you received it.', 'health-check' );
66
+ $output .= '</p></div>';
67
+ } else {
68
+ $output .= '<div class="notice notice-error inline"><p>';
69
+ $output .= esc_html__( 'It seems there was a problem sending the e-mail.', 'health-check' );
70
+ $output .= '</p></div>';
71
+ }
72
+
73
+ $response = array(
74
+ 'message' => $output,
75
+ );
76
+
77
+ wp_send_json_success( $response );
78
+
79
+ wp_die();
80
+
81
+ }
82
+
83
+ /**
84
+ * Add the Mail Checker to the tools tab.
85
+ *
86
+ * @param array $tabs
87
+ *
88
+ * return array
89
+ */
90
+ public static function tools_tab( $tabs ) {
91
+ ob_start();
92
+ ?>
93
+
94
+ <div>
95
+ <p>
96
+ <?php _e( 'The Mail Check will invoke the <code>wp_mail()</code> function and check if it succeeds. We will use the E-mail address you have set up, but you can change it below if you like.', 'health-check' ); ?>
97
+ </p>
98
+ <form action="#" id="health-check-mail-check" method="POST">
99
+ <table class="widefat tools-email-table">
100
+ <tr>
101
+ <td>
102
+ <p>
103
+ <?php
104
+ $current_user = wp_get_current_user();
105
+ ?>
106
+ <label for="email"><?php _e( 'E-mail', 'health-check' ); ?></label>
107
+ <input type="text" name="email" id="email" value="<?php echo $current_user->user_email; ?>">
108
+ </p>
109
+ </td>
110
+ <td>
111
+ <p>
112
+ <label for="email_message"><?php _e( 'Additional message', 'health-check' ); ?></label>
113
+ <input type="text" name="email_message" id="email_message" value="">
114
+ </p>
115
+ </td>
116
+ </tr>
117
+ </table>
118
+ <input type="submit" class="button button-primary" value="<?php esc_html_e( 'Send test mail', 'health-check' ); ?>">
119
+ </form>
120
+
121
+ <div id="tools-mail-check-response-holder">
122
+ <span class="spinner"></span>
123
+ </div>
124
+ </div>
125
+
126
+ <?php
127
+ $tab_content = ob_get_clean();
128
+
129
+ $tabs[] = array(
130
+ 'label' => esc_html__( 'Mail Check', 'health-check' ),
131
+ 'content' => $tab_content,
132
+ );
133
+
134
+ return $tabs;
135
+ }
136
+ }
includes/class-health-check-site-status.php CHANGED
@@ -1,765 +1,1068 @@
1
- <?php
2
-
3
- class Health_Check_Site_Status {
4
- private $php_min_version_check;
5
- private $php_supported_version_check;
6
- private $php_rec_version_check;
7
-
8
- private $mysql_min_version_check;
9
- private $mysql_rec_version_check;
10
-
11
- public $mariadb = false;
12
- private $mysql_server_version = null;
13
- private $health_check_mysql_rec_version = null;
14
-
15
- public function __construct() {
16
- $this->init();
17
- }
18
-
19
- public function init() {
20
- $this->php_min_version_check = version_compare( HEALTH_CHECK_PHP_MIN_VERSION, PHP_VERSION, '<=' );
21
- $this->php_supported_version_check = version_compare( HEALTH_CHECK_PHP_SUPPORTED_VERSION, PHP_VERSION, '<=' );
22
- $this->php_rec_version_check = version_compare( HEALTH_CHECK_PHP_REC_VERSION, PHP_VERSION, '<=' );
23
-
24
- $this->prepare_sql_data();
25
-
26
- add_action( 'wp_ajax_health-check-site-status', array( $this, 'site_status' ) );
27
-
28
- add_action( 'wp_loaded', array( $this, 'check_wp_version_check_exists' ) );
29
- }
30
-
31
- private function prepare_sql_data() {
32
- global $wpdb;
33
-
34
- if ( method_exists( $wpdb, 'db_version' ) ) {
35
- if ( $wpdb->use_mysqli ) {
36
- // phpcs:ignore WordPress.DB.RestrictedFunctions.mysql_mysqli_get_server_info
37
- $mysql_server_type = mysqli_get_server_info( $wpdb->dbh );
38
- } else {
39
- // phpcs:ignore WordPress.DB.RestrictedFunctions.mysql_mysql_get_server_info
40
- $mysql_server_type = mysql_get_server_info( $wpdb->dbh );
41
- }
42
-
43
- $this->mysql_server_version = $wpdb->get_var( 'SELECT VERSION()' );
44
- }
45
-
46
- $this->health_check_mysql_rec_version = HEALTH_CHECK_MYSQL_REC_VERSION;
47
-
48
- if ( stristr( $mysql_server_type, 'mariadb' ) ) {
49
- $this->mariadb = true;
50
- $this->health_check_mysql_rec_version = '10.0';
51
- }
52
-
53
- $this->mysql_min_version_check = version_compare( HEALTH_CHECK_MYSQL_MIN_VERSION, $this->mysql_server_version, '<=' );
54
- $this->mysql_rec_version_check = version_compare( $this->health_check_mysql_rec_version, $this->mysql_server_version, '<=' );
55
- }
56
-
57
- public function check_wp_version_check_exists() {
58
- if ( ! is_admin() || ! is_user_logged_in() || ! current_user_can( 'manage_options' ) || ! isset( $_GET['health-check-test-wp_version_check'] ) ) {
59
- return;
60
- }
61
-
62
- echo ( has_filter( 'wp_version_check', 'wp_version_check' ) ? 'yes' : 'no' );
63
-
64
- die();
65
- }
66
-
67
- public function site_status() {
68
- $function = sprintf(
69
- 'test_%s',
70
- $_POST['feature']
71
- );
72
-
73
- if ( ! method_exists( $this, $function ) || ! is_callable( array( $this, $function ) ) ) {
74
- die();
75
- }
76
-
77
- $call = call_user_func( array( $this, $function ) );
78
-
79
- die();
80
- }
81
-
82
- public function test_wordpress_version() {
83
- $core_current_version = get_bloginfo( 'version' );
84
- $core_updates = get_core_updates();
85
-
86
- if ( ! is_array( $core_updates ) ) {
87
- printf(
88
- '<span class="warning"></span> %s',
89
- sprintf(
90
- // translators: %s: Your current version of WordPress.
91
- esc_html__( '%s - We were unable to check if any new versions are available.', 'health-check' ),
92
- $core_current_version
93
- )
94
- );
95
- } else {
96
- foreach ( $core_updates as $core => $update ) {
97
- if ( 'upgrade' === $update->response ) {
98
- $current_version = explode( '.', $core_current_version );
99
- $new_version = explode( '.', $update->version );
100
-
101
- $current_major = $current_version[0] . '.' . $current_version[1];
102
- $new_major = $new_version[0] . '.' . $new_version[1];
103
-
104
- if ( $current_major !== $new_major ) {
105
- // This is a major version mismatch.
106
- printf(
107
- '<span class="warning"></span> %s',
108
- sprintf(
109
- // translators: %1$s: Your current version of WordPress. %2$s The latest version of WordPress available.
110
- esc_html__( '%1$s ( Latest version: %2$s )', 'health-check' ),
111
- $core_current_version,
112
- $update->version
113
- )
114
- );
115
- } else {
116
- // This is a minor version, sometimes considered more critical.
117
- printf(
118
- '<span class="error"></span> %s',
119
- sprintf(
120
- // translators: %1$s: Your current version of WordPress. %2$s The latest version of WordPress available.
121
- esc_html__( '%1$s ( Latest version: %2$s ) - We strongly urge you to update, as minor updates are often security related.', 'health-check' ),
122
- $core_current_version,
123
- $update->version
124
- )
125
- );
126
- }
127
- } else {
128
- printf(
129
- '<span class="good"></span> %s',
130
- esc_html( $core_current_version )
131
- );
132
- }
133
- }
134
- }
135
- }
136
-
137
- /**
138
- * Check if the user is currently in Troubleshooting Mode or not.
139
- *
140
- * @return bool
141
- */
142
- public function is_troubleshooting() {
143
- // Check if a session cookie to disable plugins has been set.
144
- if ( isset( $_COOKIE['health-check-disable-plugins'] ) ) {
145
- $_GET['health-check-disable-plugin-hash'] = $_COOKIE['health-check-disable-plugins'];
146
- }
147
-
148
- // If the disable hash isn't set, no need to interact with things.
149
- if ( ! isset( $_GET['health-check-disable-plugin-hash'] ) ) {
150
- return false;
151
- }
152
-
153
- $disable_hash = get_option( 'health-check-disable-plugin-hash', null );
154
-
155
- if ( empty( $disable_hash ) ) {
156
- return false;
157
- }
158
-
159
- // If the plugin hash is not valid, we also break out
160
- if ( $disable_hash !== $_GET['health-check-disable-plugin-hash'] ) {
161
- return false;
162
- }
163
-
164
- return true;
165
- }
166
-
167
- public function test_plugin_version() {
168
- $plugins = get_plugins();
169
- $plugin_updates = get_plugin_updates();
170
-
171
- $show_unused_plugins = true;
172
- $plugins_have_updates = false;
173
- $plugins_active = 0;
174
- $plugins_total = 0;
175
- $plugins_needs_update = 0;
176
-
177
- if ( $this->is_troubleshooting() ) {
178
- $show_unused_plugins = false;
179
- }
180
-
181
- foreach ( $plugins as $plugin_path => $plugin ) {
182
- $plugins_total++;
183
-
184
- if ( is_plugin_active( $plugin_path ) ) {
185
- $plugins_active++;
186
- }
187
-
188
- $plugin_version = $plugin['Version'];
189
-
190
- if ( array_key_exists( $plugin_path, $plugin_updates ) ) {
191
- $plugins_needs_update++;
192
- $plugins_have_updates = true;
193
- }
194
- }
195
-
196
- echo '<ul>';
197
-
198
- if ( $plugins_needs_update > 0 ) {
199
- printf(
200
- '<li><span class="error"></span> %s',
201
- sprintf(
202
- // translators: %d: The amount of outdated plugins.
203
- esc_html( _n(
204
- 'Your site has %d plugin waiting to be updated.',
205
- 'Your site has %d plugins waiting to be updated.',
206
- $plugins_needs_update,
207
- 'health-check'
208
- ) ),
209
- $plugins_needs_update
210
- )
211
- );
212
- } else {
213
- printf(
214
- '<li><span class="good"></span> %s',
215
- sprintf(
216
- // translators: %d: The amount of plugins.
217
- esc_html( _n(
218
- 'Your site has %d active plugin, and it is up to date.',
219
- 'Your site has %d active plugins, and they are all up to date.',
220
- $plugins_total,
221
- 'health-check'
222
- ) ),
223
- $plugins_total
224
- )
225
- );
226
- }
227
-
228
- if ( ( $plugins_total > $plugins_active ) && $show_unused_plugins ) {
229
- $unused_plugins = $plugins_total - $plugins_active;
230
- printf(
231
- '<li><span class="warning"></span> %s',
232
- sprintf(
233
- // translators: %d: The amount of inactive plugins.
234
- esc_html( _n(
235
- 'Your site has %d inactive plugin, it is recommended to remove any unused plugins to enhance your site security.',
236
- 'Your site has %d inactive plugins, it is recommended to remove any unused plugins to enhance your site security.',
237
- $unused_plugins,
238
- 'health-check'
239
- ) ),
240
- $unused_plugins
241
- )
242
- );
243
- }
244
-
245
- echo '</ul>';
246
- }
247
-
248
- public function test_theme_version() {
249
- $theme_updates = get_theme_updates();
250
-
251
- $themes_total = 0;
252
- $themes_need_updates = 0;
253
- $themes_inactive = 0;
254
-
255
- // This value is changed dduring processing to determine how many themes are considered a reasonable amount.
256
- $allowed_theme_count = 1;
257
-
258
- $has_default_theme = false;
259
- $has_unused_themes = false;
260
- $show_unused_themes = true;
261
-
262
- if ( $this->is_troubleshooting() ) {
263
- $show_unused_themes = false;
264
- }
265
-
266
- // Populate a list of all themes available in the install.
267
- $all_themes = wp_get_themes();
268
- $active_theme = wp_get_theme();
269
-
270
- foreach ( $all_themes as $theme_slug => $theme ) {
271
- $themes_total++;
272
-
273
- if ( WP_DEFAULT_THEME === $theme_slug ) {
274
- $has_default_theme = true;
275
- }
276
-
277
- if ( array_key_exists( $theme_slug, $theme_updates ) ) {
278
- $themes_need_updates++;
279
- }
280
- }
281
-
282
- // If this is a child theme, increase the allowed theme count by one, to account for the parent.
283
- if ( $active_theme->parent() ) {
284
- $allowed_theme_count++;
285
- }
286
-
287
- // If there's a default theme installed, we count that as allowed as well.
288
- if ( $has_default_theme ) {
289
- $allowed_theme_count++;
290
- }
291
-
292
- if ( $themes_total > $allowed_theme_count ) {
293
- $has_unused_themes = true;
294
- $themes_inactive = ( $themes_total - $allowed_theme_count );
295
- }
296
-
297
- echo '<ul>';
298
-
299
- if ( $themes_need_updates > 0 ) {
300
- printf(
301
- '<li><span class="error"></span> %s',
302
- sprintf(
303
- // translators: %d: The amount of outdated themes.
304
- esc_html( _n(
305
- 'Your site has %d theme waiting to be updated.',
306
- 'Your site has %d themes waiting to be updated.',
307
- $themes_need_updates,
308
- 'health-check'
309
- ) ),
310
- $themes_need_updates
311
- )
312
- );
313
- } else {
314
- printf(
315
- '<li><span class="good"></span> %s',
316
- sprintf(
317
- // translators: %d: The amount of themes.
318
- esc_html( _n(
319
- 'Your site has %d installed theme, and it is up to date.',
320
- 'Your site has %d installed themes, and they are all up to date.',
321
- $themes_total,
322
- 'health-check'
323
- ) ),
324
- $themes_total
325
- )
326
- );
327
- }
328
-
329
- if ( $has_unused_themes && $show_unused_themes ) {
330
-
331
- // This is a child theme, so we want to be a bit more explicit in our messages.
332
- if ( $active_theme->parent() ) {
333
- printf(
334
- '<li><span class="warning"></span> %s',
335
- sprintf(
336
- // translators: %1$d: The amount of inactive themes. %2$s: The default theme for WordPress. %3$s: The currently active theme. %4$s: The active themes parent theme.
337
- esc_html( _n(
338
- 'Your site has %1$d inactive theme. To enhance your sites security it is recommended to remove any unused themes. You should keep %2$s, the default WordPress theme, %3$s, your current theme and %4$s, the parent theme.',
339
- 'Your site has %1$d inactive themes. To enhance your sites security it is recommended to remove any unused themes. You should keep %2$s, the default WordPress theme, %3$s, your current theme and %4$s, the parent theme.',
340
- $themes_inactive,
341
- 'health-check'
342
- ) ),
343
- $themes_inactive,
344
- WP_DEFAULT_THEME,
345
- $active_theme->name,
346
- $active_theme->parent()->name
347
- )
348
- );
349
-
350
- } else {
351
- printf(
352
- '<li><span class="warning"></span> %s',
353
- sprintf(
354
- // translators: %1$d: The amount of inactive themes. %2$s: The default theme for WordPress. %3$s: The currently active theme.
355
- esc_html( _n(
356
- 'Your site has %1$d inactive theme, other than %2$s, the default WordPress theme, and %3$s, your active theme. It is recommended to remove any unused themes to enhance your sites security.',
357
- 'Your site has %1$d inactive themes, other than %2$s, the default WordPress theme, and %3$s, your active theme. It is recommended to remove any unused themes to enhance your sites security.',
358
- $themes_inactive,
359
- 'health-check'
360
- ) ),
361
- $themes_inactive,
362
- WP_DEFAULT_THEME,
363
- $active_theme->name
364
- )
365
- );
366
-
367
- }
368
- }
369
-
370
- if ( ! $has_default_theme ) {
371
- printf(
372
- '<li><span class="warning"></span> %s',
373
- esc_html__( 'Your site does not have a default theme, default themes are used by WordPress automatically if anything is wrong with your normal theme.', 'health-check' )
374
- );
375
- }
376
-
377
- echo '</ul>';
378
- }
379
-
380
- public function test_php_version() {
381
- $status = 'good';
382
- $notice = array();
383
-
384
- if ( ! $this->php_min_version_check ) {
385
- $status = 'error';
386
- $notice[] = sprintf(
387
- '<a href="%s">%s</a>',
388
- esc_url(
389
- _x( 'https://wordpress.org/support/upgrade-php/', 'The link to the Update PHP page, which may be localized.', 'health-check' )
390
- ),
391
- sprintf(
392
- // translators: %1$s: Current PHP version. %2$s: Recommended PHP version. %3$s: Minimum PHP version.
393
- esc_html__( 'Your version of PHP, %1$s, is very outdated and no longer receiving security updates and is not supported by WordPress. You should contact your host for an upgrade, WordPress recommends using PHP version %2$s, but will work with version %3$s or newer.', 'health-check' ),
394
- PHP_VERSION,
395
- HEALTH_CHECK_PHP_REC_VERSION,
396
- HEALTH_CHECK_PHP_MIN_VERSION
397
- )
398
- );
399
- } elseif ( ! $this->php_supported_version_check ) {
400
- $status = 'warning';
401
- $notice[] = sprintf(
402
- '<a href="%s">%s</a>',
403
- esc_url(
404
- _x( 'https://wordpress.org/support/upgrade-php/', 'The link to the Update PHP page, which may be localized.', 'health-check' )
405
- ),
406
- sprintf(
407
- // translators: %1$s: Current PHP version. %2$s: Recommended PHP version.
408
- esc_html__( 'Your version of PHP, %1$s, is very outdated and no longer receiving security updates. You should contact your host for an upgrade, WordPress recommends using PHP version %2$s.', 'health-check' ),
409
- PHP_VERSION,
410
- HEALTH_CHECK_PHP_REC_VERSION
411
- )
412
- );
413
- } elseif ( ! $this->php_rec_version_check ) {
414
- $status = 'warning';
415
- $notice[] = sprintf(
416
- '<a href="%s">%s</a>',
417
- esc_url(
418
- _x( 'https://wordpress.org/support/upgrade-php/', 'The link to the Update PHP page, which may be localized.', 'health-check' )
419
- ),
420
- sprintf(
421
- // translators: %s: Recommended PHP version
422
- esc_html__( 'For best performance we recommend using PHP %s or higher.', 'health-check' ),
423
- HEALTH_CHECK_PHP_REC_VERSION
424
- )
425
- );
426
- }
427
-
428
- printf(
429
- '<span class="%s"></span> %s',
430
- esc_attr( $status ),
431
- sprintf(
432
- '%s%s',
433
- PHP_VERSION,
434
- ( ! empty( $notice ) ? ' - ' . implode( '<br>', $notice ) : '' )
435
- )
436
- );
437
- }
438
-
439
- public function test_json_extension() {
440
- $json_check = Health_Check::json_check();
441
-
442
- $status = 'good';
443
- $notice = array();
444
-
445
- if ( ! $json_check ) {
446
- printf(
447
- '<span class="error"> %s',
448
- esc_html__( 'The PHP install on your server has the JSON extension disabled and is therefore not compatible with WordPress 3.2 or newer.', 'health-check' )
449
- );
450
- } else {
451
- printf(
452
- '<span class="good"> %s',
453
- esc_html__( 'Your PHP install supports JSON.', 'health-check' )
454
- );
455
- }
456
- }
457
-
458
- public function test_sql_server() {
459
- $status = 'good';
460
- $notice = array();
461
-
462
- $db_dropin = file_exists( WP_CONTENT_DIR . '/db.php' );
463
-
464
- if ( ! $this->mysql_rec_version_check ) {
465
- $status = 'warning';
466
- $notice[] = sprintf(
467
- // translators: %1$s: The database engine in use (MySQL or MariaDB). %2$s: Database server recommended version number.
468
- esc_html__( 'For performance and security reasons, we strongly recommend running %1$s version %2$s or higher.', 'health-check' ),
469
- ( $this->mariadb ? 'MariaDB' : 'MySQL' ),
470
- $this->health_check_mysql_rec_version
471
- );
472
- }
473
-
474
- if ( ! $this->mysql_min_version_check ) {
475
- $status = 'error';
476
- $notice[] = sprintf(
477
- // translators: %1$s: The database engine in use (MySQL or MariaDB). %2$s: Database server minimum version number.
478
- esc_html__( 'WordPress 3.2+ requires %1$s version %2$s or higher.', 'health-check' ),
479
- ( $this->mariadb ? 'MariaDB' : 'MySQL' ),
480
- HEALTH_CHECK_MYSQL_MIN_VERSION
481
- );
482
- }
483
-
484
- if ( $db_dropin ) {
485
- // translators: %s: The database engine in use (MySQL or MariaDB).
486
- $notice[] = wp_kses(
487
- sprintf(
488
- // translators: %s: The name of the database engine being used.
489
- __( 'You are using a <code>wp-content/db.php</code> drop-in which might mean that a %s database is not being used.', 'health-check' ),
490
- ( $this->mariadb ? 'MariaDB' : 'MySQL' )
491
- ),
492
- array(
493
- 'code' => true,
494
- )
495
- );
496
- }
497
-
498
- printf(
499
- '<span class="%s"></span> %s',
500
- esc_attr( $status ),
501
- sprintf(
502
- '%s%s',
503
- esc_html( $this->mysql_server_version ),
504
- ( ! empty( $notice ) ? '<br> - ' . implode( '<br>', $notice ) : '' )
505
- )
506
- );
507
- }
508
-
509
- public function test_utf8mb4_support() {
510
- global $wpdb;
511
-
512
- if ( ! $this->mariadb ) {
513
- if ( version_compare( $this->mysql_server_version, '5.5.3', '<' ) ) {
514
- printf(
515
- '<span class="warning"></span> %s',
516
- sprintf(
517
- /* translators: %s: Number of version. */
518
- esc_html__( 'WordPress\' utf8mb4 support requires MySQL version %s or greater', 'health-check' ),
519
- '5.5.3'
520
- )
521
- );
522
- } else {
523
- printf(
524
- '<span class="good"></span> %s',
525
- esc_html__( 'Your MySQL version supports utf8mb4', 'health-check' )
526
- );
527
- }
528
- } else { // MariaDB introduced utf8mb4 support in 5.5.0
529
- if ( version_compare( $this->mysql_server_version, '5.5.0', '<' ) ) {
530
- printf(
531
- '<span class="warning"></span> %s',
532
- sprintf(
533
- /* translators: %s: Number of version. */
534
- esc_html__( 'WordPress\' utf8mb4 support requires MariaDB version %s or greater', 'health-check' ),
535
- '5.5.0'
536
- )
537
- );
538
- } else {
539
- printf(
540
- '<span class="good"></span> %s',
541
- esc_html__( 'Your MariaDB version supports utf8mb4', 'health-check' )
542
- );
543
- }
544
- }
545
-
546
- if ( $wpdb->use_mysqli ) {
547
- // phpcs:ignore WordPress.DB.RestrictedFunctions.mysql_mysqli_get_client_info
548
- $mysql_client_version = mysqli_get_client_info();
549
- } else {
550
- // phpcs:ignore WordPress.DB.RestrictedFunctions.mysql_mysql_get_client_info
551
- $mysql_client_version = mysql_get_client_info();
552
- }
553
-
554
- /*
555
- * libmysql has supported utf8mb4 since 5.5.3, same as the MySQL server.
556
- * mysqlnd has supported utf8mb4 since 5.0.9.
557
- */
558
- if ( false !== strpos( $mysql_client_version, 'mysqlnd' ) ) {
559
- $mysql_client_version = preg_replace( '/^\D+([\d.]+).*/', '$1', $mysql_client_version );
560
- if ( version_compare( $mysql_client_version, '5.0.9', '<' ) ) {
561
- printf(
562
- '<br><span class="warning"></span> %s',
563
- sprintf(
564
- /* translators: %1$s: Name of the library, %2$s: Number of version. */
565
- __( 'WordPress\' utf8mb4 support requires MySQL client library (%1$s) version %2$s or newer.', 'health-check' ),
566
- 'mysqlnd',
567
- '5.0.9'
568
- )
569
- );
570
- }
571
- } else {
572
- if ( version_compare( $mysql_client_version, '5.5.3', '<' ) ) {
573
- printf(
574
- '<br><span class="warning"></span> %s',
575
- sprintf(
576
- /* translators: %1$s: Name of the library, %2$s: Number of version. */
577
- __( 'WordPress\' utf8mb4 support requires MySQL client library (%1$s) version %2$s or newer.', 'health-check' ),
578
- 'libmysql',
579
- '5.5.3'
580
- )
581
- );
582
- }
583
- }
584
- }
585
-
586
- public function test_dotorg_communication() {
587
- $wp_dotorg = wp_remote_get( 'https://wordpress.org', array(
588
- 'timeout' => 10,
589
- ) );
590
- if ( ! is_wp_error( $wp_dotorg ) ) {
591
- printf(
592
- '<span class="good"></span> %s',
593
- esc_html__( 'WordPress.org is reachable from your server.', 'health-check' )
594
- );
595
- } else {
596
- printf(
597
- '<span class="error"></span> %s',
598
- sprintf(
599
- // translators: %1$s: The IP address WordPress.org resolves to. %2$s: The error returned by the lookup.
600
- __( 'Unable to reach WordPress.org at %1$s: %2$s', 'health-check' ),
601
- gethostbyname( 'wordpress.org' ),
602
- $wp_dotorg->get_error_message()
603
- )
604
- );
605
- }
606
- }
607
-
608
- public function test_https_status() {
609
- if ( is_ssl() ) {
610
- $wp_url = get_bloginfo( 'wpurl' );
611
- $site_url = get_bloginfo( 'url' );
612
-
613
- if ( 'https' !== substr( $wp_url, 0, 5 ) || 'https' !== substr( $site_url, 0, 5 ) ) {
614
- printf(
615
- '<span class="warning"></span> %s',
616
- sprintf(
617
- // translators: %s: URL to Settings > General to change options.
618
- __( 'You are accessing this website using HTTPS, but your <a href="%s">WordPress Address</a> is not set up to use HTTPS by default.', 'health-check' ),
619
- esc_url( admin_url( 'options-general.php' ) )
620
- )
621
- );
622
- } else {
623
- printf(
624
- '<span class="good"></span> %s',
625
- esc_html__( 'You are accessing this website using HTTPS.', 'health-check' )
626
- );
627
- }
628
- } else {
629
- printf(
630
- '<span class="warning"></span> %s',
631
- esc_html__( 'You are not using HTTPS to access this website.', 'health-check' )
632
- );
633
- }
634
- }
635
-
636
- public function test_rest_availability() {
637
- $cookies = wp_unslash( $_COOKIE );
638
- $timeout = 10;
639
- $headers = array(
640
- 'Cache-Control' => 'no-cache',
641
- );
642
-
643
- // Include Basic auth in loopback requests.
644
- if ( isset( $_SERVER['PHP_AUTH_USER'] ) && isset( $_SERVER['PHP_AUTH_PW'] ) ) {
645
- $headers['Authorization'] = 'Basic ' . base64_encode( wp_unslash( $_SERVER['PHP_AUTH_USER'] ) . ':' . wp_unslash( $_SERVER['PHP_AUTH_PW'] ) );
646
- }
647
-
648
- $url = rest_url( 'wp/v2/posts' );
649
-
650
- // We only need the first post to ensure this works, to make it low impact.
651
- $url = add_query_arg( array(
652
- 'per_page' => 1,
653
- ), $url );
654
-
655
- $r = wp_remote_get( $url, compact( 'cookies', 'headers', 'timeout' ) );
656
-
657
- if ( is_wp_error( $r ) ) {
658
- printf(
659
- '<span class="error"></span> %s',
660
- sprintf(
661
- '%s<br>%s',
662
- esc_html__( 'The REST API request failed due to an error.', 'health-check' ),
663
- sprintf(
664
- /* translators: %1$d: The HTTP response code. %2$s: The error message returned. */
665
- esc_html__( 'Error encountered: (%1$d) %2$s', 'health-check' ),
666
- wp_remote_retrieve_response_code( $r ),
667
- $r->get_error_message()
668
- )
669
- )
670
- );
671
- } elseif ( 200 !== wp_remote_retrieve_response_code( $r ) ) {
672
- printf(
673
- '<span class="warning"></span> %s',
674
- sprintf(
675
- /* translators: %1$d: The HTTP response code returned. %2$s: The error message returned. */
676
- esc_html__( 'The REST API call gave the following unexpected result: (%1$d) %2$s.', 'health-check' ),
677
- wp_remote_retrieve_response_code( $r ),
678
- wp_remote_retrieve_body( $r )
679
- )
680
- );
681
- } else {
682
-
683
- printf(
684
- '<span class="good"></span> %s',
685
- __( 'The REST API is available.', 'health-check' )
686
- );
687
- }
688
- }
689
-
690
- public function test_ssl_support() {
691
- $supports_https = wp_http_supports( array( 'ssl' ) );
692
-
693
- if ( $supports_https ) {
694
- printf(
695
- '<span class="good"></span> %s',
696
- esc_html__( 'Your WordPress install can communicate securely with other services.', 'health-check' )
697
- );
698
- } else {
699
- printf(
700
- '<span class="error"></span> %s',
701
- esc_html__( 'Your WordPress install cannot communicate securely with other services. Talk to your web host about OpenSSL support for PHP.', 'health-check' )
702
- );
703
- }
704
- }
705
-
706
- public function test_scheduled_events() {
707
- $scheduled_events = new Health_Check_WP_Cron();
708
-
709
- if ( is_wp_error( $scheduled_events->has_missed_cron() ) ) {
710
- printf(
711
- '<span class="error"></span> %s',
712
- esc_html( $scheduled_events->has_missed_cron()->get_error_message() )
713
- );
714
- } else {
715
- if ( $scheduled_events->has_missed_cron() ) {
716
- printf(
717
- '<span class="warning"></span> %s',
718
- sprintf(
719
- // translators: %s: The name of the failed cron event.
720
- esc_html__( 'A scheduled event (%s) has failed to run. Your site still works, but this may indicate that scheduling posts or automated updates may not work as intended.', 'health-check' ),
721
- $scheduled_events->last_missed_cron
722
- )
723
- );
724
- } else {
725
- printf(
726
- '<span class="good"></span> %s',
727
- esc_html__( 'No scheduled events have been missed.', 'health-check' )
728
- );
729
- }
730
- }
731
- }
732
-
733
- public function test_background_updates() {
734
- $automatic_updates = new Health_Check_Auto_Updates();
735
- $tests = $automatic_updates->run_tests();
736
-
737
- echo '<ul>';
738
-
739
- foreach ( $tests as $test ) {
740
- printf(
741
- '<li><span class="%s"></span> %s</li>',
742
- esc_attr( $test->severity ),
743
- $test->desc
744
- );
745
- }
746
-
747
- echo '</ul>';
748
- }
749
-
750
- public function test_loopback_requests() {
751
- $check_loopback = Health_Check_Loopback::can_perform_loopback();
752
-
753
- printf(
754
- '<span class="%s"></span> %s',
755
- esc_attr( $check_loopback->status ),
756
- $check_loopback->message
757
- );
758
-
759
- if ( 'error' === $check_loopback->status ) {
760
- echo '<br><button type="button" id="loopback-no-plugins" class="button button-primary">Test without plugins</button>';
761
- }
762
- }
763
- }
764
-
765
- new Health_Check_Site_Status();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Health_Check_Site_Status {
4
+ private $php_min_version_check;
5
+ private $php_supported_version_check;
6
+ private $php_rec_version_check;
7
+
8
+ private $mysql_min_version_check;
9
+ private $mysql_rec_version_check;
10
+
11
+ public $mariadb = false;
12
+ private $mysql_server_version = null;
13
+ private $health_check_mysql_rec_version = null;
14
+
15
+ public function __construct() {
16
+ $this->init();
17
+ }
18
+
19
+ public function init() {
20
+ $this->php_min_version_check = version_compare( HEALTH_CHECK_PHP_MIN_VERSION, PHP_VERSION, '<=' );
21
+ $this->php_supported_version_check = version_compare( HEALTH_CHECK_PHP_SUPPORTED_VERSION, PHP_VERSION, '<=' );
22
+ $this->php_rec_version_check = version_compare( HEALTH_CHECK_PHP_REC_VERSION, PHP_VERSION, '<=' );
23
+
24
+ $this->prepare_sql_data();
25
+
26
+ add_action( 'wp_ajax_health-check-site-status', array( $this, 'site_status' ) );
27
+
28
+ add_action( 'wp_loaded', array( $this, 'check_wp_version_check_exists' ) );
29
+ }
30
+
31
+ private function prepare_sql_data() {
32
+ global $wpdb;
33
+
34
+ if ( method_exists( $wpdb, 'db_version' ) ) {
35
+ if ( $wpdb->use_mysqli ) {
36
+ // phpcs:ignore WordPress.DB.RestrictedFunctions.mysql_mysqli_get_server_info
37
+ $mysql_server_type = mysqli_get_server_info( $wpdb->dbh );
38
+ } else {
39
+ // phpcs:ignore WordPress.DB.RestrictedFunctions.mysql_mysql_get_server_info
40
+ $mysql_server_type = mysql_get_server_info( $wpdb->dbh );
41
+ }
42
+
43
+ $this->mysql_server_version = $wpdb->get_var( 'SELECT VERSION()' );
44
+ }
45
+
46
+ $this->health_check_mysql_rec_version = HEALTH_CHECK_MYSQL_REC_VERSION;
47
+
48
+ if ( stristr( $mysql_server_type, 'mariadb' ) ) {
49
+ $this->mariadb = true;
50
+ $this->health_check_mysql_rec_version = '10.0';
51
+ }
52
+
53
+ $this->mysql_min_version_check = version_compare( HEALTH_CHECK_MYSQL_MIN_VERSION, $this->mysql_server_version, '<=' );
54
+ $this->mysql_rec_version_check = version_compare( $this->health_check_mysql_rec_version, $this->mysql_server_version, '<=' );
55
+ }
56
+
57
+ public function check_wp_version_check_exists() {
58
+ if ( ! is_admin() || ! is_user_logged_in() || ! current_user_can( 'manage_options' ) || ! isset( $_GET['health-check-test-wp_version_check'] ) ) {
59
+ return;
60
+ }
61
+
62
+ echo ( has_filter( 'wp_version_check', 'wp_version_check' ) ? 'yes' : 'no' );
63
+
64
+ die();
65
+ }
66
+
67
+ public function site_status() {
68
+ check_ajax_referer( 'health-check-site-status' );
69
+
70
+ if ( ! current_user_can( 'manage_options' ) ) {
71
+ wp_send_json_error();
72
+ }
73
+
74
+ $function = sprintf(
75
+ 'test_%s',
76
+ $_POST['feature']
77
+ );
78
+
79
+ if ( ! method_exists( $this, $function ) || ! is_callable( array( $this, $function ) ) ) {
80
+ die();
81
+ }
82
+
83
+ $call = call_user_func( array( $this, $function ) );
84
+
85
+ die();
86
+ }
87
+
88
+ /**
89
+ * Tests for WordPress version and outputs it.
90
+ *
91
+ * @return void It is an AJAX call.
92
+ */
93
+ public function test_wordpress_version() {
94
+ $core_current_version = get_bloginfo( 'version' );
95
+ $core_updates = get_core_updates();
96
+
97
+ // Prepare for a class and text for later use.
98
+ $text = '';
99
+ $class = '';
100
+
101
+ if ( ! is_array( $core_updates ) ) {
102
+ $class = 'warning';
103
+ $text = sprintf(
104
+ // translators: %s: Your current version of WordPress.
105
+ __( '%s - We were unable to check if any new versions are available.', 'health-check' ),
106
+ $core_current_version
107
+ );
108
+ } else {
109
+ foreach ( $core_updates as $core => $update ) {
110
+ if ( 'upgrade' === $update->response ) {
111
+ $current_version = explode( '.', $core_current_version );
112
+ $new_version = explode( '.', $update->version );
113
+
114
+ $current_major = $current_version[0] . '.' . $current_version[1];
115
+ $new_major = $new_version[0] . '.' . $new_version[1];
116
+
117
+ if ( $current_major !== $new_major ) {
118
+ // This is a major version mismatch.
119
+ $class = 'warning';
120
+ $text = sprintf(
121
+ // translators: %1$s: Your current version of WordPress. %2$s The latest version of WordPress available.
122
+ __( '%1$s ( Latest version: %2$s )', 'health-check' ),
123
+ $core_current_version,
124
+ $update->version
125
+ );
126
+ } else {
127
+ // This is a minor version, sometimes considered more critical.
128
+ $class = 'error';
129
+ $text = sprintf(
130
+ // translators: %1$s: Your current version of WordPress. %2$s The latest version of WordPress available.
131
+ __( '%1$s ( Latest version: %2$s ) - We strongly urge you to update, as minor updates are often security related.', 'health-check' ),
132
+ $core_current_version,
133
+ $update->version
134
+ );
135
+ }
136
+ } else {
137
+ $class = 'good';
138
+ $text = $core_current_version;
139
+ }
140
+ }
141
+ }
142
+
143
+ printf( '<span class="%1$s"></span> %2$s', esc_attr( $class ), esc_html( $text ) );
144
+ }
145
+
146
+ /**
147
+ * Check if the user is currently in Troubleshooting Mode or not.
148
+ *
149
+ * @return bool
150
+ */
151
+ public function is_troubleshooting() {
152
+ // Check if a session cookie to disable plugins has been set.
153
+ if ( isset( $_COOKIE['health-check-disable-plugins'] ) ) {
154
+ $_GET['health-check-disable-plugin-hash'] = $_COOKIE['health-check-disable-plugins'];
155
+ }
156
+
157
+ // If the disable hash isn't set, no need to interact with things.
158
+ if ( ! isset( $_GET['health-check-disable-plugin-hash'] ) ) {
159
+ return false;
160
+ }
161
+
162
+ $disable_hash = get_option( 'health-check-disable-plugin-hash', null );
163
+
164
+ if ( empty( $disable_hash ) ) {
165
+ return false;
166
+ }
167
+
168
+ // If the plugin hash is not valid, we also break out
169
+ if ( $disable_hash !== $_GET['health-check-disable-plugin-hash'] ) {
170
+ return false;
171
+ }
172
+
173
+ return true;
174
+ }
175
+
176
+ public function test_plugin_version() {
177
+ $plugins = get_plugins();
178
+ $plugin_updates = get_plugin_updates();
179
+
180
+ $show_unused_plugins = true;
181
+ $plugins_have_updates = false;
182
+ $plugins_active = 0;
183
+ $plugins_total = 0;
184
+ $plugins_needs_update = 0;
185
+
186
+ if ( $this->is_troubleshooting() ) {
187
+ $show_unused_plugins = false;
188
+ }
189
+
190
+ foreach ( $plugins as $plugin_path => $plugin ) {
191
+ $plugins_total++;
192
+
193
+ if ( is_plugin_active( $plugin_path ) ) {
194
+ $plugins_active++;
195
+ }
196
+
197
+ $plugin_version = $plugin['Version'];
198
+
199
+ if ( array_key_exists( $plugin_path, $plugin_updates ) ) {
200
+ $plugins_needs_update++;
201
+ $plugins_have_updates = true;
202
+ }
203
+ }
204
+
205
+ echo '<ul>';
206
+
207
+ if ( $plugins_needs_update > 0 ) {
208
+ printf(
209
+ '<li><span class="error"></span> %s',
210
+ sprintf(
211
+ // translators: %d: The amount of outdated plugins.
212
+ esc_html( _n(
213
+ 'Your site has %d plugin waiting to be updated.',
214
+ 'Your site has %d plugins waiting to be updated.',
215
+ $plugins_needs_update,
216
+ 'health-check'
217
+ ) ),
218
+ $plugins_needs_update
219
+ )
220
+ );
221
+ } else {
222
+ printf(
223
+ '<li><span class="good"></span> %s',
224
+ sprintf(
225
+ // translators: %d: The amount of plugins.
226
+ esc_html( _n(
227
+ 'Your site has %d active plugin, and it is up to date.',
228
+ 'Your site has %d active plugins, and they are all up to date.',
229
+ $plugins_active,
230
+ 'health-check'
231
+ ) ),
232
+ $plugins_active
233
+ )
234
+ );
235
+ }
236
+
237
+ if ( ( $plugins_total > $plugins_active ) && $show_unused_plugins ) {
238
+ $unused_plugins = $plugins_total - $plugins_active;
239
+ printf(
240
+ '<li><span class="warning"></span> %s',
241
+ sprintf(
242
+ // translators: %d: The amount of inactive plugins.
243
+ esc_html( _n(
244
+ 'Your site has %d inactive plugin, it is recommended to remove any unused plugins to enhance your site security.',
245
+ 'Your site has %d inactive plugins, it is recommended to remove any unused plugins to enhance your site security.',
246
+ $unused_plugins,
247
+ 'health-check'
248
+ ) ),
249
+ $unused_plugins
250
+ )
251
+ );
252
+ }
253
+
254
+ echo '</ul>';
255
+ }
256
+
257
+ public function test_theme_version() {
258
+ $theme_updates = get_theme_updates();
259
+
260
+ $themes_total = 0;
261
+ $themes_need_updates = 0;
262
+ $themes_inactive = 0;
263
+
264
+ // This value is changed dduring processing to determine how many themes are considered a reasonable amount.
265
+ $allowed_theme_count = 1;
266
+
267
+ $has_default_theme = false;
268
+ $has_unused_themes = false;
269
+ $show_unused_themes = true;
270
+
271
+ if ( $this->is_troubleshooting() ) {
272
+ $show_unused_themes = false;
273
+ }
274
+
275
+ // Populate a list of all themes available in the install.
276
+ $all_themes = wp_get_themes();
277
+ $active_theme = wp_get_theme();
278
+
279
+ foreach ( $all_themes as $theme_slug => $theme ) {
280
+ $themes_total++;
281
+
282
+ if ( WP_DEFAULT_THEME === $theme_slug ) {
283
+ $has_default_theme = true;
284
+ }
285
+
286
+ if ( array_key_exists( $theme_slug, $theme_updates ) ) {
287
+ $themes_need_updates++;
288
+ }
289
+ }
290
+
291
+ // If this is a child theme, increase the allowed theme count by one, to account for the parent.
292
+ if ( $active_theme->parent() ) {
293
+ $allowed_theme_count++;
294
+ }
295
+
296
+ // If there's a default theme installed, we count that as allowed as well.
297
+ if ( $has_default_theme ) {
298
+ $allowed_theme_count++;
299
+ }
300
+
301
+ if ( $themes_total > $allowed_theme_count ) {
302
+ $has_unused_themes = true;
303
+ $themes_inactive = ( $themes_total - $allowed_theme_count );
304
+ }
305
+
306
+ echo '<ul>';
307
+
308
+ if ( $themes_need_updates > 0 ) {
309
+ printf(
310
+ '<li><span class="error"></span> %s',
311
+ sprintf(
312
+ // translators: %d: The amount of outdated themes.
313
+ esc_html( _n(
314
+ 'Your site has %d theme waiting to be updated.',
315
+ 'Your site has %d themes waiting to be updated.',
316
+ $themes_need_updates,
317
+ 'health-check'
318
+ ) ),
319
+ $themes_need_updates
320
+ )
321
+ );
322
+ } else {
323
+ printf(
324
+ '<li><span class="good"></span> %s',
325
+ sprintf(
326
+ // translators: %d: The amount of themes.
327
+ esc_html( _n(
328
+ 'Your site has %d installed theme, and it is up to date.',
329
+ 'Your site has %d installed themes, and they are all up to date.',
330
+ $themes_total,
331
+ 'health-check'
332
+ ) ),
333
+ $themes_total
334
+ )
335
+ );
336
+ }
337
+
338
+ if ( $has_unused_themes && $show_unused_themes ) {
339
+
340
+ // This is a child theme, so we want to be a bit more explicit in our messages.
341
+ if ( $active_theme->parent() ) {
342
+ printf(
343
+ '<li><span class="warning"></span> %s',
344
+ sprintf(
345
+ // translators: %1$d: The amount of inactive themes. %2$s: The default theme for WordPress. %3$s: The currently active theme. %4$s: The active themes parent theme.
346
+ esc_html( _n(
347
+ 'Your site has %1$d inactive theme. To enhance your sites security it is recommended to remove any unused themes. You should keep %2$s, the default WordPress theme, %3$s, your current theme and %4$s, the parent theme.',
348
+ 'Your site has %1$d inactive themes. To enhance your sites security it is recommended to remove any unused themes. You should keep %2$s, the default WordPress theme, %3$s, your current theme and %4$s, the parent theme.',
349
+ $themes_inactive,
350
+ 'health-check'
351
+ ) ),
352
+ $themes_inactive,
353
+ WP_DEFAULT_THEME,
354
+ $active_theme->name,
355
+ $active_theme->parent()->name
356
+ )
357
+ );
358
+
359
+ } else {
360
+ printf(
361
+ '<li><span class="warning"></span> %s',
362
+ sprintf(
363
+ // translators: %1$d: The amount of inactive themes. %2$s: The default theme for WordPress. %3$s: The currently active theme.
364
+ esc_html( _n(
365
+ 'Your site has %1$d inactive theme, other than %2$s, the default WordPress theme, and %3$s, your active theme. It is recommended to remove any unused themes to enhance your sites security.',
366
+ 'Your site has %1$d inactive themes, other than %2$s, the default WordPress theme, and %3$s, your active theme. It is recommended to remove any unused themes to enhance your sites security.',
367
+ $themes_inactive,
368
+ 'health-check'
369
+ ) ),
370
+ $themes_inactive,
371
+ WP_DEFAULT_THEME,
372
+ $active_theme->name
373
+ )
374
+ );
375
+
376
+ }
377
+ }
378
+
379
+ if ( ! $has_default_theme ) {
380
+ printf(
381
+ '<li><span class="warning"></span> %s',
382
+ esc_html__( 'Your site does not have a default theme, default themes are used by WordPress automatically if anything is wrong with your normal theme.', 'health-check' )
383
+ );
384
+ }
385
+
386
+ echo '</ul>';
387
+ }
388
+
389
+ public function test_php_version() {
390
+ $status = 'good';
391
+ $notice = array();
392
+
393
+ if ( ! $this->php_min_version_check ) {
394
+ $status = 'error';
395
+ $notice[] = sprintf(
396
+ '<a href="%s">%s</a>',
397
+ esc_url(
398
+ _x( 'https://wordpress.org/support/upgrade-php/', 'The link to the Update PHP page, which may be localized.', 'health-check' )
399
+ ),
400
+ sprintf(
401
+ // translators: %1$s: Current PHP version. %2$s: Recommended PHP version. %3$s: Minimum PHP version.
402
+ esc_html__( 'Your version of PHP, %1$s, is very outdated and no longer receiving security updates and is not supported by WordPress. You should contact your host for an upgrade, WordPress recommends using PHP version %2$s, but will work with version %3$s or newer.', 'health-check' ),
403
+ PHP_VERSION,
404
+ HEALTH_CHECK_PHP_REC_VERSION,
405
+ HEALTH_CHECK_PHP_MIN_VERSION
406
+ )
407
+ );
408
+ } elseif ( ! $this->php_supported_version_check ) {
409
+ $status = 'warning';
410
+ $notice[] = sprintf(
411
+ '<a href="%s">%s</a>',
412
+ esc_url(
413
+ _x( 'https://wordpress.org/support/upgrade-php/', 'The link to the Update PHP page, which may be localized.', 'health-check' )
414
+ ),
415
+ sprintf(
416
+ // translators: %1$s: Current PHP version. %2$s: Recommended PHP version.
417
+ esc_html__( 'Your version of PHP, %1$s, is very outdated and no longer receiving security updates. You should contact your host for an upgrade, WordPress recommends using PHP version %2$s.', 'health-check' ),
418
+ PHP_VERSION,
419
+ HEALTH_CHECK_PHP_REC_VERSION
420
+ )
421
+ );
422
+ } elseif ( ! $this->php_rec_version_check ) {
423
+ $status = 'warning';
424
+ $notice[] = sprintf(
425
+ '<a href="%s">%s</a>',
426
+ esc_url(
427
+ _x( 'https://wordpress.org/support/upgrade-php/', 'The link to the Update PHP page, which may be localized.', 'health-check' )
428
+ ),
429
+ sprintf(
430
+ // translators: %s: Recommended PHP version
431
+ esc_html__( 'For best performance we recommend using PHP %s or higher.', 'health-check' ),
432
+ HEALTH_CHECK_PHP_REC_VERSION
433
+ )
434
+ );
435
+ }
436
+
437
+ printf(
438
+ '<span class="%s"></span> %s',
439
+ esc_attr( $status ),
440
+ sprintf(
441
+ '%s%s',
442
+ PHP_VERSION,
443
+ ( ! empty( $notice ) ? ' - ' . implode( '<br>', $notice ) : '' )
444
+ )
445
+ );
446
+ }
447
+
448
+ public function child_test_php_extension_availability( $extension = null, $function = null ) {
449
+ // If no extension or function is passed, claim to fail testing, as we have nothing to test against.
450
+ if ( null === $extension && null === $function ) {
451
+ return false;
452
+ }
453
+
454
+ $available = true;
455
+
456
+ if ( null !== $extension && ! extension_loaded( $extension ) ) {
457
+ $available = false;
458
+ }
459
+ if ( null !== $function && ! function_exists( $function ) ) {
460
+ $available = false;
461
+ }
462
+
463
+ return $available;
464
+ }
465
+
466
+ public function test_php_extensions() {
467
+ /*
468
+ * An array representing all the modules we wish to test for.
469
+ *
470
+ * array $modules {
471
+ * An associated array of modules to test for.
472
+ *
473
+ * array $module {
474
+ * An associated array of module properties used during testing.
475
+ * One of either `$function` or `$extension` must be provided, or they will fail by default.
476
+ *
477
+ * string $function Optional. A function name to test for the existence of.
478
+ * string $extension Optional. An extension to check if is loaded in PHP.
479
+ * bool $required Is this a required feature or not.
480
+ * string $fallback_for Optional. The module this module replaces as a fallback.
481
+ * }
482
+ * }
483
+ */
484
+ $modules = array(
485
+ 'bcmath' => array(
486
+ 'function' => 'bcadd',
487
+ 'required' => false,
488
+ ),
489
+ 'curl' => array(
490
+ 'function' => 'curl_version',
491
+ 'required' => false,
492
+ ),
493
+ 'exif' => array(
494
+ 'function' => 'exif_read_data',
495
+ 'required' => false,
496
+ ),
497
+ 'filter' => array(
498
+ 'function' => 'filter_list',
499
+ 'required' => false,
500
+ ),
501
+ 'fileinfo' => array(
502
+ 'function' => 'finfo_file',
503
+ 'required' => false,
504
+ ),
505
+ 'mod_xml' => array(
506
+ 'extension' => 'libxml',
507
+ 'required' => false,
508
+ ),
509
+ 'mysqli' => array(
510
+ 'function' => 'mysqli_connect',
511
+ 'required' => false,
512
+ ),
513
+ 'libsodium' => array(
514
+ 'function' => 'sodium_compare',
515
+ 'required' => false,
516
+ ),
517
+ 'openssl' => array(
518
+ 'function' => 'openssl_encrypt',
519
+ 'required' => false,
520
+ ),
521
+ 'pcre' => array(
522
+ 'function' => 'preg_match',
523
+ 'required' => false,
524
+ ),
525
+ 'imagick' => array(
526
+ 'extension' => 'imagick',
527
+ 'required' => false,
528
+ ),
529
+ 'gd' => array(
530
+ 'extension' => 'gd',
531
+ 'required' => false,
532
+ 'fallback_for' => 'imagick',
533
+ ),
534
+ 'mcrypt' => array(
535
+ 'extension' => 'mcrypt',
536
+ 'required' => false,
537
+ 'fallback_for' => 'libsodium',
538
+ ),
539
+ 'xmlreader' => array(
540
+ 'extension' => 'xmlreader',
541
+ 'required' => false,
542
+ 'fallback_for' => 'xml',
543
+ ),
544
+ 'zlib' => array(
545
+ 'extension' => 'zlib',
546
+ 'required' => false,
547
+ 'fallback_for' => 'zip',
548
+ ),
549
+ );
550
+
551
+ $failures = array();
552
+
553
+ foreach ( $modules as $library => $module ) {
554
+ $extension = ( isset( $module['extension'] ) ? $module['extension'] : null );
555
+ $function = ( isset( $module['function'] ) ? $module['function'] : null );
556
+
557
+ // If this module is a fallback for another function, check if that other function passed.
558
+ if ( isset( $module['fallback_for'] ) ) {
559
+ /*
560
+ * If that other function has a failure, mark this module as required for normal operations.
561
+ * If that other function hasn't failed, skip this test as it's only a fallback.
562
+ */
563
+ if ( isset( $failures[ $module['fallback_for'] ] ) ) {
564
+ $module['required'] = true;
565
+ } else {
566
+ continue;
567
+ }
568
+ }
569
+
570
+ if ( ! $this->child_test_php_extension_availability( $extension, $function ) ) {
571
+ $failures[ $library ] = sprintf(
572
+ '<span class="%s"></span> %s',
573
+ ( $module['required'] ? 'error' : 'warning' ),
574
+ sprintf(
575
+ // translators: %1$2: If a module is required or recommended. %2$s: The module name.
576
+ __( 'The %1$s module, %2$s, is not installer, or has been disabled.', 'health-check' ),
577
+ ( $module['required'] ? __( 'required', 'health-check' ) : __( 'optional', 'health-check' ) ),
578
+ $library
579
+ )
580
+ );
581
+ }
582
+ }
583
+
584
+ if ( ! empty( $failures ) ) {
585
+ echo '<ul>';
586
+
587
+ foreach ( $failures as $failure ) {
588
+ printf(
589
+ '<li>%s</li>',
590
+ $failure
591
+ );
592
+ }
593
+
594
+ echo '</ul>';
595
+ } else {
596
+ printf(
597
+ '<span class="good"></span> %s',
598
+ __( 'All required and recommended modules are installed.', 'health-check' )
599
+ );
600
+ }
601
+ }
602
+
603
+ public function test_sql_server() {
604
+ $status = 'good';
605
+ $notice = array();
606
+
607
+ $db_dropin = file_exists( WP_CONTENT_DIR . '/db.php' );
608
+
609
+ if ( ! $this->mysql_rec_version_check ) {
610
+ $status = 'warning';
611
+ $notice[] = sprintf(
612
+ // translators: %1$s: The database engine in use (MySQL or MariaDB). %2$s: Database server recommended version number.
613
+ esc_html__( 'For performance and security reasons, we strongly recommend running %1$s version %2$s or higher.', 'health-check' ),
614
+ ( $this->mariadb ? 'MariaDB' : 'MySQL' ),
615
+ $this->health_check_mysql_rec_version
616
+ );
617
+ }
618
+
619
+ if ( ! $this->mysql_min_version_check ) {
620
+ $status = 'error';
621
+ $notice[] = sprintf(
622
+ // translators: %1$s: The database engine in use (MySQL or MariaDB). %2$s: Database server minimum version number.
623
+ esc_html__( 'WordPress 3.2+ requires %1$s version %2$s or higher.', 'health-check' ),
624
+ ( $this->mariadb ? 'MariaDB' : 'MySQL' ),
625
+ HEALTH_CHECK_MYSQL_MIN_VERSION
626
+ );
627
+ }
628
+
629
+ if ( $db_dropin ) {
630
+ // translators: %s: The database engine in use (MySQL or MariaDB).
631
+ $notice[] = wp_kses(
632
+ sprintf(
633
+ // translators: %s: The name of the database engine being used.
634
+ __( 'You are using a <code>wp-content/db.php</code> drop-in which might mean that a %s database is not being used.', 'health-check' ),
635
+ ( $this->mariadb ? 'MariaDB' : 'MySQL' )
636
+ ),
637
+ array(
638
+ 'code' => true,
639
+ )
640
+ );
641
+ }
642
+
643
+ printf(
644
+ '<span class="%s"></span> %s',
645
+ esc_attr( $status ),
646
+ sprintf(
647
+ '%s%s',
648
+ esc_html( $this->mysql_server_version ),
649
+ ( ! empty( $notice ) ? '<br> - ' . implode( '<br>', $notice ) : '' )
650
+ )
651
+ );
652
+ }
653
+
654
+ public function test_utf8mb4_support() {
655
+ global $wpdb;
656
+
657
+ if ( ! $this->mariadb ) {
658
+ if ( version_compare( $this->mysql_server_version, '5.5.3', '<' ) ) {
659
+ printf(
660
+ '<span class="warning"></span> %s',
661
+ sprintf(
662
+ /* translators: %s: Number of version. */
663
+ esc_html__( 'WordPress\' utf8mb4 support requires MySQL version %s or greater', 'health-check' ),
664
+ '5.5.3'
665
+ )
666
+ );
667
+ } else {
668
+ printf(
669
+ '<span class="good"></span> %s',
670
+ esc_html__( 'Your MySQL version supports utf8mb4', 'health-check' )
671
+ );
672
+ }
673
+ } else { // MariaDB introduced utf8mb4 support in 5.5.0
674
+ if ( version_compare( $this->mysql_server_version, '5.5.0', '<' ) ) {
675
+ printf(
676
+ '<span class="warning"></span> %s',
677
+ sprintf(
678
+ /* translators: %s: Number of version. */
679
+ esc_html__( 'WordPress\' utf8mb4 support requires MariaDB version %s or greater', 'health-check' ),
680
+ '5.5.0'
681
+ )
682
+ );
683
+ } else {
684
+ printf(
685
+ '<span class="good"></span> %s',
686
+ esc_html__( 'Your MariaDB version supports utf8mb4', 'health-check' )
687
+ );
688
+ }
689
+ }
690
+
691
+ if ( $wpdb->use_mysqli ) {
692
+ // phpcs:ignore WordPress.DB.RestrictedFunctions.mysql_mysqli_get_client_info
693
+ $mysql_client_version = mysqli_get_client_info();
694
+ } else {
695
+ // phpcs:ignore WordPress.DB.RestrictedFunctions.mysql_mysql_get_client_info
696
+ $mysql_client_version = mysql_get_client_info();
697
+ }
698
+
699
+ /*
700
+ * libmysql has supported utf8mb4 since 5.5.3, same as the MySQL server.
701
+ * mysqlnd has supported utf8mb4 since 5.0.9.
702
+ */
703
+ if ( false !== strpos( $mysql_client_version, 'mysqlnd' ) ) {
704
+ $mysql_client_version = preg_replace( '/^\D+([\d.]+).*/', '$1', $mysql_client_version );
705
+ if ( version_compare( $mysql_client_version, '5.0.9', '<' ) ) {
706
+ printf(
707
+ '<br><span class="warning"></span> %s',
708
+ sprintf(
709
+ /* translators: %1$s: Name of the library, %2$s: Number of version. */
710
+ __( 'WordPress\' utf8mb4 support requires MySQL client library (%1$s) version %2$s or newer.', 'health-check' ),
711
+ 'mysqlnd',
712
+ '5.0.9'
713
+ )
714
+ );
715
+ }
716
+ } else {
717
+ if ( version_compare( $mysql_client_version, '5.5.3', '<' ) ) {
718
+ printf(
719
+ '<br><span class="warning"></span> %s',
720
+ sprintf(
721
+ /* translators: %1$s: Name of the library, %2$s: Number of version. */
722
+ __( 'WordPress\' utf8mb4 support requires MySQL client library (%1$s) version %2$s or newer.', 'health-check' ),
723
+ 'libmysql',
724
+ '5.5.3'
725
+ )
726
+ );
727
+ }
728
+ }
729
+ }
730
+
731
+ public function test_dotorg_communication() {
732
+ $wp_dotorg = wp_remote_get( 'https://wordpress.org', array(
733
+ 'timeout' => 10,
734
+ ) );
735
+ if ( ! is_wp_error( $wp_dotorg ) ) {
736
+ printf(
737
+ '<span class="good"></span> %s',
738
+ esc_html__( 'WordPress.org is reachable from your server.', 'health-check' )
739
+ );
740
+ } else {
741
+ printf(
742
+ '<span class="error"></span> %s',
743
+ sprintf(
744
+ // translators: %1$s: The IP address WordPress.org resolves to. %2$s: The error returned by the lookup.
745
+ __( 'Unable to reach WordPress.org at %1$s: %2$s', 'health-check' ),
746
+ gethostbyname( 'wordpress.org' ),
747
+ $wp_dotorg->get_error_message()
748
+ )
749
+ );
750
+ }
751
+ }
752
+
753
+ public function test_https_status() {
754
+ if ( is_ssl() ) {
755
+ $wp_url = get_bloginfo( 'wpurl' );
756
+ $site_url = get_bloginfo( 'url' );
757
+
758
+ if ( 'https' !== substr( $wp_url, 0, 5 ) || 'https' !== substr( $site_url, 0, 5 ) ) {
759
+ printf(
760
+ '<span class="warning"></span> %s',
761
+ sprintf(
762
+ // translators: %s: URL to Settings > General to change options.
763
+ __( 'You are accessing this website using HTTPS, but your <a href="%s">WordPress Address</a> is not set up to use HTTPS by default.', 'health-check' ),
764
+ esc_url( admin_url( 'options-general.php' ) )
765
+ )
766
+ );
767
+ } else {
768
+ printf(
769
+ '<span class="good"></span> %s',
770
+ esc_html__( 'You are accessing this website using HTTPS.', 'health-check' )
771
+ );
772
+ }
773
+ } else {
774
+ printf(
775
+ '<span class="warning"></span> %s',
776
+ esc_html__( 'You are not using HTTPS to access this website.', 'health-check' )
777
+ );
778
+ }
779
+ }
780
+
781
+ public function test_ssl_support() {
782
+ $supports_https = wp_http_supports( array( 'ssl' ) );
783
+
784
+ if ( $supports_https ) {
785
+ printf(
786
+ '<span class="good"></span> %s',
787
+ esc_html__( 'Your WordPress install can communicate securely with other services.', 'health-check' )
788
+ );
789
+ } else {
790
+ printf(
791
+ '<span class="error"></span> %s',
792
+ esc_html__( 'Your WordPress install cannot communicate securely with other services. Talk to your web host about OpenSSL support for PHP.', 'health-check' )
793
+ );
794
+ }
795
+ }
796
+
797
+ public function test_scheduled_events() {
798
+ $scheduled_events = new Health_Check_WP_Cron();
799
+
800
+ if ( is_wp_error( $scheduled_events->has_missed_cron() ) ) {
801
+ printf(
802
+ '<span class="error"></span> %s',
803
+ esc_html( $scheduled_events->has_missed_cron()->get_error_message() )
804
+ );
805
+ } else {
806
+ if ( $scheduled_events->has_missed_cron() ) {
807
+ printf(
808
+ '<span class="warning"></span> %s',
809
+ sprintf(
810
+ // translators: %s: The name of the failed cron event.
811
+ esc_html__( 'A scheduled event (%s) has failed to run. Your site still works, but this may indicate that scheduling posts or automated updates may not work as intended.', 'health-check' ),
812
+ $scheduled_events->last_missed_cron
813
+ )
814
+ );
815
+ } else {
816
+ printf(
817
+ '<span class="good"></span> %s',
818
+ esc_html__( 'No scheduled events have been missed.', 'health-check' )
819
+ );
820
+ }
821
+ }
822
+ }
823
+
824
+ public function test_background_updates() {
825
+ $automatic_updates = new Health_Check_Auto_Updates();
826
+ $tests = $automatic_updates->run_tests();
827
+
828
+ echo '<ul>';
829
+
830
+ foreach ( $tests as $test ) {
831
+ printf(
832
+ '<li><span class="%s"></span> %s</li>',
833
+ esc_attr( $test->severity ),
834
+ $test->desc
835
+ );
836
+ }
837
+
838
+ echo '</ul>';
839
+ }
840
+
841
+ public function test_extension_updates() {
842
+ $updates = new Health_Check_Updates();
843
+ $tests = $updates->run_tests();
844
+
845
+ echo '<ul>';
846
+
847
+ foreach ( $tests as $test ) {
848
+ printf(
849
+ '<li><span class="%s"></span> %s</li>',
850
+ esc_attr( $test->severity ),
851
+ $test->desc
852
+ );
853
+ }
854
+
855
+ echo '</ul>';
856
+ }
857
+
858
+ public function test_loopback_requests() {
859
+ $check_loopback = Health_Check_Loopback::can_perform_loopback();
860
+
861
+ printf(
862
+ '<span class="%s"></span> %s',
863
+ esc_attr( $check_loopback->status ),
864
+ $check_loopback->message
865
+ );
866
+
867
+ if ( 'error' === $check_loopback->status ) {
868
+ printf(
869
+ '<br><button type="button" id="loopback-no-plugins" class="button button-primary">%s</button>',
870
+ esc_html__( 'Test without plugins', 'health-check' )
871
+ );
872
+ }
873
+ }
874
+
875
+ public function test_http_requests() {
876
+ $blocked = false;
877
+ $hosts = array();
878
+
879
+ if ( defined( 'WP_HTTP_BLOCK_EXTERNAL' ) ) {
880
+ $blocked = true;
881
+ }
882
+
883
+ if ( defined( 'WP_ACCESSIBLE_HOSTS' ) ) {
884
+ $hosts = explode( ',', WP_ACCESSIBLE_HOSTS );
885
+ }
886
+
887
+ if ( $blocked && 0 === sizeof( $hosts ) ) {
888
+ printf(
889
+ '<span class="%s"></span> %s',
890
+ esc_attr( 'fail' ),
891
+ esc_html__( 'HTTP requests have been blocked by the WP_HTTP_BLOCK_EXTERNAL constant, with no allowed hosts.', 'health-check' )
892
+ );
893
+ }
894
+
895
+ if ( $blocked && 0 < sizeof( $hosts ) ) {
896
+ printf(
897
+ '<span class="%s"></span> %s',
898
+ esc_attr( 'warning' ),
899
+ sprintf(
900
+ /* translators: %s: List of hostnames whitelisted. */
901
+ esc_html__( 'HTTP requests have been blocked by the WP_HTTP_BLOCK_EXTERNAL constant, with some hosts whitelisted: %s.', 'health-check' ),
902
+ implode( ',', $hosts )
903
+ )
904
+ );
905
+ }
906
+
907
+ if ( ! $blocked ) {
908
+ printf(
909
+ '<span class="%s"></span> %s',
910
+ esc_attr( 'good' ),
911
+ esc_html__( 'HTTP requests should be working as expected.', 'health-check' )
912
+ );
913
+ }
914
+ }
915
+
916
+ public function test_rest_availability() {
917
+ $cookies = wp_unslash( $_COOKIE );
918
+ $timeout = 10;
919
+ $headers = array(
920
+ 'Cache-Control' => 'no-cache',
921
+ );
922
+
923
+ // Include Basic auth in loopback requests.
924
+ if ( isset( $_SERVER['PHP_AUTH_USER'] ) && isset( $_SERVER['PHP_AUTH_PW'] ) ) {
925
+ $headers['Authorization'] = 'Basic ' . base64_encode( wp_unslash( $_SERVER['PHP_AUTH_USER'] ) . ':' . wp_unslash( $_SERVER['PHP_AUTH_PW'] ) );
926
+ }
927
+
928
+ $url = rest_url( 'wp/v2/types/post' );
929
+
930
+ // We only need the first post to ensure this works, to make it low impact.
931
+ $url = add_query_arg( array(
932
+ 'context' => 'edit',
933
+ ), $url );
934
+
935
+ $r = wp_remote_get( $url, compact( 'cookies', 'headers', 'timeout' ) );
936
+
937
+ if ( is_wp_error( $r ) ) {
938
+ printf(
939
+ '<span class="error"></span> %s',
940
+ sprintf(
941
+ '%s<br>%s',
942
+ esc_html__( 'The REST API request failed due to an error.', 'health-check' ),
943
+ sprintf(
944
+ /* translators: %1$d: The HTTP response code. %2$s: The error message returned. */
945
+ esc_html__( 'Error encountered: (%1$d) %2$s', 'health-check' ),
946
+ wp_remote_retrieve_response_code( $r ),
947
+ $r->get_error_message()
948
+ )
949
+ )
950
+ );
951
+ } elseif ( 200 !== wp_remote_retrieve_response_code( $r ) ) {
952
+ printf(
953
+ '<span class="warning"></span> %s',
954
+ sprintf(
955
+ /* translators: %1$d: The HTTP response code returned. %2$s: The error message returned. */
956
+ esc_html__( 'The REST API call gave the following unexpected result: (%1$d) %2$s.', 'health-check' ),
957
+ wp_remote_retrieve_response_code( $r ),
958
+ wp_remote_retrieve_body( $r )
959
+ )
960
+ );
961
+ } else {
962
+ $json = json_decode( wp_remote_retrieve_body( $r ), true );
963
+
964
+ if ( false !== $json && ! isset( $json['capabilities'] ) ) {
965
+ printf(
966
+ '<span class="warning"></span> %s',
967
+ esc_html__( 'The REST API did not process the \'context\' query parameter correctly.', 'health-check' )
968
+ );
969
+ } else {
970
+ printf(
971
+ '<span class="good"></span> %s',
972
+ __( 'The REST API is available.', 'health-check' )
973
+ );
974
+ }
975
+ }
976
+ }
977
+
978
+ /**
979
+ * Return a set of tests that belong to the site status page.
980
+ *
981
+ * Each site status test is defined here, they may be `direct` tests, that run on page load,
982
+ * or `async` tests which will run later down the line via JavaScript calls to improve page
983
+ * performance and hopefully also user experiences.
984
+ *
985
+ * @return array
986
+ */
987
+ public static function get_tests() {
988
+ $tests = array(
989
+ 'direct' => array(
990
+ array(
991
+ 'label' => __( 'WordPress Version', 'health-check' ),
992
+ 'test' => 'wordpress_version',
993
+ ),
994
+ array(
995
+ 'label' => __( 'Plugin Versions', 'health-check' ),
996
+ 'test' => 'plugin_version',
997
+ ),
998
+ array(
999
+ 'label' => __( 'Theme Versions', 'health-check' ),
1000
+ 'test' => 'theme_version',
1001
+ ),
1002
+ array(
1003
+ 'label' => __( 'PHP Version', 'health-check' ),
1004
+ 'test' => 'php_version',
1005
+ ),
1006
+ array(
1007
+ 'label' => __( 'Database Server version', 'health-check' ),
1008
+ 'test' => 'sql_server',
1009
+ ),
1010
+ array(
1011
+ 'label' => __( 'PHP Extensions', 'health-check' ),
1012
+ 'test' => 'php_extensions',
1013
+ ),
1014
+ array(
1015
+ 'label' => __( 'MySQL utf8mb4 support', 'health-check' ),
1016
+ 'test' => 'utf8mb4_support',
1017
+ ),
1018
+ array(
1019
+ 'label' => __( 'HTTPS status', 'health-check' ),
1020
+ 'test' => 'https_status',
1021
+ ),
1022
+ array(
1023
+ 'label' => __( 'Secure communication', 'health-check' ),
1024
+ 'test' => 'ssl_support',
1025
+ ),
1026
+ array(
1027
+ 'label' => __( 'Scheduled events', 'health-check' ),
1028
+ 'test' => 'scheduled_events',
1029
+ ),
1030
+ array(
1031
+ 'label' => __( 'Plugin and Theme Updates', 'health-check' ),
1032
+ 'test' => 'extension_updates',
1033
+ ),
1034
+ array(
1035
+ 'label' => __( 'HTTP Requests', 'health-check' ),
1036
+ 'test' => 'http_requests',
1037
+ ),
1038
+ ),
1039
+ 'async' => array(
1040
+ array(
1041
+ 'label' => __( 'Communication with WordPress.org', 'health-check' ),
1042
+ 'test' => 'dotorg_communication',
1043
+ ),
1044
+ array(
1045
+ 'label' => __( 'Background updates', 'health-check' ),
1046
+ 'test' => 'background_updates',
1047
+ ),
1048
+ array(
1049
+ 'label' => __( 'Loopback request', 'health-check' ),
1050
+ 'test' => 'loopback_requests',
1051
+ ),
1052
+ ),
1053
+ );
1054
+
1055
+ // Conditionally include REST rules if the function for it exists.
1056
+ if ( function_exists( 'rest_url' ) ) {
1057
+ $tests['direct'][] = array(
1058
+ 'label' => __( 'REST API availability', 'health-check' ),
1059
+ 'test' => 'rest_availability',
1060
+ );
1061
+ }
1062
+
1063
+ return $tests;
1064
+ }
1065
+ }
1066
+
1067
+ global $health_check_site_status;
1068
+ $health_check_site_status = new Health_Check_Site_Status();
includes/class-health-check-troubleshoot.php CHANGED
@@ -1,320 +1,327 @@
1
- <?php
2
- /**
3
- * Handle troubleshooting options.
4
- *
5
- * @package Health Check
6
- */
7
-
8
- /**
9
- * Class Health_Check_Troubleshoot
10
- */
11
- class Health_Check_Troubleshoot {
12
-
13
- /**
14
- * Initiate the troubleshooting mode by setting meta data and cookies.
15
- *
16
- * @uses is_array()
17
- * @uses md5()
18
- * @uses rand()
19
- * @uses update_option()
20
- * @uses setcookie()
21
- *
22
- * @param array $allowed_plugins An array of plugins that may be active right away.
23
- *
24
- * @return void
25
- */
26
- static function initiate_troubleshooting_mode( $allowed_plugins = array() ) {
27
- if ( ! is_array( $allowed_plugins ) ) {
28
- $allowed_plugins = (array) $allowed_plugins;
29
- }
30
-
31
- $loopback_hash = md5( rand() );
32
-
33
- update_option( 'health-check-allowed-plugins', $allowed_plugins );
34
-
35
- update_option( 'health-check-disable-plugin-hash', $loopback_hash );
36
-
37
- setcookie( 'health-check-disable-plugins', $loopback_hash, 0, COOKIEPATH, COOKIE_DOMAIN );
38
- }
39
-
40
- /**
41
- * Check if our Must-Use plugin exists.
42
- *
43
- * @uses file_exists()
44
- *
45
- * @return bool
46
- */
47
- static function mu_plugin_exists() {
48
- return file_exists( WPMU_PLUGIN_DIR . '/health-check-troubleshooting-mode.php' );
49
- }
50
-
51
- /**
52
- * Check if the old Must-Use plugin exists.
53
- *
54
- * @uses file_exists()
55
- *
56
- * @return bool
57
- */
58
- static function old_mu_plugin_exists() {
59
- return file_exists( WPMU_PLUGIN_DIR . '/health-check-disable-plugins.php' );
60
- }
61
-
62
- /**
63
- * Check if the user has been shown the backup warning.
64
- *
65
- * @uses get_user_meta()
66
- * @uses get_current_user_id()
67
- *
68
- * @return bool
69
- */
70
- static function has_seen_warning() {
71
- /**
72
- * Filter who may see the backup warning from the plugin.
73
- *
74
- * The plugin displays a warning reminding users to keep backups when active.
75
- * This filter allows anyone to declare what capability is needed to view the warning, it is set to
76
- * the `manage_options` capability by default. This means the feature is available to any site admin,
77
- * even in a multisite environment.
78
- *
79
- * @param string $capability Default manage_options. The capability required to see the warning.
80
- */
81
- $capability_to_see = apply_filters( 'health_check_backup_warning_required_capability', 'manage_options' );
82
-
83
- // If the current user lacks the capabilities to use the plugin, pretend they've seen the warning so it isn't displayed.
84
- if ( ! current_user_can( $capability_to_see ) ) {
85
- return true;
86
- }
87
-
88
- $meta = get_user_meta( get_current_user_id(), 'health-check', true );
89
- if ( empty( $meta ) ) {
90
- return false;
91
- }
92
-
93
- if ( 'seen' === $meta['warning']['backup'] ) {
94
- return true;
95
- }
96
-
97
- return false;
98
- }
99
-
100
- /**
101
- * Save the confirmation of having seen a warning.
102
- *
103
- * @uses get_user_meta()
104
- * @uses get_current_user_id()
105
- * @uses update_user_meta()
106
- *
107
- * @return void
108
- */
109
- static function confirm_warning() {
110
- $user_meta = get_user_meta( get_current_user_id(), 'health-check', true );
111
- if ( empty( $user_meta ) ) {
112
- $user_meta = array(
113
- 'warning',
114
- );
115
- }
116
-
117
- $user_meta['warning'][ $_POST['warning'] ] = 'seen';
118
-
119
- update_user_meta( get_current_user_id(), 'health-check', $user_meta );
120
- }
121
-
122
- /**
123
- * Introduce our Must-Use plugin.
124
- *
125
- * Move the Must-Use plugin out to the correct directory, and prompt for credentials if required.
126
- *
127
- * @global $wp_filesystem
128
- *
129
- * @uses is_dir()
130
- * @uses WP_Filesystem::mkdir()
131
- * @uses Health_Check::display_notice()
132
- * @uses esc_html__()
133
- * @uses WP_Filesystem::copy()
134
- * @uses trailingslashit()
135
- * @uses Health_Check_Troubleshoot::session_started()
136
- *
137
- * @return bool
138
- */
139
- static function setup_must_use_plugin( $redirect = true ) {
140
- global $wp_filesystem;
141
-
142
- // Make sure the `mu-plugins` directory exists.
143
- if ( ! is_dir( WPMU_PLUGIN_DIR ) ) {
144
- if ( ! $wp_filesystem->mkdir( WPMU_PLUGIN_DIR ) ) {
145
- Health_Check::display_notice( esc_html__( 'We were unable to create the mu-plugins directory.', 'health-check' ), 'error' );
146
- return false;
147
- }
148
- }
149
-
150
- // Remove instances of the old plugin, to avoid collisions.
151
- if ( Health_Check_Troubleshoot::old_mu_plugin_exists() ) {
152
- if ( ! $wp_filesystem->delete( trailingslashit( WPMU_PLUGIN_DIR ) . 'health-check-disable-plugins.php' ) ) {
153
- Health_Check::display_notice( esc_html__( 'We could not remove the old must-use plugin.', 'health-check' ), 'error' );
154
- return false;
155
- }
156
- }
157
-
158
- // Copy the must-use plugin to the local directory.
159
- if ( ! $wp_filesystem->copy( trailingslashit( HEALTH_CHECK_PLUGIN_DIRECTORY ) . 'assets/mu-plugin/health-check-troubleshooting-mode.php', trailingslashit( WPMU_PLUGIN_DIR ) . 'health-check-troubleshooting-mode.php' ) ) {
160
- Health_Check::display_notice( esc_html__( 'We were unable to copy the plugin file required to enable the Troubleshooting Mode.', 'health-check' ), 'error' );
161
- return false;
162
- }
163
-
164
- if ( $redirect ) {
165
- Health_Check_Troubleshoot::session_started();
166
- }
167
-
168
- return true;
169
- }
170
-
171
- /**
172
- * Check if our Must-Use plugin needs updating, and do so if necessary.
173
- *
174
- * @global $wp_filesystem
175
- *
176
- * @uses Health_Check_Troubleshoot::mu_plugin_exists()
177
- * @uses Health_Check::get_filesystem_credentials()
178
- * @uses get_plugin_data()
179
- * @uses trailingslashit()
180
- * @uses version_compare()
181
- * @uses WP_Filesystem::copy()
182
- * @uses esc_html__()
183
- *
184
- * @return bool
185
- */
186
- static function maybe_update_must_use_plugin() {
187
- if ( ! Health_Check_Troubleshoot::mu_plugin_exists() ) {
188
- return false;
189
- }
190
- if ( ! Health_Check::get_filesystem_credentials() ) {
191
- return false;
192
- }
193
-
194
- $current = get_plugin_data( trailingslashit( HEALTH_CHECK_PLUGIN_DIRECTORY ) . 'assets/mu-plugin/health-check-troubleshooting-mode.php' );
195
- $active = get_plugin_data( trailingslashit( WPMU_PLUGIN_DIR ) . 'health-check-troubleshooting-mode.php' );
196
-
197
- $current_version = ( isset( $current['Version'] ) ? $current['Version'] : '0.0' );
198
- $active_version = ( isset( $active['Version'] ) ? $active['Version'] : '0.0' );
199
-
200
- if ( version_compare( $current_version, $active_version, '>' ) ) {
201
- global $wp_filesystem;
202
-
203
- if ( ! $wp_filesystem->copy( trailingslashit( HEALTH_CHECK_PLUGIN_DIRECTORY ) . 'assets/mu-plugin/health-check-troubleshooting-mode.php', trailingslashit( WPMU_PLUGIN_DIR ) . 'health-check-troubleshooting-mode.php', true ) ) {
204
- Health_Check::display_notice( esc_html__( 'We were unable to replace the plugin file required to enable the Troubleshooting Mode.', 'health-check' ), 'error' );
205
- return false;
206
- }
207
- }
208
-
209
- return true;
210
- }
211
-
212
- /**
213
- * Output a notice if our Troubleshooting Mode has been initiated.
214
- *
215
- * @uses Health_Check::display_notice()
216
- * @uses sprintf()
217
- * @uses esc_html__()
218
- * @uses esc_url()
219
- * @uses admin_url()
220
- *
221
- * @return void
222
- */
223
- static function session_started() {
224
- Health_Check::display_notice(
225
- sprintf(
226
- '%s<br>%s',
227
- esc_html__( 'You have successfully enabled Troubleshooting Mode, all plugins will appear inactive until you disable Troubleshooting Mode, or log out and back in again.', 'health-check' ),
228
- sprintf(
229
- '<a href="%1$s">%2$s</a><script type="text/javascript">window.location = "%1$s";</script>',
230
- esc_url( admin_url( '/' ) ),
231
- esc_html__( 'Return to the Dashboard', 'health-check' )
232
- )
233
- )
234
- );
235
- }
236
-
237
- /**
238
- * Display the form for enabling troubleshooting mode.
239
- *
240
- * @uses printf()
241
- * @uses esc_html__()
242
- * @uses Health_Check_Troubleshoot::mu_plugin_exists()
243
- * @uses Health_Check_Troubleshoot::maybe_update_must_use_plugin()
244
- * @uses Health_Check_Troubleshoot::session_started()
245
- * @uses Health_Check::get_filesystem_credentials()
246
- * @uses Health_Check_Troubleshoot::setup_must_use_plugin()
247
- * @uses esc_html_e()
248
- *
249
- * @return void
250
- */
251
-
252
- /**
253
- * Display the form for enabling troubleshooting mode.
254
- *
255
- * @uses printf()
256
- * @uses esc_html__()
257
- * @uses Health_Check_Troubleshoot::mu_plugin_exists()
258
- * @uses Health_Check_Troubleshoot::maybe_update_must_use_plugin()
259
- * @uses Health_Check_Troubleshoot::session_started()
260
- * @uses Health_Check::get_filesystem_credentials()
261
- * @uses Health_Check_Troubleshoot::setup_must_use_plugin()
262
- * @uses Health_Check_Troubleshooting_MU::is_troubleshooting()
263
- * @uses esc_url()
264
- * @uses add_query_arg()
265
- * @uses esc_html_e()
266
- *
267
- * @return void
268
- */
269
- static function show_enable_troubleshoot_form() {
270
- if ( isset( $_POST['health-check-troubleshoot-mode'] ) ) {
271
- if ( Health_Check_Troubleshoot::mu_plugin_exists() ) {
272
- if ( ! Health_Check_Troubleshoot::maybe_update_must_use_plugin() ) {
273
- return;
274
- }
275
- Health_Check_Troubleshoot::session_started();
276
- } else {
277
- if ( ! Health_Check::get_filesystem_credentials() ) {
278
- return;
279
- } else {
280
- Health_Check_Troubleshoot::setup_must_use_plugin();
281
- }
282
- }
283
- }
284
-
285
- ?>
286
- <div class="notice inline">
287
-
288
- <?php
289
- $troubleshooting = null;
290
-
291
- if ( class_exists( 'Health_Check_Troubleshooting_MU' ) ) {
292
- $troubleshooting = new Health_Check_Troubleshooting_MU();
293
- }
294
-
295
- if ( null !== $troubleshooting && is_callable( array( $troubleshooting, 'is_troubleshooting' ) ) && $troubleshooting->is_troubleshooting() ) :
296
- ?>
297
- <p style="text-align: center;">
298
- <a class="button button-primary" href="<?php echo esc_url( add_query_arg( array( 'health-check-disable-troubleshooting' => true ) ) ); ?>">
299
- <?php esc_html_e( 'Disable Troubleshooting Mode', 'health-check' ); ?>
300
- </a>
301
- </p>
302
-
303
- <?php else : ?>
304
-
305
- <form action="" method="post" class="form" style="text-align: center;">
306
- <input type="hidden" name="health-check-troubleshoot-mode" value="true">
307
- <p>
308
- <button type="submit" class="button button-primary">
309
- <?php esc_html_e( 'Enable Troubleshooting Mode', 'health-check' ); ?>
310
- </button>
311
- </p>
312
- </form>
313
-
314
- <?php endif; ?>
315
-
316
- </div>
317
-
318
- <?php
319
- }
320
- }
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Handle troubleshooting options.
4
+ *
5
+ * @package Health Check
6
+ */
7
+
8
+ /**
9
+ * Class Health_Check_Troubleshoot
10
+ */
11
+ class Health_Check_Troubleshoot {
12
+
13
+ /**
14
+ * Initiate the troubleshooting mode by setting meta data and cookies.
15
+ *
16
+ * @uses is_array()
17
+ * @uses md5()
18
+ * @uses rand()
19
+ * @uses update_option()
20
+ * @uses setcookie()
21
+ *
22
+ * @param array $allowed_plugins An array of plugins that may be active right away.
23
+ *
24
+ * @return void
25
+ */
26
+ static function initiate_troubleshooting_mode( $allowed_plugins = array() ) {
27
+ if ( ! is_array( $allowed_plugins ) ) {
28
+ $allowed_plugins = (array) $allowed_plugins;
29
+ }
30
+
31
+ $loopback_hash = md5( rand() );
32
+
33
+ update_option( 'health-check-allowed-plugins', $allowed_plugins );
34
+
35
+ update_option( 'health-check-disable-plugin-hash', $loopback_hash . md5( $_SERVER['REMOTE_ADDR'] ) );
36
+
37
+ setcookie( 'health-check-disable-plugins', $loopback_hash, 0, COOKIEPATH, COOKIE_DOMAIN );
38
+ }
39
+
40
+ /**
41
+ * Check if our Must-Use plugin exists.
42
+ *
43
+ * @uses file_exists()
44
+ *
45
+ * @return bool
46
+ */
47
+ static function mu_plugin_exists() {
48
+ return file_exists( WPMU_PLUGIN_DIR . '/health-check-troubleshooting-mode.php' );
49
+ }
50
+
51
+ /**
52
+ * Check if the old Must-Use plugin exists.
53
+ *
54
+ * @uses file_exists()
55
+ *
56
+ * @return bool
57
+ */
58
+ static function old_mu_plugin_exists() {
59
+ return file_exists( WPMU_PLUGIN_DIR . '/health-check-disable-plugins.php' );
60
+ }
61
+
62
+ /**
63
+ * Check if the user has been shown the backup warning.
64
+ *
65
+ * @uses get_user_meta()
66
+ * @uses get_current_user_id()
67
+ *
68
+ * @return bool
69
+ */
70
+ static function has_seen_warning() {
71
+ /**
72
+ * Filter who may see the backup warning from the plugin.
73
+ *
74
+ * The plugin displays a warning reminding users to keep backups when active.
75
+ * This filter allows anyone to declare what capability is needed to view the warning, it is set to
76
+ * the `manage_options` capability by default. This means the feature is available to any site admin,
77
+ * even in a multisite environment.
78
+ *
79
+ * @param string $capability Default manage_options. The capability required to see the warning.
80
+ */
81
+ $capability_to_see = apply_filters( 'health_check_backup_warning_required_capability', 'manage_options' );
82
+
83
+ // If the current user lacks the capabilities to use the plugin, pretend they've seen the warning so it isn't displayed.
84
+ if ( ! current_user_can( $capability_to_see ) ) {
85
+ return true;
86
+ }
87
+
88
+ $meta = get_user_meta( get_current_user_id(), 'health-check', true );
89
+ if ( empty( $meta ) ) {
90
+ return false;
91
+ }
92
+
93
+ if ( 'seen' === $meta['warning']['backup'] ) {
94
+ return true;
95
+ }
96
+
97
+ return false;
98
+ }
99
+
100
+ /**
101
+ * Save the confirmation of having seen a warning.
102
+ *
103
+ * @uses get_user_meta()
104
+ * @uses get_current_user_id()
105
+ * @uses update_user_meta()
106
+ *
107
+ * @return void
108
+ */
109
+ static function confirm_warning() {
110
+ check_ajax_referer( 'health-check-confirm-warning' );
111
+
112
+ if ( ! current_user_can( 'manage_options' ) ) {
113
+ wp_send_json_error();
114
+ }
115
+
116
+ $user_meta = get_user_meta( get_current_user_id(), 'health-check', true );
117
+ if ( empty( $user_meta ) ) {
118
+ $user_meta = array(
119
+ 'warning',
120
+ );
121
+ }
122
+
123
+ $user_meta['warning'][ $_POST['warning'] ] = 'seen';
124
+
125
+ update_user_meta( get_current_user_id(), 'health-check', $user_meta );
126
+ }
127
+
128
+ /**
129
+ * Introduce our Must-Use plugin.
130
+ *
131
+ * Move the Must-Use plugin out to the correct directory, and prompt for credentials if required.
132
+ *
133
+ * @global $wp_filesystem
134
+ *
135
+ * @uses is_dir()
136
+ * @uses WP_Filesystem::mkdir()
137
+ * @uses Health_Check::display_notice()
138
+ * @uses esc_html__()
139
+ * @uses WP_Filesystem::copy()
140
+ * @uses trailingslashit()
141
+ * @uses Health_Check_Troubleshoot::session_started()
142
+ *
143
+ * @return bool
144
+ */
145
+ static function setup_must_use_plugin( $redirect = true ) {
146
+ global $wp_filesystem;
147
+
148
+ // Make sure the `mu-plugins` directory exists.
149
+ if ( ! is_dir( WPMU_PLUGIN_DIR ) ) {
150
+ if ( ! $wp_filesystem->mkdir( WPMU_PLUGIN_DIR ) ) {
151
+ Health_Check::display_notice( esc_html__( 'We were unable to create the mu-plugins directory.', 'health-check' ), 'error' );
152
+ return false;
153
+ }
154
+ }
155
+
156
+ // Remove instances of the old plugin, to avoid collisions.
157
+ if ( Health_Check_Troubleshoot::old_mu_plugin_exists() ) {
158
+ if ( ! $wp_filesystem->delete( trailingslashit( WPMU_PLUGIN_DIR ) . 'health-check-disable-plugins.php' ) ) {
159
+ Health_Check::display_notice( esc_html__( 'We could not remove the old must-use plugin.', 'health-check' ), 'error' );
160
+ return false;
161
+ }
162
+ }
163
+
164
+ // Copy the must-use plugin to the local directory.
165
+ if ( ! $wp_filesystem->copy( trailingslashit( HEALTH_CHECK_PLUGIN_DIRECTORY ) . 'assets/mu-plugin/health-check-troubleshooting-mode.php', trailingslashit( WPMU_PLUGIN_DIR ) . 'health-check-troubleshooting-mode.php' ) ) {
166
+ Health_Check::display_notice( esc_html__( 'We were unable to copy the plugin file required to enable the Troubleshooting Mode.', 'health-check' ), 'error' );
167
+ return false;
168
+ }
169
+
170
+ if ( $redirect ) {
171
+ Health_Check_Troubleshoot::session_started();
172
+ }
173
+
174
+ return true;
175
+ }
176
+
177
+ /**
178
+ * Check if our Must-Use plugin needs updating, and do so if necessary.
179
+ *
180
+ * @global $wp_filesystem
181
+ *
182
+ * @uses Health_Check_Troubleshoot::mu_plugin_exists()
183
+ * @uses Health_Check::get_filesystem_credentials()
184
+ * @uses get_plugin_data()
185
+ * @uses trailingslashit()
186
+ * @uses version_compare()
187
+ * @uses WP_Filesystem::copy()
188
+ * @uses esc_html__()
189
+ *
190
+ * @return bool
191
+ */
192
+ static function maybe_update_must_use_plugin() {
193
+ if ( ! Health_Check_Troubleshoot::mu_plugin_exists() ) {
194
+ return false;
195
+ }
196
+ if ( ! Health_Check::get_filesystem_credentials() ) {
197
+ return false;
198
+ }
199
+
200
+ $current = get_plugin_data( trailingslashit( HEALTH_CHECK_PLUGIN_DIRECTORY ) . 'assets/mu-plugin/health-check-troubleshooting-mode.php' );
201
+ $active = get_plugin_data( trailingslashit( WPMU_PLUGIN_DIR ) . 'health-check-troubleshooting-mode.php' );
202
+
203
+ $current_version = ( isset( $current['Version'] ) ? $current['Version'] : '0.0' );
204
+ $active_version = ( isset( $active['Version'] ) ? $active['Version'] : '0.0' );
205
+
206
+ if ( version_compare( $current_version, $active_version, '>' ) ) {
207
+ global $wp_filesystem;
208
+
209
+ if ( ! $wp_filesystem->copy( trailingslashit( HEALTH_CHECK_PLUGIN_DIRECTORY ) . 'assets/mu-plugin/health-check-troubleshooting-mode.php', trailingslashit( WPMU_PLUGIN_DIR ) . 'health-check-troubleshooting-mode.php', true ) ) {
210
+ Health_Check::display_notice( esc_html__( 'We were unable to replace the plugin file required to enable the Troubleshooting Mode.', 'health-check' ), 'error' );
211
+ return false;
212
+ }
213
+ }
214
+
215
+ return true;
216
+ }
217
+
218
+ /**
219
+ * Output a notice if our Troubleshooting Mode has been initiated.
220
+ *
221
+ * @uses Health_Check::display_notice()
222
+ * @uses sprintf()
223
+ * @uses esc_html__()
224
+ * @uses esc_url()
225
+ * @uses admin_url()
226
+ *
227
+ * @return void
228
+ */
229
+ static function session_started() {
230
+ Health_Check::display_notice(
231
+ sprintf(
232
+ '%s<br>%s',
233
+ esc_html__( 'You have successfully enabled Troubleshooting Mode, all plugins will appear inactive until you disable Troubleshooting Mode, or log out and back in again.', 'health-check' ),
234
+ sprintf(
235
+ '<a href="%1$s">%2$s</a><script type="text/javascript">window.location = "%1$s";</script>',
236
+ esc_url( admin_url( '/' ) ),
237
+ esc_html__( 'Return to the Dashboard', 'health-check' )
238
+ )
239
+ )
240
+ );
241
+ }
242
+
243
+ /**
244
+ * Display the form for enabling troubleshooting mode.
245
+ *
246
+ * @uses printf()
247
+ * @uses esc_html__()
248
+ * @uses Health_Check_Troubleshoot::mu_plugin_exists()
249
+ * @uses Health_Check_Troubleshoot::maybe_update_must_use_plugin()
250
+ * @uses Health_Check_Troubleshoot::session_started()
251
+ * @uses Health_Check::get_filesystem_credentials()
252
+ * @uses Health_Check_Troubleshoot::setup_must_use_plugin()
253
+ * @uses esc_html_e()
254
+ *
255
+ * @return void
256
+ */
257
+
258
+ /**
259
+ * Display the form for enabling troubleshooting mode.
260
+ *
261
+ * @uses printf()
262
+ * @uses esc_html__()
263
+ * @uses Health_Check_Troubleshoot::mu_plugin_exists()
264
+ * @uses Health_Check_Troubleshoot::maybe_update_must_use_plugin()
265
+ * @uses Health_Check_Troubleshoot::session_started()
266
+ * @uses Health_Check::get_filesystem_credentials()
267
+ * @uses Health_Check_Troubleshoot::setup_must_use_plugin()
268
+ * @uses Health_Check_Troubleshooting_MU::is_troubleshooting()
269
+ * @uses esc_url()
270
+ * @uses add_query_arg()
271
+ * @uses esc_html_e()
272
+ *
273
+ * @return void
274
+ */
275
+ static function show_enable_troubleshoot_form() {
276
+ if ( isset( $_POST['health-check-troubleshoot-mode'] ) ) {
277
+ if ( Health_Check_Troubleshoot::mu_plugin_exists() ) {
278
+ if ( ! Health_Check_Troubleshoot::maybe_update_must_use_plugin() ) {
279
+ return;
280
+ }
281
+ Health_Check_Troubleshoot::session_started();
282
+ } else {
283
+ if ( ! Health_Check::get_filesystem_credentials() ) {
284
+ return;
285
+ } else {
286
+ Health_Check_Troubleshoot::setup_must_use_plugin();
287
+ }
288
+ }
289
+ }
290
+
291
+ ?>
292
+ <div class="notice inline">
293
+
294
+ <?php
295
+ $troubleshooting = null;
296
+
297
+ if ( class_exists( 'Health_Check_Troubleshooting_MU' ) ) {
298
+ $troubleshooting = new Health_Check_Troubleshooting_MU();
299
+ }
300
+
301
+ if ( null !== $troubleshooting && is_callable( array( $troubleshooting, 'is_troubleshooting' ) ) && $troubleshooting->is_troubleshooting() ) :
302
+ ?>
303
+ <p style="text-align: center;">
304
+ <a class="button button-primary" href="<?php echo esc_url( add_query_arg( array( 'health-check-disable-troubleshooting' => true ) ) ); ?>">
305
+ <?php esc_html_e( 'Disable Troubleshooting Mode', 'health-check' ); ?>
306
+ </a>
307
+ </p>
308
+
309
+ <?php else : ?>
310
+
311
+ <form action="" method="post" class="form" style="text-align: center;">
312
+ <?php wp_nonce_field( 'health-check-enable-troubleshooting' ); ?>
313
+ <input type="hidden" name="health-check-troubleshoot-mode" value="true">
314
+ <p>
315
+ <button type="submit" class="button button-primary">
316
+ <?php esc_html_e( 'Enable Troubleshooting Mode', 'health-check' ); ?>
317
+ </button>
318
+ </p>
319
+ </form>
320
+
321
+ <?php endif; ?>
322
+
323
+ </div>
324
+
325
+ <?php
326
+ }
327
+ }
includes/class-health-check-updates.php ADDED
@@ -0,0 +1,587 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Class for testing plugin/theme updates in the WordPress code.
4
+ *
5
+ * @package Health Check
6
+ */
7
+
8
+ /**
9
+ * Class Health_Check_Updates
10
+ */
11
+ class Health_Check_Updates {
12
+ private $plugins_before;
13
+ private $plugins_after;
14
+ private static $plugins_blocked;
15
+ private $themes_before;
16
+ private $themes_after;
17
+ private static $themes_blocked;
18
+
19
+ /**
20
+ * Health_Check_Updates constructor.
21
+ *
22
+ * @uses Health_Check_Updates::init()
23
+ *
24
+ * @return void
25
+ */
26
+ public function __construct() {
27
+ $this->init();
28
+ }
29
+
30
+ /**
31
+ * Initiate the plugin class.
32
+ *
33
+ * @return void
34
+ */
35
+ public function init() {
36
+ $this->plugins_before = (array) array();
37
+ $this->plugins_after = (array) array();
38
+ self::$plugins_blocked = (bool) false;
39
+
40
+ $this->themes_before = (array) array();
41
+ $this->themes_after = (array) array();
42
+ self::$themes_blocked = (bool) false;
43
+ }
44
+
45
+ /**
46
+ * Run tests to determine if auto-updates can run.
47
+ *
48
+ * @uses get_class_methods()
49
+ * @uses substr()
50
+ * @uses call_user_func()
51
+ *
52
+ * @return array
53
+ */
54
+ public function run_tests() {
55
+ $tests = array();
56
+
57
+ foreach ( get_class_methods( $this ) as $method ) {
58
+ if ( 'test_' !== substr( $method, 0, 5 ) ) {
59
+ continue;
60
+ }
61
+
62
+ $result = call_user_func( array( $this, $method ) );
63
+
64
+ if ( false === $result || null === $result ) {
65
+ continue;
66
+ }
67
+
68
+ $result = (object) $result;
69
+
70
+ if ( empty( $result->severity ) ) {
71
+ $result->severity = 'warning';
72
+ }
73
+
74
+ $tests[ $method ] = $result;
75
+ }
76
+
77
+ return $tests;
78
+ }
79
+
80
+ /**
81
+ * Check if plugin updates have been tampered with.
82
+ *
83
+ * @uses Health_Check_Updates::check_plugin_update_hooks()
84
+ * @uses esc_html__()
85
+ * @uses Health_Check_Updates::check_plugin_update_pre_request()
86
+ * @uses Health_Check_Updates::check_plugin_update_request_args()
87
+ *
88
+ * @return array
89
+ */
90
+ function test_plugin_updates() {
91
+ // Check if any update hooks have been removed.
92
+ $hooks = $this->check_plugin_update_hooks();
93
+ if ( ! $hooks ) {
94
+ return array(
95
+ 'desc' => esc_html__( 'Plugin update hooks have been removed.', 'health-check' ),
96
+ 'severity' => 'fail',
97
+ );
98
+ }
99
+
100
+ // Check if update requests are being blocked.
101
+ $blocked = $this->check_plugin_update_pre_request();
102
+ if ( true === $blocked ) {
103
+ return array(
104
+ 'desc' => esc_html__( 'Plugin update requests have been blocked.', 'health-check' ),
105
+ 'severity' => 'fail',
106
+ );
107
+ }
108
+
109
+ // Check if plugins have been removed from the update requests.
110
+ $diff = (array) $this->check_plugin_update_request_args();
111
+ if ( 0 !== count( $diff ) ) {
112
+ return array(
113
+ 'desc' => sprintf(
114
+ /* translators: %s: List of plugin names. */
115
+ esc_html__( 'The following Plugins have been removed from update checks: %s.', 'health-check' ),
116
+ implode( ',', $diff )
117
+ ),
118
+ 'severity' => 'warning',
119
+ );
120
+ }
121
+
122
+ return array(
123
+ 'desc' => esc_html__( 'Plugin updates should be working as expected.', 'health-check' ),
124
+ 'severity' => 'pass',
125
+ );
126
+ }
127
+
128
+ /**
129
+ * Check if any plugin update hooks have been removed.
130
+ *
131
+ * @uses has_filter()
132
+ * @uses wp_next_scheduled()
133
+ *
134
+ * @return array
135
+ */
136
+ function check_plugin_update_hooks() {
137
+ $test1 = has_filter( 'load-plugins.php', 'wp_update_plugins' );
138
+ $test2 = has_filter( 'load-update.php', 'wp_update_plugins' );
139
+ $test3 = has_filter( 'load-update-core.php', 'wp_update_plugins' );
140
+ $test4 = has_filter( 'wp_update_plugins', 'wp_update_plugins' );
141
+ $test5 = has_filter( 'admin_init', '_maybe_update_plugins' );
142
+ $test6 = wp_next_scheduled( 'wp_update_plugins' );
143
+
144
+ return $test1 && $test2 && $test3 && $test4 && $test5 && $test6;
145
+ }
146
+
147
+ /**
148
+ * Check if plugin update request checks are being tampered with at the 'pre_http_request' filter.
149
+ *
150
+ * @uses add_action()
151
+ * @uses Health_Check_Updates::wp_plugin_update_fake_request()
152
+ * @uses esc_html__()
153
+ *
154
+ * @return array
155
+ */
156
+ function check_plugin_update_pre_request() {
157
+ add_action( 'pre_http_request', array( $this, 'plugin_pre_request_check' ), PHP_INT_MAX, 3 );
158
+ add_action( 'pre_http_request', array( $this, 'block_fake_request' ), PHP_INT_MAX, 3 );
159
+
160
+ $this->plugin_update_fake_request();
161
+
162
+ remove_action( 'pre_http_request', array( $this, 'plugin_pre_request_check' ), PHP_INT_MAX );
163
+ remove_action( 'pre_http_request', array( $this, 'block_fake_request' ), PHP_INT_MAX );
164
+
165
+ return self::$plugins_blocked;
166
+ }
167
+
168
+ /**
169
+ * Check plugin update requests to see if they are being blocked.
170
+ *
171
+ * @param bool $pre If not false, request cancelled.
172
+ * @param array $r Request parameters.
173
+ * @param string $url Request URL.
174
+ * @return bool
175
+ */
176
+ function plugin_pre_request_check( $pre, $r, $url ) {
177
+ $check_url = 'api.wordpress.org/plugins/update-check/1.1/';
178
+ if ( 0 !== substr_compare( $url, $check_url, -strlen( $check_url ) ) ) {
179
+ return $pre; // Not a plugin update request.
180
+ }
181
+
182
+ // If not false something is blocking update checks
183
+ if ( false !== $pre ) {
184
+ self::$plugins_blocked = (bool) true;
185
+ }
186
+
187
+ return $pre;
188
+ }
189
+
190
+ /**
191
+ * Check if plugins are being removed at the 'http_request_args' filter.
192
+ *
193
+ * @uses add_action()
194
+ * @uses Health_Check_Updates::wp_plugin_update_fake_request()
195
+ * @uses remove_action()
196
+ *
197
+ * @return array
198
+ */
199
+ function check_plugin_update_request_args() {
200
+ add_action( 'http_request_args', array( $this, 'plugin_request_args_before' ), 1, 2 );
201
+ add_action( 'http_request_args', array( $this, 'plugin_request_args_after' ), PHP_INT_MAX, 2 );
202
+ add_action( 'pre_http_request', array( $this, 'block_fake_request' ), PHP_INT_MAX, 3 );
203
+
204
+ $this->plugin_update_fake_request();
205
+
206
+ remove_action( 'http_request_args', array( $this, 'plugin_request_args_before' ), 1 );
207
+ remove_action( 'http_request_args', array( $this, 'plugin_request_args_after' ), PHP_INT_MAX );
208
+ remove_action( 'pre_http_request', array( $this, 'block_fake_request' ), PHP_INT_MAX );
209
+
210
+ $diff = array_diff_key( $this->plugins_before['plugins'], $this->plugins_after['plugins'] );
211
+
212
+ $titles = array();
213
+ foreach ( $diff as $item ) {
214
+ $titles[] = $item['Title'];
215
+ }
216
+
217
+ return $titles;
218
+ }
219
+
220
+ /**
221
+ * Record the list of plugins from plugin update requests at the start of filtering.
222
+ *
223
+ * @param array $r Request parameters.
224
+ * @param string $url Request URL.
225
+ * @return array
226
+ */
227
+ function plugin_request_args_before( $r, $url ) {
228
+ $check_url = 'api.wordpress.org/plugins/update-check/1.1/';
229
+ if ( 0 !== substr_compare( $url, $check_url, -strlen( $check_url ) ) ) {
230
+ return $r; // Not a plugin update request.
231
+ }
232
+
233
+ $this->plugins_before = (array) json_decode( $r['body']['plugins'], true );
234
+
235
+ return $r;
236
+ }
237
+
238
+ /**
239
+ * Record the list of plugins from plugin update requests at the end of filtering.
240
+ *
241
+ * @param array $r Request parameters.
242
+ * @param string $url Request URL.
243
+ * @return array
244
+ */
245
+ function plugin_request_args_after( $r, $url ) {
246
+ $check_url = 'api.wordpress.org/plugins/update-check/1.1/';
247
+ if ( 0 !== substr_compare( $url, $check_url, -strlen( $check_url ) ) ) {
248
+ return $r; // Not a plugin update request.
249
+ }
250
+
251
+ $this->plugins_after = (array) json_decode( $r['body']['plugins'], true );
252
+
253
+ return $r;
254
+ }
255
+
256
+ /**
257
+ * Create and trigger a fake plugin update check request.
258
+ *
259
+ * @uses get_plugins()
260
+ * @uses get_option()
261
+ * @uses wp_get_installed_translations()
262
+ * @uses apply_filters()
263
+ * @uses wp_json_encode()
264
+ * @uses get_bloginfo()
265
+ * @uses home_url()
266
+ * @uses wp_http_supports()
267
+ * @uses set_url_scheme()
268
+ * @uses wp_remote_post()
269
+ *
270
+ * @return void
271
+ */
272
+ function plugin_update_fake_request() {
273
+ if ( ! function_exists( 'get_plugins' ) ) {
274
+ require_once( ABSPATH . 'wp-admin/includes/plugin.php' );
275
+ }
276
+
277
+ // Prepare data for the request.
278
+ $plugins = get_plugins();
279
+ $active = get_option( 'active_plugins', array() );
280
+ $to_send = compact( 'plugins', 'active' );
281
+ $translations = wp_get_installed_translations( 'plugins' );
282
+ $locales = array_values( get_available_languages() );
283
+ $locales = (array) apply_filters( 'plugins_update_check_locales', $locales );
284
+ $locales = array_unique( $locales );
285
+ $timeout = 3 + (int) ( count( $plugins ) / 10 );
286
+
287
+ // Setup the request options.
288
+ if ( function_exists( 'wp_json_encode' ) ) {
289
+ $options = array(
290
+ 'timeout' => $timeout,
291
+ 'body' => array(
292
+ 'plugins' => wp_json_encode( $to_send ),
293
+ 'translations' => wp_json_encode( $translations ),
294
+ 'locale' => wp_json_encode( $locales ),
295
+ 'all' => wp_json_encode( true ),
296
+ ),
297
+ 'user-agent' => 'WordPress/' . get_bloginfo( 'version' ) . '; ' . home_url( '/' ),
298
+ );
299
+ } else {
300
+ $options = array(
301
+ 'timeout' => $timeout,
302
+ 'body' => array(
303
+ 'plugins' => json_encode( $to_send ),
304
+ 'translations' => json_encode( $translations ),
305
+ 'locale' => json_encode( $locales ),
306
+ 'all' => json_encode( true ),
307
+ ),
308
+ 'user-agent' => 'WordPress/' . get_bloginfo( 'version' ) . '; ' . home_url( '/' ),
309
+ );
310
+ }
311
+
312
+ // Set the URL
313
+ $http_url = 'http://api.wordpress.org/plugins/update-check/1.1/';
314
+ $url = wp_http_supports( array( 'ssl' ) ) ? set_url_scheme( $http_url, 'https' ) : $http_url;
315
+
316
+ // Ignore the response. Just need the hooks to fire.
317
+ wp_remote_post( $url, $options );
318
+ }
319
+
320
+ /**
321
+ * Check if theme updates have been tampered with.
322
+ *
323
+ * @uses Health_Check_Updates::check_theme_update_hooks()
324
+ * @uses esc_html__()
325
+ * @uses Health_Check_Updates::check_theme_update_pre_request()
326
+ * @uses Health_Check_Updates::check_theme_update_request_args()
327
+ *
328
+ * @return array
329
+ */
330
+ function test_constant_theme_updates() {
331
+ // Check if any update hooks have been removed.
332
+ $hooks = $this->check_theme_update_hooks();
333
+ if ( ! $hooks ) {
334
+ return array(
335
+ 'desc' => esc_html__( 'Theme update hooks have been removed.', 'health-check' ),
336
+ 'severity' => 'fail',
337
+ );
338
+ }
339
+
340
+ // Check if update requests are being blocked.
341
+ $blocked = $this->check_theme_update_pre_request();
342
+ if ( true === $blocked ) {
343
+ return array(
344
+ 'desc' => esc_html__( 'Theme update requests have been blocked.', 'health-check' ),
345
+ 'severity' => 'fail',
346
+ );
347
+ }
348
+
349
+ // Check if themes have been removed from the update requests.
350
+ $diff = (array) $this->check_theme_update_request_args();
351
+ if ( 0 !== count( $diff ) ) {
352
+ return array(
353
+ 'desc' => sprintf(
354
+ /* translators: %s: List of theme names. */
355
+ esc_html__( 'The following Themes have been removed from update checks: %s.', 'health-check' ),
356
+ implode( ',', $diff )
357
+ ),
358
+ 'severity' => 'warning',
359
+ );
360
+ }
361
+
362
+ return array(
363
+ 'desc' => esc_html__( 'Theme updates should be working as expected.', 'health-check' ),
364
+ 'severity' => 'pass',
365
+ );
366
+ }
367
+
368
+ /**
369
+ * Check if any theme update hooks have been removed.
370
+ *
371
+ * @uses has_filter()
372
+ * @uses wp_next_scheduled()
373
+ *
374
+ * @return array
375
+ */
376
+ function check_theme_update_hooks() {
377
+ $test1 = has_filter( 'load-themes.php', 'wp_update_themes' );
378
+ $test2 = has_filter( 'load-update.php', 'wp_update_themes' );
379
+ $test3 = has_filter( 'load-update-core.php', 'wp_update_themes' );
380
+ $test4 = has_filter( 'wp_update_themes', 'wp_update_themes' );
381
+ $test5 = has_filter( 'admin_init', '_maybe_update_themes' );
382
+ $test6 = wp_next_scheduled( 'wp_update_themes' );
383
+
384
+ return $test1 && $test2 && $test3 && $test4 && $test5 && $test6;
385
+ }
386
+
387
+ /**
388
+ * Check if theme update request checks are being tampered with at the 'pre_http_request' filter.
389
+ *
390
+ * @uses add_action()
391
+ * @uses Health_Check_Updates::wp_theme_update_fake_request()
392
+ * @uses esc_html__()
393
+ *
394
+ * @return array
395
+ */
396
+ function check_theme_update_pre_request() {
397
+ add_action( 'pre_http_request', array( $this, 'theme_pre_request_check' ), PHP_INT_MAX, 3 );
398
+ add_action( 'pre_http_request', array( $this, 'block_fake_request' ), PHP_INT_MAX, 3 );
399
+
400
+ $this->theme_update_fake_request();
401
+
402
+ remove_action( 'pre_http_request', array( $this, 'theme_pre_request_check' ), PHP_INT_MAX );
403
+ remove_action( 'pre_http_request', array( $this, 'block_fake_request' ), PHP_INT_MAX );
404
+
405
+ return self::$themes_blocked;
406
+ }
407
+
408
+ /**
409
+ * Check theme update requests to see if they are being blocked.
410
+ *
411
+ * @param bool $pre If not false, request cancelled.
412
+ * @param array $r Request parameters.
413
+ * @param string $url Request URL.
414
+ * @return bool
415
+ */
416
+ function theme_pre_request_check( $pre, $r, $url ) {
417
+ $check_url = 'api.wordpress.org/themes/update-check/1.1/';
418
+ if ( 0 !== substr_compare( $url, $check_url, -strlen( $check_url ) ) ) {
419
+ return $pre; // Not a theme update request.
420
+ }
421
+
422
+ // If not false something is blocking update checks
423
+ if ( false !== $pre ) {
424
+ self::$themes_blocked = (bool) true;
425
+ }
426
+
427
+ return $pre;
428
+ }
429
+
430
+ /**
431
+ * Check if themes are being removed at the 'http_request_args' filter.
432
+ *
433
+ * @uses add_action()
434
+ * @uses Health_Check_Updates::wp_theme_update_fake_request()
435
+ * @uses remove_action()
436
+ *
437
+ * @return array
438
+ */
439
+ function check_theme_update_request_args() {
440
+ add_action( 'http_request_args', array( $this, 'theme_request_args_before' ), 1, 2 );
441
+ add_action( 'http_request_args', array( $this, 'theme_request_args_after' ), PHP_INT_MAX, 2 );
442
+ add_action( 'pre_http_request', array( $this, 'block_fake_request' ), PHP_INT_MAX, 3 );
443
+
444
+ $this->theme_update_fake_request();
445
+
446
+ remove_action( 'http_request_args', array( $this, 'theme_request_args_before' ), 1 );
447
+ remove_action( 'http_request_args', array( $this, 'theme_request_args_after' ), PHP_INT_MAX );
448
+ remove_action( 'pre_http_request', array( $this, 'block_fake_request' ), PHP_INT_MAX );
449
+
450
+ $diff = array_diff_key( $this->themes_before['themes'], $this->themes_after['themes'] );
451
+
452
+ $titles = array();
453
+ foreach ( $diff as $item ) {
454
+ $titles[] = $item['Title'];
455
+ }
456
+
457
+ return $titles;
458
+ }
459
+
460
+ /**
461
+ * Record the list of themes from theme update requests at the start of filtering.
462
+ *
463
+ * @param array $r Request parameters.
464
+ * @param string $url Request URL.
465
+ * @return array
466
+ */
467
+ function theme_request_args_before( $r, $url ) {
468
+ $check_url = 'api.wordpress.org/themes/update-check/1.1/';
469
+ if ( 0 !== substr_compare( $url, $check_url, -strlen( $check_url ) ) ) {
470
+ return $r; // Not a theme update request.
471
+ }
472
+
473
+ $this->themes_before = (array) json_decode( $r['body']['themes'], true );
474
+
475
+ return $r;
476
+ }
477
+
478
+ /**
479
+ * Record the list of themes from theme update requests at the end of filtering.
480
+ *
481
+ * @param array $r Request parameters.
482
+ * @param string $url Request URL.
483
+ * @return array
484
+ */
485
+ function theme_request_args_after( $r, $url ) {
486
+ $check_url = 'api.wordpress.org/themes/update-check/1.1/';
487
+ if ( 0 !== substr_compare( $url, $check_url, -strlen( $check_url ) ) ) {
488
+ return $r; // Not a theme update request.
489
+ }
490
+
491
+ $this->themes_after = (array) json_decode( $r['body']['themes'], true );
492
+
493
+ return $r;
494
+ }
495
+
496
+ /**
497
+ * Create and trigger a fake theme update check request.
498
+ *
499
+ * @uses wp_get_themes()
500
+ * @uses wp_get_installed_translations()
501
+ * @uses get_option()
502
+ * @uses get_available_languages()
503
+ * @uses wp_json_encode()
504
+ * @uses get_bloginfo()
505
+ * @uses home_url()
506
+ * @uses wp_http_supports()
507
+ * @uses set_url_scheme()
508
+ * @uses wp_remote_post()
509
+ *
510
+ * @return void
511
+ */
512
+ function theme_update_fake_request() {
513
+ $themes = array();
514
+ $checked = array();
515
+ $request = array();
516
+ $installed_themes = wp_get_themes();
517
+ $translations = wp_get_installed_translations( 'themes' );
518
+ $request['active'] = get_option( 'stylesheet' );
519
+
520
+ foreach ( $installed_themes as $theme ) {
521
+ $checked[ $theme->get_stylesheet() ] = $theme->get( 'Version' );
522
+
523
+ $themes[ $theme->get_stylesheet() ] = array(
524
+ 'Name' => $theme->get( 'Name' ),
525
+ 'Title' => $theme->get( 'Name' ),
526
+ 'Version' => $theme->get( 'Version' ),
527
+ 'Author' => $theme->get( 'Author' ),
528
+ 'Author URI' => $theme->get( 'AuthorURI' ),
529
+ 'Template' => $theme->get_template(),
530
+ 'Stylesheet' => $theme->get_stylesheet(),
531
+ );
532
+ }
533
+
534
+ $request['themes'] = $themes;
535
+
536
+ $locales = array_values( get_available_languages() );
537
+ $timeout = 3 + (int) ( count( $themes ) / 10 );
538
+
539
+ if ( function_exists( 'wp_json_encode' ) ) {
540
+ $options = array(
541
+ 'timeout' => $timeout,
542
+ 'body' => array(
543
+ 'themes' => wp_json_encode( $request ),
544
+ 'translations' => wp_json_encode( $translations ),
545
+ 'locale' => wp_json_encode( $locales ),
546
+ ),
547
+ 'user-agent' => 'WordPress/' . get_bloginfo( 'version' ) . '; ' . home_url( '/' ),
548
+ );
549
+ } else {
550
+ $options = array(
551
+ 'timeout' => $timeout,
552
+ 'body' => array(
553
+ 'themes' => json_encode( $request ),
554
+ 'translations' => json_encode( $translations ),
555
+ 'locale' => json_encode( $locales ),
556
+ ),
557
+ 'user-agent' => 'WordPress/' . get_bloginfo( 'version' ) . '; ' . home_url( '/' ),
558
+ );
559
+ }
560
+
561
+ // Set the URL
562
+ $http_url = 'http://api.wordpress.org/themes/update-check/1.1/';
563
+ $url = wp_http_supports( array( 'ssl' ) ) ? set_url_scheme( $http_url, 'https' ) : $http_url;
564
+
565
+ // Ignore the response. Just need the hooks to fire.
566
+ wp_remote_post( $url, $options );
567
+ }
568
+
569
+ /**
570
+ * Blocks the fake update requests, ensuring they do not slow down page loads.
571
+ *
572
+ * @param bool $pre If not false, request cancelled.
573
+ * @param array $r Request parameters.
574
+ * @param string $url Request URL.
575
+ * @return bool
576
+ */
577
+ function block_fake_request( $pre, $r, $url ) {
578
+ switch ( $url ) {
579
+ case 'https://api.wordpress.org/plugins/update-check/1.1/':
580
+ return 'block_request';
581
+ case 'https://api.wordpress.org/themes/update-check/1.1/':
582
+ return 'block_request';
583
+ default:
584
+ return $pre;
585
+ }
586
+ }
587
+ }
includes/class-health-check.php CHANGED
@@ -1,456 +1,460 @@
1
- <?php
2
- /**
3
- * Primary class file for the Health Check plugin.
4
- *
5
- * @package Health Check
6
- */
7
-
8
- /**
9
- * Class HealthCheck
10
- */
11
- class Health_Check {
12
-
13
- /**
14
- * Notices to show at the head of the admin screen.
15
- *
16
- * @access public
17
- *
18
- * @var array
19
- */
20
- public $admin_notices = array();
21
-
22
- /**
23
- * HealthCheck constructor.
24
- *
25
- * @uses Health_Check::init()
26
- *
27
- * @return void
28
- */
29
- public function __construct() {
30
- $this->init();
31
- }
32
-
33
- /**
34
- * Plugin initiation.
35
- *
36
- * A helper function, called by `HealthCheck::__construct()` to initiate actions, hooks and other features needed.
37
- *
38
- * @uses add_action()
39
- * @uses add_filter()
40
- *
41
- * @return void
42
- */
43
- public function init() {
44
- add_action( 'plugins_loaded', array( $this, 'load_i18n' ) );
45
-
46
- add_action( 'admin_menu', array( $this, 'action_admin_menu' ) );
47
-
48
- add_filter( 'plugin_row_meta', array( $this, 'settings_link' ), 10, 2 );
49
-
50
- add_filter( 'plugin_action_links', array( $this, 'troubeshoot_plugin_action' ), 20, 4 );
51
-
52
- add_action( 'admin_footer', array( $this, 'show_backup_warning' ) );
53
-
54
- add_action( 'admin_notices', array( $this, 'admin_notices' ) );
55
-
56
- add_action( 'admin_enqueue_scripts', array( $this, 'enqueues' ) );
57
-
58
- add_action( 'init', array( $this, 'start_troubleshoot_mode' ) );
59
- add_action( 'load-plugins.php', array( $this, 'start_troubleshoot_single_plugin_mode' ) );
60
-
61
- add_action( 'wp_ajax_health-check-loopback-no-plugins', array( 'Health_Check_Loopback', 'loopback_no_plugins' ) );
62
- add_action( 'wp_ajax_health-check-loopback-individual-plugins', array( 'Health_Check_Loopback', 'loopback_test_individual_plugins' ) );
63
- add_action( 'wp_ajax_health-check-loopback-default-theme', array( 'Health_Check_Loopback', 'loopback_test_default_theme' ) );
64
- add_action( 'wp_ajax_health-check-files-integrity-check', array( 'Health_Check_Files_Integrity', 'run_files_integrity_check' ) );
65
- add_action( 'wp_ajax_health-check-view-file-diff', array( 'Health_Check_Files_Integrity', 'view_file_diff' ) );
66
- add_action( 'wp_ajax_health-check-mail-check', array( 'Health_Check_Mail_Check', 'run_mail_check' ) );
67
- add_action( 'wp_ajax_health-check-confirm-warning', array( 'Health_Check_Troubleshoot', 'confirm_warning' ) );
68
-
69
- add_filter( 'health_check_tools_tab', array( 'Health_Check_Files_Integrity', 'tools_tab' ) );
70
- add_filter( 'health_check_tools_tab', array( 'Health_Check_Mail_Check', 'tools_tab' ) );
71
- }
72
-
73
- /**
74
- * Show a warning modal about keeping backups.
75
- *
76
- * @uses Health_Check_Troubleshoot::has_seen_warning()
77
- *
78
- * @return void
79
- */
80
- public function show_backup_warning() {
81
- if ( Health_Check_Troubleshoot::has_seen_warning() ) {
82
- return;
83
- }
84
-
85
- include_once( HEALTH_CHECK_PLUGIN_DIRECTORY . '/modals/backup-warning.php' );
86
- }
87
-
88
- /**
89
- * Initiate troubleshooting mode.
90
- *
91
- * Catch when the troubleshooting form has been submitted, and appropriately set required options and cookies.
92
- *
93
- * @uses current_user_can()
94
- * @uses Health_Check_Troubleshoot::initiate_troubleshooting_mode()
95
- *
96
- * @return void
97
- */
98
- public function start_troubleshoot_mode() {
99
- if ( ! isset( $_POST['health-check-troubleshoot-mode'] ) || ! current_user_can( 'manage_options' ) ) {
100
- return;
101
- }
102
-
103
- Health_Check_Troubleshoot::initiate_troubleshooting_mode();
104
- }
105
-
106
- /**
107
- * Initiate troubleshooting mode for a specific plugin.
108
- *
109
- * Catch when the troubleshooting link on an individual plugin has been clicked, and appropriately sets the
110
- * required options and cookies.
111
- *
112
- * @uses current_user_can()
113
- * @uses ob_start()
114
- * @uses Health_Check_Troubleshoot::mu_plugin_exists()
115
- * @uses Health_Check::get_filesystem_credentials()
116
- * @uses Health_Check_Troubleshoot::setup_must_use_plugin()
117
- * @uses Health_Check_Troubleshoot::maybe_update_must_use_plugin()
118
- * @uses ob_get_clean()
119
- * @uses Health_Check_Troubleshoot::initiate_troubleshooting_mode()
120
- * @uses wp_redirect()
121
- * @uses admin_url()
122
- *
123
- * @return void
124
- */
125
- public function start_troubleshoot_single_plugin_mode() {
126
- if ( ! isset( $_GET['health-check-troubleshoot-plugin'] ) || ! current_user_can( 'manage_options' ) ) {
127
- return;
128
- }
129
-
130
- ob_start();
131
-
132
- $needs_credentials = false;
133
-
134
- if ( ! Health_Check_Troubleshoot::mu_plugin_exists() ) {
135
- if ( ! Health_Check::get_filesystem_credentials() ) {
136
- $needs_credentials = true;
137
- } else {
138
- $check_output = Health_Check_Troubleshoot::setup_must_use_plugin( false );
139
- if ( false === $check_output ) {
140
- $needs_credentials = true;
141
- }
142
- }
143
- } else {
144
- if ( ! Health_Check_Troubleshoot::maybe_update_must_use_plugin() ) {
145
- $needs_credentials = true;
146
- }
147
- }
148
-
149
- $result = ob_get_clean();
150
-
151
- if ( $needs_credentials ) {
152
- $this->admin_notices[] = (object) array(
153
- 'message' => $result,
154
- 'type' => 'warning',
155
- );
156
- return;
157
- }
158
-
159
- Health_Check_Troubleshoot::initiate_troubleshooting_mode( array(
160
- $_GET['health-check-troubleshoot-plugin'] => $_GET['health-check-troubleshoot-plugin'],
161
- ) );
162
-
163
- wp_redirect( admin_url( 'plugins.php' ) );
164
- }
165
-
166
- /**
167
- * Load translations.
168
- *
169
- * Loads the textdomain needed to get translations for our plugin.
170
- *
171
- * @uses load_plugin_textdomain()
172
- * @uses basename()
173
- * @uses dirname()
174
- *
175
- * @return void
176
- */
177
- public function load_i18n() {
178
- load_plugin_textdomain( 'health-check', false, basename( dirname( __FILE__ ) ) . '/languages/' );
179
- }
180
-
181
- /**
182
- * Enqueue assets.
183
- *
184
- * Conditionally enqueue our CSS and JavaScript when viewing plugin related pages in wp-admin.
185
- *
186
- * @uses wp_enqueue_style()
187
- * @uses plugins_url()
188
- * @uses wp_enqueue_script()
189
- * @uses wp_localize_script()
190
- * @uses esc_html__()
191
- *
192
- * @return void
193
- */
194
- public function enqueues() {
195
- // Don't enqueue anything unless we're on the health check page
196
- if ( ! isset( $_GET['page'] ) || 'health-check' !== $_GET['page'] ) {
197
-
198
- /*
199
- * Special consideration, if warnings are not dismissed we need to display
200
- * our modal, and thus require our styles, in other locations, before bailing.
201
- */
202
- if ( ! Health_Check_Troubleshoot::has_seen_warning() ) {
203
- wp_enqueue_style( 'health-check', HEALTH_CHECK_PLUGIN_URL . '/assets/css/health-check.css', array(), HEALTH_CHECK_PLUGIN_VERSION );
204
- }
205
- return;
206
- }
207
-
208
- wp_enqueue_style( 'health-check', HEALTH_CHECK_PLUGIN_URL . '/assets/css/health-check.css', array(), HEALTH_CHECK_PLUGIN_VERSION );
209
-
210
- wp_enqueue_script( 'health-check', HEALTH_CHECK_PLUGIN_URL . '/assets/javascript/health-check.js', array( 'jquery' ), HEALTH_CHECK_PLUGIN_VERSION, true );
211
-
212
- wp_localize_script( 'health-check', 'HealthCheck', array(
213
- 'string' => array(
214
- 'please_wait' => esc_html__( 'Please wait...', 'health-check' ),
215
- 'copied' => esc_html__( 'Copied', 'health-check' ),
216
- 'running_tests' => esc_html__( 'Currently being tested...', 'health-check' ),
217
- ),
218
- 'warning' => array(
219
- 'seen_backup' => Health_Check_Troubleshoot::has_seen_warning(),
220
- ),
221
- ) );
222
- }
223
-
224
- /**
225
- * Add item to the admin menu.
226
- *
227
- * @uses add_dashboard_page()
228
- * @uses __()
229
- *
230
- * @return void
231
- */
232
- public function action_admin_menu() {
233
- add_dashboard_page( _x( 'Health Check', 'Menu, Section and Page Title', 'health-check' ), _x( 'Health Check', 'Menu, Section and Page Title', 'health-check' ), 'manage_options', 'health-check', array( $this, 'dashboard_page' ) );
234
- }
235
-
236
- /**
237
- * Add a quick-access link under our plugin name on the plugins-list.
238
- *
239
- * @uses plugin_basename()
240
- * @uses sprintf()
241
- * @uses menu_page_url()
242
- *
243
- * @param array $meta An array containing meta links.
244
- * @param string $name The plugin slug that these metas relate to.
245
- *
246
- * @return array
247
- */
248
- public function settings_link( $meta, $name ) {
249
- if ( plugin_basename( __FILE__ ) === $name ) {
250
- $meta[] = sprintf( '<a href="%s">' . _x( 'Health Check', 'Menu, Section and Page Title', 'health-check' ) . '</a>', menu_page_url( 'health-check', false ) );
251
- }
252
-
253
- return $meta;
254
- }
255
-
256
- /**
257
- * Add a troubleshooting action link to plugins.
258
- *
259
- * @param $actions
260
- * @param $plugin_file
261
- * @param $plugin_data
262
- * @param $context
263
- *
264
- * @return array
265
- */
266
- public function troubeshoot_plugin_action( $actions, $plugin_file, $plugin_data, $context ) {
267
- // Don't add anything if this is a Must-Use plugin, we can't touch those.
268
- if ( 'mustuse' === $context ) {
269
- return $actions;
270
- }
271
-
272
- // Only add troubleshooting actions to active plugins.
273
- if ( ! is_plugin_active( $plugin_file ) ) {
274
- return $actions;
275
- }
276
-
277
- // Set a slug if the plugin lives in the plugins directory root.
278
- if ( ! stristr( $plugin_file, '/' ) ) {
279
- $plugin_data['slug'] = $plugin_file;
280
- }
281
-
282
- $actions['troubleshoot'] = sprintf(
283
- '<a href="%s">%s</a>',
284
- esc_url( add_query_arg( array(
285
- 'health-check-troubleshoot-plugin' => ( isset( $plugin_data['slug'] ) ? $plugin_data['slug'] : sanitize_title( $plugin_data['Name'] ) ),
286
- ), admin_url( 'plugins.php' ) ) ),
287
- esc_html__( 'Troubleshoot', 'health-check' )
288
- );
289
-
290
- return $actions;
291
- }
292
-
293
- /**
294
- * Render our admin page.
295
- *
296
- * @uses _e()
297
- * @uses esc_html__()
298
- * @uses printf()
299
- * @uses sprintf()
300
- * @uses menu_page_url()
301
- * @uses dirname()
302
- *
303
- * @return void
304
- */
305
- public function dashboard_page() {
306
- ?>
307
- <div class="wrap">
308
- <h1>
309
- <?php _ex( 'Health Check', 'Menu, Section and Page Title', 'health-check' ); ?>
310
- </h1>
311
-
312
- <?php
313
- $tabs = array(
314
- 'site-status' => esc_html__( 'Site Status', 'health-check' ),
315
- 'debug' => esc_html__( 'Debug Information', 'health-check' ),
316
- 'troubleshoot' => esc_html__( 'Troubleshooting', 'health-check' ),
317
- 'phpinfo' => esc_html__( 'PHP Information', 'health-check' ),
318
- 'tools' => esc_html__( 'Tools', 'health-check' ),
319
- );
320
-
321
- $current_tab = ( isset( $_GET['tab'] ) ? $_GET['tab'] : 'site-status' );
322
- ?>
323
-
324
- <h2 class="nav-tab-wrapper wp-clearfix">
325
- <?php
326
- foreach ( $tabs as $tab => $label ) {
327
- printf(
328
- '<a href="%s" class="nav-tab %s">%s</a>',
329
- sprintf(
330
- '%s&tab=%s',
331
- menu_page_url( 'health-check', false ),
332
- $tab
333
- ),
334
- ( $current_tab === $tab ? 'nav-tab-active' : '' ),
335
- $label
336
- );
337
- }
338
- ?>
339
- </h2>
340
-
341
- <?php
342
- switch ( $current_tab ) {
343
- case 'debug':
344
- include_once( HEALTH_CHECK_PLUGIN_DIRECTORY . '/pages/debug-data.php' );
345
- break;
346
- case 'phpinfo':
347
- include_once( HEALTH_CHECK_PLUGIN_DIRECTORY . '/pages/phpinfo.php' );
348
- break;
349
- case 'troubleshoot':
350
- include_once( HEALTH_CHECK_PLUGIN_DIRECTORY . '/pages/troubleshoot.php' );
351
- break;
352
- case 'tools':
353
- include_once( HEALTH_CHECK_PLUGIN_DIRECTORY . '/pages/tools.php' );
354
- break;
355
- case 'site-status':
356
- default:
357
- include_once( HEALTH_CHECK_PLUGIN_DIRECTORY . '/pages/site-status.php' );
358
- }
359
- ?>
360
- </div>
361
- <?php
362
- }
363
-
364
- /**
365
- * Display styled admin notices.
366
- *
367
- * @uses printf()
368
- *
369
- * @param string $message A sanitized string containing our notice message.
370
- * @param string $status A string representing the status type.
371
- *
372
- * @return void
373
- */
374
- static function display_notice( $message, $status = 'success' ) {
375
- printf(
376
- '<div class="notice notice-%s inline">',
377
- $status
378
- );
379
-
380
- printf(
381
- '<p>%s</p>',
382
- $message
383
- );
384
-
385
- echo '</div>';
386
- }
387
-
388
- /**
389
- * Display admin notices if we have any queued.
390
- *
391
- * @return void
392
- */
393
- public function admin_notices() {
394
- foreach ( $this->admin_notices as $admin_notice ) {
395
- printf(
396
- '<div class="notice notice-%s"><p>%s</p></div>',
397
- esc_attr( $admin_notice->type ),
398
- $admin_notice->message
399
- );
400
- }
401
- }
402
-
403
-
404
- /**
405
- * Conditionally show a form for providing filesystem credentials when introducing our troubleshooting mode plugin.
406
- *
407
- * @uses wp_nonce_url()
408
- * @uses add_query_arg()
409
- * @uses admin_url()
410
- * @uses request_filesystem_credentials()
411
- * @uses WP_Filesystem
412
- *
413
- * @param array $args Any WP_Filesystem arguments you wish to pass.
414
- *
415
- * @return bool
416
- */
417
- static function get_filesystem_credentials( $args = array() ) {
418
- $args = array_merge(
419
- array(
420
- 'page' => 'health-check',
421
- 'tab' => 'troubleshoot',
422
- ),
423
- $args
424
- );
425
-
426
- $url = wp_nonce_url( add_query_arg( $args, admin_url() ) );
427
- $creds = request_filesystem_credentials( $url, '', false, WP_CONTENT_DIR, array( 'health-check-troubleshoot-mode', 'action' ) );
428
- if ( false === $creds ) {
429
- return false;
430
- }
431
-
432
- if ( ! WP_Filesystem( $creds ) ) {
433
- request_filesystem_credentials( $url, '', true, WPMU_PLUGIN_DIR, array( 'health-check-troubleshoot-mode', 'action' ) );
434
- return false;
435
- }
436
-
437
- return true;
438
- }
439
-
440
- /**
441
- * Perform a check to see is JSON is enabled.
442
- *
443
- * @uses extension_loaded()
444
- * @uses function_Exists()
445
- * @uses son_encode()
446
- *
447
- * @return bool
448
- */
449
- static function json_check() {
450
- $extension_loaded = extension_loaded( 'json' );
451
- $functions_exist = function_exists( 'json_encode' ) && function_exists( 'json_decode' );
452
- $functions_work = function_exists( 'json_encode' ) && ( '' != json_encode( 'my test string' ) );
453
-
454
- return $extension_loaded && $functions_exist && $functions_work;
455
- }
456
- }
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Primary class file for the Health Check plugin.
4
+ *
5
+ * @package Health Check
6
+ */
7
+
8
+ /**
9
+ * Class HealthCheck
10
+ */
11
+ class Health_Check {
12
+
13
+ /**
14
+ * Notices to show at the head of the admin screen.
15
+ *
16
+ * @access public
17
+ *
18
+ * @var array
19
+ */
20
+ public $admin_notices = array();
21
+
22
+ /**
23
+ * HealthCheck constructor.
24
+ *
25
+ * @uses Health_Check::init()
26
+ *
27
+ * @return void
28
+ */
29
+ public function __construct() {
30
+ $this->init();
31
+ }
32
+
33
+ /**
34
+ * Plugin initiation.
35
+ *
36
+ * A helper function, called by `HealthCheck::__construct()` to initiate actions, hooks and other features needed.
37
+ *
38
+ * @uses add_action()
39
+ * @uses add_filter()
40
+ *
41
+ * @return void
42
+ */
43
+ public function init() {
44
+ add_action( 'plugins_loaded', array( $this, 'load_i18n' ) );
45
+
46
+ add_action( 'admin_menu', array( $this, 'action_admin_menu' ) );
47
+
48
+ add_filter( 'plugin_row_meta', array( $this, 'settings_link' ), 10, 2 );
49
+
50
+ add_filter( 'plugin_action_links', array( $this, 'troubeshoot_plugin_action' ), 20, 4 );
51
+
52
+ add_action( 'admin_footer', array( $this, 'show_backup_warning' ) );
53
+
54
+ add_action( 'admin_notices', array( $this, 'admin_notices' ) );
55
+
56
+ add_action( 'admin_enqueue_scripts', array( $this, 'enqueues' ) );
57
+
58
+ add_action( 'init', array( $this, 'start_troubleshoot_mode' ) );
59
+ add_action( 'load-plugins.php', array( $this, 'start_troubleshoot_single_plugin_mode' ) );
60
+
61
+ add_action( 'wp_ajax_health-check-loopback-no-plugins', array( 'Health_Check_Loopback', 'loopback_no_plugins' ) );
62
+ add_action( 'wp_ajax_health-check-loopback-individual-plugins', array( 'Health_Check_Loopback', 'loopback_test_individual_plugins' ) );
63
+ add_action( 'wp_ajax_health-check-loopback-default-theme', array( 'Health_Check_Loopback', 'loopback_test_default_theme' ) );
64
+ add_action( 'wp_ajax_health-check-files-integrity-check', array( 'Health_Check_Files_Integrity', 'run_files_integrity_check' ) );
65
+ add_action( 'wp_ajax_health-check-view-file-diff', array( 'Health_Check_Files_Integrity', 'view_file_diff' ) );
66
+ add_action( 'wp_ajax_health-check-mail-check', array( 'Health_Check_Mail_Check', 'run_mail_check' ) );
67
+ add_action( 'wp_ajax_health-check-confirm-warning', array( 'Health_Check_Troubleshoot', 'confirm_warning' ) );
68
+
69
+ add_filter( 'health_check_tools_tab', array( 'Health_Check_Files_Integrity', 'tools_tab' ) );
70
+ add_filter( 'health_check_tools_tab', array( 'Health_Check_Mail_Check', 'tools_tab' ) );
71
+ }
72
+
73
+ /**
74
+ * Show a warning modal about keeping backups.
75
+ *
76
+ * @uses Health_Check_Troubleshoot::has_seen_warning()
77
+ *
78
+ * @return void
79
+ */
80
+ public function show_backup_warning() {
81
+ if ( Health_Check_Troubleshoot::has_seen_warning() ) {
82
+ return;
83
+ }
84
+
85
+ include_once( HEALTH_CHECK_PLUGIN_DIRECTORY . '/modals/backup-warning.php' );
86
+ }
87
+
88
+ /**
89
+ * Initiate troubleshooting mode.
90
+ *
91
+ * Catch when the troubleshooting form has been submitted, and appropriately set required options and cookies.
92
+ *
93
+ * @uses current_user_can()
94
+ * @uses Health_Check_Troubleshoot::initiate_troubleshooting_mode()
95
+ *
96
+ * @return void
97
+ */
98
+ public function start_troubleshoot_mode() {
99
+ if ( ! isset( $_POST['health-check-troubleshoot-mode'] ) || ! current_user_can( 'manage_options' ) ) {
100
+ return;
101
+ }
102
+
103
+ // Don't enable troubleshooting if nonces are missing or do not match.
104
+ if ( ! isset( $_POST['_wpnonce'] ) || ! wp_verify_nonce( $_POST['_wpnonce'], 'health-check-enable-troubleshooting' ) ) {
105
+ return;
106
+ }
107
+
108
+ Health_Check_Troubleshoot::initiate_troubleshooting_mode();
109
+ }
110
+
111
+ /**
112
+ * Initiate troubleshooting mode for a specific plugin.
113
+ *
114
+ * Catch when the troubleshooting link on an individual plugin has been clicked, and appropriately sets the
115
+ * required options and cookies.
116
+ *
117
+ * @uses current_user_can()
118
+ * @uses ob_start()
119
+ * @uses Health_Check_Troubleshoot::mu_plugin_exists()
120
+ * @uses Health_Check::get_filesystem_credentials()
121
+ * @uses Health_Check_Troubleshoot::setup_must_use_plugin()
122
+ * @uses Health_Check_Troubleshoot::maybe_update_must_use_plugin()
123
+ * @uses ob_get_clean()
124
+ * @uses Health_Check_Troubleshoot::initiate_troubleshooting_mode()
125
+ * @uses wp_redirect()
126
+ * @uses admin_url()
127
+ *
128
+ * @return void
129
+ */
130
+ public function start_troubleshoot_single_plugin_mode() {
131
+ if ( ! isset( $_GET['health-check-troubleshoot-plugin'] ) || ! current_user_can( 'manage_options' ) ) {
132
+ return;
133
+ }
134
+
135
+ // Don't enable troubleshooting for an individual plugin if the nonce is missing or invalid.
136
+ if ( ! isset( $_GET['_wpnonce'] ) || ! wp_verify_nonce( $_GET['_wpnonce'], 'health-check-troubleshoot-plugin-' . $_GET['health-check-troubleshoot-plugin'] ) ) {
137
+ return;
138
+ }
139
+
140
+ ob_start();
141
+
142
+ $needs_credentials = false;
143
+
144
+ if ( ! Health_Check_Troubleshoot::mu_plugin_exists() ) {
145
+ if ( ! Health_Check::get_filesystem_credentials() ) {
146
+ $needs_credentials = true;
147
+ } else {
148
+ $check_output = Health_Check_Troubleshoot::setup_must_use_plugin( false );
149
+ if ( false === $check_output ) {
150
+ $needs_credentials = true;
151
+ }
152
+ }
153
+ } else {
154
+ if ( ! Health_Check_Troubleshoot::maybe_update_must_use_plugin() ) {
155
+ $needs_credentials = true;
156
+ }
157
+ }
158
+
159
+ $result = ob_get_clean();
160
+
161
+ if ( $needs_credentials ) {
162
+ $this->admin_notices[] = (object) array(
163
+ 'message' => $result,
164
+ 'type' => 'warning',
165
+ );
166
+ return;
167
+ }
168
+
169
+ Health_Check_Troubleshoot::initiate_troubleshooting_mode( array(
170
+ $_GET['health-check-troubleshoot-plugin'] => $_GET['health-check-troubleshoot-plugin'],
171
+ ) );
172
+
173
+ wp_redirect( admin_url( 'plugins.php' ) );
174
+ }
175
+
176
+ /**
177
+ * Load translations.
178
+ *
179
+ * Loads the textdomain needed to get translations for our plugin.
180
+ *
181
+ * @uses load_plugin_textdomain()
182
+ * @uses basename()
183
+ * @uses dirname()
184
+ *
185
+ * @return void
186
+ */
187
+ public function load_i18n() {
188
+ load_plugin_textdomain( 'health-check', false, basename( dirname( __FILE__ ) ) . '/languages/' );
189
+ }
190
+
191
+ /**
192
+ * Enqueue assets.
193
+ *
194
+ * Conditionally enqueue our CSS and JavaScript when viewing plugin related pages in wp-admin.
195
+ *
196
+ * @uses wp_enqueue_style()
197
+ * @uses plugins_url()
198
+ * @uses wp_enqueue_script()
199
+ * @uses wp_localize_script()
200
+ * @uses esc_html__()
201
+ *
202
+ * @return void
203
+ */
204
+ public function enqueues() {
205
+ // Don't enqueue anything unless we're on the health check page
206
+ if ( ! isset( $_GET['page'] ) || 'health-check' !== $_GET['page'] ) {
207
+
208
+ /*
209
+ * Special consideration, if warnings are not dismissed we need to display
210
+ * our modal, and thus require our styles, in other locations, before bailing.
211
+ */
212
+ if ( ! Health_Check_Troubleshoot::has_seen_warning() ) {
213
+ wp_enqueue_style( 'health-check', HEALTH_CHECK_PLUGIN_URL . '/assets/css/health-check.css', array(), HEALTH_CHECK_PLUGIN_VERSION );
214
+ }
215
+ return;
216
+ }
217
+
218
+ wp_enqueue_style( 'health-check', HEALTH_CHECK_PLUGIN_URL . '/assets/css/health-check.css', array(), HEALTH_CHECK_PLUGIN_VERSION );
219
+
220
+ wp_enqueue_script( 'health-check', HEALTH_CHECK_PLUGIN_URL . '/assets/javascript/health-check.js', array( 'jquery' ), HEALTH_CHECK_PLUGIN_VERSION, true );
221
+
222
+ wp_localize_script( 'health-check', 'HealthCheck', array(
223
+ 'string' => array(
224
+ 'please_wait' => esc_html__( 'Please wait...', 'health-check' ),
225
+ 'copied' => esc_html__( 'Copied', 'health-check' ),
226
+ 'running_tests' => esc_html__( 'Currently being tested...', 'health-check' ),
227
+ ),
228
+ 'warning' => array(
229
+ 'seen_backup' => Health_Check_Troubleshoot::has_seen_warning(),
230
+ ),
231
+ 'nonce' => array(
232
+ 'loopback_no_plugins' => wp_create_nonce( 'health-check-loopback-no-plugins' ),
233
+ 'loopback_individual_plugins' => wp_create_nonce( 'health-check-loopback-individual-plugins' ),
234
+ 'loopback_default_theme' => wp_create_nonce( 'health-check-loopback-default-theme' ),
235
+ 'files_integrity_check' => wp_create_nonce( 'health-check-files-integrity-check' ),
236
+ 'view_file_diff' => wp_create_nonce( 'health-check-view-file-diff' ),
237
+ 'mail_check' => wp_create_nonce( 'health-check-mail-check' ),
238
+ 'confirm_warning' => wp_create_nonce( 'health-check-confirm-warning' ),
239
+ 'site_status' => wp_create_nonce( 'health-check-site-status' ),
240
+ ),
241
+ ) );
242
+ }
243
+
244
+ /**
245
+ * Add item to the admin menu.
246
+ *
247
+ * @uses add_dashboard_page()
248
+ * @uses __()
249
+ *
250
+ * @return void
251
+ */
252
+ public function action_admin_menu() {
253
+ add_dashboard_page( _x( 'Health Check', 'Menu, Section and Page Title', 'health-check' ), _x( 'Health Check', 'Menu, Section and Page Title', 'health-check' ), 'manage_options', 'health-check', array( $this, 'dashboard_page' ) );
254
+ }
255
+
256
+ /**
257
+ * Add a quick-access link under our plugin name on the plugins-list.
258
+ *
259
+ * @uses plugin_basename()
260
+ * @uses sprintf()
261
+ * @uses menu_page_url()
262
+ *
263
+ * @param array $meta An array containing meta links.
264
+ * @param string $name The plugin slug that these metas relate to.
265
+ *
266
+ * @return array
267
+ */
268
+ public function settings_link( $meta, $name ) {
269
+ if ( plugin_basename( __FILE__ ) === $name ) {
270
+ $meta[] = sprintf( '<a href="%s">' . _x( 'Health Check', 'Menu, Section and Page Title', 'health-check' ) . '</a>', menu_page_url( 'health-check', false ) );
271
+ }
272
+
273
+ return $meta;
274
+ }
275
+
276
+ /**
277
+ * Add a troubleshooting action link to plugins.
278
+ *
279
+ * @param $actions
280
+ * @param $plugin_file
281
+ * @param $plugin_data
282
+ * @param $context
283
+ *
284
+ * @return array
285
+ */
286
+ public function troubeshoot_plugin_action( $actions, $plugin_file, $plugin_data, $context ) {
287
+ // Don't add anything if this is a Must-Use plugin, we can't touch those.
288
+ if ( 'mustuse' === $context ) {
289
+ return $actions;
290
+ }
291
+
292
+ // Only add troubleshooting actions to active plugins.
293
+ if ( ! is_plugin_active( $plugin_file ) ) {
294
+ return $actions;
295
+ }
296
+
297
+ // Set a slug if the plugin lives in the plugins directory root.
298
+ if ( ! stristr( $plugin_file, '/' ) ) {
299
+ $plugin_data['slug'] = $plugin_file;
300
+ }
301
+
302
+ $actions['troubleshoot'] = sprintf(
303
+ '<a href="%s">%s</a>',
304
+ esc_url( add_query_arg( array(
305
+ 'health-check-troubleshoot-plugin' => ( isset( $plugin_data['slug'] ) ? $plugin_data['slug'] : sanitize_title( $plugin_data['Name'] ) ),
306
+ '_wpnonce' => wp_create_nonce( 'health-check-troubleshoot-plugin-' . $plugin_data['slug'] ),
307
+ ), admin_url( 'plugins.php' ) ) ),
308
+ esc_html__( 'Troubleshoot', 'health-check' )
309
+ );
310
+
311
+ return $actions;
312
+ }
313
+
314
+ /**
315
+ * Render our admin page.
316
+ *
317
+ * @uses _e()
318
+ * @uses esc_html__()
319
+ * @uses printf()
320
+ * @uses sprintf()
321
+ * @uses menu_page_url()
322
+ * @uses dirname()
323
+ *
324
+ * @return void
325
+ */
326
+ public function dashboard_page() {
327
+ ?>
328
+ <div class="wrap">
329
+ <h1>
330
+ <?php _ex( 'Health Check', 'Menu, Section and Page Title', 'health-check' ); ?>
331
+ </h1>
332
+
333
+ <?php
334
+ $tabs = array(
335
+ 'site-status' => esc_html__( 'Site Status', 'health-check' ),
336
+ 'debug' => esc_html__( 'Debug Information', 'health-check' ),
337
+ 'troubleshoot' => esc_html__( 'Troubleshooting', 'health-check' ),
338
+ 'phpinfo' => esc_html__( 'PHP Information', 'health-check' ),
339
+ 'tools' => esc_html__( 'Tools', 'health-check' ),
340
+ );
341
+
342
+ $current_tab = ( isset( $_GET['tab'] ) ? $_GET['tab'] : 'site-status' );
343
+ ?>
344
+
345
+ <h2 class="nav-tab-wrapper wp-clearfix">
346
+ <?php
347
+ foreach ( $tabs as $tab => $label ) {
348
+ printf(
349
+ '<a href="%s" class="nav-tab %s">%s</a>',
350
+ sprintf(
351
+ '%s&tab=%s',
352
+ menu_page_url( 'health-check', false ),
353
+ $tab
354
+ ),
355
+ ( $current_tab === $tab ? 'nav-tab-active' : '' ),
356
+ $label
357
+ );
358
+ }
359
+ ?>
360
+ </h2>
361
+
362
+ <?php
363
+ switch ( $current_tab ) {
364
+ case 'debug':
365
+ include_once( HEALTH_CHECK_PLUGIN_DIRECTORY . '/pages/debug-data.php' );
366
+ break;
367
+ case 'phpinfo':
368
+ include_once( HEALTH_CHECK_PLUGIN_DIRECTORY . '/pages/phpinfo.php' );
369
+ break;
370
+ case 'troubleshoot':
371
+ include_once( HEALTH_CHECK_PLUGIN_DIRECTORY . '/pages/troubleshoot.php' );
372
+ break;
373
+ case 'tools':
374
+ include_once( HEALTH_CHECK_PLUGIN_DIRECTORY . '/pages/tools.php' );
375
+ break;
376
+ case 'site-status':
377
+ default:
378
+ include_once( HEALTH_CHECK_PLUGIN_DIRECTORY . '/pages/site-status.php' );
379
+ }
380
+ ?>
381
+ </div>
382
+ <?php
383
+ }
384
+
385
+ /**
386
+ * Display styled admin notices.
387
+ *
388
+ * @uses printf()
389
+ *
390
+ * @param string $message A sanitized string containing our notice message.
391
+ * @param string $status A string representing the status type.
392
+ *
393
+ * @return void
394
+ */
395
+ static function display_notice( $message, $status = 'success' ) {
396
+ printf(
397
+ '<div class="notice notice-%s inline">',
398
+ $status
399
+ );
400
+
401
+ printf(
402
+ '<p>%s</p>',
403
+ $message
404
+ );
405
+
406
+ echo '</div>';
407
+ }
408
+
409
+ /**
410
+ * Display admin notices if we have any queued.
411
+ *
412
+ * @return void
413
+ */
414
+ public function admin_notices() {
415
+ foreach ( $this->admin_notices as $admin_notice ) {
416
+ printf(
417
+ '<div class="notice notice-%s"><p>%s</p></div>',
418
+ esc_attr( $admin_notice->type ),
419
+ $admin_notice->message
420
+ );
421
+ }
422
+ }
423
+
424
+
425
+ /**
426
+ * Conditionally show a form for providing filesystem credentials when introducing our troubleshooting mode plugin.
427
+ *
428
+ * @uses wp_nonce_url()
429
+ * @uses add_query_arg()
430
+ * @uses admin_url()
431
+ * @uses request_filesystem_credentials()
432
+ * @uses WP_Filesystem
433
+ *
434
+ * @param array $args Any WP_Filesystem arguments you wish to pass.
435
+ *
436
+ * @return bool
437
+ */
438
+ static function get_filesystem_credentials( $args = array() ) {
439
+ $args = array_merge(
440
+ array(
441
+ 'page' => 'health-check',
442
+ 'tab' => 'troubleshoot',
443
+ ),
444
+ $args
445
+ );
446
+
447
+ $url = wp_nonce_url( add_query_arg( $args, admin_url() ) );
448
+ $creds = request_filesystem_credentials( $url, '', false, WP_CONTENT_DIR, array( 'health-check-troubleshoot-mode', 'action', '_wpnonce' ) );
449
+ if ( false === $creds ) {
450
+ return false;
451
+ }
452
+
453
+ if ( ! WP_Filesystem( $creds ) ) {
454
+ request_filesystem_credentials( $url, '', true, WPMU_PLUGIN_DIR, array( 'health-check-troubleshoot-mode', 'action', '_wpnonce' ) );
455
+ return false;
456
+ }
457
+
458
+ return true;
459
+ }
460
+ }
modals/backup-warning.php CHANGED
@@ -1,45 +1,46 @@
1
- <div class="health-check-modal" id="health-check-backup-warning" data-modal-action="" data-parent-field="">
2
- <div class="modal-content">
3
- <h2>
4
- <?php esc_html_e( 'Remember to keep backups', 'health-check' ); ?>
5
- </h2>
6
-
7
- <p>
8
- <?php _e( 'Because of how Troubleshooting Mode functions, unforeseen conflicts with other plugins or themes may in rare cases occur, leading to unexpected behaviors.', 'health-check' ); ?>
9
- </p>
10
-
11
- <p>
12
- <?php _e( 'We therefore strongly recommend <a href="https://codex.wordpress.org/WordPress_Backups">making a backup of your site</a> before you enable troubleshooting mode.', 'health-check' ); ?>
13
- </p>
14
-
15
- <p>
16
- <?php _e( 'Additionally, since we really want to make this plugin as safe as possible, if you should have any problems with the troubleshooting mode, please create a new topic in the <a href="https://wordpress.org/support/plugin/health-check">plugins support forum</a> with details about what theme and what plugins you’re using and the steps needed to reproduce the problem. This will help us to analyze and fix such problems.', 'health-check' ); ?>
17
- </p>
18
-
19
- <p>
20
- <button class="button button-primary" id="health-check-accept-backup-warning"><?php esc_html_e( 'I understand', 'health-check' ); ?></button>
21
- </p>
22
- </div>
23
- </div>
24
-
25
- <script type="text/javascript">
26
- jQuery( document ).ready(function( $ ) {
27
- if ( 'undefined' === typeof( health_check ) || false === health_check.warning.seen_backup ) {
28
- $( "#health-check-backup-warning" ).show();
29
- }
30
-
31
- $( "#health-check-accept-backup-warning" ).click(function( e ) {
32
- $( "#health-check-backup-warning" ).hide();
33
-
34
- var data = {
35
- action: 'health-check-confirm-warning',
36
- warning: 'backup'
37
- };
38
-
39
- $.post(
40
- ajaxurl,
41
- data
42
- );
43
- });
44
- });
45
- </script>
 
1
+ <div class="health-check-modal" id="health-check-backup-warning" data-modal-action="" data-parent-field="">
2
+ <div class="modal-content">
3
+ <h2>
4
+ <?php esc_html_e( 'Remember to keep backups', 'health-check' ); ?>
5
+ </h2>
6
+
7
+ <p>
8
+ <?php _e( 'Because of how Troubleshooting Mode functions, unforeseen conflicts with other plugins or themes may in rare cases occur, leading to unexpected behaviors.', 'health-check' ); ?>
9
+ </p>
10
+
11
+ <p>
12
+ <?php _e( 'We therefore strongly recommend <a href="https://codex.wordpress.org/WordPress_Backups">making a backup of your site</a> before you enable troubleshooting mode.', 'health-check' ); ?>
13
+ </p>
14
+
15
+ <p>
16
+ <?php _e( 'Additionally, since we really want to make this plugin as safe as possible, if you should have any problems with the troubleshooting mode, please create a new topic in the <a href="https://wordpress.org/support/plugin/health-check">plugins support forum</a> with details about what theme and what plugins you’re using and the steps needed to reproduce the problem. This will help us to analyze and fix such problems.', 'health-check' ); ?>
17
+ </p>
18
+
19
+ <p>
20
+ <button class="button button-primary" id="health-check-accept-backup-warning"><?php esc_html_e( 'I understand', 'health-check' ); ?></button>
21
+ </p>
22
+ </div>
23
+ </div>
24
+
25
+ <script type="text/javascript">
26
+ jQuery( document ).ready(function( $ ) {
27
+ if ( 'undefined' === typeof( health_check ) || false === health_check.warning.seen_backup ) {
28
+ $( "#health-check-backup-warning" ).show();
29
+ }
30
+
31
+ $( "#health-check-accept-backup-warning" ).click(function( e ) {
32
+ $( "#health-check-backup-warning" ).hide();
33
+
34
+ var data = {
35
+ 'action': 'health-check-confirm-warning',
36
+ 'warning': 'backup',
37
+ '_wpnonce': HealthCheck.nonce.confirm_warning
38
+ };
39
+
40
+ $.post(
41
+ ajaxurl,
42
+ data
43
+ );
44
+ });
45
+ });
46
+ </script>
modals/diff.php CHANGED
@@ -6,4 +6,4 @@
6
  <div id="health-check-diff-modal-diff">
7
  </div>
8
  </div>
9
- </div>
6
  <div id="health-check-diff-modal-diff">
7
  </div>
8
  </div>
9
+ </div>
modals/js-result-warnings.php CHANGED
@@ -5,4 +5,4 @@
5
  &nbsp;
6
  </div>
7
  </div>
8
- </div>
5
  &nbsp;
6
  </div>
7
  </div>
8
+ </div>
pages/debug-data.php CHANGED
@@ -1,222 +1,140 @@
1
- <?php
2
- /**
3
- * Debug tab contents.
4
- *
5
- * @package Health Check
6
- */
7
-
8
- // Make sure the file is not directly accessible.
9
- if ( ! defined( 'ABSPATH' ) ) {
10
- die( 'We\'re sorry, but you can not directly access this file.' );
11
- }
12
-
13
- Health_Check_Debug_Data::check_for_updates();
14
-
15
- $info = Health_Check_Debug_Data::debug_data();
16
- ?>
17
-
18
-
19
- <div class="notice notice-info inline">
20
- <p>
21
- <?php esc_html_e( 'The system information shown below can also be copied and pasted into support requests such as on the WordPress.org forums, or to your theme and plugin developers.', 'health-check' ); ?>
22
- </p>
23
- <p>
24
- <button type="button" class="button button-primary" onclick="document.getElementById('system-information-copy-wrapper').style.display = 'block'; this.style.display = 'none';"><?php esc_html_e( 'Show copy and paste field', 'health-check' ); ?></button>
25
- <?php if ( 'en_US' !== get_locale() && version_compare( get_bloginfo( 'version' ), '4.7', '>=' ) ) : ?>
26
- <button type="button" class="button" onclick="document.getElementById('system-information-english-copy-wrapper').style.display = 'block'; this.style.display = 'none';"><?php esc_html_e( 'Show copy and paste field in English', 'health-check' ); ?></button>
27
- <?php endif; ?>
28
- </p>
29
-
30
- <?php
31
- if ( 'en_US' !== get_locale() && version_compare( get_bloginfo( 'version' ), '4.7', '>=' ) ) :
32
-
33
- $english_info = Health_Check_Debug_Data::debug_data( 'en_US' );
34
-
35
- // Workaround for locales not being properly loaded back, see issue #30 on GitHub.
36
- if ( ! is_textdomain_loaded( 'health-check' ) && _get_path_to_translation( 'health-check' ) ) {
37
- load_textdomain( 'health-check', _get_path_to_translation( 'health-check' ) );
38
- }
39
- ?>
40
- <div id="system-information-english-copy-wrapper" style="display: none;">
41
- <textarea id="system-information-english-copy-field" class="widefat" rows="10">`
42
- <?php
43
- foreach ( $english_info as $section => $details ) {
44
- // Skip this section if there are no fields, or the section has been declared as private.
45
- if ( empty( $details['fields'] ) || ( isset( $details['private'] ) && $details['private'] ) ) {
46
- continue;
47
- }
48
-
49
- printf(
50
- "### %s%s ###\n\n",
51
- $details['label'],
52
- ( isset( $details['show_count'] ) && $details['show_count'] ? sprintf( ' (%d)', count( $details['fields'] ) ) : '' )
53
- );
54
-
55
- foreach ( $details['fields'] as $field ) {
56
- if ( isset( $field['private'] ) && true === $field['private'] ) {
57
- continue;
58
- }
59
-
60
- $values = $field['value'];
61
- if ( is_array( $field['value'] ) ) {
62
- $values = '';
63
-
64
- foreach ( $field['value'] as $name => $value ) {
65
- $values .= sprintf(
66
- "\n\t%s: %s",
67
- $name,
68
- $value
69
- );
70
- }
71
- }
72
-
73
- printf(
74
- "%s: %s\n",
75
- $field['label'],
76
- $values
77
- );
78
- }
79
- echo "\n";
80
- }
81
- ?>
82
- `</textarea>
83
- <p>
84
- <?php esc_html_e( 'Some information may be filtered out from the list you are about to copy, this is information that may be considered private, and is not meant to be shared in a public forum.', 'health-check' ); ?>
85
- <br>
86
- <button type="button" class="button button-primary health-check-copy-field"><?php esc_html_e( 'Mark field for copying', 'health-check' ); ?></button>
87
- </p>
88
- </div>
89
-
90
- <?php endif; ?>
91
-
92
- <div id="system-information-copy-wrapper" style="display: none;">
93
- <textarea id="system-information-copy-field" class="widefat" rows="10">`
94
- <?php
95
- foreach ( $info as $section => $details ) {
96
- // Skip this section if there are no fields, or the section has been declared as private.
97
- if ( empty( $details['fields'] ) || ( isset( $details['private'] ) && $details['private'] ) ) {
98
- continue;
99
- }
100
-
101
- printf(
102
- "### %s%s ###\n\n",
103
- $details['label'],
104
- ( isset( $details['show_count'] ) && $details['show_count'] ? sprintf( ' (%d)', count( $details['fields'] ) ) : '' )
105
- );
106
-
107
- foreach ( $details['fields'] as $field ) {
108
- if ( isset( $field['private'] ) && true === $field['private'] ) {
109
- continue;
110
- }
111
-
112
- $values = $field['value'];
113
- if ( is_array( $field['value'] ) ) {
114
- $values = '';
115
-
116
- foreach ( $field['value'] as $name => $value ) {
117
- $values .= sprintf(
118
- "\n\t%s: %s",
119
- $name,
120
- $value
121
- );
122
- }
123
- }
124
-
125
- printf(
126
- "%s: %s\n",
127
- $field['label'],
128
- $values
129
- );
130
- }
131
- echo "\n";
132
- }
133
- ?>
134
- `</textarea>
135
- <p>
136
- <?php esc_html_e( 'Some information may be filtered out from the list you are about to copy, this is information that may be considered private, and is not meant to be shared in a public forum.', 'health-check' ); ?>
137
- <br>
138
- <button type="button" class="button button-primary health-check-copy-field"><?php esc_html_e( 'Mark field for copying', 'health-check' ); ?></button>
139
- </p>
140
- </div>
141
- </div>
142
-
143
- <h2 id="system-information-table-of-contents">
144
- <?php esc_html_e( 'Table Of Contents', 'health-check' ); ?>
145
- </h2>
146
- <div>
147
- <?php
148
- $toc = array();
149
-
150
- foreach ( $info as $section => $details ) {
151
- if ( empty( $details['fields'] ) ) {
152
- continue;
153
- }
154
-
155
- $toc[] = sprintf(
156
- '<a href="#%s" class="health-check-toc">%s</a>',
157
- esc_attr( $section ),
158
- esc_html( $details['label'] )
159
- );
160
- }
161
-
162
- echo implode( ' | ', $toc );
163
- ?>
164
- </div>
165
-
166
- <?php
167
- foreach ( $info as $section => $details ) {
168
- if ( ! isset( $details['fields'] ) || empty( $details['fields'] ) ) {
169
- continue;
170
- }
171
-
172
- printf(
173
- '<h2 id="%s">%s%s</h2>',
174
- esc_attr( $section ),
175
- esc_html( $details['label'] ),
176
- ( isset( $details['show_count'] ) && $details['show_count'] ? sprintf( ' (%d)', count( $details['fields'] ) ) : '' )
177
- );
178
-
179
- if ( isset( $details['description'] ) && ! empty( $details['description'] ) ) {
180
- printf(
181
- '<p>%s</p>',
182
- wp_kses( $details['description'], array(
183
- 'a' => array(
184
- 'href' => true,
185
- ),
186
- 'strong' => true,
187
- 'em' => true,
188
- ) )
189
- );
190
- }
191
- ?>
192
- <table class="widefat striped health-check-table">
193
- <tbody>
194
- <?php
195
- foreach ( $details['fields'] as $field ) {
196
- if ( is_array( $field['value'] ) ) {
197
- $values = '';
198
- foreach ( $field['value'] as $name => $value ) {
199
- $values .= sprintf(
200
- '<li>%s: %s</li>',
201
- esc_html( $name ),
202
- esc_html( $value )
203
- );
204
- }
205
- } else {
206
- $values = esc_html( $field['value'] );
207
- }
208
-
209
- printf(
210
- '<tr><td>%s</td><td>%s</td></tr>',
211
- esc_html( $field['label'] ),
212
- $values
213
- );
214
- }
215
- ?>
216
- </tbody>
217
- </table>
218
- <span style="display: block; width: 100%; text-align: <?php echo ( is_rtl() ? 'left' : 'right' ); ?>">
219
- <a href="#system-information-table-of-contents" class="health-check-toc"><?php esc_html_e( 'Return to table of contents', 'health-check' ); ?></a>
220
- </span>
221
- <?php
222
- }
1
+ <?php
2
+ /**
3
+ * Debug tab contents.
4
+ *
5
+ * @package Health Check
6
+ */
7
+
8
+ // Make sure the file is not directly accessible.
9
+ if ( ! defined( 'ABSPATH' ) ) {
10
+ die( 'We\'re sorry, but you can not directly access this file.' );
11
+ }
12
+
13
+ Health_Check_Debug_Data::check_for_updates();
14
+
15
+ $info = Health_Check_Debug_Data::debug_data();
16
+ ?>
17
+
18
+
19
+ <div class="notice notice-info inline">
20
+ <p>
21
+ <?php esc_html_e( 'The system information shown below can also be copied and pasted into support requests such as on the WordPress.org forums, or to your theme and plugin developers.', 'health-check' ); ?>
22
+ </p>
23
+ <p>
24
+ <button type="button" class="button button-primary" onclick="document.getElementById('system-information-copy-wrapper').style.display = 'block'; this.style.display = 'none';"><?php esc_html_e( 'Show copy and paste field', 'health-check' ); ?></button>
25
+ <?php if ( 'en_US' !== get_locale() && version_compare( get_bloginfo( 'version' ), '4.7', '>=' ) ) : ?>
26
+ <button type="button" class="button" onclick="document.getElementById('system-information-english-copy-wrapper').style.display = 'block'; this.style.display = 'none';"><?php esc_html_e( 'Show copy and paste field in English', 'health-check' ); ?></button>
27
+ <?php endif; ?>
28
+ </p>
29
+
30
+ <?php
31
+ if ( 'en_US' !== get_locale() && version_compare( get_bloginfo( 'version' ), '4.7', '>=' ) ) :
32
+
33
+ $english_info = Health_Check_Debug_Data::debug_data( 'en_US' );
34
+
35
+ // Workaround for locales not being properly loaded back, see issue #30 on GitHub.
36
+ if ( ! is_textdomain_loaded( 'health-check' ) && _get_path_to_translation( 'health-check' ) ) {
37
+ load_textdomain( 'health-check', _get_path_to_translation( 'health-check' ) );
38
+ }
39
+ ?>
40
+ <div id="system-information-english-copy-wrapper" style="display: none;">
41
+ <textarea id="system-information-english-copy-field" class="widefat" rows="10"><?php Health_Check_Debug_Data::textarea_format( $english_info ); ?></textarea>
42
+ <p>
43
+ <?php esc_html_e( 'Some information may be filtered out from the list you are about to copy, this is information that may be considered private, and is not meant to be shared in a public forum.', 'health-check' ); ?>
44
+ <br>
45
+ <button type="button" class="button button-primary health-check-copy-field"><?php esc_html_e( 'Mark field for copying', 'health-check' ); ?></button>
46
+ </p>
47
+ </div>
48
+
49
+ <?php endif; ?>
50
+
51
+ <div id="system-information-copy-wrapper" style="display: none;">
52
+ <textarea id="system-information-copy-field" class="widefat" rows="10"><?php Health_Check_Debug_Data::textarea_format( $info ); ?></textarea>
53
+ <p>
54
+ <?php esc_html_e( 'Some information may be filtered out from the list you are about to copy, this is information that may be considered private, and is not meant to be shared in a public forum.', 'health-check' ); ?>
55
+ <br>
56
+ <button type="button" class="button button-primary health-check-copy-field"><?php esc_html_e( 'Mark field for copying', 'health-check' ); ?></button>
57
+ </p>
58
+ </div>
59
+ </div>
60
+
61
+ <h2 id="system-information-table-of-contents">
62
+ <?php esc_html_e( 'Table Of Contents', 'health-check' ); ?>
63
+ </h2>
64
+ <div>
65
+ <?php
66
+ $toc = array();
67
+
68
+ foreach ( $info as $section => $details ) {
69
+ if ( empty( $details['fields'] ) ) {
70
+ continue;
71
+ }
72
+
73
+ $toc[] = sprintf(
74
+ '<a href="#%s" class="health-check-toc">%s</a>',
75
+ esc_attr( $section ),
76
+ esc_html( $details['label'] )
77
+ );
78
+ }
79
+
80
+ echo implode( ' | ', $toc );
81
+ ?>
82
+ </div>
83
+
84
+ <?php
85
+ foreach ( $info as $section => $details ) {
86
+ if ( ! isset( $details['fields'] ) || empty( $details['fields'] ) ) {
87
+ continue;
88
+ }
89
+
90
+ printf(
91
+ '<h2 id="%s">%s%s</h2>',
92
+ esc_attr( $section ),
93
+ esc_html( $details['label'] ),
94
+ ( isset( $details['show_count'] ) && $details['show_count'] ? sprintf( ' (%d)', count( $details['fields'] ) ) : '' )
95
+ );
96
+
97
+ if ( isset( $details['description'] ) && ! empty( $details['description'] ) ) {
98
+ printf(
99
+ '<p>%s</p>',
100
+ wp_kses( $details['description'], array(
101
+ 'a' => array(
102
+ 'href' => true,
103
+ ),
104
+ 'strong' => true,
105
+ 'em' => true,
106
+ ) )
107
+ );
108
+ }
109
+ ?>
110
+ <table class="widefat striped health-check-table">
111
+ <tbody>
112
+ <?php
113
+ foreach ( $details['fields'] as $field ) {
114
+ if ( is_array( $field['value'] ) ) {
115
+ $values = '';
116
+ foreach ( $field['value'] as $name => $value ) {
117
+ $values .= sprintf(
118
+ '<li>%s: %s</li>',
119
+ esc_html( $name ),
120
+ esc_html( $value )
121
+ );
122
+ }
123
+ } else {
124
+ $values = esc_html( $field['value'] );
125
+ }
126
+
127
+ printf(
128
+ '<tr><td>%s</td><td>%s</td></tr>',
129
+ esc_html( $field['label'] ),
130
+ $values
131
+ );
132
+ }
133
+ ?>
134
+ </tbody>
135
+ </table>
136
+ <span style="display: block; width: 100%; text-align: <?php echo ( is_rtl() ? 'left' : 'right' ); ?>">
137
+ <a href="#system-information-table-of-contents" class="health-check-toc"><?php esc_html_e( 'Return to table of contents', 'health-check' ); ?></a>
138
+ </span>
139
+ <?php
140
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
pages/site-status.php CHANGED
@@ -1,125 +1,57 @@
1
- <?php
2
- /**
3
- * Health Check tab contents.
4
- *
5
- * @package Health Check
6
- */
7
-
8
- // Make sure the file is not directly accessible.
9
- if ( ! defined( 'ABSPATH' ) ) {
10
- die( 'We\'re sorry, but you can not directly access this file.' );
11
- }
12
- ?>
13
-
14
- <div class="notice notice-info inline">
15
- <p>
16
- <?php esc_html_e( 'The health check shows critical information about your WordPress configuration and items that require your attention.', 'health-check' ); ?>
17
- </p>
18
- </div>
19
-
20
- <table class="widefat striped health-check-table">
21
- <tbody>
22
- <tr>
23
- <td><?php esc_html_e( 'WordPress Version', 'health-check' ); ?></td>
24
- <td class="health-check-site-status-test" data-site-status="wordpress_version">
25
- <span class="spinner is-active"></span>
26
- </td>
27
- </tr>
28
-
29
- <tr>
30
- <td><?php esc_html_e( 'Plugin Versions', 'health-check' ); ?></td>
31
- <td class="health-check-site-status-test" data-site-status="plugin_version">
32
- <span class="spinner is-active"></span>
33
- </td>
34
- </tr>
35
-
36
- <tr>
37
- <td><?php esc_html_e( 'Theme Versions', 'health-check' ); ?></td>
38
- <td class="health-check-site-status-test" data-site-status="theme_version">
39
- <span class="spinner is-active"></span>
40
- </td>
41
- </tr>
42
-
43
- <tr>
44
- <td><?php esc_html_e( 'PHP Version', 'health-check' ); ?></td>
45
- <td class="health-check-site-status-test" data-site-status="php_version">
46
- <span class="spinner is-active"></span>
47
- </td>
48
- </tr>
49
-
50
- <tr>
51
- <td>
52
- <?php esc_html_e( 'Database Server version', 'health-check' ); ?>
53
- </td>
54
- <td class="health-check-site-status-test" data-site-status="sql_server">
55
- <span class="spinner is-active"></span>
56
- </td>
57
- </tr>
58
-
59
- <tr>
60
- <td><?php esc_html_e( 'JSON Extension', 'health-check' ); ?></td>
61
- <td class="health-check-site-status-test" data-site-status="json_extension">
62
- <span class="spinner is-active"></span>
63
- </td>
64
- </tr>
65
-
66
- <tr>
67
- <td><?php esc_html_e( 'MySQL utf8mb4 support', 'health-check' ); ?></td>
68
- <td class="health-check-site-status-test" data-site-status="utf8mb4_support">
69
- <span class="spinner is-active"></span>
70
- </td>
71
- </tr>
72
-
73
- <tr>
74
- <td><?php esc_html_e( 'Communication with WordPress.org', 'health-check' ); ?></td>
75
- <td class="health-check-site-status-test" data-site-status="dotorg_communication">
76
- <span class="spinner is-active"></span>
77
- </td>
78
- </tr>
79
-
80
- <tr>
81
- <td><?php esc_html_e( 'REST API availability', 'health-check' ); ?></td>
82
- <td class="health-check-site-status-test" data-site-status="rest_availability">
83
- <span class="spinner is-active"></span>
84
- </td>
85
- </tr>
86
-
87
- <tr>
88
- <td><?php esc_html_e( 'HTTPS status', 'health-check' ); ?></td>
89
- <td class="health-check-site-status-test" data-site-status="https_status">
90
- <span class="spinner is-active"></span>
91
- </td>
92
- </tr>
93
-
94
- <tr>
95
- <td><?php esc_html_e( 'Secure communication', 'health-check' ); ?></td>
96
- <td class="health-check-site-status-test" data-site-status="ssl_support">
97
- <span class="spinner is-active"></span>
98
- </td>
99
- </tr>
100
-
101
- <tr>
102
- <td><?php esc_html_e( 'Scheduled events', 'health-check' ); ?></td>
103
- <td class="health-check-site-status-test" data-site-status="scheduled_events">
104
- <span class="spinner is-active"></span>
105
- </td>
106
- </tr>
107
-
108
- <tr>
109
- <td><?php esc_html_e( 'Background updates', 'health-check' ); ?></td>
110
- <td class="health-check-site-status-test" data-site-status="background_updates">
111
- <span class="spinner is-active"></span>
112
- </td>
113
- </tr>
114
-
115
- <tr>
116
- <td><?php esc_html_e( 'Loopback request', 'health-check' ); ?></td>
117
- <td class="health-check-site-status-test" data-site-status="loopback_requests">
118
- <span class="spinner is-active"></span>
119
- </td>
120
- </tr>
121
- </tbody>
122
- </table>
123
-
124
- <?php
125
- include_once( HEALTH_CHECK_PLUGIN_DIRECTORY . '/modals/js-result-warnings.php' );
1
+ <?php
2
+ /**
3
+ * Health Check tab contents.
4
+ *
5
+ * @package Health Check
6
+ */
7
+
8
+ // Make sure the file is not directly accessible.
9
+ if ( ! defined( 'ABSPATH' ) ) {
10
+ die( 'We\'re sorry, but you can not directly access this file.' );
11
+ }
12
+
13
+ global $health_check_site_status;
14
+ ?>
15
+
16
+ <div class="notice notice-info inline">
17
+ <p>
18
+ <?php esc_html_e( 'The health check shows critical information about your WordPress configuration and items that require your attention.', 'health-check' ); ?>
19
+ </p>
20
+ </div>
21
+
22
+ <table class="widefat striped health-check-table">
23
+ <tbody>
24
+ <?php
25
+ $tests = Health_Check_Site_Status::get_tests();
26
+ foreach ( $tests['direct'] as $test ) :
27
+ ?>
28
+ <tr>
29
+ <td><?php echo esc_html( $test['label'] ); ?></td>
30
+ <td class="" data-site-status="<?php echo esc_attr( $test['test'] ); ?>">
31
+ <?php
32
+ $test_function = sprintf(
33
+ 'test_%s',
34
+ $test['test']
35
+ );
36
+
37
+ if ( method_exists( $health_check_site_status, $test_function ) && is_callable( array( $health_check_site_status, $test_function ) ) ) {
38
+ call_user_func( array( $health_check_site_status, $test_function ) );
39
+ }
40
+ ?>
41
+ </td>
42
+ </tr>
43
+ <?php endforeach; ?>
44
+
45
+ <?php foreach ( $tests['async'] as $test ) : ?>
46
+ <tr>
47
+ <td><?php echo esc_html( $test['label'] ); ?></td>
48
+ <td class="health-check-site-status-test" data-site-status="<?php echo esc_attr( $test['test'] ); ?>">
49
+ <span class="spinner is-active"></span>
50
+ </td>
51
+ </tr>
52
+ <?php endforeach; ?>
53
+ </tbody>
54
+ </table>
55
+
56
+ <?php
57
+ include_once( HEALTH_CHECK_PLUGIN_DIRECTORY . '/modals/js-result-warnings.php' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
pages/tools.php CHANGED
@@ -1,58 +1,58 @@
1
- <?php
2
- /**
3
- * Health Check tab contents.
4
- *
5
- * @package Health Check
6
- */
7
-
8
- // Make sure the file is not directly accessible.
9
- if ( ! defined( 'ABSPATH' ) ) {
10
- die( 'We\'re sorry, but you can not directly access this file.' );
11
- }
12
-
13
- ?>
14
-
15
- <dl id="health-check-tools" role="presentation" class="health-check-accordion">
16
- <?php
17
- /**
18
- * Filter the features available under the Tools tab.
19
- *
20
- * You may introduce your own, or modify the behavior of existing tools here,
21
- * although we recommend not modifying anything provided by the plugin it self.
22
- *
23
- * Any interactive elements should be introduced using JavaScript and/or CSS, either
24
- * inline, or by enqueueing them via the appropriate actions.
25
- *
26
- * @param array $args {
27
- * An unassociated array of tabs, listed in the order they are registered.
28
- *
29
- * @type array $tab {
30
- * An associated array containing the tab title, and content.
31
- *
32
- * @type string $label A pre-escaped string used to label your tool section.
33
- * @type string $content The content of your tool tab, with any code you may need.
34
- * }
35
- * }
36
- */
37
- $tabs = apply_filters( 'health_check_tools_tab', array() );
38
-
39
- foreach ( $tabs as $count => $tab ) :
40
- ?>
41
-
42
- <dt role="heading" aria-level="2">
43
- <button aria-expanded="false" class="health-check-accordion-trigger" aria-controls="health-check-accordion-block-<?php echo esc_attr( $count ); ?>" id="health-check-accordion-heading-<?php echo esc_attr( $count ); ?>" type="button">
44
- <span class="title">
45
- <?php echo $tab['label']; ?>
46
- </span>
47
- <span class="icon"></span>
48
- </button>
49
- </dt>
50
- <dd id="health-check-accordion-block-<?php echo esc_attr( $count ); ?>" role="region" aria-labelledby="health-check-accordion-heading-<?php echo esc_attr( $count ); ?>" class="health-check-accordion-panel" hidden="hidden">
51
- <?php echo $tab['content']; ?>
52
- </dd>
53
-
54
- <?php endforeach; ?>
55
- </dl>
56
-
57
- <?php
58
- include_once( HEALTH_CHECK_PLUGIN_DIRECTORY . '/modals/diff.php' );
1
+ <?php
2
+ /**
3
+ * Health Check tab contents.
4
+ *
5
+ * @package Health Check
6
+ */
7
+
8
+ // Make sure the file is not directly accessible.
9
+ if ( ! defined( 'ABSPATH' ) ) {
10
+ die( 'We\'re sorry, but you can not directly access this file.' );
11
+ }
12
+
13
+ ?>
14
+
15
+ <dl id="health-check-tools" role="presentation" class="health-check-accordion">
16
+ <?php
17
+ /**
18
+ * Filter the features available under the Tools tab.
19
+ *
20
+ * You may introduce your own, or modify the behavior of existing tools here,
21
+ * although we recommend not modifying anything provided by the plugin it self.
22
+ *
23
+ * Any interactive elements should be introduced using JavaScript and/or CSS, either
24
+ * inline, or by enqueueing them via the appropriate actions.
25
+ *
26
+ * @param array $args {
27
+ * An unassociated array of tabs, listed in the order they are registered.
28
+ *
29
+ * @type array $tab {
30
+ * An associated array containing the tab title, and content.
31
+ *
32
+ * @type string $label A pre-escaped string used to label your tool section.
33
+ * @type string $content The content of your tool tab, with any code you may need.
34
+ * }
35
+ * }
36
+ */
37
+ $tabs = apply_filters( 'health_check_tools_tab', array() );
38
+
39
+ foreach ( $tabs as $count => $tab ) :
40
+ ?>
41
+
42
+ <dt role="heading" aria-level="2">
43
+ <button aria-expanded="false" class="health-check-accordion-trigger" aria-controls="health-check-accordion-block-<?php echo esc_attr( $count ); ?>" id="health-check-accordion-heading-<?php echo esc_attr( $count ); ?>" type="button">
44
+ <span class="title">
45
+ <?php echo $tab['label']; ?>
46
+ </span>
47
+ <span class="icon"></span>
48
+ </button>
49
+ </dt>
50
+ <dd id="health-check-accordion-block-<?php echo esc_attr( $count ); ?>" role="region" aria-labelledby="health-check-accordion-heading-<?php echo esc_attr( $count ); ?>" class="health-check-accordion-panel" hidden="hidden">
51
+ <?php echo $tab['content']; ?>
52
+ </dd>
53
+
54
+ <?php endforeach; ?>
55
+ </dl>
56
+
57
+ <?php
58
+ include_once( HEALTH_CHECK_PLUGIN_DIRECTORY . '/modals/diff.php' );
readme.txt CHANGED
@@ -1,61 +1,73 @@
1
- === Health Check & Troubleshooting ===
2
- Tags: health check
3
- Contributors: wordpressdotorg, westi, pento, Clorith
4
- Requires at least: 4.0
5
- Tested up to: 5.0
6
- Stable tag: 1.2.3
7
- License: GPLv2
8
- License URI: https://www.gnu.org/licenses/gpl-2.0.html
9
-
10
- == Description ==
11
-
12
- This plugin will perform a number of checks on your WordPress install to detect common configuration errors and known issues.
13
-
14
- It currently checks your PHP and MySQL versions, some extensions which are needed or may improve WordPress, and that the WordPress.org services are accessible to you.
15
-
16
- The debug section, which allows you to gather information about your WordPress and server configuration that you may easily share with support representatives for themes, plugins or on the official WordPress.org support forums.
17
-
18
- Troubleshooting allows you to have a vanilla WordPress session, where all plugins are disabled, and a default theme is used, but only for your user.
19
-
20
- For a more extensive example of how to efficiently use the Health Check plugin, check out the [WordPress.org support team handbook page about this plugin](https://make.wordpress.org/support/handbook/appendix/troubleshooting-using-the-health-check/).
21
-
22
- In the future we may introduce more checks, and welcome feedback both through the [WordPress.org forums](https://wordpress.org/support/plugin/health-check), and the [GitHub project page](https://github.com/WordPress/health-check).
23
-
24
- == Frequently Asked Questions ==
25
-
26
- = I am unable to access my site after enabling troubleshooting =
27
-
28
- If you should find your self stuck in Troubleshooting Mode for any reason, you can easily disable it by clearing your cookies.
29
-
30
- Are you unfamiliar with how to clear your cookies? No worries, you may also close all your browser windows, or perform a computer restart and it will clear this specific cookie automatically.
31
-
32
- == Screenshots ==
33
-
34
- 1. The health check screen after the automated tests have gone over the system.
35
- 2. The debug information, with the copy and paste field expanded.
36
- 3. The generic PHP information tab, when more detailed information is required.
37
-
38
- == Changelog ==
39
-
40
- = v1.2.3 =
41
- * Added REST API availability test to the Site Status
42
-
43
- = v 1.2.2 =
44
- * Added Twenty Nineteen as a recognized core theme.
45
-
46
- = v 1.2.1 =
47
- * Make sure only those with access to the plugin see the backup encouragement notice.
48
- * Make sure the `is_troubleshooting()` checks are available to the Site Status tester when the MU plugin may not have updated yet.
49
- * Avoid a warning of an undefined variable if you have the latest WordPress version installed.
50
-
51
- = v 1.2.0 =
52
- * Changed plugin name, it now better describes the plugins two primary purposes.
53
- * Changed the `Health Check` tab, it's now named `Site Status`, as we used the old name too many places and it was confusing.
54
- * Site status tests now run asynchronously, making the page load much faster.
55
- * The HTTPS tests now also check your Site URL settings to make sure they are following recommended best practices.
56
- * Fixed a warning preventing plugin names from displaying on the front-end in some cases.
57
- * Fixed an issue where you might get a 500 error if you tried using Troubleshooting Mode while using a child theme.
58
- * Automatically disable/enable a plugin or theme in Troubleshooting Mode if they are detected to cause errors.
59
- * Introduce a new dashboard widget during Troubleshooting Mode (and a simplified version on the plugins screen) to better explain what is going on, and make available actions more discoverable than the admin menu is.
60
- * Some text improvements throughout the plugin.
61
- * When loopback tests fail, we previously tested all plugins at once, for sites that have many plugins this may fail as the request times out. We now test one plugin at a time to avoid this, while also showing more information at the tests are running to the end user.
 
 
 
 
 
 
 
 
 
 
 
 
1
+ === Health Check & Troubleshooting ===
2
+ Tags: health check
3
+ Contributors: wordpressdotorg, westi, pento, Clorith
4
+ Requires at least: 4.0
5
+ Tested up to: 5.0
6
+ Stable tag: 1.2.4
7
+ License: GPLv2
8
+ License URI: https://www.gnu.org/licenses/gpl-2.0.html
9
+
10
+ Health Check identifies common problems, and helps you troubleshoot plugin and theme conflicts.
11
+
12
+ == Description ==
13
+
14
+ This plugin will perform a number of checks on your WordPress install to detect common configuration errors and known issues.
15
+
16
+ It currently checks your PHP and MySQL versions, some extensions which are needed or may improve WordPress, and that the WordPress.org services are accessible to you.
17
+
18
+ The debug section, which allows you to gather information about your WordPress and server configuration that you may easily share with support representatives for themes, plugins or on the official WordPress.org support forums.
19
+
20
+ Troubleshooting allows you to have a vanilla WordPress session, where all plugins are disabled, and a default theme is used, but only for your user.
21
+
22
+ For a more extensive example of how to efficiently use the Health Check plugin, check out the [WordPress.org support team handbook page about this plugin](https://make.wordpress.org/support/handbook/appendix/troubleshooting-using-the-health-check/).
23
+
24
+ In the future we may introduce more checks, and welcome feedback both through the [WordPress.org forums](https://wordpress.org/support/plugin/health-check), and the [GitHub project page](https://github.com/WordPress/health-check).
25
+
26
+ == Frequently Asked Questions ==
27
+
28
+ = I am unable to access my site after enabling troubleshooting =
29
+
30
+ If you should find your self stuck in Troubleshooting Mode for any reason, you can easily disable it by clearing your cookies.
31
+
32
+ Are you unfamiliar with how to clear your cookies? No worries, you may also close all your browser windows, or perform a computer restart and it will clear this specific cookie automatically.
33
+
34
+ == Screenshots ==
35
+
36
+ 1. The health check screen after the automated tests have gone over the system.
37
+ 2. The debug information, with the copy and paste field expanded.
38
+ 3. The generic PHP information tab, when more detailed information is required.
39
+
40
+ == Changelog ==
41
+
42
+ = v1.2.4 =
43
+ * Security: Prevent arbitrary file viewing through the integrity file actions. Independently reported by Julien Legras of [Synacktiv](https://synacktiv.com) and siliconforks.
44
+ * Security: Site status was available to any user with a subscriber role or higher on a site. Reported by Julien Legras of [Synacktiv](https://synacktiv.com).
45
+ * Security: Hardened the troubleshooting mode session so it is locked to the users location when active.
46
+ * New enhancement: Check that various PHP extensions exist, as recommended by the WordPress Hosting Community.
47
+ * New enhancement: Check if update APIs are being manipulated by plugins or themes.
48
+ * Fix: Copying debug information had the wrong indentation for easier readability.
49
+ * Fix: Toggling plugins and themes from the troubleshooting widget on in the dashboard now lets you expand/collapse them as intended.
50
+ * Fix: When debugging was enabled in WordPress, disabling a plugin in troubleshooting mode would cause a WSOD if the disabled plugin caused a fatal error.
51
+
52
+ = v1.2.3 =
53
+ * Added REST API availability test to the Site Status
54
+
55
+ = v 1.2.2 =
56
+ * Added Twenty Nineteen as a recognized core theme.
57
+
58
+ = v 1.2.1 =
59
+ * Make sure only those with access to the plugin see the backup encouragement notice.
60
+ * Make sure the `is_troubleshooting()` checks are available to the Site Status tester when the MU plugin may not have updated yet.
61
+ * Avoid a warning of an undefined variable if you have the latest WordPress version installed.
62
+
63
+ = v 1.2.0 =
64
+ * Changed plugin name, it now better describes the plugins two primary purposes.
65
+ * Changed the `Health Check` tab, it's now named `Site Status`, as we used the old name too many places and it was confusing.
66
+ * Site status tests now run asynchronously, making the page load much faster.
67
+ * The HTTPS tests now also check your Site URL settings to make sure they are following recommended best practices.
68
+ * Fixed a warning preventing plugin names from displaying on the front-end in some cases.
69
+ * Fixed an issue where you might get a 500 error if you tried using Troubleshooting Mode while using a child theme.
70
+ * Automatically disable/enable a plugin or theme in Troubleshooting Mode if they are detected to cause errors.
71
+ * Introduce a new dashboard widget during Troubleshooting Mode (and a simplified version on the plugins screen) to better explain what is going on, and make available actions more discoverable than the admin menu is.
72
+ * Some text improvements throughout the plugin.
73
+ * When loopback tests fail, we previously tested all plugins at once, for sites that have many plugins this may fail as the request times out. We now test one plugin at a time to avoid this, while also showing more information at the tests are running to the end user.
uninstall.php CHANGED
@@ -1,40 +1,40 @@
1
- <?php
2
- /**
3
- * Perform plugin installation routines.
4
- *
5
- * @package Health Check
6
- */
7
-
8
- global $wpdb;
9
-
10
- // Make sure the uninstall file can't be accessed directly.
11
- if ( ! defined( 'WP_UNINSTALL_PLUGIN' ) ) {
12
- die;
13
- }
14
-
15
- // Remove options introduced by the plugin.
16
- delete_option( 'health-check-disable-plugin-hash' );
17
- delete_option( 'health-check-default-theme' );
18
- delete_option( 'health-check-current-theme' );
19
- delete_option( 'health-check-dashboard-notices' );
20
-
21
- /*
22
- * Remove any user meta entries we made, done with a custom query as core
23
- * does not provide an option to clear them for all users.
24
- */
25
- $wpdb->delete(
26
- $wpdb->usermeta,
27
- array(
28
- 'meta_key' => 'health-check',
29
- )
30
- );
31
-
32
- // Remove the old Must-Use plugin if it was implemented.
33
- if ( file_exists( trailingslashit( WPMU_PLUGIN_DIR ) . 'health-check-disable-plugins.php' ) ) {
34
- wp_delete_file( trailingslashit( WPMU_PLUGIN_DIR ) . 'health-check-disable-plugins.php' );
35
- }
36
-
37
- // Remove the renamed Must-Use plugin if it exists
38
- if ( file_exists( trailingslashit( WPMU_PLUGIN_DIR ) . 'health-check-troubleshooting-mode.php' ) ) {
39
- wp_delete_file( trailingslashit( WPMU_PLUGIN_DIR ) . 'health-check-troubleshooting-mode.php' );
40
- }
1
+ <?php
2
+ /**
3
+ * Perform plugin installation routines.
4
+ *
5
+ * @package Health Check
6
+ */
7
+
8
+ global $wpdb;
9
+
10
+ // Make sure the uninstall file can't be accessed directly.
11
+ if ( ! defined( 'WP_UNINSTALL_PLUGIN' ) ) {
12
+ die;
13
+ }
14
+
15
+ // Remove options introduced by the plugin.
16
+ delete_option( 'health-check-disable-plugin-hash' );
17
+ delete_option( 'health-check-default-theme' );
18
+ delete_option( 'health-check-current-theme' );
19
+ delete_option( 'health-check-dashboard-notices' );
20
+
21
+ /*
22
+ * Remove any user meta entries we made, done with a custom query as core
23
+ * does not provide an option to clear them for all users.
24
+ */
25
+ $wpdb->delete(
26
+ $wpdb->usermeta,
27
+ array(
28
+ 'meta_key' => 'health-check',
29
+ )
30
+ );
31
+
32
+ // Remove the old Must-Use plugin if it was implemented.
33
+ if ( file_exists( trailingslashit( WPMU_PLUGIN_DIR ) . 'health-check-disable-plugins.php' ) ) {
34
+ wp_delete_file( trailingslashit( WPMU_PLUGIN_DIR ) . 'health-check-disable-plugins.php' );
35
+ }
36
+
37
+ // Remove the renamed Must-Use plugin if it exists
38
+ if ( file_exists( trailingslashit( WPMU_PLUGIN_DIR ) . 'health-check-troubleshooting-mode.php' ) ) {
39
+ wp_delete_file( trailingslashit( WPMU_PLUGIN_DIR ) . 'health-check-troubleshooting-mode.php' );
40
+ }