Health Check - Version 1.4.0

Version Description

Download this release

Release Info

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

Code changes from version 1.3.2 to 1.4.0

assets/css/health-check.css CHANGED
@@ -1,4 +1,3 @@
1
- @charset "UTF-8";
2
  body {
3
  /* Accordion styles */
4
  }
@@ -64,105 +63,45 @@ body.tools_page_health-check .health-check-header {
64
  border-bottom: 1px solid #e2e4e7;
65
  }
66
 
67
- body.tools_page_health-check .health-check-header .health-check-title-section {
68
- display: flex;
69
- align-items: center;
70
- justify-content: center;
71
- clear: both;
72
- }
73
-
74
- body.tools_page_health-check .health-check-header .health-check-title-section h1 {
75
- display: inline-block;
76
- font-weight: 600;
77
- font-size: 23px;
78
- margin: 1rem 0.8rem;
79
- padding: 9px 0 4px;
80
- line-height: 1.3;
81
- font-family: inherit;
82
- }
83
-
84
- body.tools_page_health-check .health-check-header .health-check-title-section .site-health-progress {
85
- display: inline-block;
86
- height: 40px;
87
- width: 40px;
88
- margin: 0;
89
- border-radius: 100%;
90
- position: relative;
91
- font-weight: 600;
92
- font-size: 0.4rem;
93
- }
94
-
95
- body.tools_page_health-check .health-check-header .health-check-title-section .site-health-progress.loading .site-health-progress-count:after {
96
- content: "···";
97
- }
98
-
99
- body.tools_page_health-check .health-check-header .health-check-title-section .site-health-progress.loading svg #bar {
100
- stroke-dashoffset: 0;
101
- stroke: #adc5d2;
102
- animation: loadingPulse 3s infinite ease-in-out;
103
  }
104
 
105
- body.tools_page_health-check .health-check-header .health-check-title-section .site-health-progress .site-health-progress-count {
106
- position: absolute;
107
  display: block;
108
- height: 80px;
109
- width: 80px;
110
- left: 50%;
111
- top: 50%;
112
- margin-top: -40px;
113
- margin-left: -40px;
114
- border-radius: 100%;
115
- line-height: 6.3;
116
- font-size: 2em;
117
- }
118
-
119
- body.tools_page_health-check .health-check-header .health-check-title-section .site-health-progress .site-health-progress-count:after {
120
- content: "";
121
- }
122
-
123
- body.tools_page_health-check .health-check-header .health-check-title-section .site-health-progress svg circle {
124
- stroke-dashoffset: 0;
125
- transition: stroke-dashoffset 1s linear;
126
- stroke: #ccc;
127
- stroke-width: 2em;
128
  }
129
 
130
- body.tools_page_health-check .health-check-header .health-check-title-section .site-health-progress svg #bar {
131
- stroke-dashoffset: 565;
132
- stroke: #dc3232;
133
  }
134
 
135
- body.tools_page_health-check .health-check-header .health-check-title-section .site-health-progress svg #bar.green {
136
- stroke: #46b450;
 
137
  }
138
 
139
- body.tools_page_health-check .health-check-header .health-check-title-section .site-health-progress svg #bar.orange {
140
- stroke: #ffb900;
 
141
  }
142
 
143
- @keyframes loadingPulse {
144
- 0% {
145
- stroke: #adc5d2;
146
- }
147
- 50% {
148
- stroke: #00a0d2;
149
- }
150
- 100% {
151
- stroke: #adc5d2;
152
- }
153
- }
154
-
155
- body.tools_page_health-check .health-check-header .health-check-tabs-wrapper {
156
- display: block;
157
- }
158
-
159
- body.tools_page_health-check .health-check-header .health-check-tabs-wrapper .health-check-tab {
160
- display: inline-block;
161
- text-decoration: none;
162
- color: inherit;
163
- padding: 0.5rem 1rem 1rem;
164
- margin: 0 1rem;
165
- transition: box-shadow 0.5s ease-in-out;
166
  }
167
 
