PluginProbe
WP Debugging / 2.10.0
WP Debugging v2.10.0
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.10.0, at src/Settings.php

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