PluginProbe
WP Debugging / 2.10.2
WP Debugging v2.10.2
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.2, at src/Settings.php

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