168
  body.tools_page_health-check .health-check-header .health-check-tabs-wrapper .health-check-tab.active {
@@ -181,6 +120,10 @@ body.tools_page_health-check .health-check-body {
181
  margin: 0 auto;
182
  }
183
 
 
 
 
 
184
  body.tools_page_health-check .health-check-table thead th,
185
  body.tools_page_health-check .health-check-table thead td {
186
  font-size: 13px;
@@ -192,12 +135,17 @@ body.tools_page_health-check .health-check-table thead td:first-child {
192
  }
193
 
194
  body.tools_page_health-check .health-check-table tbody td {
195
- width: 70%;
 
 
196
  font-size: 13px;
 
197
  }
198
 
199
  body.tools_page_health-check .health-check-table tbody td:first-child {
200
- width: 30%;
 
 
201
  }
202
 
203
  body.tools_page_health-check .health-check-table tbody td ul,
@@ -617,3 +565,87 @@ body .health-check-accordion dl dd {
617
  font-size: 28px;
618
  font-weight: 600;
619
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  body {
2
  /* Accordion styles */
3
  }
63
  border-bottom: 1px solid #e2e4e7;
64
  }
65
 
66
+ body.tools_page_health-check .health-check-header .health-check-tabs-wrapper {
67
+ /* IE 11 */
68
+ display: -ms-inline-grid;
69
+ -ms-grid-columns: 1fr 1fr 1fr 1fr;
70
+ vertical-align: top;
71
+ /* modern browsers */
72
+ display: inline-grid;
73
+ /* stylelint-disable-line declaration-block-no-duplicate-properties */
74
+ grid-template-columns: 1fr 1fr 1fr 1fr;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75
  }
76
 
77
+ body.tools_page_health-check .health-check-header .health-check-tabs-wrapper .health-check-tab {
 
78
  display: block;
79
+ /* IE 11 */
80
+ text-decoration: none;
81
+ color: inherit;
82
+ padding: 0.5rem 1rem 1rem;
83
+ margin: 0 1rem;
84
+ transition: box-shadow 0.5s ease-in-out;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
85
  }
86
 
87
+ body.tools_page_health-check .health-check-header .health-check-tabs-wrapper .health-check-tab:nth-child(1) {
88
+ -ms-grid-column: 1;
89
+ /* IE 11 */
90
  }
91
 
92
+ body.tools_page_health-check .health-check-header .health-check-tabs-wrapper .health-check-tab:nth-child(2) {
93
+ -ms-grid-column: 2;
94
+ /* IE 11 */
95
  }
96
 
97
+ body.tools_page_health-check .health-check-header .health-check-tabs-wrapper .health-check-tab:nth-child(3) {
98
+ -ms-grid-column: 3;
99
+ /* IE 11 */
100
  }
101
 
102
+ body.tools_page_health-check .health-check-header .health-check-tabs-wrapper .health-check-tab:nth-child(4) {
103
+ -ms-grid-column: 4;
104
+ /* IE 11 */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
105
  }
106
 
107
  body.tools_page_health-check .health-check-header .health-check-tabs-wrapper .health-check-tab.active {
120
  margin: 0 auto;
121
  }
122
 
123
+ body.tools_page_health-check .health-check-table {
124
+ table-layout: fixed;
125
+ }
126
+
127
  body.tools_page_health-check .health-check-table thead th,
128
  body.tools_page_health-check .health-check-table thead td {
129
  font-size: 13px;
135
  }
136
 
137
  body.tools_page_health-check .health-check-table tbody td {
138
+ width: 100%;
139
+ box-sizing: border-box;
140
+ display: block;
141
  font-size: 13px;
142
+ word-wrap: break-word;
143
  }
144
 
145
  body.tools_page_health-check .health-check-table tbody td:first-child {
146
+ width: 100%;
147
+ padding-bottom: 0;
148
+ font-weight: 600;
149
  }
150
 
151
  body.tools_page_health-check .health-check-table tbody td ul,
565
  font-size: 28px;
566
  font-weight: 600;
567
  }
568
+
569
+ /* Progress indicator styles */
570
+ .health-check-title-section {
571
+ display: flex;
572
+ align-items: center;
573
+ justify-content: center;
574
+ clear: both;
575
+ }
576
+
577
+ .health-check-title-section h1 {
578
+ display: inline-block;
579
+ font-weight: 600;
580
+ font-size: 23px;
581
+ margin: 0 0.8rem 1rem;
582
+ padding: 9px 0 4px;
583
+ line-height: 1.3;
584
+ font-family: inherit;
585
+ }
586
+
587
+ .health-check-title-section.site-health-progress-wrapper {
588
+ margin-bottom: 1rem;
589
+ }
590
+
591
+ .health-check-title-section.site-health-progress-wrapper.loading .site-health-progress svg #bar {
592
+ stroke-dashoffset: 0;
593
+ stroke: #adc5d2;
594
+ animation: loadingPulse 3s infinite ease-in-out;
595
+ }
596
+
597
+ @keyframes loadingPulse {
598
+ 0% {
599
+ stroke: #adc5d2;
600
+ }
601
+ 50% {
602
+ stroke: #00a0d2;
603
+ }
604
+ 100% {
605
+ stroke: #adc5d2;
606
+ }
607
+ }
608
+
609
+ .health-check-title-section.site-health-progress-wrapper.green #bar {
610
+ stroke: #46b450;
611
+ }
612
+
613
+ .health-check-title-section.site-health-progress-wrapper.green .site-health-progress-label {
614
+ color: #46b450;
615
+ }
616
+
617
+ .health-check-title-section.site-health-progress-wrapper.orange #bar {
618
+ stroke: #ffb900;
619
+ }
620
+
621
+ .health-check-title-section.site-health-progress-wrapper.orange .site-health-progress-label {
622
+ color: #ffb900;
623
+ }
624
+
625
+ .health-check-title-section.site-health-progress-wrapper .site-health-progress {
626
+ display: inline-block;
627
+ height: 20px;
628
+ width: 20px;
629
+ margin: 0;
630
+ border-radius: 100%;
631
+ position: relative;
632
+ font-weight: 600;
633
+ font-size: 0.4rem;
634
+ }
635
+
636
+ .health-check-title-section.site-health-progress-wrapper .site-health-progress svg circle {
637
+ stroke-dashoffset: 0;
638
+ transition: stroke-dashoffset 1s linear;
639
+ stroke: #ccc;
640
+ stroke-width: 3em;
641
+ }
642
+
643
+ .health-check-title-section.site-health-progress-wrapper .site-health-progress svg #bar {
644
+ stroke-dashoffset: 565;
645
+ }
646
+
647
+ .health-check-title-section.site-health-progress-wrapper .site-health-progress-label {
648
+ font-weight: 600;
649
+ line-height: 20px;
650
+ margin-left: 0.3rem;
651
+ }
assets/javascript/health-check.js CHANGED
@@ -1,6 +1,6 @@
1
- jQuery( document ).ready(function( $ ) {
2
  $( '.health-check-accordion' ).on( 'click', '.health-check-accordion-trigger', function() {
3
- var isExpanded = ( 'true' === $( this ).attr( 'aria-expanded' ) );
4
 
5
  if ( isExpanded ) {
6
  $( this ).attr( 'aria-expanded', 'false' );
@@ -10,113 +10,111 @@ jQuery( document ).ready(function( $ ) {
10
  $( '#' + $( this ).attr( 'aria-controls' ) ).attr( 'hidden', false );
11
  }
12
  } );
13
- });
14
 
15
- /* global ClipboardJS, SiteHealth, wp */
16
  jQuery( document ).ready( function( $ ) {
17
- var clipboard;
18
 
19
  if ( 'undefined' !== typeof ClipboardJS ) {
20
  clipboard = new ClipboardJS( '.site-health-copy-buttons .copy-button' );
21
 
22
  // Debug information copy section.
23
  clipboard.on( 'success', function( e ) {
24
- var $wrapper = $( e.trigger ).closest( 'div' );
25
 
26
  $( '.success', $wrapper ).addClass( 'visible' );
27
 
28
  wp.a11y.speak( SiteHealth.string.site_info_copied );
29
- });
30
  }
31
- });
32
 
33
  /* global ajaxurl, SiteHealth */
34
- jQuery( document ).ready(function( $ ) {
35
- var isDebugTab = $( '.health-check-debug-tab.active' ).length;
36
- var pathsSizesSection = $( '#health-check-accordion-block-wp-paths-sizes' );
37
-
38
- function getDirectorySizes() {
39
- var data = {
40
- action: 'health-check-get-sizes',
41
- _wpnonce: SiteHealth.nonce.site_status_result
42
- };
43
-
44
- var timestamp = ( new Date().getTime() );
45
-
46
- // After 3 seconds announce that we're still waiting for directory sizes.
47
- var timeout = window.setTimeout( function() {
48
- wp.a11y.speak( SiteHealth.string.please_wait );
49
- }, 3000 );
50
-
51
- $.post( {
52
- type: 'POST',
53
- url: ajaxurl,
54
- data: data,
55
- dataType: 'json'
56
- } ).done( function( response ) {
57
- updateDirSizes( response.data || {} );
58
- } ).always( function() {
59
- var delay = ( new Date().getTime() ) - timestamp;
60
-
61
- $( '.health-check-wp-paths-sizes.spinner' ).css( 'visibility', 'hidden' );
62
-
63
- if ( delay > 3000 ) {
64
-
65
- // We have announced that we're waiting.
66
- // Announce that we're ready after giving at least 3 seconds for the first announcement
67
- // to be read out, or the two may collide.
68
- if ( delay > 6000 ) {
69
- delay = 0;
70
- } else {
71
- delay = 6500 - delay;
72
- }
73
-
74
- window.setTimeout( function() {
75
- wp.a11y.speak( SiteHealth.string.site_health_complete );
76
- }, delay );
77
- } else {
78
-
79
- // Cancel the announcement.
80
- window.clearTimeout( timeout );
81
- }
82
-
83
- $( document ).trigger( 'site-health-info-dirsizes-done' );
84
- } );
85
- }
86
-
87
- function updateDirSizes( data ) {
88
- var copyButton = $( 'button.button.copy-button' );
89
- var clipdoardText = copyButton.attr( 'data-clipboard-text' );
90
-
91
- $.each( data, function( name, value ) {
92
- var text = value.debug || value.size;
93
-
94
- if ( 'undefined' !== typeof text ) {
95
- clipdoardText = clipdoardText.replace( name + ': loading...', name + ': ' + text );
96
- }
97
- } );
98
-
99
- copyButton.attr( 'data-clipboard-text', clipdoardText );
100
-
101
- pathsSizesSection.find( 'td[class]' ).each( function( i, element ) {
102
- var td = $( element );
103
- var name = td.attr( 'class' );
104
-
105
- if ( data.hasOwnProperty( name ) && data[ name ].size ) {
106
- td.text( data[ name ].size );
107
- }
108
- } );
109
- }
110
-
111
- if ( isDebugTab ) {
112
- if ( pathsSizesSection.length ) {
113
- getDirectorySizes();
114
- }
115
- }
116
- });
117
 
118
  /* global ajaxurl */
119
- jQuery( document ).ready(function( $ ) {
120
  function healthCheckFailureModal( markup, action, parent ) {
121
  $( '#dynamic-content' ).html( markup );
122
  $( '.health-check-modal' ).data( 'modal-action', action ).data( 'parent-field', parent ).show();
@@ -126,13 +124,13 @@ jQuery( document ).ready(function( $ ) {
126
  modal.hide();
127
  }
128
 
129
- $( '.modal-close' ).click(function( e ) {
130
  e.preventDefault();
131
  healthCheckFailureModalClose( $( this ).closest( '.health-check-modal' ) );
132
- });
133
 
134
  $( '.health-check-modal' ).on( 'submit', 'form', function( e ) {
135
- var data = $( this ).serializeArray(),
136
  modal = $( this ).closest( '.health-check-modal' );
137
 
138
  e.preventDefault();
@@ -150,16 +148,16 @@ jQuery( document ).ready(function( $ ) {
150
  );
151
 
152
  healthCheckFailureModalClose( modal );
153
- });
154
- });
155
 
156
  /* global SiteHealth, ajaxurl, healthCheckFailureModal */
157
- jQuery( document ).ready(function( $ ) {
158
  function testDefaultTheme() {
159
- var $parent = $( '.individual-loopback-test-status', '#test-single-no-theme' ),
160
  data = {
161
- 'action': 'health-check-loopback-default-theme',
162
- '_wpnonce': SiteHealth.nonce.loopback_default_theme
163
  };
164
 
165
  $.post(
@@ -177,24 +175,21 @@ jQuery( document ).ready(function( $ ) {
177
  }
178
 
179
  function testSinglePlugin() {
180
- var $testLines = $( '.not-tested', '#loopback-individual-plugins-list' );
181
- var $parentField,
182
- $testLine,
183
- data;
184
 
185
  if ( $testLines.length < 1 ) {
186
  testDefaultTheme();
187
  return null;
188
  }
189
 
190
- $testLine = $testLines.first();
191
- data = {
192
- 'action': 'health-check-loopback-individual-plugins',
193
- 'plugin': $testLine.data( 'test-plugin' ),
194
- '_wpnonce': SiteHealth.nonce.loopback_individual_plugins
195
  };
196
 
197
- $parentField = $( '.individual-loopback-test-status', $testLine );
198
 
199
  $parentField.html( SiteHealth.string.running_tests );
200
 
@@ -215,11 +210,11 @@ jQuery( document ).ready(function( $ ) {
215
  }
216
 
217
  $( '.dashboard_page_health-check' ).on( 'click', '#loopback-no-plugins', function( e ) {
218
- var $trigger = $( this ),
219
  $parent = $( this ).closest( 'p' ),
220
  data = {
221
- 'action': 'health-check-loopback-no-plugins',
222
- '_wpnonce': SiteHealth.nonce.loopback_no_plugins
223
  };
224
 
225
  e.preventDefault();
@@ -239,36 +234,36 @@ jQuery( document ).ready(function( $ ) {
239
  },
240
  'json'
241
  );
242
- }).on( 'click', '#loopback-individual-plugins', function( e ) {
243
  e.preventDefault();
244
 
245
  $( this ).remove();
246
 
247
  testSinglePlugin();
248
- });
249
- });
250
 
251
- /* global ajaxurl, SiteHealth, wp */
252
- jQuery( document ).ready(function( $ ) {
253
- var data;
254
- var isDebugTab = $( '.health-check-debug-tab.active' ).length;
255
 
256
  $( '.site-health-view-passed' ).on( 'click', function() {
257
- var goodIssuesWrapper = $( '#health-check-issues-good' );
258
 
259
  goodIssuesWrapper.toggleClass( 'hidden' );
260
  $( this ).attr( 'aria-expanded', ! goodIssuesWrapper.hasClass( 'hidden' ) );
261
  } );
262
 
263
  function AppendIssue( issue ) {
264
- var template = wp.template( 'health-check-issue' ),
265
- issueWrapper = $( '#health-check-issues-' + issue.status ),
266
- heading,
267
- count;
268
 
269
  SiteHealth.site_status.issues[ issue.status ]++;
270
 
271
- count = SiteHealth.site_status.issues[ issue.status ];
272
 
273
  if ( 'critical' === issue.status ) {
274
  if ( count <= 1 ) {
@@ -298,23 +293,23 @@ jQuery( document ).ready(function( $ ) {
298
  }
299
 
300
  function RecalculateProgression() {
301
- var r, c, pct;
302
- var $progress = $( '.site-health-progress' );
303
- var $progressCount = $progress.find( '.site-health-progress-count' );
304
- var $circle = $( '.site-health-progress svg #bar' );
305
- var totalTests = parseInt( SiteHealth.site_status.issues.good, 0 ) + parseInt( SiteHealth.site_status.issues.recommended, 0 ) + ( parseInt( SiteHealth.site_status.issues.critical, 0 ) * 1.5 );
306
- var failedTests = parseInt( SiteHealth.site_status.issues.recommended, 0 ) + ( parseInt( SiteHealth.site_status.issues.critical, 0 ) * 1.5 );
307
- var val = 100 - Math.ceil( ( failedTests / totalTests ) * 100 );
308
 
309
  if ( 0 === totalTests ) {
310
  $progress.addClass( 'hidden' );
311
  return;
312
  }
313
 
314
- $progress.removeClass( 'loading' );
315
 
316
- r = $circle.attr( 'r' );
317
- c = Math.PI * ( r * 2 );
318
 
319
  if ( 0 > val ) {
320
  val = 0;
@@ -323,7 +318,7 @@ jQuery( document ).ready(function( $ ) {
323
  val = 100;
324
  }
325
 
326
- pct = ( ( 100 - val ) / 100 ) * c;
327
 
328
  $circle.css( { strokeDashoffset: pct } );
329
 
@@ -335,44 +330,44 @@ jQuery( document ).ready(function( $ ) {
335
  $( '#health-check-issues-recommended' ).addClass( 'hidden' );
336
  }
337
 
338
- if ( 50 <= val ) {
339
- $circle.addClass( 'orange' ).removeClass( 'red' );
340
- }
341
-
342
- if ( 90 <= val ) {
343
- $circle.addClass( 'green' ).removeClass( 'orange' );
344
- }
345
-
346
- if ( 100 === val ) {
347
- $( '.site-status-all-clear' ).removeClass( 'hide' );
348
- $( '.site-status-has-issues' ).addClass( 'hide' );
349
- }
350
-
351
- $progressCount.text( val + '%' );
352
-
353
  if ( ! isDebugTab ) {
354
  $.post(
355
  ajaxurl,
356
  {
357
- 'action': 'health-check-site-status-result',
358
- '_wpnonce': SiteHealth.nonce.site_status_result,
359
- 'counts': SiteHealth.site_status.issues
360
  }
361
  );
362
  }
363
 
364
- wp.a11y.speak( SiteHealth.string.site_health_complete_screen_reader.replace( '%s', val + '%' ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
365
  }
366
 
367
  function maybeRunNextAsyncTest() {
368
- var doCalculation = true;
369
 
370
  if ( 1 <= SiteHealth.site_status.async.length ) {
371
  $.each( SiteHealth.site_status.async, function() {
372
- var data = {
373
- 'action': 'health-check-site-status',
374
- 'feature': this.test,
375
- '_wpnonce': SiteHealth.nonce.site_status
376
  };
377
 
378
  if ( this.completed ) {
@@ -387,7 +382,11 @@ jQuery( document ).ready(function( $ ) {
387
  ajaxurl,
388
  data,
389
  function( response ) {
390
- AppendIssue( response.data );
 
 
 
 
391
  maybeRunNextAsyncTest();
392
  }
393
  );
@@ -406,9 +405,9 @@ jQuery( document ).ready(function( $ ) {
406
  RecalculateProgression();
407
  } else {
408
  SiteHealth.site_status.issues = {
409
- 'good': 0,
410
- 'recommended': 0,
411
- 'critical': 0
412
  };
413
  }
414
 
@@ -420,12 +419,12 @@ jQuery( document ).ready(function( $ ) {
420
 
421
  if ( 0 < SiteHealth.site_status.async.length ) {
422
  data = {
423
- 'action': 'health-check-site-status',
424
- 'feature': SiteHealth.site_status.async[0].test,
425
- '_wpnonce': SiteHealth.nonce.site_status
426
  };
427
 
428
- SiteHealth.site_status.async[0].completed = true;
429
 
430
  $.post(
431
  ajaxurl,
@@ -439,14 +438,20 @@ jQuery( document ).ready(function( $ ) {
439
  RecalculateProgression();
440
  }
441
  }
442
- });
 
 
 
 
 
 
443
 
444
  /* global ajaxurl, SiteHealth */
445
- jQuery( document ).ready(function( $ ) {
446
  $( '#health-check-file-integrity' ).submit( function( e ) {
447
- var data = {
448
- 'action': 'health-check-files-integrity-check',
449
- '_wpnonce': SiteHealth.nonce.files_integrity_check
450
  };
451
 
452
  e.preventDefault();
@@ -463,21 +468,20 @@ jQuery( document ).ready(function( $ ) {
463
  $( '#tools-file-integrity-response-holder' ).html( response.data.message );
464
  }
465
  );
466
- });
467
 
468
  $( '#tools-file-integrity-response-holder' ).on( 'click', 'a[href="#health-check-diff"]', function( e ) {
469
- var file = $( this ).data( 'file' ),
470
- data;
471
 
472
  e.preventDefault();
473
 
474
  $( '#health-check-diff-modal' ).toggle();
475
  $( '#health-check-diff-modal #health-check-diff-modal-content .spinner' ).addClass( 'is-active' );
476
 
477
- data = {
478
- 'action': 'health-check-view-file-diff',
479
- 'file': file,
480
- '_wpnonce': SiteHealth.nonce.view_file_diff
481
  };
482
 
483
  $.post(
@@ -489,43 +493,42 @@ jQuery( document ).ready(function( $ ) {
489
  $( '#health-check-diff-modal #health-check-diff-modal-content .spinner' ).removeClass( 'is-active' );
490
  }
491
  );
492
- });
493
- });
494
 
495
- jQuery( document ).ready(function( $ ) {
496
  $( '#health-check-diff-modal' ).on( 'click', 'a[href="#health-check-diff-modal-close"]', function( e ) {
497
  e.preventDefault();
498
  $( '#health-check-diff-modal' ).toggle();
499
  $( '#health-check-diff-modal #health-check-diff-modal-diff' ).html( '' );
500
  $( '#health-check-diff-modal #health-check-diff-modal-content h3' ).html( '' );
501
- });
502
 
503
- $( document ).keyup(function( e ) {
504
  if ( 27 === e.which ) {
505
  $( '#health-check-diff-modal' ).css( 'display', 'none' );
506
  $( '#health-check-diff-modal #health-check-diff-modal-diff' ).html( '' );
507
  $( '#health-check-diff-modal #health-check-diff-modal-content h3' ).html( '' );
508
  }
509
- });
510
- });
511
 
512
  /* global ajaxurl, SiteHealth */
513
- jQuery( document ).ready(function( $ ) {
514
  $( '#health-check-mail-check' ).submit( function( e ) {
515
- var email = $( '#health-check-mail-check #email' ).val(),
516
- emailMessage = $( '#health-check-mail-check #email_message' ).val(),
517
- data;
518
 
519
  e.preventDefault();
520
 
521
  $( '#tools-mail-check-response-holder' ).html( '<span class="spinner"></span>' );
522
  $( '#tools-mail-check-response-holder .spinner' ).addClass( 'is-active' );
523
 
524
- data = {
525
- 'action': 'health-check-mail-check',
526
- 'email': email,
527
- 'email_message': emailMessage,
528
- '_wpnonce': SiteHealth.nonce.mail_check
529
  };
530
 
531
  $.post(
@@ -537,5 +540,47 @@ jQuery( document ).ready(function( $ ) {
537
  $( '#tools-mail-check-response-holder' ).html( response.data.message );
538
  }
539
  );
540
- });
541
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ jQuery( document ).ready( function( $ ) {
2
  $( '.health-check-accordion' ).on( 'click', '.health-check-accordion-trigger', function() {
3
+ const isExpanded = ( 'true' === $( this ).attr( 'aria-expanded' ) );
4
 
5
  if ( isExpanded ) {
6
  $( this ).attr( 'aria-expanded', 'false' );
10
  $( '#' + $( this ).attr( 'aria-controls' ) ).attr( 'hidden', false );
11
  }
12
  } );
13
+ } );
14
 
15
+ /* global ClipboardJS, SiteHealth */
16
  jQuery( document ).ready( function( $ ) {
17
+ let clipboard;
18
 
19
  if ( 'undefined' !== typeof ClipboardJS ) {
20
  clipboard = new ClipboardJS( '.site-health-copy-buttons .copy-button' );
21
 
22
  // Debug information copy section.
23
  clipboard.on( 'success', function( e ) {
24
+ const $wrapper = $( e.trigger ).closest( 'div' );
25
 
26
  $( '.success', $wrapper ).addClass( 'visible' );
27
 
28
  wp.a11y.speak( SiteHealth.string.site_info_copied );
29
+ } );
30
  }
31
+ } );
32
 
33
  /* global ajaxurl, SiteHealth */
34
+ jQuery( document ).ready( function( $ ) {
35
+ const isDebugTab = $( '.health-check-debug-tab.active' ).length;
36
+ const pathsSizesSection = $( '#health-check-accordion-block-wp-paths-sizes' );
37
+
38
+ function getDirectorySizes() {
39
+ const data = {
40
+ action: 'health-check-get-sizes',
41
+ _wpnonce: SiteHealth.nonce.site_status_result,
42
+ };
43
+
44
+ const timestamp = ( new Date().getTime() );
45
+
46
+ // After 3 seconds announce that we're still waiting for directory sizes.
47
+ const timeout = window.setTimeout( function() {
48
+ wp.a11y.speak( SiteHealth.string.please_wait );
49
+ }, 3000 );
50
+
51
+ $.post( {
52
+ type: 'POST',
53
+ url: ajaxurl,
54
+ data,
55
+ dataType: 'json',
56
+ } ).done( function( response ) {
57
+ updateDirSizes( response.data || {} );
58
+ } ).always( function() {
59
+ let delay = ( new Date().getTime() ) - timestamp;
60
+
61
+ $( '.health-check-wp-paths-sizes.spinner' ).css( 'visibility', 'hidden' );
62
+
63
+ if ( delay > 3000 ) {
64
+ // We have announced that we're waiting.
65
+ // Announce that we're ready after giving at least 3 seconds for the first announcement
66
+ // to be read out, or the two may collide.
67
+ if ( delay > 6000 ) {
68
+ delay = 0;
69
+ } else {
70
+ delay = 6500 - delay;
71
+ }
72
+
73
+ window.setTimeout( function() {
74
+ wp.a11y.speak( SiteHealth.string.site_health_complete );
75
+ }, delay );
76
+ } else {
77
+ // Cancel the announcement.
78
+ window.clearTimeout( timeout );
79
+ }
80
+
81
+ $( document ).trigger( 'site-health-info-dirsizes-done' );
82
+ } );
83
+ }
84
+
85
+ function updateDirSizes( data ) {
86
+ const copyButton = $( 'button.button.copy-button' );
87
+ let clipdoardText = copyButton.attr( 'data-clipboard-text' );
88
+
89
+ $.each( data, function( name, value ) {
90
+ const text = value.debug || value.size;
91
+
92
+ if ( 'undefined' !== typeof text ) {
93
+ clipdoardText = clipdoardText.replace( name + ': loading...', name + ': ' + text );
94
+ }
95
+ } );
96
+
97
+ copyButton.attr( 'data-clipboard-text', clipdoardText );
98
+
99
+ pathsSizesSection.find( 'td[class]' ).each( function( i, element ) {
100
+ const td = $( element );
101
+ const name = td.attr( 'class' );
102
+
103
+ if ( data.hasOwnProperty( name ) && data[ name ].size ) {
104
+ td.text( data[ name ].size );
105
+ }
106
+ } );
107
+ }
108
+
109
+ if ( isDebugTab ) {
110
+ if ( pathsSizesSection.length ) {
111
+ getDirectorySizes();
112
+ }
113
+ }
114
+ } );
 
 
115
 
116
  /* global ajaxurl */
117
+ jQuery( document ).ready( function( $ ) {
118
  function healthCheckFailureModal( markup, action, parent ) {
119
  $( '#dynamic-content' ).html( markup );
120
  $( '.health-check-modal' ).data( 'modal-action', action ).data( 'parent-field', parent ).show();
124
  modal.hide();
125
  }
126
 
127
+ $( '.modal-close' ).click( function( e ) {
128
  e.preventDefault();
129
  healthCheckFailureModalClose( $( this ).closest( '.health-check-modal' ) );
130
+ } );
131
 
132
  $( '.health-check-modal' ).on( 'submit', 'form', function( e ) {
133
+ const data = $( this ).serializeArray(),
134
  modal = $( this ).closest( '.health-check-modal' );
135
 
136
  e.preventDefault();
148
  );
149
 
150
  healthCheckFailureModalClose( modal );
151
+ } );
152
+ } );
153
 
154
  /* global SiteHealth, ajaxurl, healthCheckFailureModal */
155
+ jQuery( document ).ready( function( $ ) {
156
  function testDefaultTheme() {
157
+ const $parent = $( '.individual-loopback-test-status', '#test-single-no-theme' ),
158
  data = {
159
+ action: 'health-check-loopback-default-theme',
160
+ _wpnonce: SiteHealth.nonce.loopback_default_theme,
161
  };
162
 
163
  $.post(
175
  }
176
 
177
  function testSinglePlugin() {
178
+ const $testLines = $( '.not-tested', '#loopback-individual-plugins-list' );
 
 
 
179
 
180
  if ( $testLines.length < 1 ) {
181
  testDefaultTheme();
182
  return null;
183
  }
184
 
185
+ const $testLine = $testLines.first();
186
+ const data = {
187
+ action: 'health-check-loopback-individual-plugins',
188
+ plugin: $testLine.data( 'test-plugin' ),
189
+ _wpnonce: SiteHealth.nonce.loopback_individual_plugins,
190
  };
191
 
192
+ const $parentField = $( '.individual-loopback-test-status', $testLine );
193
 
194
  $parentField.html( SiteHealth.string.running_tests );
195
 
210
  }
211
 
212
  $( '.dashboard_page_health-check' ).on( 'click', '#loopback-no-plugins', function( e ) {
213
+ const $trigger = $( this ),
214
  $parent = $( this ).closest( 'p' ),
215
  data = {
216
+ action: 'health-check-loopback-no-plugins',
217
+ _wpnonce: SiteHealth.nonce.loopback_no_plugins,
218
  };
219
 
220
  e.preventDefault();
234
  },
235
  'json'
236
  );
237
+ } ).on( 'click', '#loopback-individual-plugins', function( e ) {
238
  e.preventDefault();
239
 
240
  $( this ).remove();
241
 
242
  testSinglePlugin();
243
+ } );
244
+ } );
245
 
246
+ /* global ajaxurl, SiteHealth */
247
+ jQuery( document ).ready( function( $ ) {
248
+ let data;
249
+ const isDebugTab = $( '.health-check-debug-tab.active' ).length;
250
 
251
  $( '.site-health-view-passed' ).on( 'click', function() {
252
+ const goodIssuesWrapper = $( '#health-check-issues-good' );
253
 
254
  goodIssuesWrapper.toggleClass( 'hidden' );
255
  $( this ).attr( 'aria-expanded', ! goodIssuesWrapper.hasClass( 'hidden' ) );
256
  } );
257
 
258
  function AppendIssue( issue ) {
259
+ const template = wp.template( 'health-check-issue' ),
260
+ issueWrapper = $( '#health-check-issues-' + issue.status );
261
+
262
+ let heading;
263
 
264
  SiteHealth.site_status.issues[ issue.status ]++;
265
 
266
+ const count = SiteHealth.site_status.issues[ issue.status ];
267
 
268
  if ( 'critical' === issue.status ) {
269
  if ( count <= 1 ) {
293
  }
294
 
295
  function RecalculateProgression() {
296
+ const $progress = $( '.site-health-progress' );
297
+ const $wrapper = $progress.closest( '.site-health-progress-wrapper' );
298
+ const $progressLabel = $( '.site-health-progress-label', $wrapper );
299
+ const $circle = $( '.site-health-progress svg #bar' );
300
+ const totalTests = parseInt( SiteHealth.site_status.issues.good, 0 ) + parseInt( SiteHealth.site_status.issues.recommended, 0 ) + ( parseInt( SiteHealth.site_status.issues.critical, 0 ) * 1.5 );
301
+ const failedTests = ( parseInt( SiteHealth.site_status.issues.recommended, 0 ) * 0.5 ) + ( parseInt( SiteHealth.site_status.issues.critical, 0 ) * 1.5 );
302
+ let val = 100 - Math.ceil( ( failedTests / totalTests ) * 100 );
303
 
304
  if ( 0 === totalTests ) {
305
  $progress.addClass( 'hidden' );
306
  return;
307
  }
308
 
309
+ $wrapper.removeClass( 'loading' );
310
 
311
+ const r = $circle.attr( 'r' );
312
+ const c = Math.PI * ( r * 2 );
313
 
314
  if ( 0 > val ) {
315
  val = 0;
318
  val = 100;
319
  }
320
 
321
+ const pct = ( ( 100 - val ) / 100 ) * c;
322
 
323
  $circle.css( { strokeDashoffset: pct } );
324
 
330
  $( '#health-check-issues-recommended' ).addClass( 'hidden' );
331
  }
332
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
333
  if ( ! isDebugTab ) {
334
  $.post(
335
  ajaxurl,
336
  {
337
+ action: 'health-check-site-status-result',
338
+ _wpnonce: SiteHealth.nonce.site_status_result,
339
+ counts: SiteHealth.site_status.issues,
340
  }
341
  );
342
  }
343
 
344
+ if ( 80 <= val && 0 === parseInt( SiteHealth.site_status.issues.critical, 0 ) ) {
345
+ $wrapper.addClass( 'green' ).removeClass( 'orange' );
346
+
347
+ $progressLabel.text( SiteHealth.string.site_health_complete_pass );
348
+ wp.a11y.speak( SiteHealth.string.site_health_complete_pass_sr );
349
+ } else {
350
+ $wrapper.addClass( 'orange' ).removeClass( 'green' );
351
+
352
+ $progressLabel.text( SiteHealth.string.site_health_complete_fail );
353
+ wp.a11y.speak( SiteHealth.string.site_health_complete_fail_sr );
354
+ }
355
+
356
+ if ( 100 === val ) {
357
+ $( '.site-status-all-clear' ).removeClass( 'hide' );
358
+ $( '.site-status-has-issues' ).addClass( 'hide' );
359
+ }
360
  }
361
 
362
  function maybeRunNextAsyncTest() {
363
+ let doCalculation = true;
364
 
365
  if ( 1 <= SiteHealth.site_status.async.length ) {
366
  $.each( SiteHealth.site_status.async, function() {
367
+ data = {
368
+ action: 'health-check-site-status',
369
+ feature: this.test,
370
+ _wpnonce: SiteHealth.nonce.site_status,
371
  };
372
 
373
  if ( this.completed ) {
382
  ajaxurl,
383
  data,
384
  function( response ) {
385
+ if ( typeof wp.hooks !== 'undefined' ) {
386
+ AppendIssue( wp.hooks.applyFilters( 'site_status_test_result', response.data ) );
387
+ } else {
388
+ AppendIssue( response.data );
389
+ }
390
  maybeRunNextAsyncTest();
391
  }
392
  );
405
  RecalculateProgression();
406
  } else {
407
  SiteHealth.site_status.issues = {
408
+ good: 0,
409
+ recommended: 0,
410
+ critical: 0,
411
  };
412
  }
413
 
419
 
420
  if ( 0 < SiteHealth.site_status.async.length ) {
421
  data = {
422
+ action: 'health-check-site-status',
423
+ feature: SiteHealth.site_status.async[ 0 ].test,
424
+ _wpnonce: SiteHealth.nonce.site_status,
425
  };
426
 
427
+ SiteHealth.site_status.async[ 0 ].completed = true;
428
 
429
  $.post(
430
  ajaxurl,
438
  RecalculateProgression();
439
  }
440
  }
441
+ } );
442
+
443
+ jQuery( document ).ready( function( $ ) {
444
+ $( '.show-remaining' ).click( function() {
445
+ $( '.hidden', $( this ).closest( 'ul' ) ).removeClass( 'hidden' );
446
+ } );
447
+ } );
448
 
449
  /* global ajaxurl, SiteHealth */
450
+ jQuery( document ).ready( function( $ ) {
451
  $( '#health-check-file-integrity' ).submit( function( e ) {
452
+ const data = {
453
+ action: 'health-check-files-integrity-check',
454
+ _wpnonce: SiteHealth.nonce.files_integrity_check,
455
  };
456
 
457
  e.preventDefault();
468
  $( '#tools-file-integrity-response-holder' ).html( response.data.message );
469
  }
470
  );
471
+ } );
472
 
473
  $( '#tools-file-integrity-response-holder' ).on( 'click', 'a[href="#health-check-diff"]', function( e ) {
474
+ const file = $( this ).data( 'file' );
 
475
 
476
  e.preventDefault();
477
 
478
  $( '#health-check-diff-modal' ).toggle();
479
  $( '#health-check-diff-modal #health-check-diff-modal-content .spinner' ).addClass( 'is-active' );
480
 
481
+ const data = {
482
+ action: 'health-check-view-file-diff',
483
+ file,
484
+ _wpnonce: SiteHealth.nonce.view_file_diff,
485
  };
486
 
487
  $.post(
493
  $( '#health-check-diff-modal #health-check-diff-modal-content .spinner' ).removeClass( 'is-active' );
494
  }
495
  );
496
+ } );
497
+ } );
498
 
499
+ jQuery( document ).ready( function( $ ) {
500
  $( '#health-check-diff-modal' ).on( 'click', 'a[href="#health-check-diff-modal-close"]', function( e ) {
501
  e.preventDefault();
502
  $( '#health-check-diff-modal' ).toggle();
503
  $( '#health-check-diff-modal #health-check-diff-modal-diff' ).html( '' );
504
  $( '#health-check-diff-modal #health-check-diff-modal-content h3' ).html( '' );
505
+ } );
506
 
507
+ $( document ).keyup( function( e ) {
508
  if ( 27 === e.which ) {
509
  $( '#health-check-diff-modal' ).css( 'display', 'none' );
510
  $( '#health-check-diff-modal #health-check-diff-modal-diff' ).html( '' );
511
  $( '#health-check-diff-modal #health-check-diff-modal-content h3' ).html( '' );
512
  }
513
+ } );
514
+ } );
515
 
516
  /* global ajaxurl, SiteHealth */
517
+ jQuery( document ).ready( function( $ ) {
518
  $( '#health-check-mail-check' ).submit( function( e ) {
519
+ const email = $( '#health-check-mail-check #email' ).val(),
520
+ emailMessage = $( '#health-check-mail-check #email_message' ).val();
 
521
 
522
  e.preventDefault();
523
 
524
  $( '#tools-mail-check-response-holder' ).html( '<span class="spinner"></span>' );
525
  $( '#tools-mail-check-response-holder .spinner' ).addClass( 'is-active' );
526
 
527
+ const data = {
528
+ action: 'health-check-mail-check',
529
+ email,
530
+ email_message: emailMessage,
531
+ _wpnonce: SiteHealth.nonce.mail_check,
532
  };
533
 
534
  $.post(
540
  $( '#tools-mail-check-response-holder' ).html( response.data.message );
541
  }
542
  );
543
+ } );
544
+ } );
545
+
546
+ /* global ajaxurl, SiteHealth */
547
+ jQuery( document ).ready( function( $ ) {
548
+ $( '#health-check-tool-plugin-compat' ).click( function() {
549
+ $( 'tr', '#health-check-tool-plugin-compat-list' ).data( 'plugin-checked', false );
550
+ $( '.spinner', '#health-check-tool-plugin-compat-list' ).addClass( 'is-active' );
551
+
552
+ $( this ).attr( 'disabled', true );
553
+
554
+ HealthCheckToolsPluginCompatTest();
555
+ } );
556
+
557
+ function HealthCheckToolsPluginCompatTest() {
558
+ const $plugins = $( '[data-plugin-checked="false"]', '#health-check-tool-plugin-compat-list' );
559
+
560
+ if ( $plugins.length <= 0 ) {
561
+ return;
562
+ }
563
+
564
+ const $nextPlugin = $( $plugins[ 0 ] );
565
+
566
+ $nextPlugin.attr( 'data-plugin-checked', 'true' );
567
+
568
+ const data = {
569
+ action: 'health-check-tools-plugin-compat',
570
+ slug: $nextPlugin.data( 'plugin-slug' ),
571
+ version: $nextPlugin.data( 'plugin-version' ),
572
+ _wpnonce: SiteHealth.nonce.tools_plugin_compat,
573
+ };
574
+
575
+ $.post(
576
+ ajaxurl,
577
+ data,
578
+ function( response ) {
579
+ $( '.spinner', $nextPlugin ).removeClass( 'is-active' );
580
+ $( '.supported-version', $nextPlugin ).append( response.data.version );
581
+
582
+ HealthCheckToolsPluginCompatTest();
583
+ }
584
+ );
585
+ }
586
+ } );
assets/mu-plugin/health-check-troubleshooting-mode.php CHANGED
@@ -2,7 +2,7 @@
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.6.0
6
  */
7
 
8
  if ( ! defined( 'ABSPATH' ) ) {
@@ -10,7 +10,7 @@ if ( ! defined( 'ABSPATH' ) ) {
10
  }
11
 
12
  // Set the MU plugin version.
13
- define( 'HEALTH_CHECK_TROUBLESHOOTING_MODE_PLUGIN_VERSION', '1.6.0' );
14
 
15
  class Health_Check_Troubleshooting_MU {
16
  private $disable_hash = null;
@@ -64,6 +64,11 @@ class Health_Check_Troubleshooting_MU {
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
 
@@ -112,7 +117,25 @@ class Health_Check_Troubleshooting_MU {
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
- wp_enqueue_script( 'health-check', plugins_url( '/health-check/assets/javascript/health-check.js' ), array( 'jquery' ), HEALTH_CHECK_TROUBLESHOOTING_MODE_PLUGIN_VERSION, true );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
116
  }
117
 
118
  /**
@@ -132,10 +155,14 @@ class Health_Check_Troubleshooting_MU {
132
  printf(
133
  '<div class="notice notice-warning dismissable"><p>%s</p><p><a href="%s" class="button button-primary">%s</a></p></div>',
134
  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' ),
135
- esc_url( admin_url( sprintf(
136
- 'theme-install.php?theme=%s',
137
- $this->default_themes[0]
138
- ) ) ),
 
 
 
 
139
  esc_html__( 'Install a default theme', 'health-check' )
140
  );
141
  }
@@ -189,6 +216,104 @@ class Health_Check_Troubleshooting_MU {
189
  update_option( 'active_plugins', $this->active_plugins );
190
  }
191
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
192
  /**
193
  * Modify plugin actions.
194
  *
@@ -228,25 +353,36 @@ class Health_Check_Troubleshooting_MU {
228
 
229
  // Set a slug if the plugin lives in the plugins directory root.
230
  if ( ! stristr( $plugin_file, '/' ) ) {
231
- $plugin_data['slug'] = $plugin_file;
 
 
 
232
  }
233
 
234
- $plugin_slug = ( isset( $plugin_data['slug'] ) ? $plugin_data['slug'] : sanitize_title( $plugin_data['Name'] ) );
235
-
236
  if ( in_array( $plugin_slug, $this->allowed_plugins ) ) {
237
  $actions['troubleshoot-disable'] = sprintf(
238
  '<a href="%s">%s</a>',
239
- esc_url( add_query_arg( array(
240
- 'health-check-troubleshoot-disable-plugin' => $plugin_slug,
241
- ), admin_url( 'plugins.php' ) ) ),
 
 
 
 
 
242
  esc_html__( 'Disable while troubleshooting', 'health-check' )
243
  );
244
  } else {
245
  $actions['troubleshoot-disable'] = sprintf(
246
  '<a href="%s">%s</a>',
247
- esc_url( add_query_arg( array(
248
- 'health-check-troubleshoot-enable-plugin' => $plugin_slug,
249
- ), admin_url( 'plugins.php' ) ) ),
 
 
 
 
 
250
  esc_html__( 'Enable while troubleshooting', 'health-check' )
251
  );
252
  }
@@ -620,36 +756,46 @@ class Health_Check_Troubleshooting_MU {
620
  include_once( trailingslashit( ABSPATH ) . 'wp-admin/includes/theme.php' );
621
 
622
  // Add top-level menu item.
623
- $wp_menu->add_menu( array(
624
- 'id' => 'health-check',
625
- 'title' => esc_html__( 'Troubleshooting Mode', 'health-check' ),
626
- 'href' => admin_url( '/' ),
627
- ) );
 
 
628
 
629
  // Add a link to manage plugins if there are more than 20 set to be active.
630
  if ( count( $this->active_plugins ) > 20 ) {
631
- $wp_menu->add_node( array(
632
- 'id' => 'health-check-plugins',
633
- 'title' => esc_html__( 'Manage active plugins', 'health-check' ),
634
- 'parent' => 'health-check',
635
- 'href' => admin_url( 'plugins.php' ),
636
- ) );
 
 
637
  } else {
638
- $wp_menu->add_node( array(
639
- 'id' => 'health-check-plugins',
640
- 'title' => esc_html__( 'Plugins', 'health-check' ),
641
- 'parent' => 'health-check',
642
- 'href' => admin_url( 'plugins.php' ),
643
- ) );
644
-
645
- $wp_menu->add_group( array(
646
- 'id' => 'health-check-plugins-enabled',
647
- 'parent' => 'health-check-plugins',
648
- ) );
649
- $wp_menu->add_group( array(
650
- 'id' => 'health-check-plugins-disabled',
651
- 'parent' => 'health-check-plugins',
652
- ) );
 
 
 
 
 
 
653
 
654
  foreach ( $this->active_plugins as $single_plugin ) {
655
  $plugin_slug = explode( '/', $single_plugin );
@@ -668,9 +814,11 @@ class Health_Check_Troubleshooting_MU {
668
  $plugin_data['Name']
669
  )
670
  );
671
- $url = add_query_arg( array(
672
- 'health-check-troubleshoot-disable-plugin' => $plugin_slug,
673
- ) );
 
 
674
  } else {
675
  $enabled = false;
676
  $label = sprintf(
@@ -681,29 +829,35 @@ class Health_Check_Troubleshooting_MU {
681
  $plugin_data['Name']
682
  )
683
  );
684
- $url = add_query_arg( array(
685
- 'health-check-troubleshoot-enable-plugin' => $plugin_slug,
686
- ) );
 
 
687
  }
688
 
689
- $wp_menu->add_node( array(
690
- 'id' => sprintf(
691
- 'health-check-plugin-%s',
692
- $plugin_slug
693
- ),
694
- 'title' => $label,
695
- 'parent' => ( $enabled ? 'health-check-plugins-enabled' : 'health-check-plugins-disabled' ),
696
- 'href' => $url,
697
- ) );
 
 
698
  }
699
  }
700
 
701
- $wp_menu->add_node( array(
702
- 'id' => 'health-check-theme',
703
- 'title' => esc_html__( 'Themes', 'health-check' ),
704
- 'parent' => 'health-check',
705
- 'href' => admin_url( 'themes.php' ),
706
- ) );
 
 
707
 
708
  $themes = wp_prepare_themes_for_js();
709
 
@@ -722,23 +876,29 @@ class Health_Check_Troubleshooting_MU {
722
  );
723
 
724
  if ( ! $theme['active'] ) {
725
- $node['href'] = add_query_arg( array(
726
- 'health-check-change-active-theme' => $theme['id'],
727
- ) );
 
 
728
  }
729
 
730
  $wp_menu->add_node( $node );
731
  }
732
 
733
  // Add a link to disable Troubleshooting Mode.
734
- $wp_menu->add_node( array(
735
- 'id' => 'health-check-disable',
736
- 'title' => esc_html__( 'Disable Troubleshooting Mode', 'health-check' ),
737
- 'parent' => 'health-check',
738
- 'href' => add_query_arg( array(
739
- 'health-check-disable-troubleshooting' => true,
740
- ) ),
741
- ) );
 
 
 
 
742
  }
743
 
744
  public function test_site_state() {
@@ -815,9 +975,13 @@ class Health_Check_Troubleshooting_MU {
815
  <?php
816
  printf(
817
  '<a href="%s" class="button button-primary">%s</a>',
818
- esc_url( add_query_arg( array(
819
- 'health-check-disable-troubleshooting' => true,
820
- ) ) ),
 
 
 
 
821
  esc_html__( 'Disable Troubleshooting Mode', 'health-check' )
822
  );
823
  ?>
@@ -852,6 +1016,8 @@ class Health_Check_Troubleshooting_MU {
852
  <dd id="health-check-accordion-block-plugins" role="region" aria-labelledby="health-check-accordion-heading-plugins" class="health-check-accordion-panel" hidden="hidden">
853
  <ul id="health-check-plugins" role="list">
854
  <?php
 
 
855
  foreach ( $this->active_plugins as $count => $single_plugin ) {
856
  $plugin_slug = explode( '/', $single_plugin );
857
  $plugin_slug = $plugin_slug[0];
@@ -868,9 +1034,13 @@ class Health_Check_Troubleshooting_MU {
868
  if ( in_array( $plugin_slug, $this->allowed_plugins ) ) {
869
  $actions[] = sprintf(
870
  '<a href="%s" aria-label="%s">%s</a>',
871
- esc_url( add_query_arg( array(
872
- 'health-check-troubleshoot-disable-plugin' => $plugin_slug,
873
- ) ) ),
 
 
 
 
874
  esc_attr(
875
  sprintf(
876
  // translators: %s: Plugin name.
@@ -883,9 +1053,13 @@ class Health_Check_Troubleshooting_MU {
883
  } else {
884
  $actions[] = sprintf(
885
  '<a href="%s" aria-label="%s">%s</a>',
886
- esc_url( add_query_arg( array(
887
- 'health-check-troubleshoot-enable-plugin' => $plugin_slug,
888
- ) ) ),
 
 
 
 
889
  esc_attr(
890
  sprintf(
891
  // translators: %s: Plugin name.
@@ -897,6 +1071,19 @@ class Health_Check_Troubleshooting_MU {
897
  );
898
  }
899
 
 
 
 
 
 
 
 
 
 
 
 
 
 
900
  printf(
901
  '<li class="%s">%s - %s</li>',
902
  ( ! $plugin_is_visible ? 'toggle-visibility hidden' : '' ),
@@ -925,6 +1112,8 @@ class Health_Check_Troubleshooting_MU {
925
  <dd id="health-check-accordion-block-themes" role="region" aria-labelledby="health-check-accordion-heading-themes" class="health-check-accordion-panel" hidden="hidden">
926
  <ul id="health-check-themes" role="list">
927
  <?php
 
 
928
  foreach ( $themes as $count => $theme ) {
929
  $theme_is_visible = true;
930
  if ( $count >= 5 ) {
@@ -933,9 +1122,13 @@ class Health_Check_Troubleshooting_MU {
933
 
934
  $actions = sprintf(
935
  '<a href="%s" aria-label="%s">%s</a>',
936
- esc_url( add_query_arg( array(
937
- 'health-check-change-active-theme' => $theme['id'],
938
- ) ) ),
 
 
 
 
939
  esc_attr(
940
  sprintf(
941
  // translators: %s: Theme name.
@@ -957,6 +1150,19 @@ class Health_Check_Troubleshooting_MU {
957
  $plugin_label .= ' - ' . $actions;
958
  }
959
 
 
 
 
 
 
 
 
 
 
 
 
 
 
960
  printf(
961
  '<li class="%s">%s</li>',
962
  ( ! $theme_is_visible ? 'toggle-visibility hidden' : '' ),
@@ -1012,9 +1218,13 @@ class Health_Check_Troubleshooting_MU {
1012
  if ( ! empty( $notices ) ) {
1013
  printf(
1014
  '<div class="dismiss-notices"><a href="%s" class="">%s</a></div>',
1015
- esc_url( add_query_arg( array(
1016
- 'health-check-dismiss-notices' => true,
1017
- ) ) ),
 
 
 
 
1018
  esc_html__( 'Dismiss notices', 'health-check' )
1019
  );
1020
  }
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.7.0
6
  */
7
 
8
  if ( ! defined( 'ABSPATH' ) ) {
10
  }
11
 
12
  // Set the MU plugin version.
13
+ define( 'HEALTH_CHECK_TROUBLESHOOTING_MODE_PLUGIN_VERSION', '1.7.0' );
14
 
15
  class Health_Check_Troubleshooting_MU {
16
  private $disable_hash = null;
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_filter( 'wp_fatal_error_handler_enabled', array( $this, 'wp_fatal_error_handler_enabled' ) );
68
+
69
+ add_filter( 'bulk_actions-plugins', array( $this, 'remove_plugin_bulk_actions' ) );
70
+ add_filter( 'handle_bulk_actions-plugins', array( $this, 'handle_plugin_bulk_actions' ), 10, 3 );
71
+
72
  add_action( 'admin_notices', array( $this, 'prompt_install_default_theme' ) );
73
  add_filter( 'user_has_cap', array( $this, 'remove_plugin_theme_install' ) );
74
 
117
  }
118
 
119
  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 );
120
+ wp_enqueue_script( 'health-check', plugins_url( '/health-check/assets/javascript/health-check.js' ), array( 'jquery', 'wp-a11y', 'clipboard', 'wp-util' ), HEALTH_CHECK_TROUBLESHOOTING_MODE_PLUGIN_VERSION, true );
121
+ }
122
+
123
+ /**
124
+ * Allow troubleshooting Mode to override the WSOD protection introduced in WordPress 5.2.0
125
+ *
126
+ * This will prevent incorrect reporting of errors while testing sites, without touching the
127
+ * settings put in by site admins in regular scenarios.
128
+ *
129
+ * @param bool $enabled
130
+ *
131
+ * @return bool
132
+ */
133
+ public function wp_fatal_error_handler_enabled( $enabled ) {
134
+ if ( ! $this->is_troubleshooting() ) {
135
+ return $enabled;
136
+ }
137
+
138
+ return false;
139
  }
140
 
141
  /**
155
  printf(
156
  '<div class="notice notice-warning dismissable"><p>%s</p><p><a href="%s" class="button button-primary">%s</a></p></div>',
157
  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' ),
158
+ esc_url(
159
+ admin_url(
160
+ sprintf(
161
+ 'theme-install.php?theme=%s',
162
+ $this->default_themes[0]
163
+ )
164
+ )
165
+ ),
166
  esc_html__( 'Install a default theme', 'health-check' )
167
  );
168
  }
216
  update_option( 'active_plugins', $this->active_plugins );
217
  }
218
 
219
+ public function handle_plugin_bulk_actions( $sendback, $action, $plugins ) {
220
+ if ( ! $this->is_troubleshooting() && 'health-check-troubleshoot' !== $action ) {
221
+ return $sendback;
222
+ }
223
+
224
+ $sendback = self_admin_url( 'plugins.php' );
225
+
226
+ if ( 'health-check-troubleshoot' === $action ) {
227
+ foreach ( $plugins as $single_plugin ) {
228
+ $plugin_slug = explode( '/', $single_plugin );
229
+ $plugin_slug = $plugin_slug[0];
230
+
231
+ if ( in_array( $single_plugin, $this->active_plugins ) ) {
232
+ $this->allowed_plugins[ $plugin_slug ] = $plugin_slug;
233
+ }
234
+ }
235
+
236
+ Health_Check_Troubleshoot::initiate_troubleshooting_mode( $this->allowed_plugins );
237
+
238
+ if ( ! $this->test_site_state() ) {
239
+ $this->allowed_plugins = array();
240
+ update_option( 'health-check-allowed-plugins', $this->allowed_plugins );
241
+
242
+ $this->add_dashboard_notice(
243
+ __( 'When enabling troubleshooting on the selected plugins, a site failure occurred. Because of this the selected plugins were kept disabled while troubleshooting mode started.', 'health-check' ),
244
+ 'warning'
245
+ );
246
+ }
247
+ }
248
+
249
+ if ( 'health-check-enable' === $action ) {
250
+ $old_allowed_plugins = $this->allowed_plugins;
251
+
252
+ foreach ( $plugins as $single_plugin ) {
253
+ $plugin_slug = explode( '/', $single_plugin );
254
+ $plugin_slug = $plugin_slug[0];
255
+
256
+ if ( in_array( $single_plugin, $this->active_plugins ) ) {
257
+ $this->allowed_plugins[ $plugin_slug ] = $plugin_slug;
258
+ }
259
+ }
260
+
261
+ update_option( 'health-check-allowed-plugins', $this->allowed_plugins );
262
+
263
+ if ( ! $this->test_site_state() ) {
264
+ $this->allowed_plugins = $old_allowed_plugins;
265
+ update_option( 'health-check-allowed-plugins', $old_allowed_plugins );
266
+
267
+ $this->add_dashboard_notice(
268
+ __( 'When bulk-enabling plugins, a site failure occurred. Because of this the change was automatically reverted.', 'health-check' ),
269
+ 'warning'
270
+ );
271
+ }
272
+ }
273
+
274
+ if ( 'health-check-disable' === $action ) {
275
+ $old_allowed_plugins = $this->allowed_plugins;
276
+
277
+ foreach ( $plugins as $single_plugin ) {
278
+ $plugin_slug = explode( '/', $single_plugin );
279
+ $plugin_slug = $plugin_slug[0];
280
+
281
+ if ( in_array( $single_plugin, $this->active_plugins ) ) {
282
+ unset( $this->allowed_plugins[ $plugin_slug ] );
283
+ }
284
+ }
285
+
286
+ update_option( 'health-check-allowed-plugins', $this->allowed_plugins );
287
+
288
+ if ( ! $this->test_site_state() ) {
289
+ $this->allowed_plugins = $old_allowed_plugins;
290
+ update_option( 'health-check-allowed-plugins', $old_allowed_plugins );
291
+
292
+ $this->add_dashboard_notice(
293
+ __( 'When bulk-disabling plugins, a site failure occurred. Because of this the change was automatically reverted.', 'health-check' ),
294
+ 'warning'
295
+ );
296
+ }
297
+ }
298
+
299
+ return $sendback;
300
+ }
301
+
302
+ public function remove_plugin_bulk_actions( $actions ) {
303
+ if ( ! $this->is_troubleshooting() ) {
304
+ $actions['health-check-troubleshoot'] = __( 'Troubleshoot', 'health-check' );
305
+
306
+ return $actions;
307
+ }
308
+
309
+ $actions = array(
310
+ 'health-check-enable' => __( 'Enable while troubleshooting', 'health-check' ),
311
+ 'health-check-disable' => __( 'Disable while troubleshooting', 'health-check' ),
312
+ );
313
+
314
+ return $actions;
315
+ }
316
+
317
  /**
318
  * Modify plugin actions.
319
  *
353
 
354
  // Set a slug if the plugin lives in the plugins directory root.
355
  if ( ! stristr( $plugin_file, '/' ) ) {
356
+ $plugin_slug = $plugin_file;
357
+ } else { // Set the slug for plugin inside a folder.
358
+ $plugin_slug = explode( '/', $plugin_file );
359
+ $plugin_slug = $plugin_slug[0];
360
  }
361
 
 
 
362
  if ( in_array( $plugin_slug, $this->allowed_plugins ) ) {
363
  $actions['troubleshoot-disable'] = sprintf(
364
  '<a href="%s">%s</a>',
365
+ esc_url(
366
+ add_query_arg(
367
+ array(
368
+ 'health-check-troubleshoot-disable-plugin' => $plugin_slug,
369
+ ),
370
+ admin_url( 'plugins.php' )
371
+ )
372
+ ),
373
  esc_html__( 'Disable while troubleshooting', 'health-check' )
374
  );
375
  } else {
376
  $actions['troubleshoot-disable'] = sprintf(
377
  '<a href="%s">%s</a>',
378
+ esc_url(
379
+ add_query_arg(
380
+ array(
381
+ 'health-check-troubleshoot-enable-plugin' => $plugin_slug,
382
+ ),
383
+ admin_url( 'plugins.php' )
384
+ )
385
+ ),
386
  esc_html__( 'Enable while troubleshooting', 'health-check' )
387
  );
388
  }
756
  include_once( trailingslashit( ABSPATH ) . 'wp-admin/includes/theme.php' );
757
 
758
  // Add top-level menu item.
759
+ $wp_menu->add_menu(
760
+ array(
761
+ 'id' => 'health-check',
762
+ 'title' => esc_html__( 'Troubleshooting Mode', 'health-check' ),
763
+ 'href' => admin_url( '/' ),
764
+ )
765
+ );
766
 
767
  // Add a link to manage plugins if there are more than 20 set to be active.
768
  if ( count( $this->active_plugins ) > 20 ) {
769
+ $wp_menu->add_node(
770
+ array(
771
+ 'id' => 'health-check-plugins',
772
+ 'title' => esc_html__( 'Manage active plugins', 'health-check' ),
773
+ 'parent' => 'health-check',
774
+ 'href' => admin_url( 'plugins.php' ),
775
+ )
776
+ );
777
  } else {
778
+ $wp_menu->add_node(
779
+ array(
780
+ 'id' => 'health-check-plugins',
781
+ 'title' => esc_html__( 'Plugins', 'health-check' ),
782
+ 'parent' => 'health-check',
783
+ 'href' => admin_url( 'plugins.php' ),
784
+ )
785
+ );
786
+
787
+ $wp_menu->add_group(
788
+ array(
789
+ 'id' => 'health-check-plugins-enabled',
790
+ 'parent' => 'health-check-plugins',
791
+ )
792
+ );
793
+ $wp_menu->add_group(
794
+ array(
795
+ 'id' => 'health-check-plugins-disabled',
796
+ 'parent' => 'health-check-plugins',
797
+ )
798
+ );
799
 
800
  foreach ( $this->active_plugins as $single_plugin ) {
801
  $plugin_slug = explode( '/', $single_plugin );
814
  $plugin_data['Name']
815
  )
816
  );
817
+ $url = add_query_arg(
818
+ array(
819
+ 'health-check-troubleshoot-disable-plugin' => $plugin_slug,
820
+ )
821
+ );
822
  } else {
823
  $enabled = false;
824
  $label = sprintf(
829
  $plugin_data['Name']
830
  )
831
  );
832
+ $url = add_query_arg(
833
+ array(
834
+ 'health-check-troubleshoot-enable-plugin' => $plugin_slug,
835
+ )
836
+ );
837
  }
838
 
839
+ $wp_menu->add_node(
840
+ array(
841
+ 'id' => sprintf(
842
+ 'health-check-plugin-%s',
843
+ $plugin_slug
844
+ ),
845
+ 'title' => $label,
846
+ 'parent' => ( $enabled ? 'health-check-plugins-enabled' : 'health-check-plugins-disabled' ),
847
+ 'href' => $url,
848
+ )
849
+ );
850
  }
851
  }
852
 
853
+ $wp_menu->add_node(
854
+ array(
855
+ 'id' => 'health-check-theme',
856
+ 'title' => esc_html__( 'Themes', 'health-check' ),
857
+ 'parent' => 'health-check',
858
+ 'href' => admin_url( 'themes.php' ),
859
+ )
860
+ );
861
 
862
  $themes = wp_prepare_themes_for_js();
863
 
876
  );
877
 
878
  if ( ! $theme['active'] ) {
879
+ $node['href'] = add_query_arg(
880
+ array(
881
+ 'health-check-change-active-theme' => $theme['id'],
882
+ )
883
+ );
884
  }
885
 
886
  $wp_menu->add_node( $node );
887
  }
888
 
889
  // Add a link to disable Troubleshooting Mode.
890
+ $wp_menu->add_node(
891
+ array(
892
+ 'id' => 'health-check-disable',
893
+ 'title' => esc_html__( 'Disable Troubleshooting Mode', 'health-check' ),
894
+ 'parent' => 'health-check',
895
+ 'href' => add_query_arg(
896
+ array(
897
+ 'health-check-disable-troubleshooting' => true,
898
+ )
899
+ ),
900
+ )
901
+ );
902
  }
903
 
904
  public function test_site_state() {
975
  <?php
976
  printf(
977
  '<a href="%s" class="button button-primary">%s</a>',
978
+ esc_url(
979
+ add_query_arg(
980
+ array(
981
+ 'health-check-disable-troubleshooting' => true,
982
+ )
983
+ )
984
+ ),
985
  esc_html__( 'Disable Troubleshooting Mode', 'health-check' )
986
  );
987
  ?>
1016
  <dd id="health-check-accordion-block-plugins" role="region" aria-labelledby="health-check-accordion-heading-plugins" class="health-check-accordion-panel" hidden="hidden">
1017
  <ul id="health-check-plugins" role="list">
1018
  <?php
1019
+ $has_toggle = false;
1020
+
1021
  foreach ( $this->active_plugins as $count => $single_plugin ) {
1022
  $plugin_slug = explode( '/', $single_plugin );
1023
  $plugin_slug = $plugin_slug[0];
1034
  if ( in_array( $plugin_slug, $this->allowed_plugins ) ) {
1035
  $actions[] = sprintf(
1036
  '<a href="%s" aria-label="%s">%s</a>',
1037
+ esc_url(
1038
+ add_query_arg(
1039
+ array(
1040
+ 'health-check-troubleshoot-disable-plugin' => $plugin_slug,
1041
+ )
1042
+ )
1043
+ ),
1044
  esc_attr(
1045
  sprintf(
1046
  // translators: %s: Plugin name.
1053
  } else {
1054
  $actions[] = sprintf(
1055
  '<a href="%s" aria-label="%s">%s</a>',
1056
+ esc_url(
1057
+ add_query_arg(
1058
+ array(
1059
+ 'health-check-troubleshoot-enable-plugin' => $plugin_slug,
1060
+ )
1061
+ )
1062
+ ),
1063
  esc_attr(
1064
  sprintf(
1065
  // translators: %s: Plugin name.
1071
  );
1072
  }
1073
 
1074
+ if ( ! $plugin_is_visible && ! $has_toggle ) {
1075
+ $has_toggle = true;
1076
+
1077
+ printf(
1078
+ '<li><button type="button" class="show-remaining button button-link">%s</button></li>',
1079
+ sprintf(
1080
+ // translators: %d: Amount of hidden plugins.
1081
+ __( 'Show %d remaining plugins', 'health-check' ),
1082
+ ( is_countable( $this->active_plugins ) ? ( count( $this->active_plugins ) - 5 ) : 0 )
1083
+ )
1084
+ );
1085
+ }
1086
+
1087
  printf(
1088
  '<li class="%s">%s - %s</li>',
1089
  ( ! $plugin_is_visible ? 'toggle-visibility hidden' : '' ),
1112
  <dd id="health-check-accordion-block-themes" role="region" aria-labelledby="health-check-accordion-heading-themes" class="health-check-accordion-panel" hidden="hidden">
1113
  <ul id="health-check-themes" role="list">
1114
  <?php
1115
+ $has_toggle = false;
1116
+
1117
  foreach ( $themes as $count => $theme ) {
1118
  $theme_is_visible = true;
1119
  if ( $count >= 5 ) {
1122
 
1123
  $actions = sprintf(
1124
  '<a href="%s" aria-label="%s">%s</a>',
1125
+ esc_url(
1126
+ add_query_arg(
1127
+ array(
1128
+ 'health-check-change-active-theme' => $theme['id'],
1129
+ )
1130
+ )
1131
+ ),
1132
  esc_attr(
1133
  sprintf(
1134
  // translators: %s: Theme name.
1150
  $plugin_label .= ' - ' . $actions;
1151
  }
1152
 
1153
+ if ( ! $theme_is_visible && ! $has_toggle ) {
1154
+ $has_toggle = true;
1155
+
1156
+ printf(
1157
+ '<li><button type="button" class="show-remaining button button-link">%s</button></li>',
1158
+ sprintf(
1159
+ // translators: %d: Amount of hidden themes.
1160
+ __( 'Show %d remaining themes', 'health-check' ),
1161
+ ( is_countable( $themes ) ? ( count( $themes ) - 5 ) : 0 )
1162
+ )
1163
+ );
1164
+ }
1165
+
1166
  printf(
1167
  '<li class="%s">%s</li>',
1168
  ( ! $theme_is_visible ? 'toggle-visibility hidden' : '' ),
1218
  if ( ! empty( $notices ) ) {
1219
  printf(
1220
  '<div class="dismiss-notices"><a href="%s" class="">%s</a></div>',
1221
+ esc_url(
1222
+ add_query_arg(
1223
+ array(
1224
+ 'health-check-dismiss-notices' => true,
1225
+ )
1226
+ )
1227
+ ),
1228
  esc_html__( 'Dismiss notices', 'health-check' )
1229
  );
1230
  }
changelog.txt CHANGED
@@ -1,3 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  = v1.2.5 =
2
  * Fix: Ensure the REST API status test runs as intended.
3
  * Fix: Remove warning on plugin screens when premium plugins are used.
1
+ = v1.3.2 =
2
+ * Add polyfill for directory size calculations for sites running WordPress versions older than 5.2.0
3
+ * Fix link for the extended PHP information
4
+
5
+ = v1.3.1 =
6
+ * Include missing dependency for JavaScript files, first introduced in WordPress 5.2
7
+
8
+ = v1.3.0 =
9
+ * Plugin moved to the Tools section in the admin menu
10
+ * New UI/UX for the plugin pages
11
+ * New troubleshooting mode UI/UX
12
+ * Removed the backup reminder nag
13
+ * Improved security hardening
14
+ * Changed cookie names for improved hosting compatibility
15
+ * Improved accessibility
16
+ * Automatically check for critical issues once a week (adds a counter next to the menu item)
17
+ * Dates in the email tester now follow your site settings
18
+
19
  = v1.2.5 =
20
  * Fix: Ensure the REST API status test runs as intended.
21
  * Fix: Remove warning on plugin screens when premium plugins are used.
health-check.php CHANGED
@@ -9,7 +9,7 @@
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.3.2
13
  * Author URI: https://wordpress.org/plugins/health-check/
14
  * Text Domain: health-check
15
  */
@@ -35,7 +35,10 @@ define( 'HEALTH_CHECK_MYSQL_MIN_VERSION', '5.0' );
35
  define( 'HEALTH_CHECK_MYSQL_REC_VERSION', '5.6' );
36
 
37
  // Set the plugin version.
38
- define( 'HEALTH_CHECK_PLUGIN_VERSION', '1.3.2' );
 
 
 
39
 
40
  // Set the absolute path for the plugin.
41
  define( 'HEALTH_CHECK_PLUGIN_DIRECTORY', plugin_dir_path( __FILE__ ) );
@@ -49,6 +52,9 @@ define( 'HEALTH_CHECK_CURL_VERSION', '7.58' );
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' );
@@ -56,14 +62,26 @@ 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();
66
 
 
 
 
67
  // Setup up scheduled events.
68
  register_activation_hook( __FILE__, array( 'Health_Check', 'plugin_activation' ) );
69
  register_deactivation_hook( __FILE__, array( 'Health_Check', 'plugin_deactivation' ) );
 
 
 
 
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.4.0
13
  * Author URI: https://wordpress.org/plugins/health-check/
14
  * Text Domain: health-check
15
  */
35
  define( 'HEALTH_CHECK_MYSQL_REC_VERSION', '5.6' );
36
 
37
  // Set the plugin version.
38
+ define( 'HEALTH_CHECK_PLUGIN_VERSION', '1.4.0' );
39
+
40
+ // Set the plugin file.
41
+ define( 'HEALTH_CHECK_PLUGIN_FILE', __FILE__ );
42
 
43
  // Set the absolute path for the plugin.
44
  define( 'HEALTH_CHECK_PLUGIN_DIRECTORY', plugin_dir_path( __FILE__ ) );
52
  // Set the minimum cURL version that we've tested that core works with.
53
  define( 'HEALTH_CHECK_CURL_MIN_VERSION', '7.38' );
54
 
55
+ // Always include our compatibility file first.
56
+ require_once( dirname( __FILE__ ) . '/includes/compat.php' );
57
+
58
  // Include class-files used by our plugin.
59
  require_once( dirname( __FILE__ ) . '/includes/class-health-check.php' );
60
  require_once( dirname( __FILE__ ) . '/includes/class-health-check-auto-updates.php' );
62
  require_once( dirname( __FILE__ ) . '/includes/class-health-check-debug-data.php' );
63
  require_once( dirname( __FILE__ ) . '/includes/class-health-check-loopback.php' );
64
  require_once( dirname( __FILE__ ) . '/includes/class-health-check-troubleshoot.php' );
 
 
65
  require_once( dirname( __FILE__ ) . '/includes/class-health-check-site-status.php' );
66
  require_once( dirname( __FILE__ ) . '/includes/class-health-check-updates.php' );
67
+ require_once( dirname( __FILE__ ) . '/includes/class-health-check-dashboard-widget.php' );
68
+
69
+ // Tools section.
70
+ require_once( dirname( __FILE__ ) . '/includes/tools/class-health-check-tool.php' );
71
+ require_once( dirname( __FILE__ ) . '/includes/tools/class-health-check-files-integrity.php' );
72
+ require_once( dirname( __FILE__ ) . '/includes/tools/class-health-check-mail-check.php' );
73
+ require_once( dirname( __FILE__ ) . '/includes/tools/class-health-check-plugin-compatibility.php' );
74
 
75
  // Initialize our plugin.
76
  new Health_Check();
77
 
78
+ // Initialize the dashboard widget.
79
+ new Health_Check_Dashboard_Widget();
80
+
81
  // Setup up scheduled events.
82
  register_activation_hook( __FILE__, array( 'Health_Check', 'plugin_activation' ) );
83
  register_deactivation_hook( __FILE__, array( 'Health_Check', 'plugin_deactivation' ) );
84
+
85
+ if ( defined( 'WP_CLI' ) && WP_CLI ) {
86
+ require_once( dirname( __FILE__ ) . '/includes/class-health-check-wp-cli.php' );
87
+ }
includes/class-health-check-dashboard-widget.php ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // Check that the file is not accessed directly.
4
+ if ( ! defined( 'ABSPATH' ) ) {
5
+ die( 'We\'re sorry, but you can not directly access this file.' );
6
+ }
7
+
8
+ class Health_Check_Dashboard_Widget {
9
+
10
+ public function __construct() {
11
+ add_action( 'wp_dashboard_setup', array( $this, 'dashboard_setup' ) );
12
+ }
13
+
14
+ function dashboard_setup() {
15
+ wp_add_dashboard_widget(
16
+ 'health_check_status',
17
+ __( 'Site Health Status', 'health-check' ),
18
+ array( $this, 'widget_render' )
19
+ );
20
+ }
21
+
22
+ function widget_render() {
23
+ $issue_counts = get_transient( 'health-check-site-status-result' );
24
+
25
+ if ( false !== $issue_counts ) {
26
+ $issue_counts = json_decode( $issue_counts );
27
+ } else {
28
+ $issue_counts = array(
29
+ 'good' => 0,
30
+ 'recommended' => 0,
31
+ 'critical' => 0,
32
+ );
33
+ }
34
+
35
+ $issues_total = $issue_counts->recommended + $issue_counts->critical;
36
+ ?>
37
+ <div class="health-check-title-section site-health-progress-wrapper loading hide-if-no-js">
38
+ <div class="site-health-progress">
39
+ <svg role="img" aria-hidden="true" focusable="false" width="100%" height="100%" viewBox="0 0 200 200" version="1.1" xmlns="http://www.w3.org/2000/svg">
40
+ <circle r="90" cx="100" cy="100" fill="transparent" stroke-dasharray="565.48" stroke-dashoffset="0"></circle>
41
+ <circle id="bar" r="90" cx="100" cy="100" fill="transparent" stroke-dasharray="565.48" stroke-dashoffset="0"></circle>
42
+ </svg>
43
+ </div>
44
+ <div class="site-health-progress-label">
45
+ <?php _e( 'Results are still loading&hellip;', 'health-check' ); ?>
46
+ </div>
47
+ </div>
48
+
49
+ <p>
50
+ <?php if ( $issue_counts->critical > 0 ) : ?>
51
+ <?php _e( 'Your site has critical issues that should be addressed as soon as possible to improve the performance or security of your website.', 'health-check' ); ?>
52
+ <?php elseif ( $issues_total <= 0 ) : ?>
53
+ <?php _e( 'Great job! Your site currently passes all site health checks.', 'health-check' ); ?>
54
+ <?php else : ?>
55
+ <?php _e( 'Your site scores pretty well on the Health Check, but there are still some things you can do to improve the performance and security of your website.', 'health-check' ); ?>
56
+ <?php endif; ?>
57
+ </p>
58
+
59
+ <?php if ( $issues_total > 0 ) : ?>
60
+ <p>
61
+ <?php
62
+ printf(
63
+ // translators: 1: Count of issues. 2: URL for the Site Health page.
64
+ __( 'Take a look at the <strong>%1$d items</strong> on the <a href="%2$s">Site Health Check status page</a>.', 'health-check' ),
65
+ $issues_total,
66
+ esc_url( admin_url( 'tools.php?page=health-check' ) )
67
+ );
68
+ ?>
69
+ </p>
70
+ <?php endif; ?>
71
+
72
+ <?php
73
+ }
74
+ }
includes/class-health-check-debug-data.php CHANGED
@@ -43,7 +43,7 @@ class Health_Check_Debug_Data {
43
  * @return array The debug data for the site.
44
  */
45
  static function debug_data() {
46
- global $wpdb;
47
 
48
  // Save few function calls.
49
  $upload_dir = wp_get_upload_dir();
@@ -141,8 +141,13 @@ class Health_Check_Debug_Data {
141
  'fields' => array(),
142
  );
143
 
144
- $info['wp-themes'] = array(
145
- 'label' => __( 'Other Themes', 'health-check' ),
 
 
 
 
 
146
  'show_count' => true,
147
  'fields' => array(),
148
  );
@@ -593,11 +598,27 @@ class Health_Check_Debug_Data {
593
  $php_sapi = 'unknown';
594
  }
595
 
 
 
 
 
 
 
 
 
 
 
596
  $info['wp-server']['fields']['server_architecture'] = array(
597
  'label' => __( 'Server architecture', 'health-check' ),
598
  'value' => ( 'unknown' !== $server_architecture ? $server_architecture : __( 'Unable to determine server architecture', 'health-check' ) ),
599
  'debug' => $server_architecture,
600
  );
 
 
 
 
 
 
601
  $info['wp-server']['fields']['httpd_software'] = array(
602
  'label' => __( 'Web server', 'health-check' ),
603
  'value' => ( isset( $_SERVER['SERVER_SOFTWARE'] ) ? $_SERVER['SERVER_SOFTWARE'] : __( 'Unable to determine what web server software is used', 'health-check' ) ),
@@ -681,8 +702,25 @@ class Health_Check_Debug_Data {
681
  'debug' => $imagick_loaded,
682
  );
683
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
684
  // Check if a .htaccess file exists.
685
- if ( is_file( ABSPATH . '.htaccess' ) ) {
686
  // If the file exists, grab the content of it.
687
  $htaccess_content = file_get_contents( ABSPATH . '.htaccess' );
688
 
@@ -709,22 +747,7 @@ class Health_Check_Debug_Data {
709
  $extension = null;
710
  }
711
 
712
- /*
713
- * Check what database engine is used, this will throw compatibility
714
- * warnings from PHP compatibility testers, but `mysql_*` is
715
- * still valid in PHP 5.6, so we need to account for that.
716
- */
717
- if ( method_exists( $wpdb, 'db_version' ) ) {
718
- if ( $wpdb->use_mysqli ) {
719
- // phpcs:ignore WordPress.DB.RestrictedFunctions.mysql_mysqli_get_server_info
720
- $server = mysqli_get_server_info( $wpdb->dbh );
721
- } else {
722
- // phpcs:ignore WordPress.DB.RestrictedFunctions.mysql_mysql_get_server_info
723
- $server = mysql_get_server_info( $wpdb->dbh );
724
- }
725
- } else {
726
- $server = null;
727
- }
728
 
729
  if ( isset( $wpdb->use_mysqli ) && $wpdb->use_mysqli ) {
730
  $client_version = $wpdb->dbh->client_info;
@@ -868,7 +891,7 @@ class Health_Check_Debug_Data {
868
  $active_theme = wp_get_theme();
869
  $theme_updates = get_theme_updates();
870
 
871
- // phpcs:ignore WordPress.NamingConventions.ValidVariableName.NotSnakeCaseMemberVar
872
  $active_theme_version = $active_theme->Version;
873
  $active_theme_version_debug = $active_theme_version;
874
 
@@ -885,8 +908,13 @@ class Health_Check_Debug_Data {
885
  $info['wp-active-theme']['fields'] = array(
886
  'name' => array(
887
  'label' => __( 'Name', 'health-check' ),
888
- // phpcs:ignore WordPress.NamingConventions.ValidVariableName.NotSnakeCaseMemberVar
889
- 'value' => $active_theme->Name,
 
 
 
 
 
890
  ),
891
  'version' => array(
892
  'label' => __( 'Version', 'health-check' ),
@@ -895,7 +923,7 @@ class Health_Check_Debug_Data {
895
  ),
896
  'author' => array(
897
  'label' => __( 'Author', 'health-check' ),
898
- // phpcs:ignore WordPress.NamingConventions.ValidVariableName.NotSnakeCaseMemberVar
899
  'value' => wp_kses( $active_theme->Author, array() ),
900
  ),
901
  'author_website' => array(
@@ -905,8 +933,8 @@ class Health_Check_Debug_Data {
905
  ),
906
  'parent_theme' => array(
907
  'label' => __( 'Parent theme', 'health-check' ),
908
- 'value' => ( $active_theme->parent_theme ? $active_theme->parent_theme : __( 'None', 'health-check' ) ),
909
- 'debug' => ( $active_theme->parent_theme ? $active_theme->parent_theme : 'none' ),
910
  ),
911
  'theme_features' => array(
912
  'label' => __( 'Theme features', 'health-check' ),
@@ -914,10 +942,60 @@ class Health_Check_Debug_Data {
914
  ),
915
  'theme_path' => array(
916
  'label' => __( 'Theme directory location', 'health-check' ),
917
- 'value' => get_template_directory(),
918
  ),
919
  );
920
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
921
  // Populate a list of all themes available in the install.
922
  $all_themes = wp_get_themes();
923
 
@@ -926,9 +1004,15 @@ class Health_Check_Debug_Data {
926
  if ( $active_theme->stylesheet === $theme_slug ) {
927
  continue;
928
  }
929
- // phpcs:ignore WordPress.NamingConventions.ValidVariableName.NotSnakeCaseMemberVar
 
 
 
 
 
 
930
  $theme_version = $theme->Version;
931
- // phpcs:ignore WordPress.NamingConventions.ValidVariableName.NotSnakeCaseMemberVar
932
  $theme_author = $theme->Author;
933
 
934
  // Sanitize
@@ -961,12 +1045,12 @@ class Health_Check_Debug_Data {
961
  $theme_version_string_debug .= sprintf( ' (latest version: %s)', $theme_updates[ $theme_slug ]->update['new_version'] );
962
  }
963
 
964
- // phpcs:ignore WordPress.NamingConventions.ValidVariableName.NotSnakeCaseMemberVar
965
- $info['wp-themes']['fields'][ sanitize_text_field( $theme->Name ) ] = array(
966
  'label' => sprintf(
967
  // translators: 1: Theme name. 2: Theme slug.
968
  __( '%1$s (%2$s)', 'health-check' ),
969
- // phpcs:ignore WordPress.NamingConventions.ValidVariableName.NotSnakeCaseMemberVar
970
  $theme->Name,
971
  $theme_slug
972
  ),
@@ -1126,7 +1210,7 @@ class Health_Check_Debug_Data {
1126
  public static function ajax_get_sizes() {
1127
  check_ajax_referer( 'health-check-site-status-result' );
1128
 
1129
- if ( ! current_user_can( 'install_plugins' ) || is_multisite() ) {
1130
  wp_send_json_error();
1131
  }
1132
 
43
  * @return array The debug data for the site.
44
  */
45
  static function debug_data() {
46
+ global $wpdb, $is_apache;
47
 
48
  // Save few function calls.
49
  $upload_dir = wp_get_upload_dir();
141
  'fields' => array(),
142
  );
143
 
144
+ $info['wp-parent-theme'] = array(
145
+ 'label' => __( 'Parent Theme', 'health-check' ),
146
+ 'fields' => array(),
147
+ );
148
+
149
+ $info['wp-themes-inactive'] = array(
150
+ 'label' => __( 'Inactive Themes', 'health-check' ),
151
  'show_count' => true,
152
  'fields' => array(),
153
  );
598
  $php_sapi = 'unknown';
599
  }
600
 
601
+ if ( function_exists( 'get_current_user' ) && function_exists( 'getmyuid' ) ) {
602
+ $php_getuid = sprintf(
603
+ '%s (%s)',
604
+ get_current_user(),
605
+ getmyuid()
606
+ );
607
+ } else {
608
+ $php_getuid = 'unknown';
609
+ }
610
+
611
  $info['wp-server']['fields']['server_architecture'] = array(
612
  'label' => __( 'Server architecture', 'health-check' ),
613
  'value' => ( 'unknown' !== $server_architecture ? $server_architecture : __( 'Unable to determine server architecture', 'health-check' ) ),
614
  'debug' => $server_architecture,
615
  );
616
+ $info['wp-server']['fields']['php-uid'] = array(
617
+ 'label' => __( 'Website server user', 'health-check' ),
618
+ 'value' => ( 'unknown' !== $php_getuid ? $php_getuid : __( 'Unable to determine the websites server user', 'health-check' ) ),
619
+ 'debug' => $php_getuid,
620
+ 'private' => true,
621
+ );
622
  $info['wp-server']['fields']['httpd_software'] = array(
623
  'label' => __( 'Web server', 'health-check' ),
624
  'value' => ( isset( $_SERVER['SERVER_SOFTWARE'] ) ? $_SERVER['SERVER_SOFTWARE'] : __( 'Unable to determine what web server software is used', 'health-check' ) ),
702
  'debug' => $imagick_loaded,
703
  );
704
 
705
+ $server_request = wp_remote_get( site_url(), compact( 'cookies', 'headers', 'timeout' ) );
706
+ if ( is_wp_error( $server_request ) ) {
707
+ $info['wp-server']['fields']['server-headers'] = array(
708
+ 'label' => __( 'Server headers', 'health-check' ),
709
+ 'value' => __( 'Could not retrieve server headers', 'health-check' ),
710
+ 'debug' => 'unknown',
711
+ );
712
+ } else {
713
+ $server_headers = wp_remote_retrieve_headers( $server_request );
714
+
715
+ $info['wp-server']['fields']['server-headers'] = array(
716
+ 'label' => __( 'Server headers', 'health-check' ),
717
+ 'value' => ( $server_headers instanceof \Requests_Utility_CaseInsensitiveDictionary ? $server_headers->getAll() : $server_headers ),
718
+ 'debug' => ( $server_headers instanceof \Requests_Utility_CaseInsensitiveDictionary ? $server_headers->getAll() : $server_headers ),
719
+ );
720
+ }
721
+
722
  // Check if a .htaccess file exists.
723
+ if ( $is_apache && is_file( ABSPATH . '.htaccess' ) ) {
724
  // If the file exists, grab the content of it.
725
  $htaccess_content = file_get_contents( ABSPATH . '.htaccess' );
726
 
747
  $extension = null;
748
  }
749
 
750
+ $server = $wpdb->db_version();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
751
 
752
  if ( isset( $wpdb->use_mysqli ) && $wpdb->use_mysqli ) {
753
  $client_version = $wpdb->dbh->client_info;
891
  $active_theme = wp_get_theme();
892
  $theme_updates = get_theme_updates();
893
 
894
+ // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
895
  $active_theme_version = $active_theme->Version;
896
  $active_theme_version_debug = $active_theme_version;
897
 
908
  $info['wp-active-theme']['fields'] = array(
909
  'name' => array(
910
  'label' => __( 'Name', 'health-check' ),
911
+ 'value' => sprintf(
912
+ // translators: 1: Parent theme name. 2: Parent theme slug.
913
+ __( '%1$s (%2$s)', 'health-check' ),
914
+ // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
915
+ $active_theme->Name,
916
+ $active_theme->stylesheet
917
+ ),
918
  ),
919
  'version' => array(
920
  'label' => __( 'Version', 'health-check' ),
923
  ),
924
  'author' => array(
925
  'label' => __( 'Author', 'health-check' ),
926
+ // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
927
  'value' => wp_kses( $active_theme->Author, array() ),
928
  ),
929
  'author_website' => array(
933
  ),
934
  'parent_theme' => array(
935
  'label' => __( 'Parent theme', 'health-check' ),
936
+ 'value' => ( $active_theme->parent_theme ? $active_theme->parent_theme . ' (' . $active_theme->template . ')' : __( 'None', 'health-check' ) ),
937
+ 'debug' => ( $active_theme->parent_theme ? $active_theme->parent_theme . ' (' . $active_theme->template . ')' : 'none' ),
938
  ),
939
  'theme_features' => array(
940
  'label' => __( 'Theme features', 'health-check' ),
942
  ),
943
  'theme_path' => array(
944
  'label' => __( 'Theme directory location', 'health-check' ),
945
+ 'value' => get_stylesheet_directory(),
946
  ),
947
  );
948
 
949
+ $parent_theme = $active_theme->parent();
950
+
951
+ if ( $parent_theme ) {
952
+ // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
953
+ $parent_theme_version = $parent_theme->Version;
954
+ $parent_theme_version_debug = $parent_theme_version;
955
+
956
+ if ( array_key_exists( $parent_theme->stylesheet, $theme_updates ) ) {
957
+ $parent_theme_update_new_version = $theme_updates[ $parent_theme->stylesheet ]->update['new_version'];
958
+
959
+ // translators: %s: Latest theme version number.
960
+ $parent_theme_version .= ' ' . sprintf( __( '(Latest version: %s)', 'health-check' ), $parent_theme_update_new_version );
961
+ $parent_theme_version_debug .= sprintf( ' (latest version: %s)', $parent_theme_update_new_version );
962
+ }
963
+
964
+ $parent_theme_author_uri = $parent_theme->offsetGet( 'Author URI' );
965
+
966
+ $info['wp-parent-theme']['fields'] = array(
967
+ 'name' => array(
968
+ 'label' => __( 'Name', 'health-check' ),
969
+ 'value' => sprintf(
970
+ // translators: 1: Parent theme name. 2: Parent theme slug.
971
+ __( '%1$s (%2$s)', 'health-check' ),
972
+ // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
973
+ $parent_theme->Name,
974
+ $parent_theme->stylesheet
975
+ ),
976
+ ),
977
+ 'version' => array(
978
+ 'label' => __( 'Version', 'health-check' ),
979
+ 'value' => $parent_theme_version,
980
+ 'debug' => $parent_theme_version_debug,
981
+ ),
982
+ 'author' => array(
983
+ 'label' => __( 'Author', 'health-check' ),
984
+ // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
985
+ 'value' => wp_kses( $parent_theme->Author, array() ),
986
+ ),
987
+ 'author_website' => array(
988
+ 'label' => __( 'Author website', 'health-check' ),
989
+ 'value' => ( $parent_theme_author_uri ? $parent_theme_author_uri : __( 'Undefined', 'health-check' ) ),
990
+ 'debug' => ( $parent_theme_author_uri ? $parent_theme_author_uri : '(undefined)' ),
991
+ ),
992
+ 'theme_path' => array(
993
+ 'label' => __( 'Theme directory location', 'health-check' ),
994
+ 'value' => get_template_directory(),
995
+ ),
996
+ );
997
+ }
998
+
999
  // Populate a list of all themes available in the install.
1000
  $all_themes = wp_get_themes();
1001
 
1004
  if ( $active_theme->stylesheet === $theme_slug ) {
1005
  continue;
1006
  }
1007
+
1008
+ // Ignore the currently active parent theme from the list of all themes.
1009
+ if ( ! empty( $parent_theme ) && $parent_theme->stylesheet === $theme_slug ) {
1010
+ continue;
1011
+ }
1012
+
1013
+ // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
1014
  $theme_version = $theme->Version;
1015
+ // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
1016
  $theme_author = $theme->Author;
1017
 
1018
  // Sanitize
1045
  $theme_version_string_debug .= sprintf( ' (latest version: %s)', $theme_updates[ $theme_slug ]->update['new_version'] );
1046
  }
1047
 
1048
+ // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
1049
+ $info['wp-themes-inactive']['fields'][ sanitize_text_field( $theme->Name ) ] = array(
1050
  'label' => sprintf(
1051
  // translators: 1: Theme name. 2: Theme slug.
1052
  __( '%1$s (%2$s)', 'health-check' ),
1053
+ // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
1054
  $theme->Name,
1055
  $theme_slug
1056
  ),
1210
  public static function ajax_get_sizes() {
1211
  check_ajax_referer( 'health-check-site-status-result' );
1212
 
1213
+ if ( ! current_user_can( 'view_site_health_checks' ) || is_multisite() ) {
1214
  wp_send_json_error();
1215
  }
1216
 
includes/class-health-check-loopback.php CHANGED
@@ -49,9 +49,12 @@ class Health_Check_Loopback {
49
  $url = admin_url();
50
 
51
  if ( ! empty( $disable_plugin_hash ) ) {
52
- $url = add_query_arg( array(
53
- 'health-check-disable-plugin-hash' => $disable_plugin_hash,
54
- ), $url );
 
 
 
55
  }
56
  if ( ! empty( $allowed_plugins ) ) {
57
  if ( ! is_array( $allowed_plugins ) ) {
@@ -126,7 +129,7 @@ class Health_Check_Loopback {
126
  static function loopback_no_plugins() {
127
  check_ajax_referer( 'health-check-loopback-no-plugins' );
128
 
129
- if ( ! current_user_can( 'install_plugins' ) ) {
130
  wp_send_json_error();
131
  }
132
 
@@ -241,7 +244,7 @@ class Health_Check_Loopback {
241
  static function loopback_test_individual_plugins() {
242
  check_ajax_referer( 'health-check-loopback-individual-plugins' );
243
 
244
- if ( ! current_user_can( 'install_plugins' ) ) {
245
  wp_send_json_error();
246
  }
247
 
@@ -292,7 +295,7 @@ class Health_Check_Loopback {
292
  static function loopback_test_default_theme() {
293
  check_ajax_referer( 'health-check-loopback-default-theme' );
294
 
295
- if ( ! current_user_can( 'install_plugins' ) ) {
296
  wp_send_json_error();
297
  }
298
 
49
  $url = admin_url();
50
 
51
  if ( ! empty( $disable_plugin_hash ) ) {
52
+ $url = add_query_arg(
53
+ array(
54
+ 'health-check-disable-plugin-hash' => $disable_plugin_hash,
55
+ ),
56
+ $url
57
+ );
58
  }
59
  if ( ! empty( $allowed_plugins ) ) {
60
  if ( ! is_array( $allowed_plugins ) ) {
129
  static function loopback_no_plugins() {
130
  check_ajax_referer( 'health-check-loopback-no-plugins' );
131
 
132
+ if ( ! current_user_can( 'view_site_health_checks' ) ) {
133
  wp_send_json_error();
134
  }
135
 
244
  static function loopback_test_individual_plugins() {
245
  check_ajax_referer( 'health-check-loopback-individual-plugins' );
246
 
247
+ if ( ! current_user_can( 'view_site_health_checks' ) ) {
248
  wp_send_json_error();
249
  }
250
 
295
  static function loopback_test_default_theme() {
296
  check_ajax_referer( 'health-check-loopback-default-theme' );
297
 
298
+ if ( ! current_user_can( 'view_site_health_checks' ) ) {
299
  wp_send_json_error();
300
  }
301
 
includes/class-health-check-site-status.php CHANGED
@@ -52,7 +52,7 @@ class Health_Check_Site_Status {
52
  $mysql_server_type = mysql_get_server_info( $wpdb->dbh );
53
  }
54
 
55
- $this->mysql_server_version = $wpdb->get_var( 'SELECT VERSION()' );
56
  }
57
 
58
  $this->health_check_mysql_rec_version = '5.6';
@@ -90,7 +90,7 @@ class Health_Check_Site_Status {
90
  public function site_status_result() {
91
  check_ajax_referer( 'health-check-site-status-result' );
92
 
93
- if ( ! current_user_can( 'install_plugins' ) ) {
94
  wp_send_json_error();
95
  }
96
 
@@ -100,7 +100,7 @@ class Health_Check_Site_Status {
100
  public function site_status() {
101
  check_ajax_referer( 'health-check-site-status' );
102
 
103
- if ( ! current_user_can( 'install_plugins' ) ) {
104
  wp_send_json_error();
105
  }
106
 
@@ -626,93 +626,6 @@ class Health_Check_Site_Status {
626
  return $result;
627
  }
628
 
629
- /**
630
- * Fallback function replicating core behavior from WordPress 5.1 to check PHP versions.
631
- *
632
- * @return array|bool|mixed|object|WP_Error
633
- */
634
- private function wp_check_php_version() {
635
- $version = phpversion();
636
- $key = md5( $version );
637
-
638
- $response = get_site_transient( 'php_check_' . $key );
639
- if ( false === $response ) {
640
- $url = 'http://api.wordpress.org/core/serve-happy/1.0/';
641
- if ( wp_http_supports( array( 'ssl' ) ) ) {
642
- $url = set_url_scheme( $url, 'https' );
643
- }
644
-
645
- $url = add_query_arg( 'php_version', $version, $url );
646
-
647
- $response = wp_remote_get( $url );
648
-
649
- if ( is_wp_error( $response ) || 200 !== wp_remote_retrieve_response_code( $response ) ) {
650
- return false;
651
- }
652
-
653
- /**
654
- * Response should be an array with:
655
- * 'recommended_version' - string - The PHP version recommended by WordPress.
656
- * 'is_supported' - boolean - Whether the PHP version is actively supported.
657
- * 'is_secure' - boolean - Whether the PHP version receives security updates.
658
- * 'is_acceptable' - boolean - Whether the PHP version is still acceptable for WordPress.
659
- */
660
- $response = json_decode( wp_remote_retrieve_body( $response ), true );
661
-
662
- if ( ! is_array( $response ) ) {
663
- return false;
664
- }
665
-
666
- set_site_transient( 'php_check_' . $key, $response, WEEK_IN_SECONDS );
667
- }
668
-
669
- if ( isset( $response['is_acceptable'] ) && $response['is_acceptable'] ) {
670
- /**
671
- * Filters whether the active PHP version is considered acceptable by WordPress.
672
- *
673
- * Returning false will trigger a PHP version warning to show up in the admin dashboard to administrators.
674
- *
675
- * This filter is only run if the wordpress.org Serve Happy API considers the PHP version acceptable, ensuring
676
- * that this filter can only make this check stricter, but not loosen it.
677
- *
678
- * @since 5.1.1
679
- *
680
- * @param bool $is_acceptable Whether the PHP version is considered acceptable. Default true.
681
- * @param string $version PHP version checked.
682
- */
683
- $response['is_acceptable'] = (bool) apply_filters( 'wp_is_php_version_acceptable', true, $version );
684
- }
685
-
686
- return $response;
687
- }
688
-
689
- private function wp_get_update_php_url() {
690
- $default_url = _x( 'https://wordpress.org/support/update-php/', 'localized PHP upgrade information page', 'health-check' );
691
-
692
- $update_url = $default_url;
693
- if ( false !== getenv( 'WP_UPDATE_PHP_URL' ) ) {
694
- $update_url = getenv( 'WP_UPDATE_PHP_URL' );
695
- }
696
-
697
- /**
698
- * Filters the URL to learn more about updating the PHP version the site is running on.
699
- *
700
- * Providing an empty string is not allowed and will result in the default URL being used. Furthermore
701
- * the page the URL links to should preferably be localized in the site language.
702
- *
703
- * @since 5.1.0
704
- *
705
- * @param string $update_url URL to learn more about updating PHP.
706
- */
707
- $update_url = apply_filters( 'wp_update_php_url', $update_url );
708
-
709
- if ( empty( $update_url ) ) {
710
- $update_url = $default_url;
711
- }
712
-
713
- return $update_url;
714
- }
715
-
716
  /**
717
  * Test if the supplied PHP version is supported.
718
  *
@@ -721,11 +634,7 @@ class Health_Check_Site_Status {
721
  * @return array The test results.
722
  */
723
  public function get_test_php_version() {
724
- if ( ! function_exists( 'wp_check_php_version' ) ) {
725
- $response = $this->wp_check_php_version();
726
- } else {
727
- $response = wp_check_php_version();
728
- }
729
 
730
  $result = array(
731
  'label' => sprintf(
@@ -744,7 +653,7 @@ class Health_Check_Site_Status {
744
  ),
745
  'actions' => sprintf(
746
  '<p><a href="%s" target="_blank" rel="noopener noreferrer">%s <span class="screen-reader-text">%s</span><span aria-hidden="true" class="dashicons dashicons-external"></span></a></p>',
747
- esc_url( ( function_exists( 'wp_get_update_php_url' ) ? wp_get_update_php_url() : $this->wp_get_update_php_url() ) ),
748
  __( 'Learn more about updating PHP', 'health-check' ),
749
  /* translators: accessibility text */
750
  __( '(opens in a new tab)', 'health-check' )
@@ -790,12 +699,13 @@ class Health_Check_Site_Status {
790
  *
791
  * @param string $extension Optional. The extension name to test. Default null.
792
  * @param string $function Optional. The function name to test. Default null.
 
793
  *
794
  * @return bool Whether or not the extension and function are available.
795
  */
796
- private function test_php_extension_availability( $extension = null, $function = null ) {
797
  // If no extension or function is passed, claim to fail testing, as we have nothing to test against.
798
- if ( ! $extension && ! $function ) {
799
  return false;
800
  }
801
 
@@ -805,6 +715,9 @@ class Health_Check_Site_Status {
805
  if ( $function && ! function_exists( $function ) ) {
806
  return false;
807
  }
 
 
 
808
 
809
  return true;
810
  }
@@ -877,7 +790,7 @@ class Health_Check_Site_Status {
877
  'required' => false,
878
  ),
879
  'libsodium' => array(
880
- 'function' => 'sodium_compare',
881
  'required' => false,
882
  'php_bundled_version' => '7.2.0',
883
  ),
@@ -913,6 +826,14 @@ class Health_Check_Site_Status {
913
  'required' => false,
914
  'fallback_for' => 'zip',
915
  ),
 
 
 
 
 
 
 
 
916
  );
917
 
918
  /**
@@ -929,6 +850,7 @@ class Health_Check_Site_Status {
929
  *
930
  * string $function Optional. A function name to test for the existence of.
931
  * string $extension Optional. An extension to check if is loaded in PHP.
 
932
  * bool $required Is this a required feature or not.
933
  * string $fallback_for Optional. The module this module replaces as a fallback.
934
  * }
@@ -941,6 +863,7 @@ class Health_Check_Site_Status {
941
  foreach ( $modules as $library => $module ) {
942
  $extension = ( isset( $module['extension'] ) ? $module['extension'] : null );
943
  $function = ( isset( $module['function'] ) ? $module['function'] : null );
 
944
 
945
  // If this module is a fallback for another function, check if that other function passed.
946
  if ( isset( $module['fallback_for'] ) ) {
@@ -955,7 +878,7 @@ class Health_Check_Site_Status {
955
  }
956
  }
957
 
958
- if ( ! $this->test_php_extension_availability( $extension, $function ) && ( ! isset( $module['php_bundled_version'] ) || version_compare( PHP_VERSION, $module['php_bundled_version'], '<' ) ) ) {
959
  if ( $module['required'] ) {
960
  $result['status'] = 'critical';
961
 
@@ -1283,6 +1206,48 @@ class Health_Check_Site_Status {
1283
  wp_send_json_success( $this->get_test_dotorg_communication() );
1284
  }
1285
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1286
  /**
1287
  * Test if debug information is enabled.
1288
  *
@@ -1509,21 +1474,32 @@ class Health_Check_Site_Status {
1509
  $schedule->has_missed_cron()->get_error_message()
1510
  )
1511
  );
1512
- } else {
1513
- if ( $schedule->has_missed_cron() ) {
1514
- $result['status'] = 'recommended';
1515
 
1516
- $result['label'] = __( 'A scheduled event has failed', 'health-check' );
1517
 
1518
- $result['description'] = sprintf(
1519
- '<p>%s</p>',
1520
- sprintf(
1521
- /* translators: %s: The name of the failed cron event. */
1522
- __( 'The scheduled event, %s, failed to run. Your site still works, but this may indicate that scheduling posts or automated updates may not work as intended.', 'health-check' ),
1523
- $schedule->last_missed_cron
1524
- )
1525
- );
1526
- }
 
 
 
 
 
 
 
 
 
 
 
 
1527
  }
1528
 
1529
  return $result;
@@ -1952,6 +1928,10 @@ class Health_Check_Site_Status {
1952
  'label' => __( 'Debugging enabled', 'health-check' ),
1953
  'test' => array( $health_check_site_status, 'get_test_is_in_debug_mode' ),
1954
  ),
 
 
 
 
1955
  ),
1956
  'async' => array(
1957
  'dotorg_communication' => array(
52
  $mysql_server_type = mysql_get_server_info( $wpdb->dbh );
53
  }
54
 
55
+ $this->mysql_server_version = $wpdb->db_version();
56
  }
57
 
58
  $this->health_check_mysql_rec_version = '5.6';
90
  public function site_status_result() {
91
  check_ajax_referer( 'health-check-site-status-result' );
92
 
93
+ if ( ! current_user_can( 'view_site_health_checks' ) ) {
94
  wp_send_json_error();
95
  }
96
 
100
  public function site_status() {
101
  check_ajax_referer( 'health-check-site-status' );
102
 
103
+ if ( ! current_user_can( 'view_site_health_checks' ) ) {
104
  wp_send_json_error();
105
  }
106
 
626
  return $result;
627
  }
628
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
629
  /**
630
  * Test if the supplied PHP version is supported.
631
  *
634
  * @return array The test results.
635
  */
636
  public function get_test_php_version() {
637
+ $response = wp_check_php_version();
 
 
 
 
638
 
639
  $result = array(
640
  'label' => sprintf(
653
  ),
654
  'actions' => sprintf(
655
  '<p><a href="%s" target="_blank" rel="noopener noreferrer">%s <span class="screen-reader-text">%s</span><span aria-hidden="true" class="dashicons dashicons-external"></span></a></p>',
656
+ esc_url( wp_get_update_php_url() ),
657
  __( 'Learn more about updating PHP', 'health-check' ),
658
  /* translators: accessibility text */
659
  __( '(opens in a new tab)', 'health-check' )
699
  *
700
  * @param string $extension Optional. The extension name to test. Default null.
701
  * @param string $function Optional. The function name to test. Default null.
702
+ * @param string $constant Optional. The constant to text for. Default null.
703
  *
704
  * @return bool Whether or not the extension and function are available.
705
  */
706
+ private function test_php_extension_availability( $extension = null, $function = null, $constant = null ) {
707
  // If no extension or function is passed, claim to fail testing, as we have nothing to test against.
708
+ if ( ! $extension && ! $function && ! $constant ) {
709
  return false;
710
  }
711
 
715
  if ( $function && ! function_exists( $function ) ) {
716
  return false;
717
  }
718
+ if ( $constant && ! defined( $constant ) ) {
719
+ return false;
720
+ }
721
 
722
  return true;
723
  }
790
  'required' => false,
791
  ),
792
  'libsodium' => array(
793
+ 'constant' => 'SODIUM_LIBRARY_VERSION',
794
  'required' => false,
795
  'php_bundled_version' => '7.2.0',
796
  ),
826
  'required' => false,
827
  'fallback_for' => 'zip',
828
  ),
829
+ 'mbstring' => array(
830
+ 'extension' => 'mbstring',
831
+ 'required' => true,
832
+ ),
833
+ 'json' => array(
834
+ 'extension' => 'json',
835
+ 'required' => true,
836
+ ),
837
  );
838
 
839
  /**
850
  *
851
  * string $function Optional. A function name to test for the existence of.
852
  * string $extension Optional. An extension to check if is loaded in PHP.
853
+ * string $constant Optional. A constant to check for to verify an extension exists.
854
  * bool $required Is this a required feature or not.
855
  * string $fallback_for Optional. The module this module replaces as a fallback.
856
  * }
863
  foreach ( $modules as $library => $module ) {
864
  $extension = ( isset( $module['extension'] ) ? $module['extension'] : null );
865
  $function = ( isset( $module['function'] ) ? $module['function'] : null );
866
+ $constant = ( isset( $module['constant'] ) ? $module['constant'] : null );
867
 
868
  // If this module is a fallback for another function, check if that other function passed.
869
  if ( isset( $module['fallback_for'] ) ) {
878
  }
879
  }
880
 
881
+ if ( ! $this->test_php_extension_availability( $extension, $function, $constant ) && ( ! isset( $module['php_bundled_version'] ) || version_compare( PHP_VERSION, $module['php_bundled_version'], '<' ) ) ) {
882
  if ( $module['required'] ) {
883
  $result['status'] = 'critical';
884
 
1206
  wp_send_json_success( $this->get_test_dotorg_communication() );
1207
  }
1208
 
1209
+ /**
1210
+ * Test if the site is using timezones relative to their location, or by using an offset value.
1211
+ *
1212
+ * Daylight Savings Time (DST) may affect the times used and shown by your site, and using an UTC offset,
1213
+ * instead of a localized timezone, means that the site does not get automatic DST updates.
1214
+ *
1215
+ * This check looks for default or UTC values and recommends changing to a fixed location.
1216
+ *
1217
+ * @return array The test results.
1218
+ */
1219
+ public function get_test_timezone_not_utc() {
1220
+ $result = array(
1221
+ 'label' => __( 'Your site uses localized timezones', 'health-check' ),
1222
+ 'status' => 'good',
1223
+ 'badge' => array(
1224
+ 'label' => __( 'Performance', 'health-check' ),
1225
+ 'color' => 'blue',
1226
+ ),
1227
+ 'description' => sprintf(
1228
+ '<p>%s</p>',
1229
+ __( 'Daylight Savings Time (DST) may affect the times used and shown by your site, and using an UTC offset, instead of a localized timezone, means that the site does not get automatic DST updates.', 'health-check' )
1230
+ ),
1231
+ 'actions' => '',
1232
+ 'test' => 'timezone_not_utc',
1233
+ );
1234
+
1235
+ $timezone = get_option( 'timezone_string', null );
1236
+
1237
+ if ( empty( $timezone ) || 'UTC' === substr( $timezone, 0, 3 ) ) {
1238
+ $result['status'] = 'recommended';
1239
+ $result['label'] = __( 'Your site is not using localized timezones', 'health-check' );
1240
+
1241
+ $result['actions'] .= sprintf(
1242
+ '<p><a href="%s">%s</a></p>',
1243
+ esc_url( admin_url( 'options-general.php' ) ),
1244
+ __( 'Update your site timezone', 'health-check' )
1245
+ );
1246
+ }
1247
+
1248
+ return $result;
1249
+ }
1250
+
1251
  /**
1252
  * Test if debug information is enabled.
1253
  *
1474
  $schedule->has_missed_cron()->get_error_message()
1475
  )
1476
  );
1477
+ } elseif ( $schedule->has_missed_cron() ) {
1478
+ $result['status'] = 'recommended';
 
1479
 
1480
+ $result['label'] = __( 'A scheduled event has failed', 'health-check' );
1481
 
1482
+ $result['description'] = sprintf(
1483
+ '<p>%s</p>',
1484
+ sprintf(
1485
+ /* translators: %s: The name of the failed cron event. */
1486
+ __( 'The scheduled event, %s, failed to run. Your site still works, but this may indicate that scheduling posts or automated updates may not work as intended.', 'health-check' ),
1487
+ $schedule->last_missed_cron
1488
+ )
1489
+ );
1490
+ } elseif ( $schedule->has_late_cron() ) {
1491
+ $result['status'] = 'recommended';
1492
+
1493
+ $result['label'] = __( 'A scheduled event is late', 'health-check' );
1494
+
1495
+ $result['description'] = sprintf(
1496
+ '<p>%s</p>',
1497
+ sprintf(
1498
+ /* translators: %s: The name of the late cron event. */
1499
+ __( 'The scheduled event, %s, is late to run. Your site still works, but this may indicate that scheduling posts or automated updates may not work as intended.', 'health-check' ),
1500
+ $schedule->last_late_cron
1501
+ )
1502
+ );
1503
  }
1504
 
1505
  return $result;
1928
  'label' => __( 'Debugging enabled', 'health-check' ),
1929
  'test' => array( $health_check_site_status, 'get_test_is_in_debug_mode' ),
1930
  ),
1931
+ 'timezones' => array(
1932
+ 'label' => __( 'Timezone', 'health-check' ),
1933
+ 'test' => array( $health_check_site_status, 'get_test_timezone_not_utc' ),
1934
+ ),
1935
  ),
1936
  'async' => array(
1937
  'dotorg_communication' => array(
includes/class-health-check-wp-cli.php CHANGED
@@ -15,7 +15,7 @@ if ( ! defined( 'ABSPATH' ) ) {
15
  /**
16
  * Class Health_Check_WP_CLI
17
  */
18
- class Health_Check_WP_CLI extends WP_CLI_Command {
19
  /**
20
  * See the sites status based on best practices and WordPress recommendations.
21
  *
@@ -40,29 +40,36 @@ class Health_Check_WP_CLI extends WP_CLI_Command {
40
  global $health_check_site_status;
41
 
42
  $all_tests = $health_check_site_status::get_tests();
43
- $all_tests = array_merge( $all_tests['direct'], $all_tests['async'] );
44
 
45
  $test_result = array();
46
 
47
- foreach ( $all_tests as $test ) {
48
- ob_start();
49
- call_user_func( array( $health_check_site_status, 'test_' . $test['test'] ) );
50
- $test_output = ob_get_clean();
51
 
52
  $test_result[] = array(
53
  'test' => $test['label'],
54
- 'result' => wp_kses( $test_output, array() ),
 
 
 
 
 
 
 
 
 
 
55
  );
56
  }
57
 
58
  if ( WP_CLI\Utils\get_flag_value( $assoc_args, 'format' ) === 'json' ) {
59
- WP_CLI\Utils\format_items( 'json', $test_result, array( 'test', 'result' ) );
60
  } elseif ( WP_CLI\Utils\get_flag_value( $assoc_args, 'format' ) === 'csv' ) {
61
- WP_CLI\Utils\format_items( 'csv', $test_result, array( 'test', 'result' ) );
62
  } elseif ( WP_CLI\Utils\get_flag_value( $assoc_args, 'format' ) === 'yaml' ) {
63
- WP_CLI\Utils\format_items( 'yaml', $test_result, array( 'test', 'result' ) );
64
  } else {
65
- WP_CLI\Utils\format_items( 'table', $test_result, array( 'test', 'result' ) );
66
  }
67
  }
68
  }
15
  /**
16
  * Class Health_Check_WP_CLI
17
  */
18
+ class Health_Check_WP_CLI {
19
  /**
20
  * See the sites status based on best practices and WordPress recommendations.
21
  *
40
  global $health_check_site_status;
41
 
42
  $all_tests = $health_check_site_status::get_tests();
 
43
 
44
  $test_result = array();
45
 
46
+ foreach ( $all_tests['direct'] as $test ) {
47
+ $test_output = call_user_func( $test['test'] );
 
 
48
 
49
  $test_result[] = array(
50
  'test' => $test['label'],
51
+ 'type' => wp_kses( $test_output['badge']['label'], array() ),
52
+ 'result' => wp_kses( $test_output['status'], array() ),
53
+ );
54
+ }
55
+ foreach ( $all_tests['async'] as $test ) {
56
+ $test_output = call_user_func( array( $health_check_site_status, 'get_test_' . $test['test'] ) );
57
+
58
+ $test_result[] = array(
59
+ 'test' => $test['label'],
60
+ 'type' => wp_kses( $test_output['badge']['label'], array() ),
61
+ 'result' => wp_kses( $test_output['status'], array() ),
62
  );
63
  }
64
 
65
  if ( WP_CLI\Utils\get_flag_value( $assoc_args, 'format' ) === 'json' ) {
66
+ WP_CLI\Utils\format_items( 'json', $test_result, array( 'test', 'type', 'result' ) );
67
  } elseif ( WP_CLI\Utils\get_flag_value( $assoc_args, 'format' ) === 'csv' ) {
68
+ WP_CLI\Utils\format_items( 'csv', $test_result, array( 'test', 'type', 'result' ) );
69
  } elseif ( WP_CLI\Utils\get_flag_value( $assoc_args, 'format' ) === 'yaml' ) {
70
+ WP_CLI\Utils\format_items( 'yaml', $test_result, array( 'test', 'type', 'result' ) );
71
  } else {
72
+ WP_CLI\Utils\format_items( 'table', $test_result, array( 'test', 'type', 'result' ) );
73
  }
74
  }
75
  }
includes/class-health-check-wp-cron.php CHANGED
@@ -16,13 +16,24 @@ if ( ! defined( 'ABSPATH' ) ) {
16
  class Health_Check_WP_Cron {
17
  public $schedules;
18
  public $crons;
19
- public $last_missed_cron = null;
 
 
 
20
 
21
  /**
22
  * Health_Check_WP_Cron constructor.
23
  */
24
  public function __construct() {
25
  $this->init();
 
 
 
 
 
 
 
 
26
  }
27
 
28
  /**
@@ -94,7 +105,7 @@ class Health_Check_WP_Cron {
94
  }
95
 
96
  foreach ( $this->crons as $id => $cron ) {
97
- if ( ( $cron->time - time() ) < 0 ) {
98
  $this->last_missed_cron = $cron->hook;
99
  return true;
100
  }
@@ -102,4 +113,31 @@ class Health_Check_WP_Cron {
102
 
103
  return false;
104
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
105
  }
16
  class Health_Check_WP_Cron {
17
  public $schedules;
18
  public $crons;
19
+ public $last_missed_cron = null;
20
+ public $last_late_cron = null;
21
+ private $timeout_missed_cron = null;
22
+ private $timeout_late_cron = null;
23
 
24
  /**
25
  * Health_Check_WP_Cron constructor.
26
  */
27
  public function __construct() {
28
  $this->init();
29
+
30
+ $this->timeout_late_cron = 0;
31
+ $this->timeout_missed_cron = - 5 * MINUTE_IN_SECONDS;
32
+
33
+ if ( defined( 'DISABLE_WP_CRON' ) && DISABLE_WP_CRON ) {
34
+ $this->timeout_late_cron = - 15 * MINUTE_IN_SECONDS;
35
+ $this->timeout_missed_cron = - 1 * HOUR_IN_SECONDS;
36
+ }
37
  }
38
 
39
  /**
105
  }
106
 
107
  foreach ( $this->crons as $id => $cron ) {
108
+ if ( ( $cron->time - time() ) < $this->timeout_missed_cron ) {
109
  $this->last_missed_cron = $cron->hook;
110
  return true;
111
  }
113
 
114
  return false;
115
  }
116
+
117
+ /**
118
+ * Check if any scheduled tasks are late.
119
+ *
120
+ * Returns a boolean value of `true` if a scheduled task is late and ends processing. If the list of
121
+ * crons is an instance of WP_Error, return the instance instead of a boolean value.
122
+ *
123
+ * @return bool|WP_Error true if a cron is late, false if it wasn't. WP_Error if the cron is set to that.
124
+ */
125
+ public function has_late_cron() {
126
+ if ( is_wp_error( $this->crons ) ) {
127
+ return $this->crons;
128
+ }
129
+
130
+ foreach ( $this->crons as $id => $cron ) {
131
+ $cron_offset = $cron->time - time();
132
+ if (
133
+ $cron_offset >= $this->timeout_missed_cron &&
134
+ $cron_offset < $this->timeout_late_cron
135
+ ) {
136
+ $this->last_late_cron = $cron->hook;
137
+ return true;
138
+ }
139
+ }
140
+
141
+ return false;
142
+ }
143
  }
includes/class-health-check.php CHANGED
@@ -50,9 +50,8 @@ class Health_Check {
50
 
51
  add_action( 'admin_menu', array( $this, 'action_admin_menu' ) );
52
 
53
- add_filter( 'plugin_row_meta', array( $this, 'settings_link' ), 10, 2 );
54
-
55
  add_filter( 'plugin_action_links', array( $this, 'troubleshoot_plugin_action' ), 20, 4 );
 
56
 
57
  add_action( 'admin_notices', array( $this, 'admin_notices' ) );
58
 
@@ -64,15 +63,36 @@ class Health_Check {
64
  add_action( 'wp_ajax_health-check-loopback-no-plugins', array( 'Health_Check_Loopback', 'loopback_no_plugins' ) );
65
  add_action( 'wp_ajax_health-check-loopback-individual-plugins', array( 'Health_Check_Loopback', 'loopback_test_individual_plugins' ) );
66
  add_action( 'wp_ajax_health-check-loopback-default-theme', array( 'Health_Check_Loopback', 'loopback_test_default_theme' ) );
67
- add_action( 'wp_ajax_health-check-files-integrity-check', array( 'Health_Check_Files_Integrity', 'run_files_integrity_check' ) );
68
- add_action( 'wp_ajax_health-check-view-file-diff', array( 'Health_Check_Files_Integrity', 'view_file_diff' ) );
69
- add_action( 'wp_ajax_health-check-mail-check', array( 'Health_Check_Mail_Check', 'run_mail_check' ) );
70
  add_action( 'wp_ajax_health-check-get-sizes', array( 'Health_Check_Debug_Data', 'ajax_get_sizes' ) );
71
 
72
- add_filter( 'health_check_tools_tab', array( 'Health_Check_Files_Integrity', 'tools_tab' ) );
73
- add_filter( 'health_check_tools_tab', array( 'Health_Check_Mail_Check', 'tools_tab' ) );
74
-
75
  add_filter( 'cron_schedules', array( $this, 'cron_schedules' ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
76
  }
77
 
78
  /**
@@ -86,7 +106,7 @@ class Health_Check {
86
  * @return void
87
  */
88
  public function start_troubleshoot_mode() {
89
- if ( ! isset( $_POST['health-check-troubleshoot-mode'] ) || ! current_user_can( 'install_plugins' ) ) {
90
  return;
91
  }
92
 
@@ -118,7 +138,7 @@ class Health_Check {
118
  * @return void
119
  */
120
  public function start_troubleshoot_single_plugin_mode() {
121
- if ( ! isset( $_GET['health-check-troubleshoot-plugin'] ) || ! current_user_can( 'install_plugins' ) ) {
122
  return;
123
  }
124
 
@@ -156,9 +176,11 @@ class Health_Check {
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
  }
@@ -192,8 +214,10 @@ class Health_Check {
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
  return;
198
  }
199
 
@@ -203,10 +227,10 @@ class Health_Check {
203
  'copied' => esc_html__( 'Copied', 'health-check' ),
204
  'running_tests' => esc_html__( 'Currently being tested...', 'health-check' ),
205
  'site_health_complete' => esc_html__( 'All site health tests have finished running.', 'health-check' ),
206
- 'site_info_show_copy' => esc_html__( 'Show options for copying this information', 'health-check' ),
207
- 'site_info_hide_copy' => esc_html__( 'Hide options for copying this information', 'health-check' ),
208
- // translators: %s: The percentage pass rate for the tests.
209
- 'site_health_complete_screen_reader' => esc_html__( 'All site health tests have finished running. Your site passed %s, and the results are now available on the page.', 'health-check' ),
210
  'site_info_copied' => esc_html__( 'Site information has been added to your clipboard.', 'health-check' ),
211
  // translators: %s: Amount of critical issues.
212
  'site_info_heading_critical_single' => esc_html__( '%s Critical issue', 'health-check' ),
@@ -230,6 +254,7 @@ class Health_Check {
230
  'mail_check' => wp_create_nonce( 'health-check-mail-check' ),
231
  'site_status' => wp_create_nonce( 'health-check-site-status' ),
232
  'site_status_result' => wp_create_nonce( 'health-check-site-status-result' ),
 
233
  ),
234
  'site_status' => array(
235
  'direct' => array(),
@@ -250,7 +275,7 @@ class Health_Check {
250
  $health_check_js_variables['site_status']['issues'] = $issue_counts;
251
  }
252
 
253
- if ( ! isset( $_GET['tab'] ) || ( isset( $_GET['tab'] ) && 'site-status' === $_GET['tab'] ) ) {
254
  $tests = Health_Check_Site_Status::get_tests();
255
 
256
  // Don't run https test on localhost
@@ -266,13 +291,34 @@ class Health_Check {
266
  );
267
 
268
  if ( method_exists( $this, $test_function ) && is_callable( array( $this, $test_function ) ) ) {
269
- $health_check_js_variables['site_status']['direct'][] = call_user_func( array( $this, $test_function ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
270
  continue;
271
  }
272
  }
273
 
274
  if ( is_callable( $test['test'] ) ) {
275
- $health_check_js_variables['site_status']['direct'][] = call_user_func( $test['test'] );
276
  }
277
  }
278
 
@@ -338,32 +384,12 @@ class Health_Check {
338
  'tools.php',
339
  _x( 'Site Health', 'Page Title', 'health-check' ),
340
  $menu_title,
341
- 'install_plugins',
342
  'health-check',
343
  array( $this, 'dashboard_page' )
344
  );
345
  }
346
 
347
- /**
348
- * Add a quick-access link under our plugin name on the plugins-list.
349
- *
350
- * @uses plugin_basename()
351
- * @uses sprintf()
352
- * @uses menu_page_url()
353
- *
354
- * @param array $meta An array containing meta links.
355
- * @param string $name The plugin slug that these metas relate to.
356
- *
357
- * @return array
358
- */
359
- public function settings_link( $meta, $name ) {
360
- if ( plugin_basename( __FILE__ ) === $name ) {
361
- $meta[] = sprintf( '<a href="%s">' . _x( 'Health Check', 'Menu, Section and Page Title', 'health-check' ) . '</a>', menu_page_url( 'health-check', false ) );
362
- }
363
-
364
- return $meta;
365
- }
366
-
367
  /**
368
  * Add a troubleshooting action link to plugins.
369
  *
@@ -387,24 +413,47 @@ class Health_Check {
387
 
388
  // Set a slug if the plugin lives in the plugins directory root.
389
  if ( ! stristr( $plugin_file, '/' ) ) {
390
- $plugin_data['slug'] = $plugin_file;
 
 
 
391
  }
392
 
393
- // If a slug isn't present, use the plugin's name
394
- $plugin_name = ( isset( $plugin_data['slug'] ) ? $plugin_data['slug'] : sanitize_title( $plugin_data['Name'] ) );
395
-
396
  $actions['troubleshoot'] = sprintf(
397
  '<a href="%s">%s</a>',
398
- esc_url( add_query_arg( array(
399
- 'health-check-troubleshoot-plugin' => $plugin_name,
400
- '_wpnonce' => wp_create_nonce( 'health-check-troubleshoot-plugin-' . $plugin_name ),
401
- ), admin_url( 'plugins.php' ) ) ),
 
 
 
 
 
402
  esc_html__( 'Troubleshoot', 'health-check' )
403
  );
404
 
405
  return $actions;
406
  }
407
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
408
  /**
409
  * Render our admin page.
410
  *
50
 
51
  add_action( 'admin_menu', array( $this, 'action_admin_menu' ) );
52
 
 
 
53
  add_filter( 'plugin_action_links', array( $this, 'troubleshoot_plugin_action' ), 20, 4 );
54
+ add_filter( 'plugin_action_links_' . plugin_basename( HEALTH_CHECK_PLUGIN_FILE ), array( $this, 'page_plugin_action' ) );
55
 
56
  add_action( 'admin_notices', array( $this, 'admin_notices' ) );
57
 
63
  add_action( 'wp_ajax_health-check-loopback-no-plugins', array( 'Health_Check_Loopback', 'loopback_no_plugins' ) );
64
  add_action( 'wp_ajax_health-check-loopback-individual-plugins', array( 'Health_Check_Loopback', 'loopback_test_individual_plugins' ) );
65
  add_action( 'wp_ajax_health-check-loopback-default-theme', array( 'Health_Check_Loopback', 'loopback_test_default_theme' ) );
 
 
 
66
  add_action( 'wp_ajax_health-check-get-sizes', array( 'Health_Check_Debug_Data', 'ajax_get_sizes' ) );
67
 
 
 
 
68
  add_filter( 'cron_schedules', array( $this, 'cron_schedules' ) );
69
+
70
+ add_filter( 'user_has_cap', array( $this, 'maybe_grant_site_health_caps' ), 1, 4 );
71
+ }
72
+
73
+ /**
74
+ * Filters the user capabilities to grant the 'view_site_health_checks' capabilities as necessary.
75
+ *
76
+ * @since 5.2.2
77
+ *
78
+ * @param bool[] $allcaps An array of all the user's capabilities.
79
+ * @param string[] $caps Required primitive capabilities for the requested capability.
80
+ * @param array $args {
81
+ * Arguments that accompany the requested capability check.
82
+ *
83
+ * @type string $0 Requested capability.
84
+ * @type int $1 Concerned user ID.
85
+ * @type mixed ...$2 Optional second and further parameters, typically object ID.
86
+ * }
87
+ * @param WP_User $user The user object.
88
+ * @return bool[] Filtered array of the user's capabilities.
89
+ */
90
+ function maybe_grant_site_health_caps( $allcaps, $caps, $args, $user ) {
91
+ if ( ! empty( $allcaps['install_plugins'] ) && ( ! is_multisite() || is_super_admin( $user->ID ) ) ) {
92
+ $allcaps['view_site_health_checks'] = true;
93
+ }
94
+
95
+ return $allcaps;
96
  }
97
 
98
  /**
106
  * @return void
107
  */
108
  public function start_troubleshoot_mode() {
109
+ if ( ! isset( $_POST['health-check-troubleshoot-mode'] ) || ! current_user_can( 'view_site_health_checks' ) ) {
110
  return;
111
  }
112
 
138
  * @return void
139
  */
140
  public function start_troubleshoot_single_plugin_mode() {
141
+ if ( ! isset( $_GET['health-check-troubleshoot-plugin'] ) || ! current_user_can( 'view_site_health_checks' ) ) {
142
  return;
143
  }
144
 
176
  return;
177
  }
178
 
179
+ Health_Check_Troubleshoot::initiate_troubleshooting_mode(
180
+ array(
181
+ $_GET['health-check-troubleshoot-plugin'] => $_GET['health-check-troubleshoot-plugin'],
182
+ )
183
+ );
184
 
185
  wp_redirect( admin_url( 'plugins.php' ) );
186
  }
214
  * @return void
215
  */
216
  public function enqueues() {
217
+ $screen = get_current_screen();
218
+
219
  // Don't enqueue anything unless we're on the health check page.
220
+ if ( ( ! isset( $_GET['page'] ) || 'health-check' !== $_GET['page'] ) && 'dashboard' !== $screen->base ) {
221
  return;
222
  }
223
 
227
  'copied' => esc_html__( 'Copied', 'health-check' ),
228
  'running_tests' => esc_html__( 'Currently being tested...', 'health-check' ),
229
  'site_health_complete' => esc_html__( 'All site health tests have finished running.', 'health-check' ),
230
+ 'site_health_complete_pass_sr' => esc_html__( 'All site health tests have finished running. Your site is looking good, and the results are now available on the page.', 'health-check' ),
231
+ 'site_health_complete_fail_sr' => esc_html__( 'All site health tests have finished running. There are items that should be addressed, and the results are now available on the page.', 'health-check' ),
232
+ 'site_health_complete_pass' => esc_html__( 'Good', 'health-check' ),
233
+ 'site_health_complete_fail' => esc_html__( 'Should be improved', 'health-check' ),
234
  'site_info_copied' => esc_html__( 'Site information has been added to your clipboard.', 'health-check' ),
235
  // translators: %s: Amount of critical issues.
236
  'site_info_heading_critical_single' => esc_html__( '%s Critical issue', 'health-check' ),
254
  'mail_check' => wp_create_nonce( 'health-check-mail-check' ),
255
  'site_status' => wp_create_nonce( 'health-check-site-status' ),
256
  'site_status_result' => wp_create_nonce( 'health-check-site-status-result' ),
257
+ 'tools_plugin_compat' => wp_create_nonce( 'health-check-tools-plugin-compat' ),
258
  ),
259
  'site_status' => array(
260
  'direct' => array(),
275
  $health_check_js_variables['site_status']['issues'] = $issue_counts;
276
  }
277
 
278
+ if ( 'dashboard' !== $screen->base && ( ! isset( $_GET['tab'] ) || ( isset( $_GET['tab'] ) && 'site-status' === $_GET['tab'] ) ) ) {
279
  $tests = Health_Check_Site_Status::get_tests();
280
 
281
  // Don't run https test on localhost
291
  );
292
 
293
  if ( method_exists( $this, $test_function ) && is_callable( array( $this, $test_function ) ) ) {
294
+ /**
295
+ * Filter the output of a finished Site Health test.
296
+ *
297
+ * @since 5.3.0
298
+ *
299
+ * @param array $test_result {
300
+ * An associated array of test result data.
301
+ *
302
+ * @param string $label A label describing the test, and is used as a header in the output.
303
+ * @param string $status The status of the test, which can be a value of `good`, `recommended` or `critical`.
304
+ * @param array $badge {
305
+ * Tests are put into categories which have an associated badge shown, these can be modified and assigned here.
306
+ *
307
+ * @param string $label The test label, for example `Performance`.
308
+ * @param string $color Default `blue`. A string representing a color to use for the label.
309
+ * }
310
+ * @param string $description A more descriptive explanation of what the test looks for, and why it is important for the end user.
311
+ * @param string $actions An action to direct the user to where they can resolve the issue, if one exists.
312
+ * @param string $test The name of the test being ran, used as a reference point.
313
+ * }
314
+ */
315
+ $health_check_js_variables['site_status']['direct'][] = apply_filters( 'site_status_test_result', call_user_func( array( $this, $test_function ) ) );
316
  continue;
317
  }
318
  }
319
 
320
  if ( is_callable( $test['test'] ) ) {
321
+ $health_check_js_variables['site_status']['direct'][] = apply_filters( 'site_status_test_result', call_user_func( $test['test'] ) );
322
  }
323
  }
324
 
384
  'tools.php',
385
  _x( 'Site Health', 'Page Title', 'health-check' ),
386
  $menu_title,
387
+ 'view_site_health_checks',
388
  'health-check',
389
  array( $this, 'dashboard_page' )
390
  );
391
  }
392
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
393
  /**
394
  * Add a troubleshooting action link to plugins.
395
  *
413
 
414
  // Set a slug if the plugin lives in the plugins directory root.
415
  if ( ! stristr( $plugin_file, '/' ) ) {
416
+ $plugin_slug = $plugin_file;
417
+ } else { // Set the slug for plugin inside a folder.
418
+ $plugin_slug = explode( '/', $plugin_file );
419
+ $plugin_slug = $plugin_slug[0];
420
  }
421
 
 
 
 
422
  $actions['troubleshoot'] = sprintf(
423
  '<a href="%s">%s</a>',
424
+ esc_url(
425
+ add_query_arg(
426
+ array(
427
+ 'health-check-troubleshoot-plugin' => $plugin_slug,
428
+ '_wpnonce' => wp_create_nonce( 'health-check-troubleshoot-plugin-' . $plugin_slug ),
429
+ ),
430
+ admin_url( 'plugins.php' )
431
+ )
432
+ ),
433
  esc_html__( 'Troubleshoot', 'health-check' )
434
  );
435
 
436
  return $actions;
437
  }
438
 
439
+ /**
440
+ * Add a quick-access action link to the Heath Check page.
441
+ *
442
+ * @param $actions
443
+ *
444
+ * @return array
445
+ */
446
+ public function page_plugin_action( $actions ) {
447
+
448
+ $page_link = sprintf(
449
+ '<a href="%s">%s</a>',
450
+ menu_page_url( 'health-check', false ),
451
+ _x( 'Health Check', 'Menu, Section and Page Title', 'health-check' )
452
+ );
453
+ array_unshift( $actions, $page_link );
454
+ return $actions;
455
+ }
456
+
457
  /**
458
  * Render our admin page.
459
  *
includes/compat.php ADDED
@@ -0,0 +1,169 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // Manually include the versions file as we can't always rely on `get_bloginfo()` to fetch versions.
4
+ include ABSPATH . WPINC . '/version.php';
5
+
6
+ if ( ! function_exists( 'wp_check_php_version' ) && version_compare( '5.1', $wp_version, '>' ) ) {
7
+ /**
8
+ * Fallback function replicating core behavior from WordPress 5.1.0 to check PHP versions.
9
+ *
10
+ * @return array|bool|mixed|object|WP_Error
11
+ */
12
+ function wp_check_php_version() {
13
+ $version = phpversion();
14
+ $key = md5( $version );
15
+
16
+ $response = get_site_transient( 'php_check_' . $key );
17
+ if ( false === $response ) {
18
+ $url = 'http://api.wordpress.org/core/serve-happy/1.0/';
19
+ if ( wp_http_supports( array( 'ssl' ) ) ) {
20
+ $url = set_url_scheme( $url, 'https' );
21
+ }
22
+
23
+ $url = add_query_arg( 'php_version', $version, $url );
24
+
25
+ $response = wp_remote_get( $url );
26
+
27
+ if ( is_wp_error( $response ) || 200 !== wp_remote_retrieve_response_code( $response ) ) {
28
+ return false;
29
+ }
30
+
31
+ /**
32
+ * Response should be an array with:
33
+ * 'recommended_version' - string - The PHP version recommended by WordPress.
34
+ * 'is_supported' - boolean - Whether the PHP version is actively supported.
35
+ * 'is_secure' - boolean - Whether the PHP version receives security updates.
36
+ * 'is_acceptable' - boolean - Whether the PHP version is still acceptable for WordPress.
37
+ */
38
+ $response = json_decode( wp_remote_retrieve_body( $response ), true );
39
+
40
+ if ( ! is_array( $response ) ) {
41
+ return false;
42
+ }
43
+
44
+ set_site_transient( 'php_check_' . $key, $response, WEEK_IN_SECONDS );
45
+ }
46
+
47
+ if ( isset( $response['is_acceptable'] ) && $response['is_acceptable'] ) {
48
+ /**
49
+ * Filters whether the active PHP version is considered acceptable by WordPress.
50
+ *
51
+ * Returning false will trigger a PHP version warning to show up in the admin dashboard to administrators.
52
+ *
53
+ * This filter is only run if the wordpress.org Serve Happy API considers the PHP version acceptable, ensuring
54
+ * that this filter can only make this check stricter, but not loosen it.
55
+ *
56
+ * @since 5.1.1
57
+ *
58
+ * @param bool $is_acceptable Whether the PHP version is considered acceptable. Default true.
59
+ * @param string $version PHP version checked.
60
+ */
61
+ $response['is_acceptable'] = (bool) apply_filters( 'wp_is_php_version_acceptable', true, $version );
62
+ }
63
+
64
+ return $response;
65
+ }
66
+ }
67
+
68
+ if ( ! function_exists( 'wp_get_update_php_url' ) && version_compare( '5.1', $wp_version, '>' ) ) {
69
+ /**
70
+ * Fallback function replicating core behavior from WordPress 5.1.0 to check PHP versions.
71
+ *
72
+ * @return string URL to learn more about updating PHP.
73
+ */
74
+ function wp_get_update_php_url() {
75
+ $default_url = _x( 'https://wordpress.org/support/update-php/', 'localized PHP upgrade information page', 'health-check' );
76
+
77
+ $update_url = $default_url;
78
+ if ( false !== getenv( 'WP_UPDATE_PHP_URL' ) ) {
79
+ $update_url = getenv( 'WP_UPDATE_PHP_URL' );
80
+ }
81
+
82
+ /**
83
+ * Filters the URL to learn more about updating the PHP version the site is running on.
84
+ *
85
+ * Providing an empty string is not allowed and will result in the default URL being used. Furthermore
86
+ * the page the URL links to should preferably be localized in the site language.
87
+ *
88
+ * @since 5.1.0
89
+ *
90
+ * @param string $update_url URL to learn more about updating PHP.
91
+ */
92
+ $update_url = apply_filters( 'wp_update_php_url', $update_url );
93
+
94
+ if ( empty( $update_url ) ) {
95
+ $update_url = $default_url;
96
+ }
97
+
98
+ return $update_url;
99
+ }
100
+ }
101
+
102
+ if ( ! function_exists( 'is_countable' ) && version_compare( '4.9.6', $wp_version, '>' ) ) {
103
+ /**
104
+ * Fallback function replicating core behavior from WordPress 4.9.6 to check PHP versions.
105
+ *
106
+ * Polyfill for is_countable() function added in PHP 7.3.
107
+ *
108
+ * Verify that the content of a variable is an array or an object
109
+ * implementing the Countable interface.
110
+ *
111
+ * @param mixed $var The value to check.
112
+ *
113
+ * @return bool True if `$var` is countable, false otherwise.
114
+ */
115
+ function is_countable( $var ) {
116
+ return ( is_array( $var )
117
+ || $var instanceof Countable
118
+ || $var instanceof SimpleXMLElement
119
+ || $var instanceof ResourceBundle
120
+ );
121
+ }
122
+ }
123
+
124
+ if ( ! function_exists( 'get_user_count' ) && version_compare( '4.8', $wp_version, '>' ) ) {
125
+ /**
126
+ * Fallback function replicating core behavior from WordPress 4.8.0 to check PHP versions.
127
+ *
128
+ * @return int Number of active users on the network.
129
+ */
130
+ function get_user_count( $network_id = null ) {
131
+ return get_network_option( $network_id, 'user_count' );
132
+ }
133
+ }
134
+
135
+ if ( ! function_exists( 'get_user_locale' ) && version_compare( '4.7', $wp_version, '>' ) ) {
136
+ /**
137
+ * Fallback function replicating core behavior from WordPress 4.7.0 to check PHP versions.
138
+ *
139
+ * @return string The locale of the user.
140
+ */
141
+ function get_user_locale( $user_id = 0 ) {
142
+ $user = false;
143
+ if ( 0 === $user_id && function_exists( 'wp_get_current_user' ) ) {
144
+ $user = wp_get_current_user();
145
+ } elseif ( $user_id instanceof WP_User ) {
146
+ $user = $user_id;
147
+ } elseif ( $user_id && is_numeric( $user_id ) ) {
148
+ $user = get_user_by( 'id', $user_id );
149
+ }
150
+
151
+ if ( ! $user ) {
152
+ return get_locale();
153
+ }
154
+
155
+ $locale = $user->locale;
156
+ return $locale ? $locale : get_locale();
157
+ }
158
+ }
159
+
160
+ if ( ! function_exists( 'wp_get_upload_dir' ) && version_compare( '4.5', $wp_version, '>' ) ) {
161
+ /**
162
+ * Fallback function replicating core behavior from WordPress 4.5.0 to check PHP versions.
163
+ *
164
+ * @return array See `wp_upload_dir()` for description.
165
+ */
166
+ function wp_get_upload_dir() {
167
+ return wp_upload_dir( null, false );
168
+ }
169
+ }
includes/{class-health-check-files-integrity.php → tools/class-health-check-files-integrity.php} RENAMED
@@ -14,22 +14,31 @@ if ( ! defined( 'ABSPATH' ) ) {
14
  /**
15
  * Class Files_Integrity
16
  */
17
- class Health_Check_Files_Integrity {
 
 
 
 
 
 
 
 
 
 
18
 
19
  /**
20
  * Gathers checksums from WordPress API and cross checks the core files in the current installation.
21
  *
22
  * @return void
23
  */
24
- static function run_files_integrity_check() {
25
  check_ajax_referer( 'health-check-files-integrity-check' );
26
 
27
- $checksums = Health_Check_Files_Integrity::call_checksum_api();
28
-
29
- $files = Health_Check_Files_Integrity::parse_checksum_results( $checksums );
30
 
31
- Health_Check_Files_Integrity::create_the_response( $files );
32
 
 
33
  }
34
 
35
  /**
@@ -45,27 +54,28 @@ class Health_Check_Files_Integrity {
45
  *
46
  * @return array
47
  */
48
- static function call_checksum_api() {
49
  // Setup variables.
50
  $wpversion = get_bloginfo( 'version' );
51
  $wplocale = get_locale();
52
 
53
  // Setup API Call.
54
- $checksumapi = wp_remote_get( 'https://api.wordpress.org/core/checksums/1.0/?version=' . $wpversion . '&locale=' . $wplocale, array( 'timeout' => 10000 ) );
55
 
56
- // Encode the API response body.
57
- $checksumapibody = json_decode( wp_remote_retrieve_body( $checksumapi ), true );
 
58
 
59
- set_transient( 'health-check-checksums', $checksumapibody, 2 * HOUR_IN_SECONDS );
60
 
61
  // Remove the wp-content/ files from checking
62
- foreach ( $checksumapibody['checksums'] as $file => $checksum ) {
63
  if ( false !== strpos( $file, 'wp-content/' ) ) {
64
- unset( $checksumapibody['checksums'][ $file ] );
65
  }
66
  }
67
 
68
- return $checksumapibody;
69
  }
70
 
71
  /**
@@ -77,13 +87,18 @@ class Health_Check_Files_Integrity {
77
  *
78
  * @param array $checksums
79
  *
80
- * @return array
81
  */
82
- static function parse_checksum_results( $checksums ) {
 
 
 
 
 
83
  $filepath = ABSPATH;
84
  $files = array();
85
  // Parse the results.
86
- foreach ( $checksums['checksums'] as $file => $checksum ) {
87
  // Check the files.
88
  if ( file_exists( $filepath . $file ) && md5_file( $filepath . $file ) !== $checksum ) {
89
  $reason = esc_html__( 'Content changed', 'health-check' ) . ' <a href="#health-check-diff" data-file="' . $file . '">' . esc_html__( '(View Diff)', 'health-check' ) . '</a>';
@@ -107,7 +122,7 @@ class Health_Check_Files_Integrity {
107
  *
108
  * @return void
109
  */
110
- static function create_the_response( $files ) {
111
  $filepath = ABSPATH;
112
  $output = '';
113
 
@@ -167,10 +182,10 @@ class Health_Check_Files_Integrity {
167
  *
168
  * @return void
169
  */
170
- static function view_file_diff() {
171
  check_ajax_referer( 'health-check-view-file-diff' );
172
 
173
- if ( ! current_user_can( 'install_plugins' ) ) {
174
  wp_send_json_error();
175
  }
176
 
@@ -178,18 +193,16 @@ class Health_Check_Files_Integrity {
178
  $file = $_POST['file'];
179
  $wpversion = get_bloginfo( 'version' );
180
 
181
- if ( 0 !== validate_file( $filepath . $file ) ) {
182
  wp_send_json_error( array( 'message' => esc_html__( 'You do not have access to this file.', 'health-check' ) ) );
183
  }
184
 
185
  $allowed_files = get_transient( 'health-check-checksums' );
186
  if ( false === $allowed_files ) {
187
- Health_Check_Files_Integrity::call_checksum_api();
188
-
189
- $allowed_files = get_transient( 'health-check-checksums' );
190
  }
191
 
192
- if ( ! isset( $allowed_files['checksums'][ $file ] ) ) {
193
  wp_send_json_error( array( 'message' => esc_html__( 'You do not have access to this file.', 'health-check' ) ) );
194
  }
195
 
@@ -218,37 +231,22 @@ class Health_Check_Files_Integrity {
218
  /**
219
  * Add the Files integrity checker to the tools tab.
220
  *
221
- * @param array $tabs
222
- *
223
- * @return array
224
  */
225
- static function tools_tab( $tabs ) {
226
- ob_start();
227
  ?>
228
-
229
- <div>
230
  <p>
231
- <?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' ); ?>
232
  </p>
233
- <form action="#" id="health-check-file-integrity" method="POST">
234
- <p>
235
- <input type="submit" class="button button-primary" value="<?php esc_html_e( 'Check the Files Integrity', 'health-check' ); ?>">
236
- </p>
237
- </form>
238
-
239
- <div id="tools-file-integrity-response-holder">
240
- <span class="spinner"></span>
241
- </div>
242
  </div>
243
 
244
  <?php
245
- $tab_content = ob_get_clean();
246
-
247
- $tabs[] = array(
248
- 'label' => esc_html__( 'File Integrity', 'health-check' ),
249
- 'content' => $tab_content,
250
- );
251
-
252
- return $tabs;
253
  }
254
  }
 
 
14
  /**
15
  * Class Files_Integrity
16
  */
17
+ class Health_Check_Files_Integrity extends Health_Check_Tool {
18
+
19
+ public function __construct() {
20
+ $this->label = __( 'File integrity', 'health-check' );
21
+ $this->description = __( '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' );
22
+
23
+ add_action( 'wp_ajax_health-check-files-integrity-check', array( $this, 'run_files_integrity_check' ) );
24
+ add_action( 'wp_ajax_health-check-view-file-diff', array( $this, 'view_file_diff' ) );
25
+
26
+ parent::__construct();
27
+ }
28
 
29
  /**
30
  * Gathers checksums from WordPress API and cross checks the core files in the current installation.
31
  *
32
  * @return void
33
  */
34
+ function run_files_integrity_check() {
35
  check_ajax_referer( 'health-check-files-integrity-check' );
36
 
37
+ $checksums = $this->call_checksum_api();
 
 
38
 
39
+ $files = $this->parse_checksum_results( $checksums );
40
 
41
+ $this->create_the_response( $files );
42
  }
43
 
44
  /**
54
  *
55
  * @return array
56
  */
57
+ function call_checksum_api() {
58
  // Setup variables.
59
  $wpversion = get_bloginfo( 'version' );
60
  $wplocale = get_locale();
61
 
62
  // Setup API Call.
63
+ $checksums = get_core_checksums( $wpversion, $wplocale );
64
 
65
+ if ( false === $checksums ) {
66
+ return $checksums;
67
+ }
68
 
69
+ set_transient( 'health-check-checksums', $checksums, 2 * HOUR_IN_SECONDS );
70
 
71
  // Remove the wp-content/ files from checking
72
+ foreach ( $checksums as $file => $checksum ) {
73
  if ( false !== strpos( $file, 'wp-content/' ) ) {
74
+ unset( $checksums[ $file ] );
75
  }
76
  }
77
 
78
+ return $checksums;
79
  }
80
 
81
  /**
87
  *
88
  * @param array $checksums
89
  *
90
+ * @return array|bool
91
  */
92
+ function parse_checksum_results( $checksums ) {
93
+ // Check if the checksums are valid
94
+ if ( false === $checksums ) {
95
+ return false;
96
+ }
97
+
98
  $filepath = ABSPATH;
99
  $files = array();
100
  // Parse the results.
101
+ foreach ( $checksums as $file => $checksum ) {
102
  // Check the files.
103
  if ( file_exists( $filepath . $file ) && md5_file( $filepath . $file ) !== $checksum ) {
104
  $reason = esc_html__( 'Content changed', 'health-check' ) . ' <a href="#health-check-diff" data-file="' . $file . '">' . esc_html__( '(View Diff)', 'health-check' ) . '</a>';
122
  *
123
  * @return void
124
  */
125
+ function create_the_response( $files ) {
126
  $filepath = ABSPATH;
127
  $output = '';
128
 
182
  *
183
  * @return void
184
  */
185
+ function view_file_diff() {
186
  check_ajax_referer( 'health-check-view-file-diff' );
187
 
188
+ if ( ! current_user_can( 'view_site_health_checks' ) ) {
189
  wp_send_json_error();
190
  }
191
 
193
  $file = $_POST['file'];
194
  $wpversion = get_bloginfo( 'version' );
195
 
196
+ if ( 0 !== validate_file( $file ) ) {
197
  wp_send_json_error( array( 'message' => esc_html__( 'You do not have access to this file.', 'health-check' ) ) );
198
  }
199
 
200
  $allowed_files = get_transient( 'health-check-checksums' );
201
  if ( false === $allowed_files ) {
202
+ $allowed_files = $this->call_checksum_api();
 
 
203
  }
204
 
205
+ if ( ! isset( $allowed_files[ $file ] ) ) {
206
  wp_send_json_error( array( 'message' => esc_html__( 'You do not have access to this file.', 'health-check' ) ) );
207
  }
208
 
231
  /**
232
  * Add the Files integrity checker to the tools tab.
233
  *
234
+ * @return void
 
 
235
  */
236
+ public function tab_content() {
 
237
  ?>
238
+ <form action="#" id="health-check-file-integrity" method="POST">
 
239
  <p>
240
+ <input type="submit" class="button button-primary" value="<?php esc_html_e( 'Check the Files Integrity', 'health-check' ); ?>">
241
  </p>
242
+ </form>
243
+
244
+ <div id="tools-file-integrity-response-holder">
245
+ <span class="spinner"></span>
 
 
 
 
 
246
  </div>
247
 
248
  <?php
 
 
 
 
 
 
 
 
249
  }
250
  }
251
+
252
+ new Health_Check_Files_Integrity();
includes/{class-health-check-mail-check.php → tools/class-health-check-mail-check.php} RENAMED
@@ -14,7 +14,16 @@ if ( ! defined( 'ABSPATH' ) ) {
14
  /**
15
  * Class Mail Check
16
  */
17
- class Health_Check_Mail_Check {
 
 
 
 
 
 
 
 
 
18
 
19
  /**
20
  * Checks if wp_mail() works.
@@ -29,7 +38,7 @@ class Health_Check_Mail_Check {
29
  static function run_mail_check() {
30
  check_ajax_referer( 'health-check-mail-check' );
31
 
32
- if ( ! current_user_can( 'install_plugins' ) ) {
33
  wp_send_json_error();
34
  }
35
 
@@ -88,18 +97,10 @@ class Health_Check_Mail_Check {
88
  /**
89
  * Add the Mail Checker to the tools tab.
90
  *
91
- * @param array $tabs
92
- *
93
- * @return array
94
  */
95
- public static function tools_tab( $tabs ) {
96
- ob_start();
97
  ?>
98
-
99
- <div>
100
- <p>
101
- <?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' ); ?>
102
- </p>
103
  <form action="#" id="health-check-mail-check" method="POST">
104
  <table class="widefat tools-email-table">
105
  <tr>
@@ -108,7 +109,7 @@ class Health_Check_Mail_Check {
108
  <?php
109
  $current_user = wp_get_current_user();
110
  ?>
111
- <label for="email"><?php _e( 'E-mail', 'health-check' ); ?></label>
112
  <input type="text" name="email" id="email" value="<?php echo $current_user->user_email; ?>">
113
  </p>
114
  </td>
@@ -126,16 +127,8 @@ class Health_Check_Mail_Check {
126
  <div id="tools-mail-check-response-holder">
127
  <span class="spinner"></span>
128
  </div>
129
- </div>
130
-
131
  <?php
132
- $tab_content = ob_get_clean();
133
-
134
- $tabs[] = array(
135
- 'label' => esc_html__( 'Mail Check', 'health-check' ),
136
- 'content' => $tab_content,
137
- );
138
-
139
- return $tabs;
140
  }
141
  }
 
 
14
  /**
15
  * Class Mail Check
16
  */
17
+ class Health_Check_Mail_Check extends Health_Check_Tool {
18
+
19
+ public function __construct() {
20
+ $this->label = __( 'Mail Check', 'health-check' );
21
+ $this->description = __( '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' );
22
+
23
+ add_action( 'wp_ajax_health-check-mail-check', array( $this, 'run_mail_check' ) );
24
+
25
+ parent::__construct();
26
+ }
27
 
28
  /**
29
  * Checks if wp_mail() works.
38
  static function run_mail_check() {
39
  check_ajax_referer( 'health-check-mail-check' );
40
 
41
+ if ( ! current_user_can( 'view_site_health_checks' ) ) {
42
  wp_send_json_error();
43
  }
44
 
97
  /**
98
  * Add the Mail Checker to the tools tab.
99
  *
100
+ * @return void
 
 
101
  */
102
+ public function tab_content() {
 
103
  ?>
 
 
 
 
 
104
  <form action="#" id="health-check-mail-check" method="POST">
105
  <table class="widefat tools-email-table">
106
  <tr>
109
  <?php
110
  $current_user = wp_get_current_user();
111
  ?>
112
+ <label for="email"><?php _e( 'Email', 'health-check' ); ?></label>
113
  <input type="text" name="email" id="email" value="<?php echo $current_user->user_email; ?>">
114
  </p>
115
  </td>
127
  <div id="tools-mail-check-response-holder">
128
  <span class="spinner"></span>
129
  </div>
 
 
130
  <?php
 
 
 
 
 
 
 
 
131
  }
132
  }
133
+
134
+ new Health_Check_Mail_Check();
includes/tools/class-health-check-plugin-compatibility.php ADDED
@@ -0,0 +1,131 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Health_Check_Plugin_Compatibility extends Health_Check_Tool {
4
+
5
+ public function __construct() {
6
+ $this->label = __( 'Plugin compatibility', 'health-check' );
7
+ $this->description = sprintf(
8
+ '%s<br>%s',
9
+ __( 'Attempt to identify the compatibility of your plugins before upgrading PHP, note that a compatibility check may not always be accurate, and you may want to contact the plugin author to confirm that things will continue working.', 'health-check' ),
10
+ __( 'The compatibility check will need to send requests to the <a href="https://wptide.org">WPTide</a> project to fetch the test results for each of your plugins.', 'health-check' )
11
+ );
12
+
13
+ add_action( 'wp_ajax_health-check-tools-plugin-compat', array( $this, 'check_plugin_version' ) );
14
+
15
+ parent::__construct();
16
+ }
17
+
18
+ public function tab_content() {
19
+ ?>
20
+ <table class="wp-list-table widefat fixed striped" id="health-check-tool-plugin-compat-list">
21
+ <thead>
22
+ <tr>
23
+ <th>Plugin</th>
24
+ <th>Version</th>
25
+ <th>Minimum PHP</th>
26
+ <th>Highest supported PHP</th>
27
+ </tr>
28
+ </thead>
29
+
30
+ <tbody>
31
+ <?php
32
+ $plugins = get_plugins();
33
+
34
+ foreach ( $plugins as $slug => $plugin ) {
35
+ printf(
36
+ '<tr data-plugin-slug="%s" data-plugin-version="%s" data-plugin-checked="false"><td>%s</td><td>%s</td><td>%s</td><td class="supported-version">%s</td></tr>',
37
+ esc_attr( $slug ),
38
+ esc_attr( $plugin['Version'] ),
39
+ $plugin['Name'],
40
+ $plugin['Version'],
41
+ ( isset( $plugin['RequiresPHP'] ) && ! empty( $plugin['RequiresPHP'] ) ? $plugin['RequiresPHP'] : '&mdash;' ),
42
+ '<span class="spinner"></span>'
43
+ );
44
+ }
45
+ ?>
46
+ </tbody>
47
+ </table>
48
+
49
+ <p>
50
+ <button type="button" class="button button-primary" id="health-check-tool-plugin-compat">
51
+ <?php _e( 'Check plugins', 'health-check' ); ?>
52
+ </button>
53
+ </p>
54
+ <?php
55
+ }
56
+
57
+ function check_plugin_version() {
58
+ check_ajax_referer( 'health-check-tools-plugin-compat' );
59
+
60
+ if ( ! current_user_can( 'view_site_health_checks' ) ) {
61
+ wp_send_json_error();
62
+ }
63
+
64
+ $response = array(
65
+ 'version' => $this->get_highest_supported_php( $_POST['slug'], $_POST['version'] ),
66
+ );
67
+
68
+ wp_send_json_success( $response );
69
+
70
+ wp_die();
71
+ }
72
+
73
+ function get_highest_supported_php( $slug, $version ) {
74
+ $versions = $this->get_supported_php( $slug, $version );
75
+
76
+ if ( empty( $versions ) ) {
77
+ return __( 'Could not be determined', 'health-check' );
78
+ }
79
+
80
+ $highest = 0;
81
+
82
+ foreach ( $versions as $version ) {
83
+ if ( $highest < $version ) {
84
+ $highest = $version;
85
+ }
86
+ }
87
+
88
+ return $highest;
89
+ }
90
+
91
+ function get_supported_php( $slug, $version ) {
92
+ // Clean up the slug, in case it's got more details
93
+ if ( stristr( $slug, '/' ) ) {
94
+ $parts = explode( '/', $slug );
95
+ $slug = $parts[0];
96
+ }
97
+
98
+ $transient_name = sprintf(
99
+ 'health-check-tide-%s-%s',
100
+ $slug,
101
+ $version
102
+ );
103
+
104
+ $tide_versions = get_transient( $transient_name );
105
+
106
+ if ( false === $tide_versions ) {
107
+ $tide_api_respone = wp_remote_get(
108
+ sprintf(
109
+ 'https://wptide.org/api/tide/v1/audit/wporg/plugin/%s',
110
+ $slug
111
+ )
112
+ );
113
+
114
+ $tide_response = wp_remote_retrieve_body( $tide_api_respone );
115
+
116
+ $json = json_decode( $tide_response );
117
+
118
+ if ( empty( $json ) ) {
119
+ $tide_versions = array();
120
+ } else {
121
+ $tide_versions = $json[0]->reports->phpcs_phpcompatibility->compatible_versions;
122
+ }
123
+
124
+ set_transient( $transient_name, $tide_versions, 1 * WEEK_IN_SECONDS );
125
+ }
126
+
127
+ return $tide_versions;
128
+ }
129
+ }
130
+
131
+ new Health_Check_Plugin_Compatibility();
includes/tools/class-health-check-tool.php ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Base class for the Tools tab to be extended.
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
+ * Class Health_Check_Tools
15
+ */
16
+ abstract class Health_Check_Tool {
17
+ protected $description;
18
+ protected $label;
19
+
20
+ public function __construct() {
21
+ add_filter( 'health_check_tools_tab', array( $this, 'tab_setup' ) );
22
+ }
23
+
24
+ public function tab_setup( $tabs ) {
25
+ if ( ! isset( $this->label ) || empty( $this->label ) ) {
26
+ return $tabs;
27
+ }
28
+
29
+ ob_start();
30
+ ?>
31
+
32
+ <div>
33
+ <?php if ( $this->has_description() ) : ?>
34
+ <p><?php echo $this->get_description(); ?></p>
35
+ <?php endif; ?>
36
+
37
+ <?php $this->tab_content(); ?>
38
+ </div>
39
+
40
+ <?php
41
+
42
+ $tab_content = ob_get_clean();
43
+
44
+ $tabs[] = array(
45
+ 'label' => $this->label,
46
+ 'content' => $tab_content,
47
+ );
48
+
49
+ return $tabs;
50
+ }
51
+
52
+ public function tab_content() {}
53
+
54
+ public function has_description() {
55
+ return isset( $this->description ) && ! empty( $this->description );
56
+ }
57
+
58
+ public function get_description() {
59
+ return $this->description;
60
+ }
61
+ }
pages/debug-data.php CHANGED
@@ -20,10 +20,16 @@ $info = Health_Check_Debug_Data::debug_data();
20
  </h2>
21
 
22
  <p>
23
- <?php _e( 'This page can show you every detail about the configuration of your WordPress website. If we see anything here that could be improved, we will let you know on the Site Health Status page.', 'health-check' ); ?>
 
 
 
 
 
 
24
  </p>
25
  <p>
26
- <?php _e( 'If you want to export a handy list of all the information on this page, you can use the button below to copy it to the clipboard. You can then paste it in a text file and save it to your harddrive, or paste it in an email exchange with a support engineer or theme/plugin developer for example.', 'health-check' ); ?>
27
  </p>
28
 
29
  <div class="site-health-copy-buttons">
20
  </h2>
21
 
22
  <p>
23
+ <?php
24
+ printf(
25
+ /* translators: %s: URL to Site Health Status page */
26
+ __( 'This page can show you every detail about the configuration of your WordPress website. For any improvements that could be made, see the <a href="%s">Site Health Status</a> page.', 'health-check' ),
27
+ esc_url( admin_url( 'site-health.php' ) )
28
+ );
29
+ ?>
30
  </p>
31
  <p>
32
+ <?php _e( 'If you want to export a handy list of all the information on this page, you can use the button below to copy it to the clipboard. You can then paste it in a text file and save it to your device, or paste it in an email exchange with a support engineer or theme/plugin developer for example.', 'health-check' ); ?>
33
  </p>
34
 
35
  <div class="site-health-copy-buttons">
pages/site-health-header.php CHANGED
@@ -16,14 +16,17 @@ if ( ! defined( 'ABSPATH' ) ) {
16
  <h1>
17
  <?php esc_html_e( 'Site Health', 'health-check' ); ?>
18
  </h1>
 
19
 
20
- <div class="site-health-progress hide-if-no-js loading">
 
21
  <svg role="img" aria-hidden="true" focusable="false" width="100%" height="100%" viewBox="0 0 200 200" version="1.1" xmlns="http://www.w3.org/2000/svg">
22
  <circle r="90" cx="100" cy="100" fill="transparent" stroke-dasharray="565.48" stroke-dashoffset="0"></circle>
23
  <circle id="bar" r="90" cx="100" cy="100" fill="transparent" stroke-dasharray="565.48" stroke-dashoffset="0"></circle>
24
  </svg>
25
- <span class="screen-reader-text"><?php _e( 'Current completion rate:', 'health-check' ); ?></span>
26
- <span class="site-health-progress-count"></span>
 
27
  </div>
28
  </div>
29
 
16
  <h1>
17
  <?php esc_html_e( 'Site Health', 'health-check' ); ?>
18
  </h1>
19
+ </div>
20
 
21
+ <div class="health-check-title-section site-health-progress-wrapper loading hide-if-no-js">
22
+ <div class="site-health-progress">
23
  <svg role="img" aria-hidden="true" focusable="false" width="100%" height="100%" viewBox="0 0 200 200" version="1.1" xmlns="http://www.w3.org/2000/svg">
24
  <circle r="90" cx="100" cy="100" fill="transparent" stroke-dasharray="565.48" stroke-dashoffset="0"></circle>
25
  <circle id="bar" r="90" cx="100" cy="100" fill="transparent" stroke-dasharray="565.48" stroke-dashoffset="0"></circle>
26
  </svg>
27
+ </div>
28
+ <div class="site-health-progress-label">
29
+ <?php _e( 'Results are still loading&hellip;', 'health-check' ); ?>
30
  </div>
31
  </div>
32
 
readme.txt CHANGED
@@ -4,7 +4,7 @@ Contributors: wordpressdotorg, westi, pento, Clorith
4
  Requires at least: 4.0
5
  Requires PHP: 5.2
6
  Tested up to: 5.2
7
- Stable tag: 1.3.2
8
  License: GPLv2
9
  License URI: https://www.gnu.org/licenses/gpl-2.0.html
10
 
@@ -12,19 +12,17 @@ Health Check identifies common problems, and helps you troubleshoot plugin and t
12
 
13
  == Description ==
14
 
15
- *The plugins menu position has changed, and can now be found under **Tools** > **Site Health**, where it replaces the Site Health feature included with WordPress 5.2*
16
-
17
- This plugin will perform a number of checks on your WordPress install to detect common configuration errors and known issues.
18
-
19
- 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.
20
 
21
  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.
22
 
23
- 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.
 
 
24
 
25
  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/).
26
 
27
- 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).
28
 
29
  == Frequently Asked Questions ==
30
 
@@ -34,6 +32,14 @@ If you should find your self stuck in Troubleshooting Mode for any reason, you c
34
 
35
  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.
36
 
 
 
 
 
 
 
 
 
37
  == Screenshots ==
38
 
39
  1. The health check screen after the automated tests have gone over the system.
@@ -43,20 +49,31 @@ Are you unfamiliar with how to clear your cookies? No worries, you may also clos
43
 
44
  == Changelog ==
45
 
46
- = v1.3.2 =
47
- * Add polyfill for directory size calculations for sites running WordPress versions older than 5.2.0
48
- * Fix link for the extended PHP information
49
-
50
- = v1.3.1 =
51
- * Include missing dependency for JavaScript files, first introduced in WordPress 5.2
52
-
53
- = v1.3.0 =
54
- * Plugin moved to the Tools section in the admin menu
55
- * New UI/UX for the plugin pages
56
- * New troubleshooting mode UI/UX
57
- * Removed the backup reminder nag
58
- * Improved security hardening
59
- * Changed cookie names for improved hosting compatibility
60
- * Improved accessibility
61
- * Automatically check for critical issues once a week (adds a counter next to the menu item)
62
- * Dates in the email tester now follow your site settings
 
 
 
 
 
 
 
 
 
 
 
4
  Requires at least: 4.0
5
  Requires PHP: 5.2
6
  Tested up to: 5.2
7
+ Stable tag: 1.4.0
8
  License: GPLv2
9
  License URI: https://www.gnu.org/licenses/gpl-2.0.html
10
 
12
 
13
  == Description ==
14
 
15
+ This plugin will perform a number of checks on your WordPress installation to detect common configuration errors and known issues, and also allows plugins and themes to add their own checks.
 
 
 
 
16
 
17
  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.
18
 
19
+ Troubleshooting allows you to have a clean WordPress session, where all plugins are disabled, and a default theme is used, but only for your user until you disable it or log out.
20
+
21
+ The Tools section allows you to check that WordPress files have not been tampered with, that emails can be sent, and if your plugins are compatible with any PHP version updates in the future.
22
 
23
  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/).
24
 
25
+ Feedback is welcome both through the [WordPress.org forums](https://wordpress.org/support/plugin/health-check), the [GitHub project page](https://github.com/WordPress/health-check), or on [Slack](https://make.wordpress.org/chat) in either [#forums](https://wordpress.slack.com/messages/forums/) or [#core-site-health](https://wordpress.slack.com/messages/core-site-health/).
26
 
27
  == Frequently Asked Questions ==
28
 
32
 
33
  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.
34
 
35
+ = The PHP compatibility says this plugin only work with PHP version X? =
36
+
37
+ The plugin is made to be a support tool for as many users as possible, this means it needs code that is written for older sites as well.
38
+
39
+ Tools that check for PHP compatibility do not know how to separate this code from the real code, so it will give a false positive response.
40
+
41
+ At this time, the plugin has been tested with every version of PHP from 5.2 through 7.3, and works with all of these.
42
+
43
  == Screenshots ==
44
 
45
  1. The health check screen after the automated tests have gone over the system.
49
 
50
  == Changelog ==
51
 
52
+ = v1.4.0 =
53
+ * Fix a bug when viewing the Site Health page if enabling the Health Check plugin in troubleshooting mode.
54
+ * Fix an inconsistency with how database versions are checked.
55
+ * Fix the file comparison view on Windows systems if there are modified core files.
56
+ * Fix a bug where some premium plugins could not be enabled in troubleshooting mode
57
+ * Improved styles for older browsers.
58
+ * Improved the PHP module checks to allow for constant checks as well. Should help with some edge case tests.
59
+ * Improved the core file integrity checker.
60
+ * Improved testing of WP_cron, now works properly for those running a "real cron" outside of WordPress.
61
+ * Improved the htaccess rule test to only run if using an Apache server that supports these.
62
+ * Modify the Site Health grading indicator.
63
+ * Modified strings to make them clearer.
64
+ * Added server headers to the Debug information.
65
+ * Added polyfills for core features from WordPress 5.2 so they work for older sites.
66
+ * Added a link to the Site Health page from the plugin overview.
67
+ * Added a custom capability, `view_site_health_checks` for the plugin.
68
+ * Added support for parent/child theme output in the Debug screen.
69
+ * Added system user information to the Debug information.
70
+ * Added a Site Health test for timezone localization.
71
+ * Added `mbstring` and `json` (again) as requirements to the list of PHP extensions.
72
+ * Added a missing toggle to the list of plugins/themes to the troubleshooting dashboard widget.
73
+ * Added bulk actions to enable or disable plugins when troubleshooting, or to initiate troubleshooting mode.
74
+ * Added plugin compatibility checker ot the tools section.
75
+ * Added a dashboard widget to show your Site Health status at a glance when logging in.
76
+ * Added filters for Site Health test results.
77
+ * Added WP-CLI support, you can now run `wp health-check status` for a list of test and their status.
78
+ * Moved compatibility functions out of primary files and into a `compat.php` so they can be conditionally loaded.
79
+ * Disable the Fatal Error (WSOD) protection in WordPress while in troubleshooting mode.
uninstall.php CHANGED
@@ -29,6 +29,9 @@ $wpdb->delete(
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' );
29
  )
30
  );
31
 
32
+ // Remove any transients and similar which the plugin may have left behind.
33
+ $wpdb->query( "DELETE FROM {$wpdb->options} WHERE `option_name` LIKE '_transient_%_health-check%'" );
34
+
35
  // Remove the old Must-Use plugin if it was implemented.
36
  if ( file_exists( trailingslashit( WPMU_PLUGIN_DIR ) . 'health-check-disable-plugins.php' ) ) {
37
  wp_delete_file( trailingslashit( WPMU_PLUGIN_DIR ) . 'health-check-disable-plugins.php' );