PluginProbe
WP Debugging / 2.11.18
WP Debugging v2.11.18
2.12.6 2.12.5 trunk 2.10.0 2.10.1 2.10.2 2.11.0 2.11.1 2.11.10 2.11.11 2.11.12 2.11.13 2.11.14 2.11.15 2.11.16 2.11.17 2.11.18 2.11.19 2.11.2 2.11.20 2.11.21 2.11.22 2.11.23 2.11.24 2.11.3 All 59 releases
wp-debugging / src / Settings.php

Settings.php in WP Debugging 2.11.18, at src/Settings.php

477 lines 13.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * WP Debugging
4 *
5 * @package wp-debugging
6 * @author Andy Fragen
7 * @license MIT
8 */
9
10 namespace Fragen\WP_Debugging;
11
12 // Exit if called directly.
13 if ( ! defined( 'WPINC' ) ) {
14 die;
15 }
16
17 /**
18 * Class Settings
19 */
20 class Settings {
21 /**
22 * Hold plugin options.
23 *
24 * @var array
25 */
26 protected static $options;
27
28 /**
29 * Hold `wp-config.php` file path.
30 *
31 * @var string
32 */
33 protected static $config_path;
34
35 /**
36 * Holds pre-defined constants for `wp-config.php`.
37 *
38 * @var array
39 */
40 protected $defined_constants;
41
42 /**
43 * Holds config args for WPConfigTransformer.
44 *
45 * @var array
46 */
47 protected static $config_args;
48
49 /**
50 * Constructor.
51 *
52 * @param array $options Plugin options.
53 * @param string $config_path Path to config file.
54 * @param array $defined_constants Pre-defined constant group.
55 * @return void
56 */
57 public function __construct( $options, $config_path, $defined_constants ) {
58 self::$options = $options;
59 self::$config_path = $config_path;
60 $this->defined_constants = $defined_constants;
61 self::$config_args = [ 'normalize' => true ];
62
63 if ( false === strpos( file_get_contents( self::$config_path ), "/* That's all, stop editing!" ) ) {
64 if ( 1 === preg_match( '@\$table_prefix(.*;)@', file_get_contents( self::$config_path ), $matches ) ) {
65 self::$config_args = array_merge(
66 self::$config_args,
67 [
68 'anchor' => "$matches[0]",
69 'placement' => 'after',
70 ]
71 );
72 }
73 }
74 }
75
76 /**
77 * Load hooks for settings.
78 *
79 * @return self
80 */
81 public function load_hooks() {
82 add_action( 'admin_init', [ $this, 'add_settings' ] );
83 add_action( is_multisite() ? 'network_admin_menu' : 'admin_menu', [ $this, 'add_plugin_menu' ] );
84 add_action( 'network_admin_edit_wp_debugging', [ $this, 'update_settings' ] );
85 add_action( 'admin_init', [ $this, 'update_settings' ] );
86 add_filter(
87 is_multisite()
88 ? 'network_admin_plugin_action_links_wp-debugging/wp-debugging.php'
89 : 'plugin_action_links_wp-debugging/wp-debugging.php',
90 [ $this, 'plugin_action_links' ]
91 );
92
93 return $this;
94 }
95
96 /**
97 * Add plugin menu.
98 *
99 * @return void
100 */
101 public function add_plugin_menu() {
102 $parent = is_multisite() ? 'settings.php' : 'tools.php';
103 $capability = is_multisite() ? 'manage_network_options' : 'manage_options';
104
105 add_submenu_page(
106 $parent,
107 esc_html__( 'WP Debugging', 'wp-debugging' ),
108 esc_html_x( 'WP Debugging', 'Menu item', 'wp-debugging' ),
109 $capability,
110 'wp-debugging',
111 [ $this, 'create_settings_page' ]
112 );
113 }
114
115 /**
116 * Update settings on save.
117 *
118 * @return void
119 */
120 public function update_settings() {
121 // Exit if improper privileges.
122 if ( ! current_user_can( 'manage_options' )
123 || ( ! isset( $_POST['_wpnonce'] ) || ! wp_verify_nonce( sanitize_key( wp_unslash( $_POST['_wpnonce'] ) ), 'wp_debugging-options' ) )
124 ) {
125 return;
126 }
127
128 if ( isset( $_POST['option_page'] ) &&
129 'wp_debugging' === $_POST['option_page']
130 ) {
131 $options = isset( $_POST['wp-debugging'] )
132 ? array_map( 'sanitize_text_field', wp_unslash( $_POST['wp-debugging'] ) )
133 : [];
134
135 $options = $this->sanitize( $options );
136 $this->update_constants( self::$options, $options );
137 $filtered_options = array_filter(
138 self::$options,
139 function ( $e ) {
140 return '1' !== $e;
141 }
142 );
143 $options = array_merge( $filtered_options, $options );
144 update_site_option( 'wp_debugging', (array) $options );
145 $this->redirect_on_save();
146 }
147 }
148
149 /**
150 * Update constants in wp-config.php.
151 *
152 * @param array $old Current value of self::$options.
153 * @param mixed $new New value of $options.
154 * @return void
155 */
156 private function update_constants( $old, $new ) {
157 $remove = array_diff_assoc( $old, $new );
158 $add = array_diff_assoc( $new, $old );
159
160 if ( ! empty( $add ) ) {
161 $this->add_constants( $add );
162 }
163 if ( ! empty( $remove ) ) {
164 $this->remove_constants( $remove );
165 }
166 }
167
168 /**
169 * Add constants to wp-config.php file.
170 *
171 * @uses https://github.com/wp-cli/wp-config-transformer
172 *
173 * @param array $add Constants to add to wp-config.php.
174 * @return array $added Array of added constants.
175 */
176 public function add_constants( $add ) {
177 $added = [];
178 try {
179 $config_transformer = new \WPConfigTransformer( self::$config_path );
180 foreach ( $add as $constant => $config ) {
181 $value = 'wp_debug_display' === $constant ? 'false' : 'true';
182 $value = isset( $config['value'] ) ? $config['value'] : $value;
183 $raw = isset( $config['raw'] ) ? $config['raw'] : true;
184 self::$config_args = array_merge( self::$config_args, [ 'raw' => $raw ] );
185 $config_transformer->update( 'constant', strtoupper( $constant ), $value, self::$config_args );
186 $added[ $constant ] = $value;
187 }
188
189 return $added;
190 } catch ( \Exception $e ) {
191 $messsage = 'Caught Exception: \Fragen\WP_Debugging\Settings::add_constants() - ' . $e->getMessage();
192 // error_log( $messsage );
193 wp_die( esc_html( $messsage ) );
194 }
195 }
196
197 /**
198 * Process user defined constants added via filter.
199 *
200 * @return void
201 */
202 public function process_filter_constants() {
203 /**
204 * Filter to add user define constants.
205 *
206 * @since 2.5.0
207 *
208 * @param array Array of added constants.
209 * The format for adding constants is to return an array of arrays.
210 * Each array will have the constant as the key with an array of configuration data.
211 * array(
212 * 'my_constant' =>
213 * array(
214 * 'value' => $value, @type string
215 * 'raw' => $raw, // Optional. @type bool $raw is a boolean where false will return the value in quotes and true will return the raw value. Default is true.
216 * ),
217 * )
218 * Default is an empty array.
219 */
220 $filter_constants = apply_filters( 'wp_debugging_add_constants', [] );
221 $remove_user_defined = array_diff( self::$options, array_flip( $this->defined_constants ) );
222
223 // Remove and re-add user defined constants. Clean up for when filter removed or changed.
224 if ( ! empty( $remove_user_defined ) ) {
225 $this->remove_constants( $remove_user_defined );
226 }
227 $added_constants = $this->add_constants( $filter_constants );
228
229 $options = array_diff( self::$options, $remove_user_defined );
230 self::$options = array_merge( $options, $added_constants );
231 update_site_option( 'wp_debugging', (array) self::$options );
232 }
233
234 /**
235 * Remove constants from wp-config.php file.
236 *
237 * @uses https://github.com/wp-cli/wp-config-transformer
238 *
239 * @param array $remove Constants to remove from wp-config.php.
240 * @return void
241 */
242 public function remove_constants( $remove ) {
243 try {
244 $config_transformer = new \WPConfigTransformer( self::$config_path );
245 foreach ( array_keys( $remove ) as $constant ) {
246 $config_transformer->remove( 'constant', strtoupper( $constant ) );
247 }
248 } catch ( \Exception $e ) {
249 $messsage = 'Caught Exception: \Fragen\WP_Debugging\Settings::remove_constants() - ' . $e->getMessage();
250 // error_log( $messsage );
251 wp_die( esc_html( $messsage ) );
252 }
253 }
254
255 /**
256 * Redirect back to settings page on save.
257 *
258 * @return void
259 */
260 private function redirect_on_save() {
261 $update = false;
262
263 // phpcs:disable WordPress.Security.NonceVerification.Missing
264 if ( ( isset( $_POST['action'] ) && 'update' === $_POST['action'] ) &&
265 ( isset( $_POST['option_page'] ) && 'wp_debugging' === $_POST['option_page'] )
266 ) {
267 $update = true;
268 }
269 // phpcs:enable
270
271 $redirect_url = is_multisite() ? network_admin_url( 'settings.php' ) : admin_url( 'tools.php' );
272
273 if ( $update ) {
274 $location = add_query_arg(
275 [
276 'page' => 'wp-debugging',
277 'updated' => $update,
278 ],
279 $redirect_url
280 );
281 wp_safe_redirect( $location );
282 exit;
283 }
284 }
285
286 /**
287 * Add notice when settings are saved.
288 *
289 * @return void
290 */
291 private function saved_settings_notice() {
292 // phpcs:disable WordPress.Security.NonceVerification.Recommended
293 if ( ( isset( $_GET['updated'] ) && '1' === $_GET['updated'] ) ||
294 ( isset( $_GET['settings-updated'] ) && '1' === $_GET['settings-updated'] )
295 ) {
296 echo '<div class="updated"><p>';
297 esc_html_e( 'Saved.', 'wp-debugging' );
298 echo '</p></div>';
299 }
300 // phpcs:enable
301 }
302
303 /**
304 * Register settings.
305 *
306 * @return void
307 */
308 public function add_settings() {
309 register_setting(
310 'wp_debugging',
311 'wp_debugging',
312 [ $this, 'sanitize' ]
313 );
314
315 add_settings_section(
316 'wp_debugging',
317 esc_html__( 'Debugging Constants', 'wp-debugging' ),
318 [ $this, 'print_settings_section' ],
319 'wp_debugging'
320 );
321
322 add_settings_field(
323 'wp_debug',
324 null,
325 [ $this, 'checkbox_setting' ],
326 'wp_debugging',
327 'wp_debugging',
328 [
329 'id' => 'wp_debug',
330 'title' => esc_html__( 'Set WP_DEBUG to true.', 'wp-debugging' ),
331 ]
332 );
333
334 add_settings_field(
335 'wp_debug_display',
336 null,
337 [ $this, 'checkbox_setting' ],
338 'wp_debugging',
339 'wp_debugging',
340 [
341 'id' => 'wp_debug_display',
342 'title' => esc_html__( 'Set WP_DEBUG_DISPLAY to false, default is true.', 'wp-debugging' ),
343 ]
344 );
345
346 add_settings_field(
347 'wp_disable_fatal_error_handler',
348 null,
349 [ $this, 'checkbox_setting' ],
350 'wp_debugging',
351 'wp_debugging',
352 [
353 'id' => 'wp_disable_fatal_error_handler',
354 'title' => esc_html__( 'Set WP_DISABLE_FATAL_ERROR_HANDLER to true.', 'wp-debugging' ),
355 'class' => version_compare( get_bloginfo( 'version' ), '5.2', '>=' ) ? '' : 'hidden',
356 ]
357 );
358 }
359
360 /**
361 * Print settings section information.
362 *
363 * @return void
364 */
365 public function print_settings_section() {
366 esc_html_e( 'The following constants are set with plugin activation and removed with plugin deactivation.', 'wp-debugging' );
367 $this->print_constants();
368 esc_html_e( 'Select the debugging constants.', 'wp-debugging' );
369 }
370
371 /**
372 * Print current constants.
373 *
374 * @return void
375 */
376 private function print_constants() {
377 $added_constants = apply_filters( 'wp_debugging_add_constants', [] );
378 $additional_constants = [];
379 if ( $added_constants ) {
380 foreach ( $added_constants as $constant => $config ) {
381 $additional_constants[ $constant ] = $config['value'];
382 }
383 }
384
385 // Strip user defined constants from $constants array.
386 $constants = [ 'wp_debug_log', 'script_debug', 'savequeries' ];
387 $constants = array_merge( array_keys( self::$options ), $constants );
388 $constants = array_diff( $constants, array_keys( $additional_constants ) );
389
390 echo '<pre>';
391 foreach ( $constants as $constant ) {
392 $value = 'wp_debug_display' === $constant ? 'false' : 'true';
393 $constant = strtoupper( $constant );
394 echo wp_kses_post( "<code>define( '{$constant}', {$value} );</code><br>" );
395 }
396 foreach ( $additional_constants as $constant => $value ) {
397 $value = in_array( $value, [ 'true', 'false' ], true ) ? $value : "'$value'";
398 $constant = strtoupper( $constant );
399 echo wp_kses_post( "<code>define( '{$constant}', {$value} );</code><br>" );
400 }
401 echo '</pre>';
402 }
403
404 /**
405 * Create settings page.
406 *
407 * @return void
408 */
409 public function create_settings_page() {
410 $this->saved_settings_notice();
411 $action = is_multisite() ? 'edit.php?action=wp-debugging' : 'options.php'; ?>
412 <div class="wrap">
413 <h1><?php esc_html_e( 'WP Debugging', 'wp-debugging' ); ?></h1>
414 <div class="updated fade">
415 <p><?php echo wp_kses_post( __( '<strong>Please note:</strong> Your <code>wp-config.php</code> file must be writable by the filesystem. Any errors will result in a PHP Exception being thrown. Debug constants as documented in <a href="https://wordpress.org/documentation/article/debugging-in-wordpress/">Debugging in WordPress</a>.', 'wp-debugging' ) ); ?></p>
416 </div>
417 <div>
418 <form method="post" action="<?php echo esc_attr( $action ); ?>">
419 <?php settings_fields( 'wp_debugging' ); ?>
420 <?php do_settings_sections( 'wp_debugging' ); ?>
421 <?php submit_button(); ?>
422 </form>
423 </div>
424 <?php
425 }
426
427 /**
428 * Sanitize save settings.
429 *
430 * @param array $input Input.
431 * @return array $new_input Sanitized output.
432 */
433 public function sanitize( $input ) {
434 $new_input = [];
435 if ( ! is_array( $input ) ) {
436 $new_input = sanitize_text_field( $input );
437 } else {
438 foreach ( array_keys( (array) $input ) as $id ) {
439 $new_input[ sanitize_text_field( $id ) ] = sanitize_text_field( $input[ $id ] );
440 }
441 }
442
443 return $new_input;
444 }
445
446 /**
447 * Get the settings option array and print one of its values.
448 *
449 * @param array $args 'id' and 'title'.
450 */
451 public function checkbox_setting( $args ) {
452 $checked = isset( self::$options[ $args['id'] ] ) ? self::$options[ $args['id'] ] : null;
453 ?>
454 <style> .form-table th { display:none; } </style>
455 <label for="<?php echo esc_attr( $args['id'] ); ?>">
456 <input type="checkbox" name="wp-debugging[<?php echo esc_attr( $args['id'] ); ?>]" value="1" <?php checked( '1', $checked ); ?> >
457 <?php esc_html_e( $args['title'] ); ?>
458 </label>
459 <?php
460 }
461
462 /**
463 * Add setting link to plugin page.
464 * Applied to the list of links to display on the plugins page (beside the activate/deactivate links).
465 *
466 * @param array $links Plugin links on plugins.php.
467 *
468 * @return array
469 */
470 public function plugin_action_links( $links ) {
471 $settings_page = is_multisite() ? 'settings.php' : 'tools.php';
472 $link = [ '<a href="' . esc_url( network_admin_url( $settings_page ) ) . '?page=wp-debugging">' . esc_html__( 'Settings', 'wp-debugging' ) . '</a>' ];
473
474 return array_merge( $link, $links );
475 }
476 }
477