Health Check - Version 1.0.0

Version Description

Download this release

Release Info

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

Version 1.0.0

assets/css/health-check.css ADDED
@@ -0,0 +1,149 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ body.dashboard_page_health-check .health-check-table tbody td {
2
+ width: 80%;
3
+ }
4
+
5
+ body.dashboard_page_health-check .health-check-table tbody td ul,
6
+ body.dashboard_page_health-check .health-check-table tbody td ol {
7
+ margin: 0;
8
+ }
9
+
10
+ body.dashboard_page_health-check .health-check-table thead th:first-child,
11
+ body.dashboard_page_health-check .health-check-table tbody td:first-child {
12
+ width: 20%;
13
+ }
14
+
15
+ body.dashboard_page_health-check .file-integrity-table thead th:first-child,
16
+ body.dashboard_page_health-check .file-integrity-table tbody td:first-child,
17
+ body.dashboard_page_health-check .file-integrity-table tfoot td:first-child {
18
+ text-align: center;
19
+ width: 80px;
20
+ }
21
+
22
+ body.dashboard_page_health-check #health-check-mail-check,
23
+ body.dashboard_page_health-check #health-check-file-integrity {
24
+ margin-bottom: 15px;
25
+ }
26
+
27
+ body.dashboard_page_health-check .pass:before,
28
+ body.dashboard_page_health-check .good:before {
29
+ content: "\f147";
30
+ display: inline-block;
31
+ color: #46b450;
32
+ font-family: dashicons;
33
+ }
34
+
35
+ body.dashboard_page_health-check .warning:before {
36
+ content: "\f460";
37
+ display: inline-block;
38
+ color: #ffb900;
39
+ font-family: dashicons;
40
+ }
41
+
42
+ body.dashboard_page_health-check .info:before {
43
+ content: "\f348";
44
+ display: inline-block;
45
+ color: #00a0d2;
46
+ font-family: dashicons;
47
+ }
48
+
49
+ body.dashboard_page_health-check .fail:before,
50
+ body.dashboard_page_health-check .error:before {
51
+ content: "\f335";
52
+ display: inline-block;
53
+ color: #dc3232;
54
+ font-family: dashicons;
55
+ }
56
+
57
+ .health-check-modal {
58
+ display: none;
59
+ position: fixed;
60
+ z-index: 1000;
61
+ padding-top: 100px;
62
+ left: 0;
63
+ top: 0;
64
+ width: 100%;
65
+ height: 100%;
66
+ overflow: auto;
67
+ background-color: rgb(0,0,0);
68
+ background-color: rgba(0,0,0,0.4);
69
+ }
70
+ .health-check-modal.show {
71
+ display: block;
72
+ }
73
+
74
+ .health-check-modal .modal-content {
75
+ background-color: #fefefe;
76
+ margin: auto;
77
+ padding: 20px;
78
+ border: 1px solid #888;
79
+ width: 30%;
80
+ }
81
+
82
+ .health-check-modal .modal-content .modal-close {
83
+ color: #aaaaaa;
84
+ float: right;
85
+ font-size: 28px;
86
+ font-weight: bold;
87
+ cursor: pointer;
88
+ }
89
+
90
+ .health-check-modal .modal-content #dynamic-content {
91
+ display: block;
92
+ width: 100%;
93
+ }
94
+
95
+ .health-check-modal .modal-close:hover,
96
+ .health-check-modal .modal-close:focus {
97
+ color: #aaaaaa;
98
+ float: right;
99
+ font-size: 28px;
100
+ font-weight: bold;
101
+ }
102
+
103
+ body.dashboard_page_health-check #health-check-diff-modal {
104
+ width: 100vw;
105
+ height: 100%;
106
+ position: fixed;
107
+ display: block;
108
+ top: 0;
109
+ left: 0;
110
+ background: rgba(0,0,0,0.7);
111
+ display: none;
112
+ z-index: 99999;
113
+ }
114
+
115
+ body.dashboard_page_health-check #health-check-diff-modal #health-check-diff-modal-content {
116
+ background: #fff;
117
+ height: calc( 100% - 120px );
118
+ width: calc( 100% - 120px );
119
+ margin-top: 40px;
120
+ margin-left: 40px;
121
+ padding: 20px;
122
+ display: block;
123
+ }
124
+
125
+ body.dashboard_page_health-check #health-check-diff-modal #health-check-diff-modal-diff {
126
+ width: 100%;
127
+ height: calc( 100% - 80px );
128
+ overflow-y: auto;
129
+ display: block;
130
+ position: relative;
131
+ }
132
+
133
+ body.dashboard_page_health-check #health-check-diff-modal #health-check-diff-modal-diff table.diff td:nth-child(2) {
134
+ background: #f3f3f3;
135
+ }
136
+
137
+
138
+ body.dashboard_page_health-check #health-check-diff-modal-close-ref {
139
+ position: relative;
140
+ display: block;
141
+ float: right;
142
+ color: #000;
143
+ text-decoration: none;
144
+ }
145
+
146
+ body.dashboard_page_health-check #health-check-diff-modal #health-check-diff-modal-content .spinner,
147
+ body.dashboard_page_health-check #tools-response-holder .spinner {
148
+ float: none;
149
+ }
assets/javascript/health-check.js ADDED
@@ -0,0 +1,180 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ jQuery(document).ready(function ($) {
2
+ function health_check_failure_modal( markup, action, parent ) {
3
+ $("#dynamic-content").html( markup );
4
+ $(".health-check-modal").data( 'modal-action', action ).data( 'parent-field', parent ).show();
5
+ }
6
+
7
+ function health_check_failure_modal_close( modal ) {
8
+ modal.hide();
9
+ }
10
+
11
+ $(".modal-close").click(function (e) {
12
+ e.preventDefault();
13
+ health_check_failure_modal_close( $(this).closest('.health-check-modal') );
14
+ });
15
+
16
+ $(".health-check-toc").click(function (e) {
17
+ e.preventDefault();
18
+
19
+ // Remove the height of the admin bar, and an extra 10px for better positioning.
20
+ var offset = $( $(this).attr('href') ).offset().top - $("#wpadminbar").height() - 10;
21
+
22
+ $('html, body').animate({
23
+ scrollTop: offset
24
+ }, 1200);
25
+ });
26
+
27
+ $("#loopback-no-plugins").click(function (e) {
28
+ var $trigger = $(this),
29
+ $parent = $(this).closest('td');
30
+
31
+ $(this).html( '<span class="spinner" style="visibility: visible;"></span> ' + health_check.string.please_wait );
32
+
33
+ e.preventDefault();
34
+
35
+ var data = {
36
+ action: 'health-check-loopback-no-plugins'
37
+ };
38
+
39
+ $.post(
40
+ ajaxurl,
41
+ data,
42
+ function (response) {
43
+ $trigger.remove();
44
+ if ( true === response.success ) {
45
+ $parent.append(response.data.message);
46
+ } else {
47
+ health_check_failure_modal( response.data, data.action, $parent );
48
+ }
49
+ },
50
+ 'json'
51
+ )
52
+ });
53
+
54
+ $(".dashboard_page_health-check").on('click', '#loopback-individual-plugins', function (e) {
55
+ var $trigger = $(this),
56
+ $parent = $(this).closest('td');
57
+
58
+ $(this).html( '<span class="spinner" style="visibility: visible;"></span> ' + health_check.string.please_wait );
59
+
60
+ e.preventDefault();
61
+
62
+ var data = {
63
+ action: 'health-check-loopback-individual-plugins'
64
+ };
65
+
66
+ $.post(
67
+ ajaxurl,
68
+ data,
69
+ function (response) {
70
+ $trigger.remove();
71
+ if ( true === response.success ) {
72
+ $parent.append(response.data.message);
73
+ } else {
74
+ health_check_failure_modal( response.data, data.action, $parent );
75
+ }
76
+ },
77
+ 'json'
78
+ )
79
+ });
80
+
81
+ $(".health-check-modal").on('submit', 'form', function (e) {
82
+ var data = $(this).serializeArray(),
83
+ modal = $(this).closest('.health-check-modal');
84
+
85
+ e.preventDefault();
86
+
87
+ $.post(
88
+ ajaxurl,
89
+ data,
90
+ function (response) {
91
+ if ( true === response.success ) {
92
+ $( modal.data('parent-field') ).append(response.data.message);
93
+ } else {
94
+ health_check_failure_modal( response.data.message, data.action, modal.data('parent-field') );
95
+ }
96
+ }
97
+ );
98
+
99
+ health_check_failure_modal_close( modal );
100
+ });
101
+
102
+ $(".health-check-copy-field").click(function (e) {
103
+ e.preventDefault();
104
+
105
+ var $textarea = $( 'textarea', $(this).closest('div') ),
106
+ $button = $(this);
107
+
108
+ $textarea.select();
109
+
110
+ var copied = document.execCommand( 'copy' );
111
+ if ( copied ) {
112
+ $button.text( health_check.string.copied );
113
+ }
114
+ });
115
+
116
+ $( '#health-check-file-integrity' ).submit( function( e ) {
117
+ e.preventDefault();
118
+ $( '#tools-response-holder' ).html( '<span class="spinner"></span>' );
119
+ $( '#tools-response-holder .spinner' ).addClass( 'is-active' );
120
+
121
+ var data = {
122
+ 'action': 'health-check-files-integrity-check'
123
+ };
124
+
125
+ $.post(
126
+ ajaxurl,
127
+ data,
128
+ function( response ) {
129
+ $( '#tools-response-holder .spinner' ).removeClass( 'is-active' );
130
+ $( '#tools-response-holder').html( response.data.message );
131
+ });
132
+ });
133
+
134
+ $( '#health-check-mail-check' ).submit( function( e ) {
135
+ e.preventDefault();
136
+ var email = $('#health-check-mail-check #email').val();
137
+ $( '#tools-response-holder' ).html( '<span class="spinner"></span>' );
138
+ $( '#tools-response-holder .spinner' ).addClass( 'is-active' );
139
+
140
+ var data = {
141
+ 'action': 'health-check-mail-check',
142
+ 'email' : email
143
+ };
144
+
145
+ $.post(
146
+ ajaxurl,
147
+ data,
148
+ function( response ) {
149
+ $( '#tools-response-holder .spinner' ).removeClass( 'is-active' );
150
+ $( '#tools-response-holder').html( response.data.message );
151
+ });
152
+ });
153
+
154
+ $( '#tools-response-holder' ).on( 'click', 'a[href="#health-check-diff"]', function( e ) {
155
+ e.preventDefault();
156
+ var file = $( this ).data('file');
157
+ $( '#health-check-diff-modal' ).toggle();
158
+ $( '#health-check-diff-modal #health-check-diff-modal-content .spinner' ).addClass( 'is-active' );
159
+
160
+ var data = {
161
+ 'action': 'health-check-view-file-diff',
162
+ 'file' : file
163
+ };
164
+
165
+ $.post(
166
+ ajaxurl,
167
+ data,
168
+ function( response ) {
169
+ $( '#health-check-diff-modal #health-check-diff-modal-diff' ).html( response.data.message );
170
+ $( '#health-check-diff-modal #health-check-diff-modal-content h3' ).html( file );
171
+ $( '#health-check-diff-modal #health-check-diff-modal-content .spinner' ).removeClass( 'is-active' );
172
+ });
173
+ });
174
+
175
+ $( '#health-check-diff-modal' ).on( 'click', 'a[href="#health-check-diff-modal-close"]', function( e ) {
176
+ e.preventDefault();
177
+ $( '#health-check-diff-modal' ).toggle();
178
+ });
179
+
180
+ });
assets/mu-plugin/health-check-disable-plugins.php ADDED
@@ -0,0 +1,598 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Plugin Name: Health Check Disable Plugins
4
+ Description: Conditionally disabled plugins on your site for a given session, used to rule out plugin interactions during troubleshooting.
5
+ Version: 1.3
6
+ */
7
+
8
+ if ( ! defined( 'ABSPATH' ) ) {
9
+ die( 'We\'re sorry, but you can not directly access this file.' );
10
+ }
11
+
12
+ class Health_Check_Troubleshooting_MU {
13
+ private $override_active = true;
14
+ private $default_theme = true;
15
+ private $active_plugins = array();
16
+
17
+ private $available_query_args = array(
18
+ 'health-check-disable-plugins',
19
+ 'health-check-disable-plugins-hash',
20
+ 'health-check-disable-troubleshooting',
21
+ 'health-check-toggle-default-theme',
22
+ 'health-check-troubleshoot-enable-plugin',
23
+ 'health-check-troubleshoot-disable-plugin',
24
+ );
25
+
26
+ private $default_themes = array(
27
+ 'twentyseventeen',
28
+ 'twentysixteen',
29
+ 'twentyfifteen',
30
+ 'twentyfourteen',
31
+ 'twentythirteen',
32
+ 'twentytwelve',
33
+ 'twentyeleven',
34
+ 'twentyten',
35
+ );
36
+
37
+ /**
38
+ * Health_Check_Troubleshooting_MU constructor.
39
+ */
40
+ public function __construct() {
41
+ $this->init();
42
+ }
43
+
44
+ /**
45
+ * Actually initiation of the plugin.
46
+ *
47
+ * @return void
48
+ */
49
+ public function init() {
50
+ add_action( 'admin_bar_menu', array( $this, 'health_check_troubleshoot_menu_bar' ), 999 );
51
+
52
+ add_filter( 'option_active_plugins', array( $this, 'health_check_loopback_test_disable_plugins' ) );
53
+ add_filter( 'option_active_sitewide_plugins', array( $this, 'health_check_loopback_test_disable_plugins' ) );
54
+
55
+ add_filter( 'stylesheet', array( $this, 'health_check_troubleshoot_theme' ) );
56
+ add_filter( 'template', array( $this, 'health_check_troubleshoot_theme' ) );
57
+
58
+ add_action( 'admin_notices', array( $this, 'plugin_list_admin_notice' ) );
59
+ add_action( 'admin_notices', array( $this, 'prompt_install_default_theme' ) );
60
+ add_filter( 'user_has_cap', array( $this, 'remove_plugin_theme_install' ) );
61
+
62
+ add_action( 'plugin_action_links', array( $this, 'plugin_actions' ), 50, 4 );
63
+
64
+ add_action( 'wp_logout', array( $this, 'health_check_troubleshooter_mode_logout' ) );
65
+ add_action( 'init', array( $this, 'health_check_troubleshoot_get_captures' ) );
66
+
67
+ /*
68
+ * Plugin activations can be forced by other tools in things like themes, so let's
69
+ * attempt to work around that by forcing plugin lists back and forth.
70
+ *
71
+ * This is not an ideal scenario, but one we must accept as reality.
72
+ */
73
+ add_action( 'activated_plugin', array( $this, 'plugin_activated' ) );
74
+
75
+ $this->default_theme = ( 'yes' === get_option( 'health-check-default-theme', 'yes' ) ? true : false );
76
+ $this->active_plugins = $this->get_unfiltered_plugin_list();
77
+ }
78
+
79
+ /**
80
+ * Add a prompt to install a default theme.
81
+ *
82
+ * If no default theme exists, we can't reliably assert if an issue is
83
+ * caused by the theme. In these cases we should provide an easy step
84
+ * to get to, and install, one of the default themes.
85
+ *
86
+ * @return void
87
+ */
88
+ public function prompt_install_default_theme() {
89
+ if ( ! $this->is_troubleshooting() || $this->has_default_theme() ) {
90
+ return;
91
+ }
92
+
93
+ printf(
94
+ '<div class="notice notice-warning dismissable"><p>%s</p><p><a href="%s" class="button button-primary">%s</a></p></div>',
95
+ 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' ),
96
+ esc_url( admin_url( sprintf(
97
+ 'theme-install.php?theme=%s',
98
+ $this->default_themes[0]
99
+ ) ) ),
100
+ esc_html__( 'Install a default theme', 'health-check' )
101
+ );
102
+ }
103
+
104
+ /**
105
+ * Remove the `Add` option for plugins and themes.
106
+ *
107
+ * When troubleshooting, adding or changing themes and plugins can
108
+ * lead to unexpected results. Remove these menu items to make it less
109
+ * likely that a user breaks their site through these.
110
+ *
111
+ * @param array $caps Array containing the current users capabilities.
112
+ *
113
+ * @return array
114
+ */
115
+ public function remove_plugin_theme_install( $caps ) {
116
+ if ( ! $this->is_troubleshooting() ) {
117
+ return $caps;
118
+ }
119
+
120
+ $caps['switch_themes'] = false;
121
+
122
+ /*
123
+ * This is to early for `get_current_screen()`, so we have to do it the
124
+ * old fashioned way with `$_SERVER`.
125
+ */
126
+ if ( 'plugin-install.php' === substr( $_SERVER['REQUEST_URI'], -18 ) ) {
127
+ $caps['activate_plugins'] = false;
128
+ }
129
+
130
+ return $caps;
131
+ }
132
+
133
+ /**
134
+ * Fire on plugin activation.
135
+ *
136
+ * When in Troubleshooting Mode, plugin activations
137
+ * will clear out the DB entry for `active_plugins`, this is bad.
138
+ *
139
+ * We fix this by re-setting the DB entry if anything tries
140
+ * to modify it during troubleshooting.
141
+ *
142
+ * @return void
143
+ */
144
+ public function plugin_activated() {
145
+ if ( ! $this->is_troubleshooting() ) {
146
+ return;
147
+ }
148
+
149
+ // Force the database entry for active plugins if someone tried changing plugins while in Troubleshooting Mode.
150
+ update_option( 'active_plugins', $this->active_plugins );
151
+ }
152
+
153
+ /**
154
+ * Add a notice to the plugins screen.
155
+ *
156
+ * Make sure users are informed that all plugin actions are
157
+ * stripped away when they are troubleshooting.
158
+ *
159
+ * @return void
160
+ */
161
+ public function plugin_list_admin_notice() {
162
+ if ( ! $this->is_troubleshooting() ) {
163
+ return;
164
+ }
165
+ global $current_screen;
166
+
167
+ // Only output our notice on the plugins screen.
168
+ if ( 'plugins' !== $current_screen->base ) {
169
+ return;
170
+ }
171
+
172
+ printf(
173
+ '<div class="notice notice-warning"><p>%s</p></div>',
174
+ esc_html__( 'Plugin actions are not available while in Troubleshooting Mode.', 'health-check' )
175
+ );
176
+ }
177
+
178
+ /**
179
+ * Modify plugin actions.
180
+ *
181
+ * While in Troubleshooting Mode, weird things will happen if you start
182
+ * modifying your plugin list. Prevent this, but also add in the ability
183
+ * to enable or disable a plugin during troubleshooting from this screen.
184
+ *
185
+ * @param $actions
186
+ * @param $plugin_file
187
+ * @param $plugin_data
188
+ * @param $context
189
+ *
190
+ * @return array
191
+ */
192
+ public function plugin_actions( $actions, $plugin_file, $plugin_data, $context ) {
193
+ if ( ! $this->is_troubleshooting() ) {
194
+ return $actions;
195
+ }
196
+
197
+ if ( 'mustuse' === $context ) {
198
+ return $actions;
199
+ }
200
+
201
+ /*
202
+ * Disable all plugin actions when in Troubleshooting Mode.
203
+ *
204
+ * We intentionally remove all plugin actions to avoid accidental clicking, activating or deactivating plugins
205
+ * while our plugin is altering plugin data may lead to unexpected behaviors, so to keep things sane we do
206
+ * not allow users to perform any actions during this time.
207
+ */
208
+ $actions = array();
209
+
210
+ // This isn't an active plugin, so does not apply to our troubleshooting scenarios.
211
+ if ( ! in_array( $plugin_file, $this->active_plugins ) ) {
212
+ return $actions;
213
+ }
214
+
215
+ // Set a slug if the plugin lives in the plugins directory root.
216
+ if ( ! stristr( $plugin_file, '/' ) ) {
217
+ $plugin_data['slug'] = $plugin_file;
218
+ }
219
+
220
+ $allowed_plugins = get_option( 'health-check-allowed-plugins', array() );
221
+
222
+ $plugin_slug = ( isset( $plugin_data['slug'] ) ? $plugin_data['slug'] : sanitize_title( $plugin_data['Name'] ) );
223
+
224
+ if ( in_array( $plugin_slug, $allowed_plugins ) ) {
225
+ $actions['troubleshoot-disable'] = sprintf(
226
+ '<a href="%s">%s</a>',
227
+ esc_url( add_query_arg( array(
228
+ 'health-check-troubleshoot-disable-plugin' => $plugin_slug,
229
+ ), admin_url( 'plugins.php' ) ) ),
230
+ esc_html__( 'Disable while troubleshooting', 'health-check' )
231
+ );
232
+ } else {
233
+ $actions['troubleshoot-disable'] = sprintf(
234
+ '<a href="%s">%s</a>',
235
+ esc_url( add_query_arg( array(
236
+ 'health-check-troubleshoot-enable-plugin' => $plugin_slug,
237
+ ), admin_url( 'plugins.php' ) ) ),
238
+ esc_html__( 'Enable while troubleshooting', 'health-check' )
239
+ );
240
+ }
241
+
242
+ return $actions;
243
+ }
244
+
245
+ /**
246
+ * Get the actual list of active plugins.
247
+ *
248
+ * When in Troubleshooting Mode we override the list of plugins,
249
+ * this function lets us grab the active plugins list without
250
+ * any interference.
251
+ *
252
+ * @return array Array of active plugins.
253
+ */
254
+ private function get_unfiltered_plugin_list() {
255
+ $this->override_active = false;
256
+ $all_plugins = get_option( 'active_plugins' );
257
+ $this->override_active = true;
258
+
259
+ return $all_plugins;
260
+ }
261
+
262
+ /**
263
+ * Check if the user is currently in Troubleshooting Mode or not.
264
+ *
265
+ * @return bool
266
+ */
267
+ private function is_troubleshooting() {
268
+ // Check if a session cookie to disable plugins has been set.
269
+ if ( isset( $_COOKIE['health-check-disable-plugins'] ) ) {
270
+ $_GET['health-check-disable-plugin-hash'] = $_COOKIE['health-check-disable-plugins'];
271
+ }
272
+
273
+ // If the disable hash isn't set, no need to interact with things.
274
+ if ( ! isset( $_GET['health-check-disable-plugin-hash'] ) ) {
275
+ return false;
276
+ }
277
+
278
+ // If the plugin hash is not valid, we also break out
279
+ $disable_hash = get_option( 'health-check-disable-plugin-hash', '' );
280
+ if ( $disable_hash !== $_GET['health-check-disable-plugin-hash'] ) {
281
+ return false;
282
+ }
283
+
284
+ return true;
285
+ }
286
+
287
+ /**
288
+ * Filter the plugins that are activated in WordPress.
289
+ *
290
+ * @param array $plugins An array of plugins marked as active.
291
+ *
292
+ * @return array
293
+ */
294
+ function health_check_loopback_test_disable_plugins( $plugins ) {
295
+ if ( ! $this->is_troubleshooting() || ! $this->override_active ) {
296
+ return $plugins;
297
+ }
298
+
299
+ $allowed_plugins = get_option( 'health-check-allowed-plugins', array() );
300
+
301
+ // If we've received a comma-separated list of allowed plugins, we'll add them to the array of allowed plugins.
302
+ if ( isset( $_GET['health-check-allowed-plugins'] ) ) {
303
+ $allowed_plugins = explode( ',', $_GET['health-check-allowed-plugins'] );
304
+ }
305
+
306
+ foreach ( $plugins as $plugin_no => $plugin_path ) {
307
+ // Split up the plugin path, [0] is the slug and [1] holds the primary plugin file.
308
+ $plugin_parts = explode( '/', $plugin_path );
309
+
310
+ // We may want to allow individual, or groups of plugins, so introduce a skip-mechanic for those scenarios.
311
+ if ( in_array( $plugin_parts[0], $allowed_plugins ) ) {
312
+ continue;
313
+ }
314
+
315
+ // Remove the reference to this plugin.
316
+ unset( $plugins[ $plugin_no ] );
317
+ }
318
+
319
+ // Return a possibly modified list of activated plugins.
320
+ return $plugins;
321
+ }
322
+
323
+ /**
324
+ * Check if a default theme exists.
325
+ *
326
+ * If a default theme exists, return the most recent one, if not return `false`.
327
+ *
328
+ * @return bool|string
329
+ */
330
+ function has_default_theme() {
331
+ foreach ( $this->default_themes as $default_theme ) {
332
+ if ( $this->theme_exists( $default_theme ) ) {
333
+ return $default_theme;
334
+ }
335
+ }
336
+
337
+ return false;
338
+ }
339
+
340
+ /**
341
+ * Check if a theme exists by looking for the slug.
342
+ *
343
+ * @param string $theme_slug
344
+ *
345
+ * @return bool
346
+ */
347
+ function theme_exists( $theme_slug ) {
348
+ return is_dir( WP_CONTENT_DIR . '/themes/' . $theme_slug );
349
+ }
350
+
351
+ /**
352
+ * Check if theme overrides are active.
353
+ *
354
+ * @return bool
355
+ */
356
+ function override_theme() {
357
+ if ( ! $this->is_troubleshooting() ) {
358
+ return false;
359
+ }
360
+
361
+ if ( ! $this->override_active ) {
362
+ return false;
363
+ }
364
+
365
+ if ( ! $this->default_theme ) {
366
+ return false;
367
+ }
368
+
369
+ return true;
370
+ }
371
+
372
+ /**
373
+ * Use a default theme.
374
+ *
375
+ * Attempt to set one of the default themes as the active one
376
+ * during Troubleshooting Mode, if one exists, if not fall
377
+ * back to always showing the active theme.
378
+ *
379
+ * @param string $theme The users active theme slug.
380
+ *
381
+ * @return string Theme slug to be perceived as the active theme.
382
+ */
383
+ function health_check_troubleshoot_theme( $theme ) {
384
+ // Check if overrides are triggered if not break out.
385
+ if ( ! $this->override_theme() ) {
386
+ return $theme;
387
+ }
388
+
389
+ // Check if a default theme exists, and if so use it.
390
+ $default_theme = $this->has_default_theme();
391
+ if ( $default_theme ) {
392
+ $theme = $default_theme;
393
+ }
394
+
395
+ return $theme;
396
+ }
397
+
398
+ /**
399
+ * Disable Troubleshooting Mode on logout.
400
+ *
401
+ * If logged in, disable the Troubleshooting Mode when the logout
402
+ * event is fired, this ensures we start with a clean slate on
403
+ * the next login.
404
+ *
405
+ * @return void
406
+ */
407
+ function health_check_troubleshooter_mode_logout() {
408
+ if ( ! $this->is_troubleshooting() ) {
409
+ return;
410
+ }
411
+
412
+ if ( isset( $_COOKIE['health-check-disable-plugins'] ) ) {
413
+ unset( $_COOKIE['health-check-disable-plugins'] );
414
+ setcookie( 'health-check-disable-plugins', null, 0, COOKIEPATH, COOKIE_DOMAIN );
415
+ delete_option( 'health-check-allowed-plugins' );
416
+ }
417
+ }
418
+
419
+ /**
420
+ * Catch query arguments.
421
+ *
422
+ * When in Troubleshooting Mode, look for various GET variables that trigger
423
+ * various plugin actions.
424
+ *
425
+ * @return void
426
+ */
427
+ function health_check_troubleshoot_get_captures() {
428
+ if ( ! $this->is_troubleshooting() ) {
429
+ return;
430
+ }
431
+
432
+ // Disable Troubleshooting Mode.
433
+ if ( isset( $_GET['health-check-disable-troubleshooting'] ) ) {
434
+ unset( $_COOKIE['health-check-disable-plugins'] );
435
+ setcookie( 'health-check-disable-plugins', null, 0, COOKIEPATH, COOKIE_DOMAIN );
436
+ delete_option( 'health-check-allowed-plugins' );
437
+
438
+ wp_redirect( remove_query_arg( $this->available_query_args ) );
439
+ die();
440
+ }
441
+
442
+ // Enable an individual plugin.
443
+ if ( isset( $_GET['health-check-troubleshoot-enable-plugin'] ) ) {
444
+ $allowed_plugins = get_option( 'health-check-allowed-plugins', array() );
445
+ $allowed_plugins[ $_GET['health-check-troubleshoot-enable-plugin'] ] = $_GET['health-check-troubleshoot-enable-plugin'];
446
+
447
+ update_option( 'health-check-allowed-plugins', $allowed_plugins );
448
+
449
+ wp_redirect( remove_query_arg( $this->available_query_args ) );
450
+ die();
451
+ }
452
+
453
+ // Disable an individual plugin.
454
+ if ( isset( $_GET['health-check-troubleshoot-disable-plugin'] ) ) {
455
+ $allowed_plugins = get_option( 'health-check-allowed-plugins', array() );
456
+ unset( $allowed_plugins[ $_GET['health-check-troubleshoot-disable-plugin'] ] );
457
+
458
+ update_option( 'health-check-allowed-plugins', $allowed_plugins );
459
+
460
+ wp_redirect( remove_query_arg( $this->available_query_args ) );
461
+ die();
462
+ }
463
+
464
+ // Toggle between the active theme and a default theme.
465
+ if ( isset( $_GET['health-check-toggle-default-theme'] ) ) {
466
+ if ( $this->default_theme ) {
467
+ update_option( 'health-check-default-theme', 'no' );
468
+ } else {
469
+ update_option( 'health-check-default-theme', 'yes' );
470
+ }
471
+
472
+ wp_redirect( remove_query_arg( $this->available_query_args ) );
473
+ die();
474
+ }
475
+ }
476
+
477
+ /**
478
+ * Extend the admin bar.
479
+ *
480
+ * When in Troubleshooting Mode, introduce a new element to the admin bar to show
481
+ * enabled and disabled plugins (if conditions are met), switch between themes
482
+ * and disable Troubleshooting Mode altogether.
483
+ *
484
+ * @param WP_Admin_Bar $wp_menu
485
+ *
486
+ * @return void
487
+ */
488
+ function health_check_troubleshoot_menu_bar( $wp_menu ) {
489
+ if ( ! $this->is_troubleshooting() ) {
490
+ return;
491
+ }
492
+
493
+ // Add top-level menu item.
494
+ $wp_menu->add_menu( array(
495
+ 'id' => 'health-check',
496
+ 'title' => esc_html__( 'Troubleshooting Mode', 'health-check' ),
497
+ ) );
498
+
499
+ $allowed_plugins = get_option( 'health-check-allowed-plugins', array() );
500
+
501
+ // Add a link to manage plugins if there are more than 20 set to be active.
502
+ if ( count( $allowed_plugins ) > 20 ) {
503
+ $wp_menu->add_node( array(
504
+ 'id' => 'health-check-plugins',
505
+ 'title' => esc_html__( 'Manage active plugins', 'health-check' ),
506
+ 'parent' => 'health-check',
507
+ 'href' => admin_url( 'plugins.php' ),
508
+ ) );
509
+ } else {
510
+ $wp_menu->add_node( array(
511
+ 'id' => 'health-check-plugins',
512
+ 'title' => esc_html__( 'Plugins', 'health-check' ),
513
+ 'parent' => 'health-check',
514
+ ) );
515
+
516
+ $wp_menu->add_group( array(
517
+ 'id' => 'health-check-plugins-enabled',
518
+ 'parent' => 'health-check-plugins',
519
+ ) );
520
+ $wp_menu->add_group( array(
521
+ 'id' => 'health-check-plugins-disabled',
522
+ 'parent' => 'health-check-plugins',
523
+ ) );
524
+
525
+ foreach ( $this->active_plugins as $single_plugin ) {
526
+ $plugin_slug = explode( '/', $single_plugin );
527
+ $plugin_slug = $plugin_slug[0];
528
+
529
+ $enabled = true;
530
+
531
+ if ( in_array( $plugin_slug, $allowed_plugins ) ) {
532
+ $label = sprintf(
533
+ // Translators: %s: Plugin slug.
534
+ esc_html__( 'Disable %s', 'health-check' ),
535
+ sprintf(
536
+ '<strong>%s</strong>',
537
+ $plugin_slug
538
+ )
539
+ );
540
+ $url = add_query_arg( array( 'health-check-troubleshoot-disable-plugin' => $plugin_slug ) );
541
+ } else {
542
+ $enabled = false;
543
+ $label = sprintf(
544
+ // Translators: %s: Plugin slug.
545
+ esc_html__( 'Enable %s', 'health-check' ),
546
+ sprintf(
547
+ '<strong>%s</strong>',
548
+ $plugin_slug
549
+ )
550
+ );
551
+ $url = add_query_arg( array( 'health-check-troubleshoot-enable-plugin' => $plugin_slug ) );
552
+ }
553
+
554
+ $wp_menu->add_node( array(
555
+ 'id' => sprintf(
556
+ 'health-check-plugin-%s',
557
+ $plugin_slug
558
+ ),
559
+ 'title' => $label,
560
+ 'parent' => ( $enabled ? 'health-check-plugins-enabled' : 'health-check-plugins-disabled' ),
561
+ 'href' => $url,
562
+ ) );
563
+ }
564
+ }
565
+
566
+ $wp_menu->add_group( array(
567
+ 'id' => 'health-check-theme',
568
+ 'parent' => 'health-check',
569
+ ) );
570
+
571
+ // Check if a default theme exists before we add a menu item to toggle it.
572
+ if ( $this->has_default_theme() ) {
573
+ // Add a link to switch between active themes.
574
+ $wp_menu->add_node( array(
575
+ 'id' => 'health-check-default-theme',
576
+ 'title' => ( $this->default_theme ? esc_html__( 'Use your current theme', 'health-check' ) : esc_html__( 'Use a default theme', 'health-check' ) ),
577
+ 'parent' => 'health-check-theme',
578
+ 'href' => add_query_arg( array( 'health-check-toggle-default-theme' => true ) ),
579
+ ) );
580
+ }
581
+
582
+ $wp_menu->add_group( array(
583
+ 'id' => 'health-check-status',
584
+ 'parent' => 'health-check',
585
+ ) );
586
+
587
+ // Add a link to disable Troubleshooting Mode.
588
+ $wp_menu->add_node( array(
589
+ 'id' => 'health-check-disable',
590
+ 'title' => esc_html__( 'Disable Troubleshooting Mode', 'health-check' ),
591
+ 'parent' => 'health-check-status',
592
+ 'href' => add_query_arg( array( 'health-check-disable-troubleshooting' => true ) ),
593
+ ) );
594
+ }
595
+
596
+ }
597
+
598
+ new Health_Check_Troubleshooting_MU();
changelog.txt ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ = v 0.7.0 =
2
+ * Troubleshooting mode now also switches to a default theme.
3
+ * Introduced a method for toggling default or active theme use when in troubleshooting mode.
4
+ * Introduced a method for enabling/disabling plugins while in troubleshooting mode.
5
+ * Introduced a method for disabling troubleshooting mode without needing to log out and back in again.
6
+
7
+ = v 0.6.0 =
8
+ * Improved loopback tests
9
+ * Check if loopbacks can be completed without plugins activated
10
+ * Test individual plugins to identify loopback blockers
11
+ * Add troubleshooting mode, test your website without any plugins for your session without disabling functionality for visitors.
12
+
13
+ = v 0.5.1 =
14
+ * Introduced loopback check to the health checker status.
15
+
16
+ = v 0.5.0 =
17
+ * Added clarity to many text strings.
18
+ * Avoid listing MU directories if it's not being used.
19
+ * Add a Table of Contents heading and make navigating the debug page from it smoother.
20
+ * Only enqueue our CSS and JavaScript if we are on the health check pages.
21
+ * Add some missing version numbers nor being included in text strings.
22
+ * Avoid fatal errors if accessing files directly, caused by translation functions being used when they don't exist.
23
+ * Avoid "empty" strings when author or version is missing from plugins or themes.
24
+ * Make the health checker test background updates.
25
+ * Make the health checker look for missed scheduled events.
26
+ * If using a localized version of WordPress, also display the copy and paste field in English if using an international support resource.
27
+ * Indicate if 64bit values are supported by PHP in the debug section.
28
+ * Improved MariaDB version detection/comparison.
29
+
30
+ = v 0.4.1 =
31
+ * Better SQL version detection to account for MariaDB versions
32
+ * Added translation support
33
+ * Removed unintentional indentations in the debug copying field
34
+
35
+ = v 0.4 =
36
+ * Added debug section
37
+ * Added PHP info section
38
+ * Cleaned up the health check
39
+ * Added WordPress.org connectivity check
40
+ * Added HTTPS check
41
+
42
+ = v 0.3.1 =
43
+ * Fixed a few typos
44
+
45
+ = v 0.3 =
46
+ * Added recommended PHP and MySQL versions
47
+ * Check for utf8mb4 support
48
+ * Fixed a bunch of PHP warnings
49
+
50
+ = v 0.2.1 =
51
+ * Fixed version comparision bug - When the server had the exact required versions we reported it as out of date.
52
+
53
+ = v 0.2 =
54
+ * Updated with actual PHP and MySQL version requirements for WordPress 3.2
55
+
56
+ = v 0.1 =
57
+ * Initial release with checks for the PHP and MySQL versions we will likely target for WordPress 3.2
health-check.php ADDED
@@ -0,0 +1,471 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Plugins primary file, in charge of including all other dependencies.
4
+ *
5
+ * @package Health Check
6
+ *
7
+ * Plugin Name: Health Check
8
+ * Plugin URI: http://wordpress.org/plugins/health-check/
9
+ * Description: Checks the health of your WordPress install.
10
+ * Author: The WordPress.org community
11
+ * Version: 1.0.0
12
+ * Author URI: http://wordpress.org/plugins/health-check/
13
+ * Text Domain: health-check
14
+ */
15
+
16
+ // Check that the file is nto accessed directly.
17
+ if ( ! defined( 'ABSPATH' ) ) {
18
+ die( 'We\'re sorry, but you can not directly access this file.' );
19
+ }
20
+
21
+ // Set the minimum PHP version WordPress supports.
22
+ define( 'HEALTH_CHECK_PHP_MIN_VERSION', '5.2.4' );
23
+
24
+ // Set the lowest PHP version still receiving security updates.
25
+ define( 'HEALTH_CHECK_PHP_SUPPORTED_VERSION', '5.6' );
26
+
27
+ // Set the PHP version WordPress recommends.
28
+ define( 'HEALTH_CHECK_PHP_REC_VERSION', '7.2' );
29
+
30
+ // Set the minimum MySQL version WordPress supports.
31
+ define( 'HEALTH_CHECK_MYSQL_MIN_VERSION', '5.0' );
32
+
33
+ // Set the MySQL version WordPress recommends.
34
+ define( 'HEALTH_CHECK_MYSQL_REC_VERSION', '5.6' );
35
+
36
+ // Set the plugin version.
37
+ define( 'HEALTH_CHECK_PLUGIN_VERSION', '1.0.0' );
38
+
39
+ // Set the absolute path for the plugin.
40
+ define( 'HEALTH_CHECK_PLUGIN_DIRECTORY', plugin_dir_path( __FILE__ ) );
41
+
42
+ // Set the current cURL version.
43
+ define( 'HEALTH_CHECK_CURL_VERSION', '7.58' );
44
+
45
+ // Set the minimum cURL version that we've tested that core works with.
46
+ define( 'HEALTH_CHECK_CURL_MIN_VERSION', '7.38' );
47
+
48
+ /**
49
+ * Class HealthCheck
50
+ */
51
+ class HealthCheck {
52
+
53
+ /**
54
+ * Notices to show at the head of the admin screen.
55
+ *
56
+ * @access public
57
+ *
58
+ * @var array
59
+ */
60
+ public $admin_notices = array();
61
+
62
+ /**
63
+ * HealthCheck constructor.
64
+ *
65
+ * @uses HealthCheck::init()
66
+ *
67
+ * @return void
68
+ */
69
+ public function __construct() {
70
+ $this->init();
71
+ }
72
+
73
+ /**
74
+ * Plugin initiation.
75
+ *
76
+ * A helper function, called by `HealthCheck::__construct()` to initiate actions, hooks and other features needed.
77
+ *
78
+ * @uses add_action()
79
+ * @uses add_filter()
80
+ *
81
+ * @return void
82
+ */
83
+ public function init() {
84
+ add_action( 'plugins_loaded', array( $this, 'load_i18n' ) );
85
+
86
+ add_action( 'admin_menu', array( $this, 'action_admin_menu' ) );
87
+ add_filter( 'plugin_row_meta', array( $this, 'settings_link' ), 10, 2 );
88
+
89
+ add_filter( 'plugin_action_links', array( $this, 'troubeshoot_plugin_action' ), 20, 4 );
90
+
91
+ add_action( 'admin_footer', array( $this, 'show_backup_warning' ) );
92
+
93
+ add_action( 'admin_notices', array( $this, 'admin_notices' ) );
94
+
95
+ add_action( 'admin_enqueue_scripts', array( $this, 'enqueues' ) );
96
+
97
+ add_action( 'init', array( $this, 'start_troubleshoot_mode' ) );
98
+ add_action( 'load-plugins.php', array( $this, 'start_troubleshoot_single_plugin_mode' ) );
99
+
100
+ add_action( 'wp_ajax_health-check-loopback-no-plugins', array( 'Health_Check_Loopback', 'loopback_no_plugins' ) );
101
+ add_action( 'wp_ajax_health-check-loopback-individual-plugins', array( 'Health_Check_Loopback', 'loopback_test_individual_plugins' ) );
102
+ add_action( 'wp_ajax_health-check-files-integrity-check', array( 'Health_Check_Files_Integrity', 'run_files_integrity_check' ) );
103
+ add_action( 'wp_ajax_health-check-view-file-diff', array( 'Health_Check_Files_Integrity', 'view_file_diff' ) );
104
+ add_action( 'wp_ajax_health-check-mail-check', array( 'Mail_Check', 'run_mail_check' ) );
105
+ add_action( 'wp_ajax_health-check-confirm-warning', array( 'Health_Check_Troubleshoot', 'confirm_warning' ) );
106
+ }
107
+
108
+ /**
109
+ * Show a warning modal about keeping backups.
110
+ *
111
+ * @uses Health_Check_Troubleshoot::has_seen_warning()
112
+ *
113
+ * @return void
114
+ */
115
+ public function show_backup_warning() {
116
+ if ( Health_Check_Troubleshoot::has_seen_warning() ) {
117
+ return;
118
+ }
119
+
120
+ include_once( HEALTH_CHECK_PLUGIN_DIRECTORY . '/modals/backup-warning.php' );
121
+ }
122
+
123
+ /**
124
+ * Initiate troubleshooting mode.
125
+ *
126
+ * Catch when the troubleshooting form has been submitted, and appropriately set required options and cookies.
127
+ *
128
+ * @uses current_user_can()
129
+ * @uses md5()
130
+ * @uses rand()
131
+ * @uses update_option()
132
+ * @uses setcookie()
133
+ *
134
+ * @return void
135
+ */
136
+ public function start_troubleshoot_mode() {
137
+ if ( ! isset( $_POST['health-check-troubleshoot-mode'] ) || ! current_user_can( 'manage_options' ) ) {
138
+ return;
139
+ }
140
+
141
+ $loopback_hash = md5( rand() );
142
+ update_option( 'health-check-disable-plugin-hash', $loopback_hash );
143
+
144
+ setcookie( 'health-check-disable-plugins', $loopback_hash, 0, COOKIEPATH, COOKIE_DOMAIN );
145
+ }
146
+
147
+ /**
148
+ * Initiate troubleshooting mode for a specific plugin.
149
+ *
150
+ * Catch when the troubleshooting link on an individual plugin has been clicked, and appropriately sets the
151
+ * required options and cookies.
152
+ *
153
+ * @uses current_user_can()
154
+ * @uses md5()
155
+ * @uses rand()
156
+ * @uses update_option()
157
+ * @uses setcookie()
158
+ * @uses wp_redirect()
159
+ * @uses admin_url()
160
+ *
161
+ * @return void
162
+ */
163
+ public function start_troubleshoot_single_plugin_mode() {
164
+ if ( ! isset( $_GET['health-check-troubleshoot-plugin'] ) || ! current_user_can( 'manage_options' ) ) {
165
+ return;
166
+ }
167
+
168
+ ob_start();
169
+
170
+ $needs_credentials = false;
171
+
172
+ if ( ! Health_Check_Troubleshoot::mu_plugin_exists() ) {
173
+ if ( ! Health_Check_Troubleshoot::get_filesystem_credentials() ) {
174
+ $needs_credentials = true;
175
+ } else {
176
+ $check_output = Health_Check_Troubleshoot::setup_must_use_plugin( false );
177
+ if ( false === $check_output ) {
178
+ $needs_credentials = true;
179
+ }
180
+ }
181
+ } else {
182
+ if ( ! Health_Check_Troubleshoot::maybe_update_must_use_plugin() ) {
183
+ $needs_credentials = true;
184
+ }
185
+ }
186
+
187
+ $result = ob_get_clean();
188
+
189
+ if ( $needs_credentials ) {
190
+ $this->admin_notices[] = (object) array(
191
+ 'message' => $result,
192
+ 'type' => 'warning',
193
+ );
194
+ return;
195
+ }
196
+
197
+ $loopback_hash = md5( rand() );
198
+ update_option( 'health-check-disable-plugin-hash', $loopback_hash );
199
+
200
+ update_option( 'health-check-allowed-plugins', array( $_GET['health-check-troubleshoot-plugin'] => $_GET['health-check-troubleshoot-plugin'] ) );
201
+
202
+ setcookie( 'health-check-disable-plugins', $loopback_hash, 0, COOKIEPATH, COOKIE_DOMAIN );
203
+
204
+ wp_redirect( admin_url( 'plugins.php' ) );
205
+ }
206
+
207
+ /**
208
+ * Load translations.
209
+ *
210
+ * Loads the textdomain needed to get translations for our plugin.
211
+ *
212
+ * @uses load_plugin_textdomain()
213
+ * @uses basename()
214
+ * @uses dirname()
215
+ *
216
+ * @return void
217
+ */
218
+ public function load_i18n() {
219
+ load_plugin_textdomain( 'health-check', false, basename( dirname( __FILE__ ) ) . '/languages/' );
220
+ }
221
+
222
+ /**
223
+ * Enqueue assets.
224
+ *
225
+ * Conditionally enqueue our CSS and JavaScript when viewing plugin related pages in wp-admin.
226
+ *
227
+ * @uses wp_enqueue_style()
228
+ * @uses plugins_url()
229
+ * @uses wp_enqueue_script()
230
+ * @uses wp_localize_script()
231
+ * @uses esc_html__()
232
+ *
233
+ * @return void
234
+ */
235
+ public function enqueues() {
236
+ // Don't enqueue anything unless we're on the health check page
237
+ if ( ! isset( $_GET['page'] ) || 'health-check' !== $_GET['page'] ) {
238
+
239
+ /*
240
+ * Special consideration, if warnings are not dismissed we need to display
241
+ * our modal, and thus require our styles, in other locations, before bailing.
242
+ */
243
+ if ( ! Health_Check_Troubleshoot::has_seen_warning() ) {
244
+ wp_enqueue_style( 'health-check', plugins_url( '/assets/css/health-check.css', __FILE__ ), array(), HEALTH_CHECK_PLUGIN_VERSION );
245
+ }
246
+ return;
247
+ }
248
+
249
+ wp_enqueue_style( 'health-check', plugins_url( '/assets/css/health-check.css', __FILE__ ), array(), HEALTH_CHECK_PLUGIN_VERSION );
250
+
251
+ wp_enqueue_script( 'health-check', plugins_url( '/assets/javascript/health-check.js', __FILE__ ), array( 'jquery' ), HEALTH_CHECK_PLUGIN_VERSION, true );
252
+
253
+ wp_localize_script( 'health-check', 'health_check', array(
254
+ 'string' => array(
255
+ 'please_wait' => esc_html__( 'Please wait...', 'health-check' ),
256
+ 'copied' => esc_html__( 'Copied', 'health-check' ),
257
+ ),
258
+ 'warning' => array(
259
+ 'seen_backup' => Health_Check_Troubleshoot::has_seen_warning(),
260
+ ),
261
+ ) );
262
+ }
263
+
264
+ /**
265
+ * Add item to the admin menu.
266
+ *
267
+ * @uses add_dashboard_page()
268
+ * @uses __()
269
+ *
270
+ * @return void
271
+ */
272
+ public function action_admin_menu() {
273
+ add_dashboard_page( _x( 'Health Check', 'Menu, Section and Page Title', 'health-check' ), _x( 'Health Check', 'Menu, Section and Page Title', 'health-check' ), 'manage_options', 'health-check', array( $this, 'dashboard_page' ) );
274
+ }
275
+
276
+ /**
277
+ * Add a quick-access link under our plugin name on the plugins-list.
278
+ *
279
+ * @uses plugin_basename()
280
+ * @uses sprintf()
281
+ * @uses menu_page_url()
282
+ *
283
+ * @param array $meta An array containing meta links.
284
+ * @param string $name The plugin slug that these metas relate to.
285
+ *
286
+ * @return array
287
+ */
288
+ public function settings_link( $meta, $name ) {
289
+ if ( plugin_basename( __FILE__ ) === $name ) {
290
+ $meta[] = sprintf( '<a href="%s">' . _x( 'Health Check', 'Menu, Section and Page Title', 'health-check' ) . '</a>', menu_page_url( 'health-check', false ) );
291
+ }
292
+
293
+ return $meta;
294
+ }
295
+
296
+ /**
297
+ * Add a troubleshooting action link to plugins.
298
+ *
299
+ * @param $actions
300
+ * @param $plugin_file
301
+ * @param $plugin_data
302
+ * @param $context
303
+ *
304
+ * @return array
305
+ */
306
+ public function troubeshoot_plugin_action( $actions, $plugin_file, $plugin_data, $context ) {
307
+ // Don't add anything if this is a Must-Use plugin, we can't touch those.
308
+ if ( 'mustuse' === $context ) {
309
+ return $actions;
310
+ }
311
+
312
+ // Only add troubleshooting actions to active plugins.
313
+ if ( ! is_plugin_active( $plugin_file ) ) {
314
+ return $actions;
315
+ }
316
+
317
+ // Set a slug if the plugin lives in the plugins directory root.
318
+ if ( ! stristr( $plugin_file, '/' ) ) {
319
+ $plugin_data['slug'] = $plugin_file;
320
+ }
321
+
322
+ $actions['troubleshoot'] = sprintf(
323
+ '<a href="%s">%s</a>',
324
+ esc_url( add_query_arg( array(
325
+ 'health-check-troubleshoot-plugin' => ( isset( $plugin_data['slug'] ) ? $plugin_data['slug'] : sanitize_title( $plugin_data['Name'] ) ),
326
+ ), admin_url( 'plugins.php' ) ) ),
327
+ esc_html__( 'Troubleshoot', 'health-check' )
328
+ );
329
+
330
+ return $actions;
331
+ }
332
+
333
+ /**
334
+ * Render our admin page.
335
+ *
336
+ * @uses _e()
337
+ * @uses esc_html__()
338
+ * @uses printf()
339
+ * @uses sprintf()
340
+ * @uses menu_page_url()
341
+ * @uses dirname()
342
+ *
343
+ * @return void
344
+ */
345
+ public function dashboard_page() {
346
+ ?>
347
+ <div class="wrap">
348
+ <h1>
349
+ <?php _ex( 'Health Check', 'Menu, Section and Page Title', 'health-check' ); ?>
350
+ </h1>
351
+
352
+ <?php
353
+ $tabs = array(
354
+ 'health-check' => esc_html_x( 'Health Check', 'Menu, Section and Page Title', 'health-check' ),
355
+ 'debug' => esc_html__( 'Debug information', 'health-check' ),
356
+ 'troubleshoot' => esc_html__( 'Troubleshooting', 'health-check' ),
357
+ 'phpinfo' => esc_html__( 'PHP Information', 'health-check' ),
358
+ 'tools' => esc_html__( 'Tools', 'health-check' ),
359
+ );
360
+
361
+ $current_tab = ( isset( $_GET['tab'] ) ? $_GET['tab'] : 'health-check' );
362
+ ?>
363
+
364
+ <h2 class="nav-tab-wrapper wp-clearfix">
365
+ <?php
366
+ foreach ( $tabs as $tab => $label ) {
367
+ printf(
368
+ '<a href="%s" class="nav-tab %s">%s</a>',
369
+ sprintf(
370
+ '%s&tab=%s',
371
+ menu_page_url( 'health-check', false ),
372
+ $tab
373
+ ),
374
+ ( $current_tab === $tab ? 'nav-tab-active' : '' ),
375
+ $label
376
+ );
377
+ }
378
+ ?>
379
+ </h2>
380
+
381
+ <?php
382
+ switch ( $current_tab ) {
383
+ case 'debug':
384
+ include_once( dirname( __FILE__ ) . '/pages/debug-data.php' );
385
+ break;
386
+ case 'phpinfo':
387
+ include_once( dirname( __FILE__ ) . '/pages/phpinfo.php' );
388
+ break;
389
+ case 'troubleshoot':
390
+ include_once( dirname( __FILE__ ) . '/pages/troubleshoot.php' );
391
+ break;
392
+ case 'tools':
393
+ include_once( dirname( __FILE__ ) . '/pages/tools.php' );
394
+ break;
395
+ case 'health-check':
396
+ default:
397
+ include_once( dirname( __FILE__ ) . '/pages/health-check.php' );
398
+ }
399
+ ?>
400
+ </div>
401
+ <?php
402
+ }
403
+
404
+ /**
405
+ * Display styled admin notices.
406
+ *
407
+ * @uses printf()
408
+ *
409
+ * @param string $message A sanitized string containing our notice message.
410
+ * @param string $status A string representing the status type.
411
+ *
412
+ * @return void
413
+ */
414
+ static function display_notice( $message, $status = 'success' ) {
415
+ printf(
416
+ '<div class="notice notice-%s inline">',
417
+ $status
418
+ );
419
+
420
+ printf(
421
+ '<p>%s</p>',
422
+ $message
423
+ );
424
+
425
+ echo '</div>';
426
+ }
427
+
428
+ /**
429
+ * Display admin notices if we have any queued.
430
+ *
431
+ * @return void
432
+ */
433
+ public function admin_notices() {
434
+ foreach ( $this->admin_notices as $admin_notice ) {
435
+ printf(
436
+ '<div class="notice notice-%s"><p>%s</p></div>',
437
+ esc_attr( $admin_notice->type ),
438
+ $admin_notice->message
439
+ );
440
+ }
441
+ }
442
+
443
+ /**
444
+ * Perform a check to see is JSON is enabled.
445
+ *
446
+ * @uses extension_loaded()
447
+ * @uses function_Exists()
448
+ * @uses son_encode()
449
+ *
450
+ * @return bool
451
+ */
452
+ static function json_check() {
453
+ $extension_loaded = extension_loaded( 'json' );
454
+ $functions_exist = function_exists( 'json_encode' ) && function_exists( 'json_decode' );
455
+ $functions_work = function_exists( 'json_encode' ) && ( '' != json_encode( 'my test string' ) );
456
+
457
+ return $extension_loaded && $functions_exist && $functions_work;
458
+ }
459
+ }
460
+
461
+ // Include class-files used by our plugin.
462
+ require_once( dirname( __FILE__ ) . '/includes/class-health-check-auto-updates.php' );
463
+ require_once( dirname( __FILE__ ) . '/includes/class-health-check-wp-cron.php' );
464
+ require_once( dirname( __FILE__ ) . '/includes/class-health-check-debug-data.php' );
465
+ require_once( dirname( __FILE__ ) . '/includes/class-health-check-loopback.php' );
466
+ require_once( dirname( __FILE__ ) . '/includes/class-health-check-troubleshoot.php' );
467
+ require_once( dirname( __FILE__ ) . '/includes/class-health-check-files-integrity.php' );
468
+ require_once( dirname( __FILE__ ) . '/includes/class-health-check-mail-check.php' );
469
+
470
+ // Initialize our plugin.
471
+ new HealthCheck();
includes/class-health-check-auto-updates.php ADDED
@@ -0,0 +1,511 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Class for testing automatic updates in the WordPress code.
4
+ *
5
+ * @package Health Check
6
+ */
7
+
8
+ /**
9
+ * Class Health_Check_Auto_Updates
10
+ */
11
+ class Health_Check_Auto_Updates {
12
+ /**
13
+ * Health_Check_Auto_Updates constructor.
14
+ *
15
+ * @uses HealthCheck::init()
16
+ *
17
+ * @return void
18
+ */
19
+ public function __construct() {
20
+ $this->init();
21
+ }
22
+
23
+ /**
24
+ * Initiate the plugin class.
25
+ *
26
+ * @return void
27
+ */
28
+ public function init() {
29
+ include_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
30
+ }
31
+
32
+ /**
33
+ * Run tests to determine if auto-updates can run.
34
+ *
35
+ * @uses get_class_methods()
36
+ * @uses substr()
37
+ * @uses call_user_func()
38
+ *
39
+ * @return array
40
+ */
41
+ public function run_tests() {
42
+ $tests = array();
43
+
44
+ foreach ( get_class_methods( $this ) as $method ) {
45
+ if ( 'test_' !== substr( $method, 0, 5 ) ) {
46
+ continue;
47
+ }
48
+
49
+ $result = call_user_func( array( $this, $method ) );
50
+
51
+ if ( false === $result || null === $result ) {
52
+ continue;
53
+ }
54
+
55
+ $result = (object) $result;
56
+
57
+ if ( empty( $result->severity ) ) {
58
+ $result->severity = 'warning';
59
+ }
60
+
61
+ $tests[ $method ] = $result;
62
+ }
63
+
64
+ return $tests;
65
+ }
66
+
67
+ /**
68
+ * Test if file modifications are possible.
69
+ *
70
+ * @uses defined()
71
+ * @uses sprintf()
72
+ * @uses esc_html__()
73
+ *
74
+ * @return array
75
+ */
76
+ function test_constant_FILE_MODS() {
77
+ if ( defined( 'DISALLOW_FILE_MODS' ) && DISALLOW_FILE_MODS ) {
78
+ return array(
79
+ 'desc' => sprintf(
80
+ /* translators: %s: Name of the constant used. */
81
+ esc_html__( 'The %s constant is defined and enabled.', 'health-check' ),
82
+ '<code>DISALLOW_FILE_MODS</code>'
83
+ ),
84
+ 'severity' => 'fail',
85
+ );
86
+ }
87
+ }
88
+
89
+ /**
90
+ * Check if automatic updates are disabled with a constant.
91
+ *
92
+ * @uses defined()
93
+ * @uses sprintf()
94
+ * @uses esc_html__()
95
+ *
96
+ * @return array
97
+ */
98
+ function test_constant_AUTOMATIC_UPDATER_DISABLED() {
99
+ if ( defined( 'AUTOMATIC_UPDATER_DISABLED' ) && AUTOMATIC_UPDATER_DISABLED ) {
100
+ return array(
101
+ 'desc' => sprintf(
102
+ /* translators: %s: Name of the constant used. */
103
+ esc_html__( 'The %s constant is defined and enabled.', 'health-check' ),
104
+ '<code>AUTOMATIC_UPDATER_DISABLED</code>'
105
+ ),
106
+ 'severity' => 'fail',
107
+ );
108
+ }
109
+ }
110
+
111
+ /**
112
+ * Check if automatic core updates are disabled with a constant.
113
+ *
114
+ * @uses defined()
115
+ * @uses sprintf()
116
+ * @uses esc_html__()
117
+ *
118
+ * @return array
119
+ */
120
+ function test_constant_WP_AUTO_UPDATE_CORE() {
121
+ if ( defined( 'WP_AUTO_UPDATE_CORE' ) && false === WP_AUTO_UPDATE_CORE ) {
122
+ return array(
123
+ 'desc' => sprintf(
124
+ /* translators: %s: Name of the constant used. */
125
+ esc_html__( 'The %s constant is defined and enabled.', 'health-check' ),
126
+ '<code>WP_AUTO_UPDATE_CORE</code>'
127
+ ),
128
+ 'severity' => 'fail',
129
+ );
130
+ }
131
+ }
132
+
133
+ /**
134
+ * Check if updates are intercepted by a filter.
135
+ *
136
+ * @uses has_filter()
137
+ * @uses sprintf()
138
+ * @uses esc_html__()
139
+ *
140
+ * @return array
141
+ */
142
+ function test_wp_version_check_attached() {
143
+ if ( ! has_filter( 'wp_version_check', 'wp_version_check' ) ) {
144
+ return array(
145
+ 'desc' => sprintf(
146
+ /* translators: %s: Name of the filter used. */
147
+ esc_html__( 'A plugin has prevented updates by disabling %s.', 'health-check' ),
148
+ '<code>wp_version_check()</code>'
149
+ ),
150
+ 'severity' => 'fail',
151
+ );
152
+ }
153
+ }
154
+
155
+ /**
156
+ * Check if automatic updates are disabled by a filter.
157
+ *
158
+ * @uses apply_filters()
159
+ * @uses sprintf()
160
+ * @uses esc_html__()
161
+ *
162
+ * @return array
163
+ */
164
+ function test_filters_automatic_updater_disabled() {
165
+ if ( apply_filters( 'automatic_updater_disabled', false ) ) {
166
+ return array(
167
+ 'desc' => sprintf(
168
+ /* translators: %s: Name of the filter used. */
169
+ esc_html__( 'The %s filter is enabled.', 'health-check' ),
170
+ '<code>automatic_updater_disabled</code>'
171
+ ),
172
+ 'severity' => 'fail',
173
+ );
174
+ }
175
+ }
176
+
177
+ /**
178
+ * Check if automatic updates have tried to run, but failed, previously.
179
+ *
180
+ * @uses get_site_option()
181
+ * @uses esc_html__()
182
+ * @uses sprintf()
183
+ *
184
+ * @return array|bool
185
+ */
186
+ function test_if_failed_update() {
187
+ $failed = get_site_option( 'auto_core_update_failed' );
188
+
189
+ if ( ! $failed ) {
190
+ return false;
191
+ }
192
+
193
+ if ( ! empty( $failed['critical'] ) ) {
194
+ $desc = esc_html__( 'A previous automatic background update ended with a critical failure, so updates are now disabled.', 'health-check' );
195
+ $desc .= ' ' . esc_html__( 'You would have received an email because of this.', 'health-check' );
196
+ $desc .= ' ' . esc_html__( "When you've been able to update using the \"Update Now\" button on Dashboard > Updates, we'll clear this error for future update attempts.", 'health-check' );
197
+ $desc .= ' ' . sprintf(
198
+ /* translators: %s: Code of error shown. */
199
+ esc_html__( 'The error code was %s.', 'health-check' ),
200
+ '<code>' . $failed['error_code'] . '</code>'
201
+ );
202
+ return array(
203
+ 'desc' => $desc,
204
+ 'severity' => 'warning',
205
+ );
206
+ }
207
+
208
+ $desc = esc_html__( 'A previous automatic background update could not occur.', 'health-check' );
209
+ if ( empty( $failed['retry'] ) ) {
210
+ $desc .= ' ' . esc_html__( 'You would have received an email because of this.', 'health-check' );
211
+ }
212
+
213
+ $desc .= ' ' . esc_html__( "We'll try again with the next release.", 'health-check' );
214
+ $desc .= ' ' . sprintf(
215
+ /* translators: %s: Code of error shown. */
216
+ esc_html__( 'The error code was %s.', 'health-check' ),
217
+ '<code>' . $failed['error_code'] . '</code>'
218
+ );
219
+ return array(
220
+ 'desc' => $desc,
221
+ 'severity' => 'warning',
222
+ );
223
+ }
224
+
225
+ /**
226
+ * Check if WordPress is controlled by a VCS (Git, Subversion etc).
227
+ *
228
+ * @uses dirname()
229
+ * @uses array_unique()
230
+ * @uses is_dir()
231
+ * @uses rtrim()
232
+ * @uses apply_filters()
233
+ * @uses sprintf()
234
+ * @uses esc_html__()
235
+ *
236
+ * @param string $context The path to check from.
237
+ *
238
+ * @return array
239
+ */
240
+ function _test_is_vcs_checkout( $context ) {
241
+ $context_dirs = array( ABSPATH );
242
+ $vcs_dirs = array( '.svn', '.git', '.hg', '.bzr' );
243
+ $check_dirs = array();
244
+
245
+ foreach ( $context_dirs as $context_dir ) {
246
+ // Walk up from $context_dir to the root.
247
+ do {
248
+ $check_dirs[] = $context_dir;
249
+
250
+ // Once we've hit '/' or 'C:\', we need to stop. dirname will keep returning the input here.
251
+ if ( dirname( $context_dir ) == $context_dir ) {
252
+ break;
253
+ }
254
+
255
+ // Continue one level at a time.
256
+ } while ( $context_dir = dirname( $context_dir ) );
257
+ }
258
+
259
+ $check_dirs = array_unique( $check_dirs );
260
+
261
+ // Search all directories we've found for evidence of version control.
262
+ foreach ( $vcs_dirs as $vcs_dir ) {
263
+ foreach ( $check_dirs as $check_dir ) {
264
+ if ( $checkout = @is_dir( rtrim( $check_dir, '\\/' ) . "/$vcs_dir" ) ) {
265
+ break 2;
266
+ }
267
+ }
268
+ }
269
+
270
+ if ( $checkout && ! apply_filters( 'automatic_updates_is_vcs_checkout', true, $context ) ) {
271
+ return array(
272
+ 'desc' => sprintf(
273
+ // translators: %1$s: Folder name. %2$s: Version control directory. %3$s: Filter name.
274
+ esc_html__( 'The folder %1$s was detected as being under version control (%2$s), but the %3$s filter is allowing updates.', 'health-check' ),
275
+ '<code>' . $check_dir . '</code>',
276
+ "<code>$vcs_dir</code>",
277
+ '<code>automatic_updates_is_vcs_checkout</code>'
278
+ ),
279
+ 'severity' => 'info',
280
+ );
281
+ }
282
+
283
+ if ( $checkout ) {
284
+ return array(
285
+ 'desc' => sprintf(
286
+ // translators: %1$s: Folder name. %2$s: Version control directory.
287
+ esc_html__( 'The folder %1$s was detected as being under version control (%2$s).', 'health-check' ),
288
+ '<code>' . $check_dir . '</code>',
289
+ "<code>$vcs_dir</code>"
290
+ ),
291
+ 'severity' => 'fail',
292
+ );
293
+ }
294
+
295
+ return array(
296
+ 'desc' => esc_html__( 'No version control systems were detected.', 'health-check' ),
297
+ 'severity' => 'pass',
298
+ );
299
+ }
300
+
301
+ /**
302
+ * Check if the absolute path is under Version Control.
303
+ *
304
+ * @uses Health_Check_Auto_Updates::_test_is_vcs_checkout()
305
+ *
306
+ * @return array
307
+ */
308
+ function test_vcs_ABSPATH() {
309
+ $result = $this->_test_is_vcs_checkout( ABSPATH );
310
+ return $result;
311
+ }
312
+
313
+ /**
314
+ * Check if we can access files without providing credentials.
315
+ *
316
+ * @uses Automatic_Upgrader_Skin
317
+ * @uses Automatic_Upgrader_Skin::request_filesystem_credentials()
318
+ * @uses esc_html__()
319
+ *
320
+ * @return array
321
+ */
322
+ function test_check_wp_filesystem_method() {
323
+ $skin = new Automatic_Upgrader_Skin;
324
+ $success = $skin->request_filesystem_credentials( false, ABSPATH );
325
+
326
+ if ( ! $success ) {
327
+ $desc = esc_html__( 'Your installation of WordPress prompts for FTP credentials to perform updates.', 'health-check' );
328
+ $desc .= ' ' . esc_html__( '(Your site is performing updates over FTP due to file ownership. Talk to your hosting company.)', 'health-check' );
329
+
330
+ return array(
331
+ 'desc' => $desc,
332
+ 'severity' => 'fail',
333
+ );
334
+ }
335
+
336
+ return array(
337
+ 'desc' => esc_html__( "Your installation of WordPress doesn't require FTP credentials to perform updates.", 'health-check' ),
338
+ 'severity' => 'pass',
339
+ );
340
+ }
341
+
342
+ /**
343
+ * Check if core files are writeable by the web user/group.
344
+ *
345
+ * @global $wp_filesystem
346
+ *
347
+ * @uses Automatic_Upgrader_Skin
348
+ * @uses Automatic_Upgrader_Skin::request_filesystem_credentials()
349
+ * @uses WP_Filesystem
350
+ * @uses WP_Filesystem::method
351
+ * @uses get_core_checksums()
352
+ * @uses strpos()
353
+ * @uses sprintf()
354
+ * @uses esc_html__()
355
+ * @uses array_keys()
356
+ * @uses substr()
357
+ * @uses file_exists()
358
+ * @uses is_writable()
359
+ * @uses count()
360
+ * @uses array_slice()
361
+ * @uses implode()
362
+ *
363
+ * @return array|bool
364
+ */
365
+ function test_all_files_writable() {
366
+ global $wp_filesystem;
367
+ include ABSPATH . WPINC . '/version.php'; // $wp_version; // x.y.z
368
+
369
+ $skin = new Automatic_Upgrader_Skin;
370
+ $success = $skin->request_filesystem_credentials( false, ABSPATH );
371
+
372
+ if ( ! $success ) {
373
+ return false;
374
+ }
375
+
376
+ WP_Filesystem();
377
+
378
+ if ( 'direct' != $wp_filesystem->method ) {
379
+ return false;
380
+ }
381
+
382
+ $checksums = get_core_checksums( $wp_version, 'en_US' );
383
+ $dev = ( false !== strpos( $wp_version, '-' ) );
384
+ // Get the last stable version's files and test against that
385
+ if ( ! $checksums && $dev ) {
386
+ $checksums = get_core_checksums( (float) $wp_version - 0.1, 'en_US' );
387
+ }
388
+
389
+ // There aren't always checksums for development releases, so just skip the test if we still can't find any
390
+ if ( ! $checksums && $dev ) {
391
+ return false;
392
+ }
393
+
394
+ if ( ! $checksums ) {
395
+ $desc = sprintf(
396
+ // translators: %s: WordPress version
397
+ esc_html__( "Couldn't retrieve a list of the checksums for WordPress %s.", 'health-check' ),
398
+ $wp_version
399
+ );
400
+ $desc .= ' ' . esc_html__( 'This could mean that connections are failing to WordPress.org.', 'health-check' );
401
+ return array(
402
+ 'desc' => $desc,
403
+ 'severity' => 'warning',
404
+ );
405
+ }
406
+
407
+ $unwritable_files = array();
408
+ foreach ( array_keys( $checksums ) as $file ) {
409
+ if ( 'wp-content' == substr( $file, 0, 10 ) ) {
410
+ continue;
411
+ }
412
+ if ( ! file_exists( ABSPATH . '/' . $file ) ) {
413
+ continue;
414
+ }
415
+ if ( ! is_writable( ABSPATH . '/' . $file ) ) {
416
+ $unwritable_files[] = $file;
417
+ }
418
+ }
419
+
420
+ if ( $unwritable_files ) {
421
+ if ( count( $unwritable_files ) > 20 ) {
422
+ $unwritable_files = array_slice( $unwritable_files, 0, 20 );
423
+ $unwritable_files[] = '...';
424
+ }
425
+ return array(
426
+ 'desc' => esc_html__( 'Some files are not writable by WordPress:', 'health-check' ) . ' <ul><li>' . implode( '</li><li>', $unwritable_files ) . '</li></ul>',
427
+ 'severity' => 'fail',
428
+ );
429
+ } else {
430
+ return array(
431
+ 'desc' => esc_html__( 'All of your WordPress files are writable.', 'health-check' ),
432
+ 'severity' => 'pass',
433
+ );
434
+ }
435
+ }
436
+
437
+ /**
438
+ * Check if the install is using a development branch and can use nightly packages.
439
+ *
440
+ * @uses strpos()
441
+ * @uses defined()
442
+ * @uses sprintf()
443
+ * @uses esc_html__()
444
+ * @uses apply_filters()
445
+ *
446
+ * @return array|bool
447
+ */
448
+ function test_accepts_dev_updates() {
449
+ include ABSPATH . WPINC . '/version.php'; // $wp_version; // x.y.z
450
+ // Only for dev versions
451
+ if ( false === strpos( $wp_version, '-' ) ) {
452
+ return false;
453
+ }
454
+
455
+ if ( defined( 'WP_AUTO_UPDATE_CORE' ) && ( 'minor' === WP_AUTO_UPDATE_CORE || false === WP_AUTO_UPDATE_CORE ) ) {
456
+ return array(
457
+ 'desc' => sprintf(
458
+ /* translators: %s: Name of the constant used. */
459
+ esc_html__( 'WordPress development updates are blocked by the %s constant.', 'health-check' ),
460
+ '<code>WP_AUTO_UPDATE_CORE</code>'
461
+ ),
462
+ 'severity' => 'fail',
463
+ );
464
+ }
465
+
466
+ if ( ! apply_filters( 'allow_dev_auto_core_updates', $wp_version ) ) {
467
+ return array(
468
+ 'desc' => sprintf(
469
+ /* translators: %s: Name of the filter used. */
470
+ esc_html__( 'WordPress development updates are blocked by the %s filter.', 'health-check' ),
471
+ '<code>allow_dev_auto_core_updates</code>'
472
+ ),
473
+ 'severity' => 'fail',
474
+ );
475
+ }
476
+ }
477
+
478
+ /**
479
+ * Check if the site supports automatic minor updates.
480
+ *
481
+ * @uses defined()
482
+ * @uses sprintf()
483
+ * @uses esc_html__()
484
+ * @uses apply_filters()
485
+ *
486
+ * @return array
487
+ */
488
+ function test_accepts_minor_updates() {
489
+ if ( defined( 'WP_AUTO_UPDATE_CORE' ) && false === WP_AUTO_UPDATE_CORE ) {
490
+ return array(
491
+ 'desc' => sprintf(
492
+ /* translators: %s: Name of the constant used. */
493
+ esc_html__( 'WordPress security and maintenance releases are blocked by %s.', 'health-check' ),
494
+ "<code>define( 'WP_AUTO_UPDATE_CORE', false );</code>"
495
+ ),
496
+ 'severity' => 'fail',
497
+ );
498
+ }
499
+
500
+ if ( ! apply_filters( 'allow_minor_auto_core_updates', true ) ) {
501
+ return array(
502
+ 'desc' => sprintf(
503
+ /* translators: %s: Name of the filter used. */
504
+ esc_html__( 'WordPress security and maintenance releases are blocked by the %s filter.', 'health-check' ),
505
+ '<code>allow_minor_auto_core_updates</code>'
506
+ ),
507
+ 'severity' => 'fail',
508
+ );
509
+ }
510
+ }
511
+ }
includes/class-health-check-debug-data.php ADDED
@@ -0,0 +1,660 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Class for providing debug data based on a users WordPress environment.
4
+ *
5
+ * @package Health Check
6
+ */
7
+
8
+ /**
9
+ * Class Health_Check_Debug_Data
10
+ */
11
+ class Health_Check_Debug_Data {
12
+
13
+ static function debug_data( $locale = null ) {
14
+ if ( ! empty( $locale ) ) {
15
+ // Change the language used for translations
16
+ if ( function_exists( 'switch_to_locale' ) ) {
17
+ $original_locale = get_locale();
18
+ $switched_locale = switch_to_locale( $locale );
19
+ }
20
+ }
21
+ global $wpdb;
22
+
23
+ $upload_dir = wp_upload_dir();
24
+ if ( file_exists( ABSPATH . 'wp-config.php' ) ) {
25
+ $wp_config_path = ABSPATH . 'wp-config.php';
26
+ } elseif ( @file_exists( dirname( ABSPATH ) . '/wp-config.php' ) && ! @file_exists( dirname( ABSPATH ) . '/wp-settings.php' ) ) {
27
+ $wp_config_path = dirname( ABSPATH ) . '/wp-config.php';
28
+ }
29
+
30
+ $info = array(
31
+ 'wp-core' => array(
32
+ 'label' => __( 'WordPress', 'health-check' ),
33
+ 'fields' => array(
34
+ array(
35
+ 'label' => __( 'Version', 'health-check' ),
36
+ 'value' => get_bloginfo( 'version' ),
37
+ ),
38
+ array(
39
+ 'label' => __( 'Language', 'health-check' ),
40
+ 'value' => ( ! empty( $locale ) ? $original_locale : get_locale() ),
41
+ ),
42
+ array(
43
+ 'label' => __( 'Home URL', 'health-check' ),
44
+ 'value' => get_bloginfo( 'url' ),
45
+ 'private' => true,
46
+ ),
47
+ array(
48
+ 'label' => __( 'Site URL', 'health-check' ),
49
+ 'value' => get_bloginfo( 'wpurl' ),
50
+ 'private' => true,
51
+ ),
52
+ array(
53
+ 'label' => __( 'Permalink structure', 'health-check' ),
54
+ 'value' => get_option( 'permalink_structure' ),
55
+ ),
56
+ array(
57
+ 'label' => __( 'Is this site using HTTPS?', 'health-check' ),
58
+ 'value' => ( is_ssl() ? __( 'Yes' ) : __( 'No' ) ),
59
+ ),
60
+ array(
61
+ 'label' => __( 'Can anyone register on this site?', 'health-check' ),
62
+ 'value' => ( get_option( 'users_can_register' ) ? __( 'Yes', 'health-check' ) : __( 'No', 'health-check' ) ),
63
+ ),
64
+ array(
65
+ 'label' => __( 'Default comment status', 'health-check' ),
66
+ 'value' => get_option( 'default_comment_status' ),
67
+ ),
68
+ array(
69
+ 'label' => __( 'Is this a multisite?', 'health-check' ),
70
+ 'value' => ( is_multisite() ? __( 'Yes', 'health-check' ) : __( 'No', 'health-check' ) ),
71
+ ),
72
+ ),
73
+ ),
74
+ 'wp-dropins' => array(
75
+ 'label' => __( 'Drop-ins', 'health-check' ),
76
+ 'description' => __( 'Drop-ins are single files that replace or enhance WordPress features in ways that are not possible for traditional plugins', 'health-check' ),
77
+ 'fields' => array(),
78
+ ),
79
+ 'wp-active-theme' => array(
80
+ 'label' => __( 'Active theme', 'health-check' ),
81
+ 'fields' => array(),
82
+ ),
83
+ 'wp-themes' => array(
84
+ 'label' => __( 'Other themes', 'health-check' ),
85
+ 'show_count' => true,
86
+ 'fields' => array(),
87
+ ),
88
+ 'wp-mu-plugins' => array(
89
+ 'label' => __( 'Must Use Plugins', 'health-check' ),
90
+ 'show_count' => true,
91
+ 'fields' => array(),
92
+ ),
93
+ 'wp-plugins-active' => array(
94
+ 'label' => __( 'Active Plugins', 'health-check' ),
95
+ 'show_count' => true,
96
+ 'fields' => array(),
97
+ ),
98
+ 'wp-plugins-inactive' => array(
99
+ 'label' => __( 'Inactive Plugins', 'health-check' ),
100
+ 'show_count' => true,
101
+ 'fields' => array(),
102
+ ),
103
+ 'wp-media' => array(
104
+ 'label' => __( 'Media handling', 'health-check' ),
105
+ 'fields' => array(),
106
+ ),
107
+ 'wp-server' => array(
108
+ 'label' => __( 'Server', 'health-check' ),
109
+ 'description' => __( 'The options shown below relate to your server setup. If changes are required, you may need your web host\'s assistance.', 'health-check' ),
110
+ 'fields' => array(),
111
+ ),
112
+ 'wp-database' => array(
113
+ 'label' => __( 'Database', 'health-check' ),
114
+ 'fields' => array(),
115
+ ),
116
+ 'wp-constants' => array(
117
+ 'label' => __( 'WordPress constants', 'health-check' ),
118
+ 'description' => __( 'These values represent values set in your websites code which affect WordPress in various ways that may be of importance when seeking help with your site.', 'health-check' ),
119
+ 'fields' => array(
120
+ array(
121
+ 'label' => 'ABSPATH',
122
+ 'value' => ( ! defined( 'ABSPATH' ) ? __( 'Undefined', 'health-check' ) : ABSPATH ),
123
+ ),
124
+ array(
125
+ 'label' => 'WP_HOME',
126
+ 'value' => ( ! defined( 'WP_HOME' ) ? __( 'Undefined', 'health-check' ) : WP_HOME ),
127
+ ),
128
+ array(
129
+ 'label' => 'WP_SITEURL',
130
+ 'value' => ( ! defined( 'WP_SITEURL' ) ? __( 'Undefined', 'health-check' ) : WP_SITEURL ),
131
+ ),
132
+ array(
133
+ 'label' => 'WP_DEBUG',
134
+ 'value' => ( ! defined( 'WP_DEBUG' ) ? __( 'Undefined', 'health-check' ) : ( WP_DEBUG ? __( 'Enabled', 'health-check' ) : __( 'Disabled', 'health-check' ) ) ),
135
+ ),
136
+ array(
137
+ 'label' => 'WP_MAX_MEMORY_LIMIT',
138
+ 'value' => ( ! defined( 'WP_MAX_MEMORY_LIMIT' ) ? __( 'Undefined', 'health-check' ) : WP_MAX_MEMORY_LIMIT ),
139
+ ),
140
+ array(
141
+ 'label' => 'WP_DEBUG_DISPLAY',
142
+ 'value' => ( ! defined( 'WP_DEBUG_DISPLAY' ) ? __( 'Undefined', 'health-check' ) : ( WP_DEBUG_DISPLAY ? __( 'Enabled', 'health-check' ) : __( 'Disabled', 'health-check' ) ) ),
143
+ ),
144
+ array(
145
+ 'label' => 'WP_DEBUG_LOG',
146
+ 'value' => ( ! defined( 'WP_DEBUG_LOG' ) ? __( 'Undefined', 'health-check' ) : ( WP_DEBUG_LOG ? __( 'Enabled', 'health-check' ) : __( 'Disabled', 'health-check' ) ) ),
147
+ ),
148
+ array(
149
+ 'label' => 'SCRIPT_DEBUG',
150
+ 'value' => ( ! defined( 'SCRIPT_DEBUG' ) ? __( 'Undefined', 'health-check' ) : ( SCRIPT_DEBUG ? __( 'Enabled', 'health-check' ) : __( 'Disabled', 'health-check' ) ) ),
151
+ ),
152
+ array(
153
+ 'label' => 'WP_CACHE',
154
+ 'value' => ( ! defined( 'WP_CACHE' ) ? __( 'Undefined', 'health-check' ) : ( WP_CACHE ? __( 'Enabled', 'health-check' ) : __( 'Disabled', 'health-check' ) ) ),
155
+ ),
156
+ array(
157
+ 'label' => 'CONCATENATE_SCRIPTS',
158
+ 'value' => ( ! defined( 'CONCATENATE_SCRIPTS' ) ? __( 'Undefined', 'health-check' ) : ( CONCATENATE_SCRIPTS ? __( 'Enabled', 'health-check' ) : __( 'Disabled', 'health-check' ) ) ),
159
+ ),
160
+ array(
161
+ 'label' => 'COMPRESS_SCRIPTS',
162
+ 'value' => ( ! defined( 'COMPRESS_SCRIPTS' ) ? __( 'Undefined', 'health-check' ) : ( COMPRESS_SCRIPTS ? __( 'Enabled', 'health-check' ) : __( 'Disabled', 'health-check' ) ) ),
163
+ ),
164
+ array(
165
+ 'label' => 'COMPRESS_CSS',
166
+ 'value' => ( ! defined( 'COMPRESS_CSS' ) ? __( 'Undefined', 'health-check' ) : ( COMPRESS_CSS ? __( 'Enabled', 'health-check' ) : __( 'Disabled', 'health-check' ) ) ),
167
+ ),
168
+ array(
169
+ 'label' => 'WP_LOCAL_DEV',
170
+ 'value' => ( ! defined( 'WP_LOCAL_DEV' ) ? __( 'Undefined', 'health-check' ) : ( WP_LOCAL_DEV ? __( 'Enabled', 'health-check' ) : __( 'Disabled', 'health-check' ) ) ),
171
+ ),
172
+ ),
173
+ ),
174
+ 'wp-filesystem' => array(
175
+ 'label' => __( 'Filesystem permissions', 'health-check' ),
176
+ 'description' => __( 'The status of various locations WordPress needs to write files in various scenarios.', 'health-check' ),
177
+ 'fields' => array(
178
+ array(
179
+ 'label' => __( 'The main WordPress directory', 'health-check' ),
180
+ 'value' => ( wp_is_writable( ABSPATH ) ? __( 'Writable', 'health-check' ) : __( 'Not writable', 'health-check' ) ),
181
+ ),
182
+ array(
183
+ 'label' => __( 'The wp-content directory', 'health-check' ),
184
+ 'value' => ( wp_is_writable( WP_CONTENT_DIR ) ? __( 'Writable', 'health-check' ) : __( 'Not writable', 'health-check' ) ),
185
+ ),
186
+ array(
187
+ 'label' => __( 'The uploads directory', 'health-check' ),
188
+ 'value' => ( wp_is_writable( $upload_dir['basedir'] ) ? __( 'Writable', 'health-check' ) : __( 'Not writable', 'health-check' ) ),
189
+ ),
190
+ array(
191
+ 'label' => __( 'The plugins directory', 'health-check' ),
192
+ 'value' => ( wp_is_writable( WP_PLUGIN_DIR ) ? __( 'Writable', 'health-check' ) : __( 'Not writable', 'health-check' ) ),
193
+ ),
194
+ array(
195
+ 'label' => __( 'The themes directory', 'health-check' ),
196
+ 'value' => ( wp_is_writable( get_template_directory() . '/..' ) ? __( 'Writable', 'health-check' ) : __( 'Not writable', 'health-check' ) ),
197
+ ),
198
+ ),
199
+ ),
200
+ );
201
+
202
+ if ( is_multisite() ) {
203
+ $network_query = new WP_Network_Query();
204
+ $network_ids = $network_query->query( array(
205
+ 'fields' => 'ids',
206
+ 'number' => 100,
207
+ 'no_found_rows' => false,
208
+ ) );
209
+
210
+ $site_count = 0;
211
+ foreach ( $network_ids as $network_id ) {
212
+ $site_count += get_blog_count( $network_id );
213
+ }
214
+
215
+ $info['wp-core']['fields'][] = array(
216
+ 'label' => __( 'User Count', 'health-check' ),
217
+ 'value' => get_user_count(),
218
+ );
219
+ $info['wp-core']['fields'][] = array(
220
+ 'label' => __( 'Site Count', 'health-check' ),
221
+ 'value' => $site_count,
222
+ );
223
+ $info['wp-core']['fields'][] = array(
224
+ 'label' => __( 'Network Count', 'health-check' ),
225
+ 'value' => $network_query->found_networks,
226
+ );
227
+ } else {
228
+ $user_count = count_users();
229
+
230
+ $info['wp-core']['fields'][] = array(
231
+ 'label' => __( 'User Count', 'health-check' ),
232
+ 'value' => $user_count['total_users'],
233
+ );
234
+ }
235
+
236
+ // WordPress features requiring processing.
237
+ $wp_dotorg = wp_remote_get( 'https://wordpress.org', array( 'timeout' => 10 ) );
238
+ if ( ! is_wp_error( $wp_dotorg ) ) {
239
+ $info['wp-core']['fields'][] = array(
240
+ 'label' => __( 'Communication with WordPress.org', 'health-check' ),
241
+ 'value' => sprintf(
242
+ __( 'WordPress.org is reachable', 'health-check' )
243
+ ),
244
+ );
245
+ } else {
246
+ $info['wp-core']['fields'][] = array(
247
+ 'label' => __( 'Communication with WordPress.org', 'health-check' ),
248
+ 'value' => sprintf(
249
+ // translators: %1$s: The IP address WordPress.org resolves to. %2$s: The error returned by the lookup.
250
+ __( 'Unable to reach WordPress.org at %1$s: %2$s', 'health-check' ),
251
+ gethostbyname( 'wordpress.org' ),
252
+ $wp_dotorg->get_error_message()
253
+ ),
254
+ );
255
+ }
256
+
257
+ $loopback = Health_Check_Loopback::can_perform_loopback();
258
+ $info['wp-core']['fields'][] = array(
259
+ 'label' => __( 'Create loopback requests', 'health-check' ),
260
+ 'value' => $loopback->message,
261
+ );
262
+
263
+ // Get drop-ins.
264
+ $dropins = get_dropins();
265
+ $dropin_description = _get_dropins();
266
+ foreach ( $dropins as $dropin_key => $dropin ) {
267
+ $info['wp-dropins']['fields'][] = array(
268
+ 'label' => $dropin_key,
269
+ 'value' => $dropin_description[ $dropin_key ][0],
270
+ );
271
+ }
272
+
273
+ // Populate the media fields.
274
+ $info['wp-media']['fields'][] = array(
275
+ 'label' => __( 'Active editor', 'health-check' ),
276
+ 'value' => _wp_image_editor_choose(),
277
+ );
278
+
279
+ // Get ImageMagic information, if available.
280
+ if ( class_exists( 'Imagick' ) ) {
281
+ // Save the Imagick instance for later use.
282
+ $imagick = new Imagick();
283
+ $imagick_version = $imagick->getVersion();
284
+ } else {
285
+ $imagick_version = 'Imagick not available';
286
+ }
287
+ $info['wp-media']['fields'][] = array(
288
+ 'label' => __( 'Imagick Module Version' ),
289
+ 'value' => ( is_array( $imagick_version ) ? $imagick_version['versionNumber'] : $imagick_version ),
290
+ );
291
+ $info['wp-media']['fields'][] = array(
292
+ 'label' => __( 'ImageMagick Version' ),
293
+ 'value' => ( is_array( $imagick_version ) ? $imagick_version['versionString'] : $imagick_version ),
294
+ );
295
+
296
+ // If Imagick is used as our editor, provide some more information about its limitations.
297
+ if ( 'WP_Image_Editor_Imagick' === _wp_image_editor_choose() && isset( $imagick ) && $imagick instanceof Imagick ) {
298
+ $limits = array(
299
+ 'area' => ( defined( 'imagick::RESOURCETYPE_AREA' ) ? size_format( $imagick->getResourceLimit( imagick::RESOURCETYPE_AREA ) ) : 'Not Available' ),
300
+ 'disk' => ( defined( 'imagick::RESOURCETYPE_DISK' ) ? $imagick->getResourceLimit( imagick::RESOURCETYPE_DISK ) : 'Not Available' ),
301
+ 'file' => ( defined( 'imagick::RESOURCETYPE_FILE' ) ? $imagick->getResourceLimit( imagick::RESOURCETYPE_FILE ) : 'Not Available' ),
302
+ 'map' => ( defined( 'imagick::RESOURCETYPE_MAP' ) ? size_format( $imagick->getResourceLimit( imagick::RESOURCETYPE_MAP ) ) : 'Not Available' ),
303
+ 'memory' => ( defined( 'imagick::RESOURCETYPE_MEMORY' ) ? size_format( $imagick->getResourceLimit( imagick::RESOURCETYPE_MEMORY ) ) : 'Not Available' ),
304
+ 'thread' => ( defined( 'imagick::RESOURCETYPE_THREAD' ) ? $imagick->getResourceLimit( imagick::RESOURCETYPE_THREAD ) : 'Not Available' ),
305
+ );
306
+
307
+ $info['wp-media']['fields'][] = array(
308
+ 'label' => __( 'Imagick Resource Limits', 'health-check' ),
309
+ 'value' => $limits,
310
+ );
311
+ }
312
+
313
+ // Get GD information, if available.
314
+ if ( function_exists( 'gd_info' ) ) {
315
+ $gd = gd_info();
316
+ } else {
317
+ $gd = false;
318
+ }
319
+ $info['wp-media']['fields'][] = array(
320
+ 'label' => __( 'GD Version' ),
321
+ 'value' => ( is_array( $gd ) ? $gd['GD Version'] : 'GD not available' ),
322
+ );
323
+
324
+ // Get Ghostscript information, if available.
325
+ if ( function_exists( 'exec' ) ) {
326
+ $gs = exec( 'gs --version' );
327
+ $gs = ( ! empty( $gs ) ? $gs : 'Not available' );
328
+ } else {
329
+ $gs = __( 'Unable to determine if Ghostscript is installed', 'health-check' );
330
+ }
331
+ $info['wp-media']['fields'][] = array(
332
+ 'label' => __( 'Ghostscript Version' ),
333
+ 'value' => $gs,
334
+ );
335
+
336
+ // Populate the server debug fields.
337
+ $info['wp-server']['fields'][] = array(
338
+ 'label' => __( 'Server architecture', 'health-check' ),
339
+ 'value' => ( ! function_exists( 'php_uname' ) ? __( 'Unable to determine server architecture', 'health-check' ) : sprintf( '%s %s %s', php_uname( 's' ), php_uname( 'r' ), php_uname( 'm' ) ) ),
340
+ );
341
+ $info['wp-server']['fields'][] = array(
342
+ 'label' => __( 'PHP Version', 'health-check' ),
343
+ 'value' => ( ! function_exists( 'phpversion' ) ? __( 'Unable to determine PHP version', 'health-check' ) : sprintf(
344
+ '%s %s',
345
+ phpversion(),
346
+ ( 64 === PHP_INT_SIZE * 8 ? __( '(Supports 64bit values)', 'health-check' ) : '' )
347
+ )
348
+ ),
349
+ );
350
+ $info['wp-server']['fields'][] = array(
351
+ 'label' => __( 'PHP SAPI', 'health-check' ),
352
+ 'value' => ( ! function_exists( 'php_sapi_name' ) ? __( 'Unable to determine PHP SAPI', 'health-check' ) : php_sapi_name() ),
353
+ );
354
+
355
+ if ( ! function_exists( 'ini_get' ) ) {
356
+ $info['wp-server']['fields'][] = array(
357
+ 'label' => __( 'Server settings', 'health-check' ),
358
+ 'value' => __( 'Unable to determine some settings as the ini_get() function has been disabled', 'health-check' ),
359
+ );
360
+ } else {
361
+ $info['wp-server']['fields'][] = array(
362
+ 'label' => __( 'PHP max input variables', 'health-check' ),
363
+ 'value' => ini_get( 'max_input_vars' ),
364
+ );
365
+ $info['wp-server']['fields'][] = array(
366
+ 'label' => __( 'PHP time limit', 'health-check' ),
367
+ 'value' => ini_get( 'max_execution_time' ),
368
+ );
369
+ $info['wp-server']['fields'][] = array(
370
+ 'label' => __( 'PHP memory limit', 'health-check' ),
371
+ 'value' => ini_get( 'memory_limit' ),
372
+ );
373
+ $info['wp-server']['fields'][] = array(
374
+ 'label' => __( 'Max input time', 'health-check' ),
375
+ 'value' => ini_get( 'max_input_time' ),
376
+ );
377
+ $info['wp-server']['fields'][] = array(
378
+ 'label' => __( 'Upload max filesize', 'health-check' ),
379
+ 'value' => ini_get( 'upload_max_filesize' ),
380
+ );
381
+ $info['wp-server']['fields'][] = array(
382
+ 'label' => __( 'PHP post max size', 'health-check' ),
383
+ 'value' => ini_get( 'post_max_size' ),
384
+ );
385
+ }
386
+
387
+ if ( function_exists( 'curl_version' ) ) {
388
+ $cURL = curl_version();
389
+ $info['wp-server']['fields'][] = array(
390
+ 'label' => __( 'cURL Version', 'health-check' ),
391
+ 'value' => sprintf( '%s %s', $cURL['version'], $cURL['ssl_version'] ),
392
+ );
393
+ } else {
394
+ $info['wp-server']['fields'][] = array(
395
+ 'label' => __( 'cURL Version', 'health-check' ),
396
+ 'value' => __( 'Your server does not support cURL', 'health-check' ),
397
+ );
398
+ }
399
+
400
+ $info['wp-server']['fields'][] = array(
401
+ 'label' => __( 'SUHOSIN installed', 'health-check' ),
402
+ 'value' => ( ( extension_loaded( 'suhosin' ) || ( defined( 'SUHOSIN_PATCH' ) && constant( 'SUHOSIN_PATCH' ) ) ) ? __( 'Yes', 'health-check' ) : __( 'No', 'health-check' ) ),
403
+ );
404
+
405
+ $info['wp-server']['fields'][] = array(
406
+ 'label' => __( 'Is the Imagick library available', 'health-check' ),
407
+ 'value' => ( extension_loaded( 'imagick' ) ? __( 'Yes', 'health-check' ) : __( 'No', 'health-check' ) ),
408
+ );
409
+
410
+ // Populate the database debug fields.
411
+ if ( is_resource( $wpdb->dbh ) ) {
412
+ // Old mysql extension.
413
+ $extension = 'mysql';
414
+ } elseif ( is_object( $wpdb->dbh ) ) {
415
+ // mysqli or PDO.
416
+ $extension = get_class( $wpdb->dbh );
417
+ } else {
418
+ // Unknown sql extension.
419
+ $extension = null;
420
+ }
421
+
422
+ if ( method_exists( $wpdb, 'db_version' ) ) {
423
+ if ( $wpdb->use_mysqli ) {
424
+ $server = mysqli_get_server_info( $wpdb->dbh );
425
+ } else {
426
+ $server = mysql_get_server_info( $wpdb->dbh );
427
+ }
428
+ } else {
429
+ $server = null;
430
+ }
431
+
432
+ if ( isset( $wpdb->use_mysqli ) && $wpdb->use_mysqli ) {
433
+ $client_version = $wpdb->dbh->client_info;
434
+ } else {
435
+ if ( preg_match( '|[0-9]{1,2}\.[0-9]{1,2}\.[0-9]{1,2}|', mysql_get_client_info(), $matches ) ) {
436
+ $client_version = $matches[0];
437
+ } else {
438
+ $client_version = null;
439
+ }
440
+ }
441
+
442
+ $info['wp-database']['fields'][] = array(
443
+ 'label' => __( 'Extension', 'health-check' ),
444
+ 'value' => $extension,
445
+ );
446
+ $info['wp-database']['fields'][] = array(
447
+ 'label' => __( 'Server version', 'health-check' ),
448
+ 'value' => $server,
449
+ );
450
+ $info['wp-database']['fields'][] = array(
451
+ 'label' => __( 'Client version', 'health-check' ),
452
+ 'value' => $client_version,
453
+ );
454
+ $info['wp-database']['fields'][] = array(
455
+ 'label' => __( 'Database user', 'health-check' ),
456
+ 'value' => $wpdb->dbuser,
457
+ 'private' => true,
458
+ );
459
+ $info['wp-database']['fields'][] = array(
460
+ 'label' => __( 'Database host', 'health-check' ),
461
+ 'value' => $wpdb->dbhost,
462
+ 'private' => true,
463
+ );
464
+ $info['wp-database']['fields'][] = array(
465
+ 'label' => __( 'Database name', 'health-check' ),
466
+ 'value' => $wpdb->dbname,
467
+ 'private' => true,
468
+ );
469
+ $info['wp-database']['fields'][] = array(
470
+ 'label' => __( 'Database prefix', 'health-check' ),
471
+ 'value' => $wpdb->prefix,
472
+ );
473
+
474
+ // List must use plugins if there are any.
475
+ $mu_plugins = get_mu_plugins();
476
+
477
+ foreach ( $mu_plugins as $plugin_path => $plugin ) {
478
+ $plugin_version = $plugin['Version'];
479
+ $plugin_author = $plugin['Author'];
480
+
481
+ $plugin_version_string = __( 'No version or author information available', 'health-check' );
482
+
483
+ if ( ! empty( $plugin_version ) && ! empty( $plugin_author ) ) {
484
+ // translators: %1$s: Plugin version number. %2$s: Plugin author name.
485
+ $plugin_version_string = sprintf( __( 'Version %1$s by %2$s', 'health-check' ), $plugin_version, $plugin_author );
486
+ }
487
+ if ( empty( $plugin_version ) && ! empty( $plugin_author ) ) {
488
+ // translators: %s: Plugin author name.
489
+ $plugin_version_string = sprintf( __( 'By %s', 'health-check' ), $plugin_author );
490
+ }
491
+ if ( ! empty( $plugin_version ) && empty( $plugin_author ) ) {
492
+ // translators: %s: Plugin version number.
493
+ $plugin_version_string = sprintf( __( 'Version %s', 'health-check' ), $plugin_version );
494
+ }
495
+
496
+ $info['wp-mu-plugins']['fields'][] = array(
497
+ 'label' => $plugin['Name'],
498
+ 'value' => $plugin_version_string,
499
+ );
500
+ }
501
+
502
+ // List all available plugins.
503
+ $plugins = get_plugins();
504
+
505
+ foreach ( $plugins as $plugin_path => $plugin ) {
506
+ $plugin_part = ( is_plugin_active( $plugin_path ) ) ? 'wp-plugins-active' : 'wp-plugins-inactive';
507
+
508
+ $plugin_version = $plugin['Version'];
509
+ $plugin_author = $plugin['Author'];
510
+
511
+ $plugin_version_string = __( 'No version or author information available', 'health-check' );
512
+
513
+ if ( ! empty( $plugin_version ) && ! empty( $plugin_author ) ) {
514
+ // translators: %1$s: Plugin version number. %2$s: Plugin author name.
515
+ $plugin_version_string = sprintf( __( 'Version %1$s by %2$s', 'health-check' ), $plugin_version, $plugin_author );
516
+ }
517
+ if ( empty( $plugin_version ) && ! empty( $plugin_author ) ) {
518
+ // translators: %s: Plugin author name.
519
+ $plugin_version_string = sprintf( __( 'By %s', 'health-check' ), $plugin_author );
520
+ }
521
+ if ( ! empty( $plugin_version ) && empty( $plugin_author ) ) {
522
+ // translators: %s: Plugin version number.
523
+ $plugin_version_string = sprintf( __( 'Version %s', 'health-check' ), $plugin_version );
524
+ }
525
+
526
+ $info[ $plugin_part ]['fields'][] = array(
527
+ 'label' => $plugin['Name'],
528
+ 'value' => $plugin_version_string,
529
+ );
530
+ }
531
+
532
+ // Populate the section for the currently active theme.
533
+ global $_wp_theme_features;
534
+ $theme_features = array();
535
+ if ( ! empty( $_wp_theme_features ) ) {
536
+ foreach ( $_wp_theme_features as $feature => $options ) {
537
+ $theme_features[] = $feature;
538
+ }
539
+ }
540
+
541
+ $active_theme = wp_get_theme();
542
+ $info['wp-active-theme']['fields'] = array(
543
+ array(
544
+ 'label' => __( 'Name', 'health-check' ),
545
+ 'value' => $active_theme->Name,
546
+ ),
547
+ array(
548
+ 'label' => __( 'Version', 'health-check' ),
549
+ 'value' => $active_theme->Version,
550
+ ),
551
+ array(
552
+ 'label' => __( 'Author', 'health-check' ),
553
+ 'value' => wp_kses( $active_theme->Author, array() ),
554
+ ),
555
+ array(
556
+ 'label' => __( 'Author website', 'health-check' ),
557
+ 'value' => ( $active_theme->offsetGet( 'Author URI' ) ? $active_theme->offsetGet( 'Author URI' ) : __( 'Undefined', 'health-check' ) ),
558
+ ),
559
+ array(
560
+ 'label' => __( 'Parent theme', 'health-check' ),
561
+ 'value' => ( $active_theme->parent_theme ? $active_theme->parent_theme : __( 'Not a child theme', 'health-check' ) ),
562
+ ),
563
+ array(
564
+ 'label' => __( 'Supported theme features', 'health-check' ),
565
+ 'value' => implode( ', ', $theme_features ),
566
+ ),
567
+ );
568
+
569
+ // Populate a list of all themes available in the install.
570
+ $all_themes = wp_get_themes();
571
+
572
+ foreach ( $all_themes as $theme_slug => $theme ) {
573
+ // Ignore the currently active theme from the list of all themes.
574
+ if ( $active_theme->stylesheet == $theme_slug ) {
575
+ continue;
576
+ }
577
+
578
+ $theme_version = $theme->Version;
579
+ $theme_author = $theme->Author;
580
+
581
+ $theme_version_string = __( 'No version or author information available', 'health-check' );
582
+
583
+ if ( ! empty( $theme_version ) && ! empty( $theme_author ) ) {
584
+ // translators: %1$s: Theme version number. %2$s: Theme author name.
585
+ $theme_version_string = sprintf( __( 'Version %1$s by %2$s', 'health-check' ), $theme_version, wp_kses( $theme_author, array() ) );
586
+ }
587
+ if ( empty( $theme_version ) && ! empty( $theme_author ) ) {
588
+ // translators: %s: Theme author name.
589
+ $theme_version_string = sprintf( __( 'By %s', 'health-check' ), wp_kses( $theme_author, array() ) );
590
+ }
591
+ if ( ! empty( $theme_version ) && empty( $theme_author ) ) {
592
+ // translators: %s: Theme version number.
593
+ $theme_version_string = sprintf( __( 'Version %s', 'health-check' ), $theme_version );
594
+ }
595
+
596
+ $info['wp-themes']['fields'][] = array(
597
+ // translators: %1$s: Theme name. %2$s: Theme slug.
598
+ 'label' => sprintf( __( '%1$s (%2$s)', 'health-check' ), $theme->Name, $theme_slug ),
599
+ 'value' => $theme_version_string,
600
+ );
601
+ }
602
+
603
+ // Add more filesystem checks
604
+ if ( defined( 'WPMU_PLUGIN_DIR' ) && is_dir( WPMU_PLUGIN_DIR ) ) {
605
+ $info['wp-filesystem']['fields'][] = array(
606
+ 'label' => __( 'The Must Use Plugins directory', 'health-check' ),
607
+ 'value' => ( wp_is_writable( WPMU_PLUGIN_DIR ) ? __( 'Writable', 'health-check' ) : __( 'Not writable', 'health-check' ) ),
608
+ );
609
+ }
610
+
611
+ /**
612
+ * Add or modify new debug sections.
613
+ *
614
+ * Plugin or themes may wish to introduce their own debug information without creating additional admin pages for this
615
+ * kind of information as it is rarely needed, they can then utilize this filter to introduce their own sections.
616
+ *
617
+ * This filter intentionally does not include the fields introduced by core as those should always be un-modified
618
+ * and reliable for support related scenarios, take note that the core fields will take priority if a filtered value
619
+ * is trying to use the same array keys.
620
+ *
621
+ * Array keys added by core are all prefixed with `wp-`, plugins and themes are encouraged to use their own slug as
622
+ * a prefix, both for consistency as well as avoiding key collisions.
623
+ *
624
+ * @since 4.9.0
625
+ *
626
+ * @param array $args {
627
+ * The debug information to be added to the core information page.
628
+ *
629
+ * @type string $label The title for this section of the debug output.
630
+ * @type string $description Optional. A description for your information section which may contain basic HTML
631
+ * markup: `em`, `strong` and `a` for linking to documentation or putting emphasis.
632
+ * @type boolean $show_count Optional. If set to `true` the amount of fields will be included in the title for
633
+ * this section.
634
+ * @type boolean $private Optional. If set to `true` the section and all associated fields will be excluded
635
+ * from the copy-paste text area.
636
+ * @type array $fields {
637
+ * An associative array containing the data to be displayed.
638
+ *
639
+ * @type string $label The label for this piece of information.
640
+ * @type string $value The output that is of interest for this field.
641
+ * @type boolean $private Optional. If set to `true` the field will not be included in the copy-paste text area
642
+ * on top of the page, allowing you to show, for example, API keys here.
643
+ * }
644
+ * }
645
+ */
646
+ $external_info = apply_filters( 'debug_information', array() );
647
+
648
+ // Merge the core and external debug fields.
649
+ $info = array_replace_recursive( $info, array_replace_recursive( $external_info, $info ) );
650
+
651
+ if ( ! empty( $locale ) ) {
652
+ // Change the language used for translations
653
+ if ( function_exists( 'restore_previous_locale' ) && $switched_locale ) {
654
+ restore_previous_locale();
655
+ }
656
+ }
657
+
658
+ return $info;
659
+ }
660
+ }
includes/class-health-check-files-integrity.php ADDED
@@ -0,0 +1,187 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Check all core files against the checksums provided by WordPress API.
5
+ *
6
+ * @package Health Check
7
+ */
8
+
9
+ /**
10
+ * Class Files_Integrity
11
+ */
12
+ class Health_Check_Files_Integrity {
13
+
14
+ /**
15
+ * Gathers checksums from WordPress API and cross checks the core files in the current installation.
16
+ *
17
+ * @return void
18
+ */
19
+ static function run_files_integrity_check() {
20
+
21
+ $checksums = Health_Check_Files_Integrity::call_checksum_api();
22
+
23
+ $files = Health_Check_Files_Integrity::parse_checksum_results( $checksums );
24
+
25
+ Health_Check_Files_Integrity::create_the_response( $files );
26
+
27
+ }
28
+
29
+ /**
30
+ * Calls the WordPress API on the checksums endpoint
31
+ *
32
+ * @uses get_bloginfo()
33
+ * @uses get_locale()
34
+ * @uses ABSPATH
35
+ * @uses wp_remote_get()
36
+ * @uses get_bloginfo()
37
+ * @uses strpos()
38
+ * @uses unset()
39
+ *
40
+ * @return array
41
+ */
42
+ static function call_checksum_api() {
43
+ // Setup variables.
44
+ $wpversion = get_bloginfo( 'version' );
45
+ $wplocale = get_locale();
46
+
47
+ // Setup API Call.
48
+ $checksumapi = wp_remote_get( 'https://api.wordpress.org/core/checksums/1.0/?version=' . $wpversion . '&locale=' . $wplocale );
49
+
50
+ // Encode the API response body.
51
+ $checksumapibody = json_decode( wp_remote_retrieve_body( $checksumapi ), true );
52
+
53
+ // Remove the wp-content/ files from checking
54
+ foreach ( $checksumapibody['checksums'] as $file => $checksum ) {
55
+ if ( false !== strpos( $file, 'wp-content/' ) ) {
56
+ unset( $checksumapibody['checksums'][ $file ] );
57
+ }
58
+ }
59
+
60
+ return $checksumapibody;
61
+ }
62
+
63
+ /**
64
+ * Parses the results from the WordPress API call
65
+ *
66
+ * @uses file_exists()
67
+ * @uses md5_file()
68
+ * @uses ABSPATH
69
+ *
70
+ * @param array $checksums
71
+ *
72
+ * @return array
73
+ */
74
+ static function parse_checksum_results( $checksums ) {
75
+ $filepath = ABSPATH;
76
+ $files = array();
77
+ // Parse the results.
78
+ foreach ( $checksums['checksums'] as $file => $checksum ) {
79
+ // Check the files.
80
+ if ( file_exists( $filepath . $file ) && md5_file( $filepath . $file ) !== $checksum ) {
81
+ $reason = esc_html__( 'Content changed', 'health-check' ) . ' <a href="#health-check-diff" data-file="' . $file . '">' . esc_html__( '(View Diff)', 'health-check' ) . '</a>';
82
+ array_push( $files, array( $file, $reason ) );
83
+ } elseif ( ! file_exists( $filepath . $file ) ) {
84
+ $reason = esc_html__( 'File not found', 'health-check' );
85
+ array_push( $files, array( $file, $reason ) );
86
+ }
87
+ }
88
+ return $files;
89
+ }
90
+
91
+ /**
92
+ * Generates the response
93
+ *
94
+ * @uses wp_send_json_success()
95
+ * @uses wp_die()
96
+ * @uses ABSPATH
97
+ *
98
+ * @param null|array $files
99
+ *
100
+ * @return void
101
+ */
102
+ static function create_the_response( $files ) {
103
+ $filepath = ABSPATH;
104
+ $output = '';
105
+
106
+ if ( empty( $files ) ) {
107
+ $output .= '<div class="notice notice-success inline"><p>';
108
+ $output .= esc_html__( 'All files passed the check. Everything seems to be ok!', 'health-check' );
109
+ $output .= '</p></div>';
110
+ } else {
111
+ $output .= '<div class="notice notice-error inline"><p>';
112
+ $output .= __( 'It appears that some files may have been modified.', 'health-check' );
113
+ $output .= '</p></div><table class="widefat striped file-integrity-table"><thead><tr><th>';
114
+ $output .= esc_html__( 'Status', 'health-check' );
115
+ $output .= '</th><th>';
116
+ $output .= esc_html__( 'File', 'health-check' );
117
+ $output .= '</th><th>';
118
+ $output .= esc_html__( 'Reason', 'health-check' );
119
+ $output .= '</th></tr></thead><tfoot><tr><td>';
120
+ $output .= esc_html__( 'Status', 'health-check' );
121
+ $output .= '</td><td>';
122
+ $output .= esc_html__( 'File', 'health-check' );
123
+ $output .= '</td><td>';
124
+ $output .= esc_html__( 'Reason', 'health-check' );
125
+ $output .= '</td></tr></tfoot><tbody>';
126
+ foreach ( $files as $tampered ) {
127
+ $output .= '<tr>';
128
+ $output .= '<td><span class="error"></span></td>';
129
+ $output .= '<td>' . $filepath . $tampered[0] . '</td>';
130
+ $output .= '<td>' . $tampered[1] . '</td>';
131
+ $output .= '</tr>';
132
+ }
133
+ $output .= '</tbody>';
134
+ $output .= '</table>';
135
+ }
136
+
137
+ $response = array(
138
+ 'message' => $output,
139
+ );
140
+
141
+ wp_send_json_success( $response );
142
+
143
+ wp_die();
144
+ }
145
+
146
+ /**
147
+ * Generates Diff view
148
+ *
149
+ * @uses get_bloginfo()
150
+ * @uses wp_remote_get()
151
+ * @uses wp_remote_retrieve_body()
152
+ * @uses wp_send_json_success()
153
+ * @uses wp_die()
154
+ * @uses ABSPATH
155
+ * @uses FILE_USE_INCLUDE_PATH
156
+ * @uses wp_text_diff()
157
+ *
158
+ *
159
+ * @return void
160
+ */
161
+ static function view_file_diff() {
162
+ $filepath = ABSPATH;
163
+ $file = $_POST['file'];
164
+ $wpversion = get_bloginfo( 'version' );
165
+ $local_file_body = file_get_contents( $filepath . $file, FILE_USE_INCLUDE_PATH );
166
+ $remote_file = wp_remote_get( 'https://core.svn.wordpress.org/tags/' . $wpversion . '/' . $file );
167
+ $remote_file_body = wp_remote_retrieve_body( $remote_file );
168
+ $diff_args = array(
169
+ 'show_split_view' => true,
170
+ );
171
+
172
+ $output = '<table class="diff"><thead><tr class="diff-sub-title"><th>';
173
+ $output .= 'Original';
174
+ $output .= '</th><th>';
175
+ $output .= 'Modified';
176
+ $output .= '</th></tr></table>';
177
+ $output .= wp_text_diff( $remote_file_body, $local_file_body, $diff_args );
178
+ $response = array(
179
+ 'message' => $output,
180
+ );
181
+
182
+ wp_send_json_success( $response );
183
+
184
+ wp_die();
185
+ }
186
+
187
+ }
includes/class-health-check-loopback.php ADDED
@@ -0,0 +1,264 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Tests to determine if the WordPress loopbacks are able to run unhindered.
4
+ *
5
+ * @package Health Check
6
+ */
7
+
8
+ /**
9
+ * Class Health_Check_Loopback
10
+ */
11
+ class Health_Check_Loopback {
12
+ /**
13
+ * Run a loopback test on our site.
14
+ *
15
+ * @uses wp_unslash()
16
+ * @uses base64_encode()
17
+ * @uses admin_url()
18
+ * @uses add_query_arg()
19
+ * @uses is_array()
20
+ * @uses implode()
21
+ * @uses wp_remote_get()
22
+ * @uses compact()
23
+ * @uses is_wp_error()
24
+ * @uses wp_remote_retrieve_response_code()
25
+ * @uses sprintf()
26
+ *
27
+ * @param null|string $disable_plugin_hash Optional. A hash to send with our request to disable any plugins.
28
+ * @param null|string|array $allowed_plugins Optional. A string or array of approved plugin slugs that can run even when we globally ignore plugins.
29
+ *
30
+ * @return object
31
+ */
32
+ static function can_perform_loopback( $disable_plugin_hash = null, $allowed_plugins = null ) {
33
+ $cookies = wp_unslash( $_COOKIE );
34
+ $timeout = 10;
35
+ $headers = array(
36
+ 'Cache-Control' => 'no-cache',
37
+ );
38
+
39
+ // Include Basic auth in loopback requests.
40
+ if ( isset( $_SERVER['PHP_AUTH_USER'] ) && isset( $_SERVER['PHP_AUTH_PW'] ) ) {
41
+ $headers['Authorization'] = 'Basic ' . base64_encode( wp_unslash( $_SERVER['PHP_AUTH_USER'] ) . ':' . wp_unslash( $_SERVER['PHP_AUTH_PW'] ) );
42
+ }
43
+
44
+ $url = admin_url();
45
+
46
+ if ( ! empty( $disable_plugin_hash ) ) {
47
+ $url = add_query_arg( array( 'health-check-disable-plugin-hash' => $disable_plugin_hash ), $url );
48
+ }
49
+ if ( ! empty( $allowed_plugins ) ) {
50
+ if ( ! is_array( $allowed_plugins ) ) {
51
+ $allowed_plugins = (array) $allowed_plugins;
52
+ }
53
+
54
+ $url = add_query_arg( array( 'health-check-allowed-plugins' => implode( ',', $allowed_plugins ) ), $url );
55
+ }
56
+
57
+ $r = wp_remote_get( $url, compact( 'cookies', 'headers', 'timeout' ) );
58
+
59
+ if ( is_wp_error( $r ) ) {
60
+ return (object) array(
61
+ 'status' => 'error',
62
+ 'message' => sprintf(
63
+ '%s<br>%s',
64
+ esc_html__( 'The loopback request to your site failed, this may prevent WP_Cron from working, along with theme and plugin editors.', 'health-check' ),
65
+ sprintf(
66
+ /* translators: %1$d: The HTTP response code. %2$s: The error message returned. */
67
+ esc_html__( 'Error encountered: (%1$d) %2$s', 'health-check' ),
68
+ wp_remote_retrieve_response_code( $r ),
69
+ $r->get_error_message()
70
+ )
71
+ ),
72
+ );
73
+ }
74
+
75
+ if ( 200 !== wp_remote_retrieve_response_code( $r ) ) {
76
+ return (object) array(
77
+ 'status' => 'warning',
78
+ 'message' => sprintf(
79
+ /* translators: %d: The HTTP response code returned. */
80
+ esc_html__( 'The loopback request returned an unexpected status code, %d, this may affect tools such as WP_Cron, or theme and plugin editors.', 'health-check' ),
81
+ wp_remote_retrieve_response_code( $r )
82
+ ),
83
+ );
84
+ }
85
+
86
+ return (object) array(
87
+ 'status' => 'good',
88
+ 'message' => __( 'The loopback request to your site completed successfully.', 'health-check' ),
89
+ );
90
+ }
91
+
92
+ /**
93
+ * Perform the loopback check, but ensure no plugins are enabled when we do so.
94
+ *
95
+ * @uses ob_start()
96
+ * @uses Health_Check_Troubleshoot::mu_plugin_exists()
97
+ * @uses Health_Check_Troubleshoot::get_filesystem_credentials()
98
+ * @uses Health_Check_Troubleshoot::setup_must_use_plugin()
99
+ * @uses Health_Check_Troubleshoot::maybe_update_must_use_plugin()
100
+ * @uses ob_get_clean()
101
+ * @uses wp_send_json_error()
102
+ * @uses md5()
103
+ * @uses rand()
104
+ * @uses update_option()
105
+ * @uses Health_Check_Loopback::can_perform_loopback()
106
+ * @uses sprintf()
107
+ * @uses esc_attr()
108
+ * @uses esc_html__()
109
+ * @uses esc_html()
110
+ * @uses wp_send_json_success()
111
+ *
112
+ * @return void
113
+ */
114
+ static function loopback_no_plugins() {
115
+ ob_start();
116
+
117
+ $needs_creds = false;
118
+
119
+ if ( ! Health_Check_Troubleshoot::mu_plugin_exists() ) {
120
+ if ( ! Health_Check_Troubleshoot::get_filesystem_credentials() ) {
121
+ $needs_creds = true;
122
+ } else {
123
+ $check_output = Health_Check_Troubleshoot::setup_must_use_plugin();
124
+ if ( false === $check_output ) {
125
+ $needs_creds = true;
126
+ }
127
+ }
128
+ } else {
129
+ if ( ! Health_Check_Troubleshoot::maybe_update_must_use_plugin() ) {
130
+ $needs_creds = true;
131
+ }
132
+ }
133
+
134
+ $result = ob_get_clean();
135
+
136
+ if ( $needs_creds ) {
137
+ wp_send_json_error( $result );
138
+ die();
139
+ }
140
+
141
+ $loopback_hash = md5( rand() );
142
+ update_option( 'health-check-disable-plugin-hash', $loopback_hash );
143
+ update_option( 'health-check-default-theme', 'yes' );
144
+
145
+ $no_plugin_test = Health_Check_Loopback::can_perform_loopback( $loopback_hash );
146
+
147
+ $message = sprintf(
148
+ '<br><span class="%s"></span> %s: %s',
149
+ esc_attr( $no_plugin_test->status ),
150
+ esc_html__( 'Result from testing without any plugins active and a default theme', 'health-check' ),
151
+ $no_plugin_test->message
152
+ );
153
+
154
+ if ( 'error' !== $no_plugin_test->status ) {
155
+ $message .= '<br><button type="button" id="loopback-individual-plugins" class="button button-primary">Test individual plugins</button>';
156
+ }
157
+
158
+ $response = array(
159
+ 'message' => $message,
160
+ );
161
+
162
+ delete_option( 'health-check-default-theme' );
163
+
164
+ wp_send_json_success( $response );
165
+
166
+ die();
167
+ }
168
+
169
+ /**
170
+ * Test individual plugins for loopback compatibility issues.
171
+ *
172
+ * This function will perform the loopback check, without any plugins, then conditionally enables one plugin at a time.
173
+ *
174
+ * @uses ob_start()
175
+ * @uses Health_Check_Troubleshoot::mu_plugin_exists()
176
+ * @uses Health_Check_Troubleshoot::get_filesystem_credentials()
177
+ * @uses Health_Check_Troubleshoot::setup_must_use_plugin()
178
+ * @uses ob_get_clean()
179
+ * @uses wp_send_json_error()
180
+ * @uses delete_option()
181
+ * @uses get_option()
182
+ * @uses md5()
183
+ * @uses rand()
184
+ * @uses update_option()
185
+ * @uses explode()
186
+ * @uses Health_Check_Loopback::can_perform_loopback()
187
+ * @uses sprintf()
188
+ * @uses esc_attr()
189
+ * @uses esc_html__()
190
+ * @uses esc_html()
191
+ * @uses wp_send_json_success()
192
+ *
193
+ * @return void
194
+ */
195
+ static function loopback_test_individual_plugins() {
196
+ ob_start();
197
+
198
+ $needs_creds = false;
199
+
200
+ if ( ! Health_Check_Troubleshoot::mu_plugin_exists() ) {
201
+ if ( ! Health_Check_Troubleshoot::get_filesystem_credentials() ) {
202
+ $needs_creds = true;
203
+ } else {
204
+ Health_Check_Troubleshoot::setup_must_use_plugin();
205
+ }
206
+ }
207
+
208
+ $result = ob_get_clean();
209
+
210
+ if ( $needs_creds ) {
211
+ wp_send_json_error( $result );
212
+ die();
213
+ }
214
+
215
+ delete_option( 'health-check-disable-plugin-hash' );
216
+
217
+ $all_plugins = get_option( 'active_plugins' );
218
+
219
+ $loopback_hash = md5( rand() );
220
+ update_option( 'health-check-disable-plugin-hash', $loopback_hash );
221
+
222
+ $message = '';
223
+
224
+ foreach ( $all_plugins as $single_plugin ) {
225
+ $plugin_slug = explode( '/', $single_plugin );
226
+ $plugin_slug = $plugin_slug[0];
227
+
228
+ $single_test = Health_Check_Loopback::can_perform_loopback( $loopback_hash, $plugin_slug );
229
+
230
+ $message .= sprintf(
231
+ '<br><span class="%s"></span> %s: %s',
232
+ esc_attr( $single_test->status ),
233
+ sprintf(
234
+ // Translators: %s: Plugin slug being tested.
235
+ esc_html__( 'Testing %s', 'health-check' ),
236
+ $plugin_slug
237
+ ),
238
+ $single_test->message
239
+ );
240
+ }
241
+
242
+ // Test without a theme active.
243
+ update_option( 'health-check-default-theme', 'yes' );
244
+
245
+ $theme_test = Health_Check_Loopback::can_perform_loopback( $loopback_hash, '' );
246
+
247
+ $message .= sprintf(
248
+ '<br><span class="%s"></span> %s: %s',
249
+ esc_attr( $theme_test->status ),
250
+ esc_html__( 'Testing a default theme', 'health-check' ),
251
+ $theme_test->message
252
+ );
253
+
254
+ delete_option( 'health-check-default-theme' );
255
+
256
+ $response = array(
257
+ 'message' => $message,
258
+ );
259
+
260
+ wp_send_json_success( $response );
261
+
262
+ die();
263
+ }
264
+ }
includes/class-health-check-mail-check.php ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Checks if wp_mail() works.
5
+ *
6
+ * @package Health Check
7
+ */
8
+
9
+ /**
10
+ * Class Mail Check
11
+ */
12
+ class Health_Check_Mail_Check {
13
+
14
+ /**
15
+ * Checks if wp_mail() works.
16
+ *
17
+ * @uses sanitize_email()
18
+ * @uses wp_mail()
19
+ * @uses wp_send_json_success()
20
+ * @uses wp_die()
21
+ *
22
+ * @return void
23
+ */
24
+ static function run_mail_check() {
25
+ $output = '';
26
+ $sendmail = false;
27
+ $email = sanitize_email( $_POST['email'] );
28
+ $emailsubject = __( 'This is a test message from Health Check.', 'health-check' );
29
+ $emailbody = __( 'This is a test message from Health Check.', 'health-check' );
30
+ $sendmail = wp_mail( $email, $emailsubject, $emailbody );
31
+
32
+ if ( ! empty( $sendmail ) ) {
33
+ $output .= '<div class="notice notice-success inline"><p>';
34
+ $output .= __( 'We have just sent an e-mail using <code>wp_mail()</code> and it seems to work. Please check your inbox and spam folder to see if you received it.', 'health-check' );
35
+ $output .= '</p></div>';
36
+ } else {
37
+ $output .= '<div class="notice notice-error inline"><p>';
38
+ $output .= esc_html__( 'It seems there was a problem sending the e-mail.', 'health-check' );
39
+ $output .= '</p></div>';
40
+ }
41
+
42
+ $response = array(
43
+ 'message' => $output,
44
+ );
45
+
46
+ wp_send_json_success( $response );
47
+
48
+ wp_die();
49
+
50
+ }
51
+
52
+ }
includes/class-health-check-troubleshoot.php ADDED
@@ -0,0 +1,248 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Handle troubleshooting options.
4
+ *
5
+ * @package Health Check
6
+ */
7
+
8
+ /**
9
+ * Class Health_Check_Troubleshoot
10
+ */
11
+ class Health_Check_Troubleshoot {
12
+
13
+ /**
14
+ * Conditionally show a form for providing filesystem credentials when introducing our troubleshooting mode plugin.
15
+ *
16
+ * @uses wp_nonce_url()
17
+ * @uses add_query_arg()
18
+ * @uses admin_url()
19
+ * @uses request_filesystem_credentials()
20
+ * @uses WP_Filesystem
21
+ *
22
+ * @return bool
23
+ */
24
+ static function get_filesystem_credentials() {
25
+ $url = wp_nonce_url( add_query_arg(
26
+ array(
27
+ 'page' => 'health-check',
28
+ 'tab' => 'troubleshoot',
29
+ ),
30
+ admin_url() ) );
31
+ $creds = request_filesystem_credentials( $url, '', false, WP_CONTENT_DIR, array( 'health-check-troubleshoot-mode', 'action' ) );
32
+ if ( false === $creds ) {
33
+ return false;
34
+ }
35
+
36
+ if ( ! WP_Filesystem( $creds ) ) {
37
+ request_filesystem_credentials( $url, '', true, WPMU_PLUGIN_DIR, array( 'health-check-troubleshoot-mode', 'action' ) );
38
+ return false;
39
+ }
40
+
41
+ return true;
42
+ }
43
+
44
+ /**
45
+ * Check if our Must-Use plugin exists.
46
+ *
47
+ * @uses file_exists()
48
+ *
49
+ * @return bool
50
+ */
51
+ static function mu_plugin_exists() {
52
+ return file_exists( WPMU_PLUGIN_DIR . '/health-check-disable-plugins.php' );
53
+ }
54
+
55
+ /**
56
+ * Check if the user has been shown the backup warning.
57
+ *
58
+ * @uses get_user_meta()
59
+ * @uses get_current_user_id()
60
+ *
61
+ * @return bool
62
+ */
63
+ static function has_seen_warning() {
64
+ $meta = get_user_meta( get_current_user_id(), 'health-check', true );
65
+ if ( empty( $meta ) ) {
66
+ return false;
67
+ }
68
+
69
+ if ( 'seen' === $meta['warning']['backup'] ) {
70
+ return true;
71
+ }
72
+
73
+ return false;
74
+ }
75
+
76
+ /**
77
+ * Save the confirmation of having seen a warning.
78
+ *
79
+ * @uses get_user_meta()
80
+ * @uses get_current_user_id()
81
+ * @uses update_user_meta()
82
+ *
83
+ * @return void
84
+ */
85
+ static function confirm_warning() {
86
+ $user_meta = get_user_meta( get_current_user_id(), 'health-check', true );
87
+ if ( empty( $user_meta ) ) {
88
+ $user_meta = array(
89
+ 'warning'
90
+ );
91
+ }
92
+
93
+ $user_meta['warning'][ $_POST['warning'] ] = 'seen';
94
+
95
+ update_user_meta( get_current_user_id(), 'health-check', $user_meta );
96
+ }
97
+
98
+ /**
99
+ * Introduce our Must-Use plugin.
100
+ *
101
+ * Move the Must-Use plugin out to the correct directory, and prompt for credentials if required.
102
+ *
103
+ * @global $wp_filesystem
104
+ *
105
+ * @uses is_dir()
106
+ * @uses WP_Filesystem::mkdir()
107
+ * @uses HealthCheck::display_notice()
108
+ * @uses esc_html__()
109
+ * @uses WP_Filesystem::copy()
110
+ * @uses trailingslashit()
111
+ * @uses Health_Check_Troubleshoot::session_started()
112
+ *
113
+ * @return bool
114
+ */
115
+ static function setup_must_use_plugin( $redirect = true ) {
116
+ global $wp_filesystem;
117
+
118
+ if ( ! is_dir( WPMU_PLUGIN_DIR ) ) {
119
+ if ( ! $wp_filesystem->mkdir( WPMU_PLUGIN_DIR ) ) {
120
+ HealthCheck::display_notice( esc_html__( 'We were unable to create the mu-plugins directory.', 'health-check' ), 'error' );
121
+ return false;
122
+ }
123
+ }
124
+
125
+ if ( ! $wp_filesystem->copy( trailingslashit( HEALTH_CHECK_PLUGIN_DIRECTORY ) . 'assets/mu-plugin/health-check-disable-plugins.php', trailingslashit( WPMU_PLUGIN_DIR ) . 'health-check-disable-plugins.php' ) ) {
126
+ HealthCheck::display_notice( esc_html__( 'We were unable to copy the plugin file required to enable the Troubleshooting Mode.', 'health-check' ), 'error' );
127
+ return false;
128
+ }
129
+
130
+ if ( $redirect ) {
131
+ Health_Check_Troubleshoot::session_started();
132
+ }
133
+
134
+ return true;
135
+ }
136
+
137
+ /**
138
+ * Check if our Must-Use plugin needs updating, and do so if necessary.
139
+ *
140
+ * @global $wp_filesystem
141
+ *
142
+ * @uses Health_Check_Troubleshoot::mu_plugin_exists()
143
+ * @uses Health_Check_Troubleshoot::get_filesystem_credentials()
144
+ * @uses get_plugin_data()
145
+ * @uses trailingslashit()
146
+ * @uses version_compare()
147
+ * @uses WP_Filesystem::copy()
148
+ * @uses esc_html__()
149
+ *
150
+ * @return bool
151
+ */
152
+ static function maybe_update_must_use_plugin() {
153
+ if ( ! Health_Check_Troubleshoot::mu_plugin_exists() ) {
154
+ return false;
155
+ }
156
+ if ( ! Health_Check_Troubleshoot::get_filesystem_credentials() ) {
157
+ return false;
158
+ }
159
+
160
+ $current = get_plugin_data( trailingslashit( HEALTH_CHECK_PLUGIN_DIRECTORY ) . 'assets/mu-plugin/health-check-disable-plugins.php' );
161
+ $active = get_plugin_data( trailingslashit( WPMU_PLUGIN_DIR ) . 'health-check-disable-plugins.php' );
162
+
163
+ $current_version = ( isset( $current['Version'] ) ? $current['Version'] : '0.0' );
164
+ $active_version = ( isset( $active['Version'] ) ? $active['Version'] : '0.0' );
165
+
166
+ if ( version_compare( $current_version, $active_version, '>' ) ) {
167
+ global $wp_filesystem;
168
+
169
+ if ( ! $wp_filesystem->copy( trailingslashit( HEALTH_CHECK_PLUGIN_DIRECTORY ) . 'assets/mu-plugin/health-check-disable-plugins.php', trailingslashit( WPMU_PLUGIN_DIR ) . 'health-check-disable-plugins.php', true ) ) {
170
+ HealthCheck::display_notice( esc_html__( 'We were unable to replace the plugin file required to enable the Troubleshooting Mode.', 'health-check' ), 'error' );
171
+ return false;
172
+ }
173
+ }
174
+
175
+ return true;
176
+ }
177
+
178
+ /**
179
+ * Output a notice if our Troubleshooting Mode has been initiated.
180
+ *
181
+ * @uses HealthCheck::display_notice()
182
+ * @uses sprintf()
183
+ * @uses esc_html__()
184
+ * @uses esc_url()
185
+ * @uses admin_url()
186
+ *
187
+ * @return void
188
+ */
189
+ static function session_started() {
190
+ HealthCheck::display_notice(
191
+ sprintf(
192
+ '%s<br>%s',
193
+ esc_html__( 'You have successfully enabled Troubleshooting Mode, all plugins will appear inactive until you log out and back in again.', 'health-check' ),
194
+ sprintf(
195
+ '<a href="%1$s">%2$s</a><script type="text/javascript">window.location = "%1$s";</script>',
196
+ esc_url( admin_url( '/' ) ),
197
+ esc_html__( 'Return to the Dashboard', 'health-check' )
198
+ )
199
+ )
200
+ );
201
+ }
202
+
203
+ /**
204
+ * Display the form for enabling troubleshooting mode.
205
+ *
206
+ * @uses printf()
207
+ * @uses esc_html__()
208
+ * @uses Health_Check_Troubleshoot::mu_plugin_exists()
209
+ * @uses Health_Check_Troubleshoot::maybe_update_must_use_plugin()
210
+ * @uses Health_Check_Troubleshoot::session_started()
211
+ * @uses Health_Check_Troubleshoot::get_filesystem_credentials()
212
+ * @uses Health_Check_Troubleshoot::setup_must_use_plugin()
213
+ * @uses esc_html_e()
214
+ *
215
+ * @return void
216
+ */
217
+ static function show_enable_troubleshoot_form() {
218
+ if ( isset( $_POST['health-check-troubleshoot-mode'] ) ) {
219
+ if ( Health_Check_Troubleshoot::mu_plugin_exists() ) {
220
+ if ( ! Health_Check_Troubleshoot::maybe_update_must_use_plugin() ) {
221
+ return;
222
+ }
223
+ Health_Check_Troubleshoot::session_started();
224
+ } else {
225
+ if ( ! Health_Check_Troubleshoot::get_filesystem_credentials() ) {
226
+ return;
227
+ } else {
228
+ Health_Check_Troubleshoot::setup_must_use_plugin();
229
+ }
230
+ }
231
+ }
232
+
233
+ ?>
234
+ <div class="notice inline">
235
+ <form action="" method="post" class="form" style="text-align: center;">
236
+ <input type="hidden" name="health-check-troubleshoot-mode" value="true">
237
+
238
+ <p>
239
+ <button type="submit" class="button button-primary">
240
+ <?php esc_html_e( 'Enable Troubleshooting Mode', 'health-check' ); ?>
241
+ </button>
242
+ </p>
243
+ </form>
244
+ </div>
245
+
246
+ <?php
247
+ }
248
+ }
includes/class-health-check-wp-cron.php ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Perform tests to see if WP_Cron is operating as it should.
4
+ *
5
+ * @package Health Check
6
+ */
7
+
8
+ /**
9
+ * Class Health_Check_WP_Cron
10
+ */
11
+ class Health_Check_WP_Cron {
12
+ public $schedules;
13
+ public $crons;
14
+ public $last_missed_cron = null;
15
+
16
+ /**
17
+ * Health_Check_WP_Cron constructor.
18
+ */
19
+ public function __construct() {
20
+ $this->init();
21
+ }
22
+
23
+ /**
24
+ * Initiate the class
25
+ *
26
+ * @uses wp_get_schedules()
27
+ * @uses Health_Check_WP_Cron::get_cron_tasks()
28
+ *
29
+ * @return void
30
+ */
31
+ public function init() {
32
+ $this->schedules = wp_get_schedules();
33
+ $this->get_cron_tasks();
34
+ }
35
+
36
+ /**
37
+ * Populate our list of cron events and store them to a class-wide variable.
38
+ *
39
+ * Derived from `get_cron_events()` in WP Crontrol (https://plugins.svn.wordpress.org/wp-crontrol)
40
+ * by John Blackburn.
41
+ *
42
+ * @uses _get_cron_array()
43
+ * @uses WP_Error
44
+ *
45
+ * @return void
46
+ */
47
+ private function get_cron_tasks() {
48
+ $cron_tasks = _get_cron_array();
49
+
50
+ if ( empty( $cron_tasks ) ) {
51
+ $this->crons = new WP_Error( 'no_tasks', __( 'No scheduled events exist on this site.', 'health-check' ) );
52
+ return;
53
+ }
54
+
55
+ $this->crons = array();
56
+
57
+ foreach ( $cron_tasks as $time => $cron ) {
58
+ foreach ( $cron as $hook => $dings ) {
59
+ foreach ( $dings as $sig => $data ) {
60
+
61
+ $this->crons[ "$hook-$sig-$time" ] = (object) array(
62
+ 'hook' => $hook,
63
+ 'time' => $time,
64
+ 'sig' => $sig,
65
+ 'args' => $data['args'],
66
+ 'schedule' => $data['schedule'],
67
+ 'interval' => isset( $data['interval'] ) ? $data['interval'] : null,
68
+ );
69
+
70
+ }
71
+ }
72
+ }
73
+ }
74
+
75
+ /**
76
+ * Check if any scheduled tasks have been missed.
77
+ *
78
+ * Returns a boolean value of `true` if a scheduled task has been missed and ends processing.
79
+ * If the list of crons is an instance of WP_Error, return the instance instead of a boolean value.
80
+ *
81
+ * @uses is_wp_error()
82
+ * @uses time()
83
+ *
84
+ * @return bool|WP_Error
85
+ */
86
+ public function has_missed_cron() {
87
+ if ( is_wp_error( $this->crons ) ) {
88
+ return $this->crons;
89
+ }
90
+
91
+ foreach ( $this->crons as $id => $cron ) {
92
+ if ( ( $cron->time - time() ) < 0 ) {
93
+ $this->last_missed_cron = $cron->hook;
94
+ return true;
95
+ }
96
+ }
97
+
98
+ return false;
99
+ }
100
+ }
modals/backup-warning.php ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <div class="health-check-modal" id="health-check-backup-warning" data-modal-action="" data-parent-field="">
2
+ <div class="modal-content">
3
+ <h2>
4
+ <?php esc_html_e( 'Remember to keep backups', 'health-check' ); ?>
5
+ </h2>
6
+
7
+ <p>
8
+ <?php _e( 'Because of how Troubleshooting Mode functions, unforeseen conflicts with other plugins or themes may in rare cases occur, leading to unexpected behaviors.', 'health-check' ); ?>
9
+ </p>
10
+
11
+ <p>
12
+ <?php _e( 'We therefore strongly recommend <a href="https://codex.wordpress.org/WordPress_Backups">making a backup of your site</a> before you enter troubleshooting mode.', 'health-check' ); ?>
13
+ </p>
14
+
15
+ <p>
16
+ <?php _e( 'Additionally, since we really want to make this plugin as safe as possible, if you should have any problems with the troubleshooting mode, please create a new topic in the <a href="https://wordpress.org/support/plugin/health-check">plugins support forum</a> with details about what theme and what plugins you’re using and the steps needed to reproduce the problem. This will help us to analyze and fix such problems.', 'health-check' ); ?>
17
+ </p>
18
+
19
+ <p>
20
+ <button class="button button-primary" id="health-check-accept-backup-warning"><?php esc_html_e( 'I understand', 'health-check' ); ?></button>
21
+ </p>
22
+ </div>
23
+ </div>
24
+
25
+ <script type="text/javascript">
26
+ jQuery( document ).ready(function( $ ) {
27
+ if ( 'undefined' === typeof( health_check ) || false === health_check.warning.seen_backup ) {
28
+ $( "#health-check-backup-warning" ).show();
29
+ }
30
+
31
+ $( "#health-check-accept-backup-warning" ).click(function( e ) {
32
+ $( "#health-check-backup-warning" ).hide();
33
+
34
+ var data = {
35
+ action: 'health-check-confirm-warning',
36
+ warning: 'backup'
37
+ };
38
+
39
+ $.post(
40
+ ajaxurl,
41
+ data
42
+ );
43
+ });
44
+ });
45
+ </script>
modals/diff.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <div id="health-check-diff-modal">
2
+ <div id="health-check-diff-modal-content">
3
+ <a id="health-check-diff-modal-close-ref" href="#health-check-diff-modal-close"><span class="dashicons dashicons-no"></span></a>
4
+ <span class="spinner"></span>
5
+ <h3></h3>
6
+ <div id="health-check-diff-modal-diff">
7
+ </div>
8
+ </div>
9
+ </div>
modals/js-result-warnings.php ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ <div class="health-check-modal" data-modal-action="" data-parent-field="">
2
+ <div class="modal-content">
3
+ <span class="modal-close">&times;</span>
4
+ <div id="dynamic-content">
5
+ &nbsp;
6
+ </div>
7
+ </div>
8
+ </div>
pages/debug-data.php ADDED
@@ -0,0 +1,219 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Debug tab contents.
4
+ *
5
+ * @package Health Check
6
+ */
7
+
8
+ // Make sure the file is not directly accessible.
9
+ if ( ! defined( 'ABSPATH' ) ) {
10
+ die( 'We\'re sorry, but you can not directly access this file.' );
11
+ }
12
+
13
+ $info = Health_Check_Debug_Data::debug_data();
14
+ ?>
15
+
16
+
17
+ <div class="notice notice-info inline">
18
+ <p>
19
+ <?php esc_html_e( 'The system information shown below can also be copied and pasted into support requests such as on the WordPress.org forums, or to your theme and plugin developers.', 'health-check' ); ?>
20
+ </p>
21
+ <p>
22
+ <button type="button" class="button button-primary" onclick="document.getElementById('system-information-copy-wrapper').style.display = 'block'; this.style.display = 'none';"><?php esc_html_e( 'Show copy and paste field', 'health-check' ); ?></button>
23
+ <?php if ( 'en_US' !== get_locale() && version_compare( get_bloginfo( 'version' ), '4.7', '>=' ) ) : ?>
24
+ <button type="button" class="button" onclick="document.getElementById('system-information-english-copy-wrapper').style.display = 'block'; this.style.display = 'none';"><?php esc_html_e( 'Show copy and paste field in English', 'health-check' ); ?></button>
25
+ <?php endif; ?>
26
+ </p>
27
+
28
+ <?php
29
+ if ( 'en_US' !== get_locale() && version_compare( get_bloginfo( 'version' ), '4.7', '>=' ) ) :
30
+
31
+ $english_info = Health_Check_Debug_Data::debug_data( 'en_US' );
32
+
33
+ // Workaround for locales not being properly loaded back, see issue #30 on GitHub.
34
+ if ( ! is_textdomain_loaded( 'health-check' ) && _get_path_to_translation( 'health-check' ) ) {
35
+ load_textdomain( 'health-check', _get_path_to_translation( 'health-check' ) );
36
+ }
37
+ ?>
38
+ <div id="system-information-english-copy-wrapper" style="display: none;">
39
+ <textarea id="system-information-english-copy-field" class="widefat" rows="10">`
40
+ <?php
41
+ foreach ( $english_info as $section => $details ) {
42
+ // Skip this section if there are no fields, or the section has been declared as private.
43
+ if ( empty( $details['fields'] ) || ( isset( $details['private'] ) && $details['private'] ) ) {
44
+ continue;
45
+ }
46
+
47
+ printf(
48
+ "### %s%s ###\n\n",
49
+ $details['label'],
50
+ ( isset( $details['show_count'] ) && $details['show_count'] ? sprintf( ' (%d)', count( $details['fields'] ) ) : '' )
51
+ );
52
+
53
+ foreach ( $details['fields'] as $field ) {
54
+ if ( isset( $field['private'] ) && true === $field['private'] ) {
55
+ continue;
56
+ }
57
+
58
+ $values = $field['value'];
59
+ if ( is_array( $field['value'] ) ) {
60
+ $values = '';
61
+
62
+ foreach ( $field['value'] as $name => $value ) {
63
+ $values .= sprintf(
64
+ "\n\t%s: %s",
65
+ $name,
66
+ $value
67
+ );
68
+ }
69
+ }
70
+
71
+ printf(
72
+ "%s: %s\n",
73
+ $field['label'],
74
+ $values
75
+ );
76
+ }
77
+ echo "\n";
78
+ }
79
+ ?>
80
+ `</textarea>
81
+ <p>
82
+ <?php esc_html_e( 'Some information may be filtered out from the list you are about to copy, this is information that may be considered private, and is not meant to be shared in a public forum.', 'health-check' ); ?>
83
+ <br>
84
+ <button type="button" class="button button-primary health-check-copy-field"><?php esc_html_e( 'Mark field for copying', 'health-check' ); ?></button>
85
+ </p>
86
+ </div>
87
+
88
+ <?php endif; ?>
89
+
90
+ <div id="system-information-copy-wrapper" style="display: none;">
91
+ <textarea id="system-information-copy-field" class="widefat" rows="10">`
92
+ <?php
93
+ foreach ( $info as $section => $details ) {
94
+ // Skip this section if there are no fields, or the section has been declared as private.
95
+ if ( empty( $details['fields'] ) || ( isset( $details['private'] ) && $details['private'] ) ) {
96
+ continue;
97
+ }
98
+
99
+ printf(
100
+ "### %s%s ###\n\n",
101
+ $details['label'],
102
+ ( isset( $details['show_count'] ) && $details['show_count'] ? sprintf( ' (%d)', count( $details['fields'] ) ) : '' )
103
+ );
104
+
105
+ foreach ( $details['fields'] as $field ) {
106
+ if ( isset( $field['private'] ) && true === $field['private'] ) {
107
+ continue;
108
+ }
109
+
110
+ $values = $field['value'];
111
+ if ( is_array( $field['value'] ) ) {
112
+ $values = '';
113
+
114
+ foreach ( $field['value'] as $name => $value ) {
115
+ $values .= sprintf(
116
+ "\n\t%s: %s",
117
+ $name,
118
+ $value
119
+ );
120
+ }
121
+ }
122
+
123
+ printf(
124
+ "%s: %s\n",
125
+ $field['label'],
126
+ $values
127
+ );
128
+ }
129
+ echo "\n";
130
+ }
131
+ ?>
132
+ `</textarea>
133
+ <p>
134
+ <?php esc_html_e( 'Some information may be filtered out from the list you are about to copy, this is information that may be considered private, and is not meant to be shared in a public forum.', 'health-check' ); ?>
135
+ <br>
136
+ <button type="button" class="button button-primary health-check-copy-field"><?php esc_html_e( 'Mark field for copying', 'health-check' ); ?></button>
137
+ </p>
138
+ </div>
139
+ </div>
140
+
141
+ <h2 id="system-information-table-of-contents">
142
+ <?php esc_html_e( 'Table of contents', 'health-check' ); ?>
143
+ </h2>
144
+ <div>
145
+ <?php
146
+ $toc = array();
147
+
148
+ foreach ( $info as $section => $details ) {
149
+ if ( empty( $details['fields'] ) ) {
150
+ continue;
151
+ }
152
+
153
+ $toc[] = sprintf(
154
+ '<a href="#%s" class="health-check-toc">%s</a>',
155
+ esc_attr( $section ),
156
+ esc_html( $details['label'] )
157
+ );
158
+ }
159
+
160
+ echo implode( ' | ', $toc );
161
+ ?>
162
+ </div>
163
+
164
+ <?php
165
+ foreach ( $info as $section => $details ) {
166
+ if ( ! isset( $details['fields'] ) || empty( $details['fields'] ) ) {
167
+ continue;
168
+ }
169
+
170
+ printf(
171
+ '<h2 id="%s">%s%s</h2>',
172
+ esc_attr( $section ),
173
+ esc_html( $details['label'] ),
174
+ ( isset( $details['show_count'] ) && $details['show_count'] ? sprintf( ' (%d)', count( $details['fields'] ) ) : '' )
175
+ );
176
+
177
+ if ( isset( $details['description'] ) && ! empty( $details['description'] ) ) {
178
+ printf(
179
+ '<p>%s</p>',
180
+ wp_kses( $details['description'], array(
181
+ 'a' => array(
182
+ 'href' => true,
183
+ ),
184
+ 'strong' => true,
185
+ 'em' => true,
186
+ ) )
187
+ );
188
+ }
189
+ ?>
190
+ <table class="widefat striped health-check-table">
191
+ <tbody>
192
+ <?php
193
+ foreach ( $details['fields'] as $field ) {
194
+ $values = esc_html( $field['value'] );
195
+ if ( is_array( $field['value'] ) ) {
196
+ $values = '';
197
+ foreach ( $field['value'] as $name => $value ) {
198
+ $values .= sprintf(
199
+ '<li>%s: %s</li>',
200
+ esc_html( $name ),
201
+ esc_html( $value )
202
+ );
203
+ }
204
+ }
205
+
206
+ printf(
207
+ '<tr><td>%s</td><td>%s</td></tr>',
208
+ esc_html( $field['label'] ),
209
+ $values
210
+ );
211
+ }
212
+ ?>
213
+ </tbody>
214
+ </table>
215
+ <span style="display: block; width: 100%; text-align: <?php echo ( is_rtl() ? 'left' : 'right' ); ?>">
216
+ <a href="#system-information-table-of-contents" class="health-check-toc"><?php esc_html_e( 'Return to table of contents', 'health-check' ); ?></a>
217
+ </span>
218
+ <?php
219
+ }
pages/health-check.php ADDED
@@ -0,0 +1,462 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Health Check tab contents.
4
+ *
5
+ * @package Health Check
6
+ */
7
+
8
+ // Make sure the file is not directly accessible.
9
+ if ( ! defined( 'ABSPATH' ) ) {
10
+ die( 'We\'re sorry, but you can not directly access this file.' );
11
+ }
12
+
13
+ global $wpdb;
14
+
15
+ $php_min_version_check = version_compare( HEALTH_CHECK_PHP_MIN_VERSION, PHP_VERSION, '<=' );
16
+ $php_supported_version_check = version_compare( HEALTH_CHECK_PHP_SUPPORTED_VERSION, PHP_VERSION, '<=' );
17
+ $php_rec_version_check = version_compare( HEALTH_CHECK_PHP_REC_VERSION, PHP_VERSION, '<=' );
18
+
19
+ $mariadb = false;
20
+ $mysql_server_version = null;
21
+ if ( method_exists( $wpdb, 'db_version' ) ) {
22
+ if ( $wpdb->use_mysqli ) {
23
+ $mysql_server_type = mysqli_get_server_info( $wpdb->dbh );
24
+ } else {
25
+ $mysql_server_type = mysql_get_server_info( $wpdb->dbh );
26
+ }
27
+
28
+ $mysql_server_version = $wpdb->get_var( 'SELECT VERSION()' );
29
+ }
30
+
31
+ $health_check_mysql_rec_version = HEALTH_CHECK_MYSQL_REC_VERSION;
32
+
33
+ if ( stristr( $mysql_server_type, 'mariadb' ) ) {
34
+ $mariadb = true;
35
+ $health_check_mysql_rec_version = '10.0';
36
+ }
37
+
38
+ $mysql_min_version_check = version_compare( HEALTH_CHECK_MYSQL_MIN_VERSION, $mysql_server_version, '<=' );
39
+ $mysql_rec_version_check = version_compare( $health_check_mysql_rec_version, $mysql_server_version, '<=' );
40
+
41
+ $json_check = HealthCheck::json_check();
42
+ $db_dropin = file_exists( WP_CONTENT_DIR . '/db.php' );
43
+ ?>
44
+
45
+ <div class="notice notice-info inline">
46
+ <p>
47
+ <?php esc_html_e( 'The health check shows critical information about your WordPress configuration and items that require your attention.', 'health-check' ); ?>
48
+ </p>
49
+ </div>
50
+
51
+ <table class="widefat striped health-check-table">
52
+ <tbody>
53
+ <tr>
54
+ <td><?php esc_html_e( 'PHP Version', 'health-check' ); ?></td>
55
+ <td>
56
+ <?php
57
+ $status = 'good';
58
+ $notice = array();
59
+
60
+ if ( ! $php_rec_version_check ) {
61
+ $status = 'warning';
62
+ $notice[] = sprintf(
63
+ '<a href="%s">%s</a>',
64
+ esc_url(
65
+ _x( 'https://wordpress.org/support/upgrade-php/', 'The link to the Update PHP page, which may be localized.', 'health-check' )
66
+ ),
67
+ sprintf(
68
+ // translators: %s: Recommended PHP version
69
+ esc_html__( 'For performance and security reasons, we strongly recommend running PHP version %s or higher.', 'health-check' ),
70
+ HEALTH_CHECK_PHP_REC_VERSION
71
+ )
72
+ );
73
+ }
74
+
75
+ if ( ! $php_supported_version_check ) {
76
+ $status = 'warning';
77
+ $notice[] = sprintf(
78
+ '<a href="%s">%s</a>',
79
+ esc_url(
80
+ _x( 'https://wordpress.org/support/upgrade-php/', 'The link to the Update PHP page, which may be localized.', 'health-check' )
81
+ ),
82
+ sprintf(
83
+ // translators: %1$s: Current PHP version. %2$s: Recommended PHP version.
84
+ esc_html__( 'Your version of PHP, %1$s, is very outdated and no longer receiving security updates. You should contact your host for an upgrade, WordPress recommends using PHP version %2$s.', 'health-check' ),
85
+ PHP_VERSION,
86
+ HEALTH_CHECK_PHP_REC_VERSION
87
+ )
88
+ );
89
+ }
90
+
91
+ if ( ! $php_min_version_check ) {
92
+ $status = 'error';
93
+ $notice[] = sprintf(
94
+ '<a href="%s">%s</a>',
95
+ esc_url(
96
+ _x( 'https://wordpress.org/support/upgrade-php/', 'The link to the Update PHP page, which may be localized.', 'health-check' )
97
+ ),
98
+ sprintf(
99
+ // translators: %1$s: Current PHP version. %2$s: Recommended PHP version. %3$s: Minimum PHP version.
100
+ esc_html__( 'Your version of PHP, %1$s, is very outdated and no longer receiving security updates and is not supported by WordPress. You should contact your host for an upgrade, WordPress recommends using PHP version %2$s, but will work with version %3$s or newer.', 'health-check' ),
101
+ PHP_VERSION,
102
+ HEALTH_CHECK_PHP_REC_VERSION,
103
+ HEALTH_CHECK_PHP_MIN_VERSION
104
+ )
105
+ );
106
+ }
107
+
108
+ printf(
109
+ '<span class="%s"></span> %s',
110
+ esc_attr( $status ),
111
+ sprintf(
112
+ '%s%s',
113
+ PHP_VERSION,
114
+ ( ! empty( $notice ) ? ' - ' . implode( '<br>', $notice ) : '' )
115
+ )
116
+ );
117
+ ?>
118
+
119
+ </td>
120
+ </tr>
121
+
122
+ <tr>
123
+ <td>
124
+ <?php
125
+ if ( ! $mariadb ) {
126
+ esc_html_e( 'MySQL Server version', 'health-check' );
127
+ } else {
128
+ esc_html_e( 'MariaDB Server version', 'health-check' );
129
+ }
130
+ ?>
131
+ </td>
132
+ <td>
133
+ <?php
134
+ $status = 'good';
135
+ $notice = array();
136
+
137
+ if ( ! $mysql_rec_version_check ) {
138
+ $status = 'warning';
139
+ $notice[] = sprintf(
140
+ // translators: %1$s: The database engine in use (MySQL or MariaDB). %2$s: Database server recommended version number.
141
+ esc_html__( 'For performance and security reasons, we strongly recommend running %1$s version %2$s or higher.', 'health-check' ),
142
+ ( $mariadb ? 'MariaDB' : 'MySQL' ),
143
+ $health_check_mysql_rec_version
144
+ );
145
+ }
146
+
147
+ if ( ! $mysql_min_version_check ) {
148
+ $status = 'error';
149
+ $notice[] = sprintf(
150
+ // translators: %1$s: The database engine in use (MySQL or MariaDB). %2$s: Database server minimum version number.
151
+ esc_html__( 'WordPress 3.2+ requires %1$s version %2$s or higher.', 'health-check' ),
152
+ ( $mariadb ? 'MariaDB' : 'MySQL' ),
153
+ HEALTH_CHECK_MYSQL_MIN_VERSION
154
+ );
155
+ }
156
+
157
+ if ( $db_dropin ) {
158
+ // translators: %s: The database engine in use (MySQL or MariaDB).
159
+ $notice[] = wp_kses( sprintf( __( 'You are using a <code>wp-content/db.php</code> drop-in which might mean that a %s database is not being used.', 'health-check' ), ( $mariadb ? 'MariaDB' : 'MySQL' ) ), array( 'code' => true ) );
160
+ }
161
+
162
+ printf(
163
+ '<span class="%s"></span> %s',
164
+ esc_attr( $status ),
165
+ sprintf(
166
+ '%s%s',
167
+ esc_html( $mysql_server_version ),
168
+ ( ! empty( $notice ) ? '<br> - ' . implode( '<br>', $notice ) : '' )
169
+ )
170
+ );
171
+ ?>
172
+ </td>
173
+ </tr>
174
+
175
+ <tr>
176
+ <td><?php esc_html_e( 'JSON Extension', 'health-check' ); ?></td>
177
+ <td>
178
+ <?php
179
+ $status = 'good';
180
+ $notice = array();
181
+
182
+ if ( ! $json_check ) {
183
+ printf(
184
+ '<span class="error"> %s',
185
+ esc_html__( 'The PHP install on your server has the JSON extension disabled and is therefore not compatible with WordPress 3.2 or newer.', 'health-check' )
186
+ );
187
+ } else {
188
+ printf(
189
+ '<span class="good"> %s',
190
+ esc_html__( 'Your PHP install supports JSON.', 'health-check' )
191
+ );
192
+ }
193
+ ?>
194
+ </td>
195
+ </tr>
196
+
197
+ <tr>
198
+ <td><?php esc_html_e( 'MySQL utf8mb4 support', 'health-check' ); ?></td>
199
+ <td>
200
+ <?php
201
+ if ( ! $mariadb ) {
202
+ if ( version_compare( $mysql_server_version, '5.5.3', '<' ) ) {
203
+ printf(
204
+ '<span class="warning"></span> %s',
205
+ sprintf(
206
+ /* translators: %s: Number of version. */
207
+ esc_html__( 'WordPress\' utf8mb4 support requires MySQL version %s or greater', 'health-check' ),
208
+ '5.5.3'
209
+ )
210
+ );
211
+ } else {
212
+ printf(
213
+ '<span class="good"></span> %s',
214
+ esc_html__( 'Your MySQL version supports utf8mb4', 'health-check' )
215
+ );
216
+ }
217
+ } else { // MariaDB introduced utf8mb4 support in 5.5.0
218
+ if ( version_compare( $mysql_server_version, '5.5.0', '<' ) ) {
219
+ printf(
220
+ '<span class="warning"></span> %s',
221
+ sprintf(
222
+ /* translators: %s: Number of version. */
223
+ esc_html__( 'WordPress\' utf8mb4 support requires MariaDB version %s or greater', 'health-check' ),
224
+ '5.5.0'
225
+ )
226
+ );
227
+ } else {
228
+ printf(
229
+ '<span class="good"></span> %s',
230
+ esc_html__( 'Your MariaDB version supports utf8mb4', 'health-check' )
231
+ );
232
+ }
233
+ }
234
+
235
+ if ( $wpdb->use_mysqli ) {
236
+ $mysql_client_version = mysqli_get_client_info();
237
+ } else {
238
+ $mysql_client_version = mysql_get_client_info();
239
+ }
240
+
241
+ /*
242
+ * libmysql has supported utf8mb4 since 5.5.3, same as the MySQL server.
243
+ * mysqlnd has supported utf8mb4 since 5.0.9.
244
+ */
245
+ if ( false !== strpos( $mysql_client_version, 'mysqlnd' ) ) {
246
+ $mysql_client_version = preg_replace( '/^\D+([\d.]+).*/', '$1', $mysql_client_version );
247
+ if ( version_compare( $mysql_client_version, '5.0.9', '<' ) ) {
248
+ printf(
249
+ '<br><span class="warning"></span> %s',
250
+ sprintf(
251
+ /* translators: %1$s: Name of the library, %2$s: Number of version. */
252
+ __( 'WordPress\' utf8mb4 support requires MySQL client library (%1$s) version %2$s or newer.', 'health-check' ),
253
+ 'mysqlnd',
254
+ '5.0.9'
255
+ )
256
+ );
257
+ }
258
+ } else {
259
+ if ( version_compare( $mysql_client_version, '5.5.3', '<' ) ) {
260
+ printf(
261
+ '<br><span class="warning"></span> %s',
262
+ sprintf(
263
+ /* translators: %1$s: Name of the library, %2$s: Number of version. */
264
+ __( 'WordPress\' utf8mb4 support requires MySQL client library (%1$s) version %2$s or newer.', 'health-check' ),
265
+ 'libmysql',
266
+ '5.5.3'
267
+ )
268
+ );
269
+ }
270
+ }
271
+ ?>
272
+ </td>
273
+ </tr>
274
+
275
+ <tr>
276
+ <td><?php esc_html_e( 'Communication with WordPress.org', 'health-check' ); ?></td>
277
+ <td>
278
+ <?php
279
+ $wp_dotorg = wp_remote_get( 'https://wordpress.org', array( 'timeout' => 10 ) );
280
+ if ( ! is_wp_error( $wp_dotorg ) ) {
281
+ printf(
282
+ '<span class="good"></span> %s',
283
+ esc_html__( 'WordPress.org is reachable from your server.', 'health-check' )
284
+ );
285
+ } else {
286
+ printf(
287
+ '<span class="error"></span> %s',
288
+ sprintf(
289
+ // translators: %1$s: The IP address WordPress.org resolves to. %2$s: The error returned by the lookup.
290
+ __( 'Unable to reach WordPress.org at %1$s: %2$s', 'health-check' ),
291
+ gethostbyname( 'wordpress.org' ),
292
+ $wp_dotorg->get_error_message()
293
+ )
294
+ );
295
+ }
296
+ ?>
297
+ </td>
298
+ </tr>
299
+
300
+ <tr>
301
+ <td><?php esc_html_e( 'HTTPS status', 'health-check' ); ?></td>
302
+ <td>
303
+ <?php
304
+ if ( is_ssl() ) {
305
+ printf(
306
+ '<span class="good"></span> %s',
307
+ esc_html__( 'You are accessing this website using HTTPS.', 'health-check' )
308
+ );
309
+ } else {
310
+ printf(
311
+ '<span class="warning"></span> %s',
312
+ esc_html__( 'You are not using HTTPS to access this website.', 'health-check' )
313
+ );
314
+ }
315
+ ?>
316
+ </td>
317
+ </tr>
318
+
319
+ <tr>
320
+ <td><?php esc_html_e( 'Secure communication', 'health-check' ); ?></td>
321
+ <td>
322
+ <?php
323
+ $supports_https = wp_http_supports( array( 'ssl' ) );
324
+
325
+ if ( $supports_https ) {
326
+ printf(
327
+ '<span class="good"></span> %s',
328
+ esc_html__( 'Your WordPress install can communicate securely with other services.', 'health-check' )
329
+ );
330
+ } else {
331
+ printf(
332
+ '<span class="error"></span> %s',
333
+ esc_html__( 'Your WordPress install cannot communicate securely with other services. Talk to your web host about OpenSSL support for PHP.', 'health-check' )
334
+ );
335
+ }
336
+ ?>
337
+ </td>
338
+ </tr>
339
+
340
+ <?php if ( function_exists( 'curl_version' ) ) : ?>
341
+ <tr>
342
+ <td>
343
+ <?php
344
+ // translators: 'cURL' being a code library for communicating with other services.
345
+ esc_html_e( 'cURL version', 'health-check' );
346
+ ?>
347
+ </td>
348
+ <td>
349
+ <?php
350
+ $cURL = curl_version();
351
+ if ( version_compare( $cURL['version'], HEALTH_CHECK_CURL_MIN_VERSION, '<' ) ) {
352
+ printf(
353
+ '<span class="error"></span> %s',
354
+ sprintf(
355
+ // translators: %1$s: Current cURL version number. %2$s: Recommended minimum cURL version.
356
+ esc_html__( 'Your version of cURL, %1$s, is lower than the recommended minimum version of %2$s. Your site may experience connection problems with other services and WordPress.org', 'health-check' ),
357
+ $cURL['version'],
358
+ HEALTH_CHECK_CURL_MIN_VERSION
359
+ )
360
+ );
361
+ }
362
+ elseif ( version_compare( $cURL['version'], HEALTH_CHECK_CURL_VERSION, '<' ) ) {
363
+ printf(
364
+ '<span class="warning"></span> %s',
365
+ sprintf(
366
+ // translators: %1$s: cURL version number running on the website. %2$s: The currently available cURL version.
367
+ esc_html__( 'Your version of cURL, %1$s, is slightly out of date. The most recent version is %2$s. This may in some cases affect your sites ability to communicate with other services. If you are experiencing connectivity issues connecting to various services, please contact your host.', 'health-check' ),
368
+ $cURL['version'],
369
+ HEALTH_CHECK_CURL_VERSION
370
+ )
371
+ );
372
+ }
373
+ else {
374
+ printf(
375
+ '<span class="good"></span> %s',
376
+ sprintf(
377
+ // translators: %s: cURL version number.
378
+ esc_html__( 'Your version of cURL, %s, is up to date.', 'health-check' ),
379
+ $cURL['version']
380
+ )
381
+ );
382
+ }
383
+ ?>
384
+ </td>
385
+ </tr>
386
+ <?php endif; ?>
387
+
388
+ <tr>
389
+ <td><?php esc_html_e( 'Scheduled events', 'health-check' ); ?></td>
390
+ <td>
391
+ <?php
392
+ $scheduled_events = new Health_Check_WP_Cron();
393
+
394
+ if ( is_wp_error( $scheduled_events->has_missed_cron() ) ) {
395
+ printf(
396
+ '<span class="error"></span> %s',
397
+ esc_html( $scheduled_events->has_missed_cron()->get_error_message() )
398
+ );
399
+ } else {
400
+ if ( $scheduled_events->has_missed_cron() ) {
401
+ printf(
402
+ '<span class="warning"></span> %s',
403
+ sprintf(
404
+ // translators: %s: The name of the failed cron event.
405
+ esc_html__( 'A scheduled event (%s) has failed to run. Your site still works, but this may indicate that scheduling posts or automated updates may not work as intended.', 'health-check' ),
406
+ $scheduled_events->last_missed_cron
407
+ )
408
+ );
409
+ } else {
410
+ printf(
411
+ '<span class="good"></span> %s',
412
+ esc_html__( 'No scheduled events have been missed.', 'health-check' )
413
+ );
414
+ }
415
+ }
416
+ ?>
417
+ </td>
418
+ </tr>
419
+
420
+ <tr>
421
+ <td><?php esc_html_e( 'Background updates', 'health-check' ); ?></td>
422
+ <td>
423
+ <ul>
424
+ <?php
425
+ $automatic_updates = new Health_Check_Auto_Updates();
426
+ $tests = $automatic_updates->run_tests();
427
+
428
+ foreach ( $tests as $test ) {
429
+ printf(
430
+ '<li><span class="%s"></span> %s</li>',
431
+ esc_attr( $test->severity ),
432
+ $test->desc
433
+ );
434
+ }
435
+ ?>
436
+ </ul>
437
+ </td>
438
+ </tr>
439
+
440
+ <tr>
441
+ <td><?php esc_html_e( 'Loopback request', 'health-check' ); ?></td>
442
+ <td>
443
+ <?php
444
+ $check_loopback = Health_Check_Loopback::can_perform_loopback();
445
+
446
+ printf(
447
+ '<span class="%s"></span> %s',
448
+ esc_attr( $check_loopback->status ),
449
+ esc_html( $check_loopback->message )
450
+ );
451
+
452
+ if ( 'error' === $check_loopback->status ) {
453
+ echo '<br><button type="button" id="loopback-no-plugins" class="button button-primary">Test without plugins</button>';
454
+ }
455
+ ?>
456
+ </td>
457
+ </tr>
458
+ </tbody>
459
+ </table>
460
+
461
+ <?php
462
+ include_once( HEALTH_CHECK_PLUGIN_DIRECTORY . '/modals/js-result-warnings.php' );
pages/phpinfo.php ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * The PHPInfo tab contents.
4
+ *
5
+ * @package Health Check
6
+ */
7
+
8
+ // Make sure the file is not directly accessible.
9
+ if ( ! defined( 'ABSPATH' ) ) {
10
+ die( 'We\'re sorry, but you can not directly access this file.' );
11
+ }
12
+
13
+ if ( ! function_exists( 'phpinfo' ) ) {
14
+ ?>
15
+
16
+ <div class="notice notice-error inline">
17
+ <p>
18
+ <?php esc_html_e( 'The phpinfo() function has been disabled by your host. Please contact the host if you need more information about your setup.' ); ?>
19
+ </p>
20
+ </div>
21
+
22
+ <?php } else { ?>
23
+
24
+ <div class="notice notice-warning inline">
25
+ <p>
26
+ <?php esc_html_e( 'Some scenarios require you to look up more detailed server configurations than what is normally required. This page allows you to view all available configuration options for your PHP setup. Please be advised that WordPress does not guarantee that any information shown on this page may not be considered private.' ); ?>
27
+ </p>
28
+ </div>
29
+
30
+ <?php
31
+ ob_start();
32
+ phpinfo();
33
+ $phpinfo_raw = ob_get_clean();
34
+
35
+ // Extract the body of the `phpinfo()` call, to avoid all the styles they introduce.
36
+ preg_match_all( '/<body[^>]*>(.*)<\/body>/siU', $phpinfo_raw, $phpinfo );
37
+
38
+ // Extract the styles `phpinfo()` creates for this page.
39
+ preg_match_all( '/<style[^>]*>(.*)<\/style>/siU', $phpinfo_raw, $styles );
40
+
41
+ // We remove various styles that break the visual flow of wp-admin.
42
+ $remove_patterns = array(
43
+ "/a:.+?\n/si",
44
+ "/body.+?\n/si",
45
+ );
46
+
47
+ // Output the styles as an inline style block.
48
+ if ( isset( $styles[1][0] ) ) {
49
+ $styles = preg_replace( $remove_patterns, '', $styles[1][0] );
50
+
51
+ echo '<style type="text/css">' . $styles . '</style>';
52
+ }
53
+
54
+ // Output the actual phpinfo data.
55
+ if ( isset( $phpinfo[1][0] ) ) {
56
+ echo $phpinfo[1][0];
57
+ }
58
+ ?>
59
+
60
+ <?php
61
+ }
pages/tools.php ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Health Check tab contents.
4
+ *
5
+ * @package Health Check
6
+ */
7
+
8
+ // Make sure the file is not directly accessible.
9
+ if ( ! defined( 'ABSPATH' ) ) {
10
+ die( 'We\'re sorry, but you can not directly access this file.' );
11
+ }
12
+
13
+ ?>
14
+
15
+ <div class="notice notice-info inline">
16
+ <h2><?php esc_html_e( 'File Integrity' ); ?></h2>
17
+ <p>
18
+ <?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' ); ?>
19
+ </p>
20
+ <form action="#" id="health-check-file-integrity" method="POST">
21
+ <input type="submit" class="button button-primary" value="<?php esc_html_e( 'Check the Files Integrity', 'health-check' ); ?>">
22
+ </form>
23
+ </div>
24
+ <div class="notice notice-info inline">
25
+ <h2><?php esc_html_e( 'Mail Check' ); ?></h2>
26
+ <p>
27
+ <?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' ); ?>
28
+ </p>
29
+ <form action="#" id="health-check-mail-check" method="POST">
30
+ <p>
31
+ <?php
32
+ $current_user = wp_get_current_user();
33
+ ?>
34
+ <label for="email"><?php _e( 'E-mail', 'health-check' ); ?></label>
35
+ <input type="text" name="email" id="email" value="<?php echo $current_user->user_email; ?>">
36
+ </p>
37
+ <input type="submit" class="button button-primary" value="<?php esc_html_e( 'Check Mail', 'health-check' ); ?>">
38
+ </form>
39
+ </div>
40
+
41
+ <div id="tools-response-holder">
42
+ <span class="spinner"></span>
43
+ </div>
44
+
45
+ <?php
46
+ include_once( HEALTH_CHECK_PLUGIN_DIRECTORY . '/modals/diff.php' );
pages/troubleshoot.php ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * The Troubleshooting tab contents.
4
+ *
5
+ * @package Health Check
6
+ */
7
+
8
+ // Make sure the file is not directly accessible.
9
+ if ( ! defined( 'ABSPATH' ) ) {
10
+ die( 'We\'re sorry, but you can not directly access this file.' );
11
+ }
12
+
13
+ ?>
14
+ <div class="notice notice-warning inline">
15
+ <p>
16
+ <?php esc_html_e( 'When troubleshooting issues on your site, you are likely to be told to disable all plugins and switch to the default theme.', 'health-check' ); ?>
17
+ <?php esc_html_e( 'Understandably, you do not wish to do so as it may affect your site visitors, leaving them with lost functionality.', 'health-check' ); ?>
18
+ </p>
19
+
20
+ <p>
21
+ <?php esc_html_e( 'By enabling the Troubleshooting Mode, all plugins will appear inactive and your site will switch to the default theme only for you. All other users will see your site as usual.', 'health-check' ); ?>
22
+ </p>
23
+
24
+ <p>
25
+ <?php esc_html_e( 'A Troubleshooting Mode menu is added to your admin bar, which will allow you to enable plugins individually, switch back to your current theme, and disable Troubleshooting Mode.', 'health-check' ); ?>
26
+ </p>
27
+
28
+ <p>
29
+ <?php esc_html_e( 'Please note, that due to how Must Use plugins work, any such plugin will not be disabled for the troubleshooting session.', 'health-check' ); ?>
30
+ </p>
31
+ </div>
32
+
33
+ <?php
34
+ Health_Check_Troubleshoot::show_enable_troubleshoot_form();
35
+
36
+ if ( ! Health_Check_Troubleshoot::has_seen_warning() ) {
37
+ include_once( HEALTH_CHECK_PLUGIN_DIRECTORY . '/modals/backup-warning.php' );
38
+ }
readme.txt ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ === Health Check ===
2
+ Tags: health check
3
+ Contributors: wordpressdotorg, westi, pento, Clorith
4
+ Requires at least: 3.8
5
+ Tested up to: 4.9
6
+ Stable tag: 1.0.0
7
+
8
+ == Description ==
9
+
10
+ This plugin will perform a number of checks on your WordPress install to detect common configuration errors and known issues.
11
+
12
+ 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.
13
+
14
+ 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.
15
+
16
+ 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.
17
+
18
+ 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/).
19
+
20
+ 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).
21
+
22
+ == Installation ==
23
+
24
+ 1. Upload to your plugins folder, usually `wp-content/plugins/`
25
+ 2. Activate the plugin on the plugin screen.
26
+ 3. Once activated the plugin will appear under your `Dashboard` menu.
27
+
28
+ == Screenshots ==
29
+
30
+ 1. The health check screen after the automated tests have gone over the system.
31
+ 2. The debug information, with the copy and paste field expanded.
32
+ 3. The generic PHP information tab, when more detailed information is required.
33
+
34
+ == Changelog ==
35
+
36
+ = v 1.0.0 =
37
+ * Added minimum PHP version checks with documentation links.
38
+ * Added testing with a default theme to the loopback checker.
39
+ * Added cURL version checker to the health check tab.
40
+ * Added simple e-mail tester.
41
+ * Added core file integrity checker.
42
+ * Added capability checks, to avoid installing things that may modify the database while troubleshooting.
43
+ * Added a prompt to install a default theme if none exist.
44
+ * Added a warning encouraging users to maintain up to date backups when troubleshooting.
45
+ * Fixed MU plugin not always updating (if available) when a user tries to troubleshoot.
46
+ * Fixed fatal error when trying to troubleshoot "too early".
47
+ * Updated troubleshooting drop down, it no longer shows theme switching if no default theme exists.
48
+ * Removed the checkbox requirement from the Troubleshooting tab, it wasn't needed any more, and added pointless complexity now.
49
+
50
+ = v 0.9.0 =
51
+ * Various string changes, typo fixes and translation enhancements.
52
+ * Added conditional hiding of the plugins list from the admin bar, if there's too many plugins it becomes a bad experience. (Hidden if there are more than 20 active plugins)
53
+ * Added ability to enable/disable plugins in Troubleshooting Mode from the plugins list.
54
+ * Added filter to remove actions from the plugin list in Troubleshooting Mode.
55
+ * Fixed notices on the plugin screen when plugin data may be inconsistent.
56
+ * Fixed jumping directly to troubleshooting mode for single file plugins placed directly in the plugin directory root.
57
+ * Fixed issue where troubleshooting a plugin directly made it impossible to disable it while in Troubleshooting Mode.
58
+ * Fixed so that the original language is returned when translating the debug data for copying.
59
+ * Fixed issue where the Debug screen would turn to half-English when using a non-English language.
60
+ * Fixed an issue where plugins could become truly disabled on a site when in Troubleshooting Mode.
61
+ * Fixed so that enabled/disabled plugins don't carry over between troubleshooting sessions.
62
+
63
+ = v 0.8.0 =
64
+ * Updated recommended PHP version to mirror WordPress.org.
65
+ * Updated texts for troubleshooting mode.
66
+ * Re-labeled database terms to be more user friendly.
67
+ * Added media information to the debug tab.
68
+ * Added individual `Troubleshoot` links for the list of active plugins.
69
+ * Added automatic copy to clipboard with supported browsers in the debug tab.
70
+
uninstall.php ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Perform plugin installation routines.
4
+ *
5
+ * @package Health Check
6
+ */
7
+
8
+ global $wpdb;
9
+
10
+ // Make sure the uninstall file can't be accessed directly.
11
+ if ( ! defined( 'WP_UNINSTALL_PLUGIN' ) ) {
12
+ die;
13
+ }
14
+
15
+ // Remove options introduced by the plugin.
16
+ delete_option( 'health-check-disable-plugin-hash' );
17
+
18
+ /*
19
+ * Remove any user meta entries we made, done with a custom query as core
20
+ * does not provide an option to clear them for all users.
21
+ */
22
+ $wpdb->delete(
23
+ $wpdb->usermeta,
24
+ array(
25
+ 'meta_key' => 'health-check'
26
+ )
27
+ );
28
+
29
+ // Remove the Must-Use plugin if it was implemented.
30
+ if ( file_exists( trailingslashit( WPMU_PLUGIN_DIR ) . 'health-check-disable-plugins.php' ) ) {
31
+ unlink( trailingslashit( WPMU_PLUGIN_DIR ) . 'health-check-disable-plugins.php' );
32
+ }