Completed
Pull Request — master (#133)
by Sébastien
01:53
created

includes/admin/class-alnp-admin-settings.php (1 issue)

Labels
Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * Auto Load Next Post - Admin Settings Class.
4
 *
5
 * @since    1.0.0
6
 * @version  1.5.0
7
 * @author   Sébastien Dumont
8
 * @category Admin
9
 * @package  Auto Load Next Post/Admin/Settings
10
 * @license  GPL-2.0+
11
 */
12
13
// Exit if accessed directly.
14
if ( ! defined( 'ABSPATH' ) ) {
15
	exit;
16
}
17
18
if ( ! class_exists('Auto_Load_Next_Post_Admin_Settings' ) ) {
19
20
	class Auto_Load_Next_Post_Admin_Settings {
21
22
		/**
23
		 * Setting pages.
24
		 *
25
		 * @access private
26
		 * @static
27
		 * @var array
28
		 */
29
		private static $settings = array();
30
31
		/**
32
		 * Error messages.
33
		 *
34
		 * @access private
35
		 * @static
36
		 * @var array
37
		 */
38
		private static $errors = array();
39
40
		/**
41
		 * Update messages.
42
		 *
43
		 * @access private
44
		 * @static
45
		 * @var array
46
		 */
47
		private static $messages = array();
48
49
		/**
50
		 * Include the settings page classes.
51
		 *
52
		 * @access  public
53
		 * @static
54
		 * @since   1.0.0
55
		 * @version 1.5.0
56
		 * @return  $settings
57
		 */
58
		public static function get_settings_pages() {
59
			if ( empty( self::$settings ) ) {
60
				$settings = array();
61
62
				include_once( dirname( __FILE__ ) . '/settings/class-alnp-settings-page.php' );
63
64
				$settings[] = include( dirname( __FILE__ ) . '/settings/class-alnp-settings-theme-selectors.php');
65
				$settings[] = include( dirname( __FILE__ ) . '/settings/class-alnp-settings-misc.php');
66
67
				self::$settings = apply_filters( 'auto_load_next_post_get_settings_pages', $settings );
68
			}
69
70
			return self::$settings;
71
		} // END get_settings_page()
72
73
		/**
74
		 * Save the settings.
75
		 *
76
		 * @access  public
77
		 * @static
78
		 * @since   1.0.0
79
		 * @version 1.4.10
80
		 * @global  $current_tab
81
		 */
82
		public static function save() {
83
			global $current_tab;
84
85
			check_admin_referer( 'auto-load-next-post-settings' );
86
87
			// Trigger actions
88
			do_action( 'auto_load_next_post_settings_save_' . $current_tab );
89
			do_action( 'auto_load_next_post_update_options_' . $current_tab );
90
			do_action( 'auto_load_next_post_update_options' );
91
92
			self::add_message( __( 'Your settings have been saved.', 'auto-load-next-post' ) );
93
94
			do_action( 'auto_load_next_post_settings_saved' );
95
		} // END save()
96
97
		/**
98
		 * Add a message
99
		 *
100
		 * @access public
101
		 * @static
102
		 * @since  1.0.0
103
		 * @param  string $text Message
104
		 */
105
		public static function add_message( $text ) {
106
			self::$messages[] = $text;
107
		} // END add_message()
108
109
		/**
110
		 * Add an error
111
		 *
112
		 * @access public
113
		 * @static
114
		 * @since  1.0.0
115
		 * @param  string $text Error
116
		 */
117
		public static function add_error( $text ) {
118
			self::$errors[] = $text;
119
		} // END add_error()
120
121
		/**
122
		 * Output messages and errors.
123
		 *
124
		 * @access public
125
		 * @static
126
		 * @since  1.0.0
127
		 * @return string
128
		 */
129
		public static function show_messages() {
130
			if ( count( self::$errors ) > 0 ) {
131
				foreach ( self::$errors as $error ) {
132
					echo '<div id="message" class="error inline"><p><strong>' . esc_html( $error ) . '</strong></p></div>';
133
				}
134
			} elseif ( count( self::$messages ) > 0 ) {
135
				foreach ( self::$messages as $message ) {
136
					echo '<div id="message" class="updated inline"><p><strong>' . esc_html( $message ) . '</strong></p></div>';
137
				}
138
			}
139
		} // END show_messages()
140
141
		/**
142
		 * Settings Page.
143
		 *
144
		 * Handles the display of the main settings page in admin.
145
		 *
146
		 * @access  public
147
		 * @static
148
		 * @since   1.0.0
149
		 * @version 1.4.10
150
		 * @filter  auto_load_next_post_settings_tabs_array
151
		 * @global  string $current_section
152
		 * @global  string $current_tab
153
		 * @return  void
154
		 */
155
		public static function output() {
156
			global $current_section, $current_tab;
157
158
			do_action( 'auto_load_next_post_settings_start' );
159
160
			// Get tabs for the settings page
161
			$tabs = apply_filters( 'auto_load_next_post_settings_tabs_array', array() );
162
163
			include( dirname( __FILE__ ) . '/views/html-admin-settings.php' );
164
		} // END output()
165
166
		/**
167
		 * Get a setting from the settings API.
168
		 *
169
		 * @access public
170
		 * @static
171
		 * @since  1.0.0
172
		 * @param  mixed $option_name
173
		 * @return string
174
		 */
175
		public static function get_option( $option_name, $default = '' ) {
176
			// Array value
177
			if ( strstr( $option_name, '[' ) ) {
178
				parse_str( $option_name, $option_array );
179
180
				// Option name is first key
181
				$option_name = current( array_keys( $option_array ) );
182
183
				// Get value
184
				$option_values = get_option( $option_name, '' );
185
186
				$key = key( $option_array[$option_name] );
187
188
				if ( isset( $option_values[$key] ) ) {
189
					$option_value = $option_values[$key];
190
				} else {
191
					$option_value = null;
192
				}
193
			} else {
194
				// Single value
195
				$option_value = get_option( $option_name, null );
196
			}
197
198
			if ( is_array( $option_value ) ) {
199
				$option_value = array_map( 'stripslashes', $option_value );
200
			} elseif ( ! is_null( $option_value ) ) {
201
				$option_value = stripslashes( $option_value );
202
			}
203
204
			return $option_value === null ? $default : $option_value;
205
		} // END get_option()
206
207
		/**
208
		 * Output admin fields.
209
		 *
210
		 * Loops though the plugin options array and outputs each field.
211
		 *
212
		 * @access  public
213
		 * @static
214
		 * @since   1.0.0
215
		 * @version 1.5.0
216
		 * @param   array $options Opens array to output
217
		 */
218
		public static function output_fields( $options ) {
219
			foreach ( $options as $value ) {
220
				if ( ! isset( $value['type'] ) ) {
221
					continue;
222
				}
223
				if ( ! isset( $value['id'] ) ) {
224
					$value['id'] = '';
225
				}
226
				if ( ! isset( $value['title'] ) ) {
227
					$value['title'] = isset( $value['name'] ) ? $value['name'] : '';
228
				}
229
				if ( ! isset( $value['class'] ) ) {
230
					$value['class'] = '';
231
				}
232
				if ( ! isset( $value['css'] ) ) {
233
					$value['css'] = '';
234
				}
235
				if ( ! isset( $value['default'] ) ) {
236
					$value['default'] = '';
237
				}
238
				if ( ! isset( $value['desc'] ) ) {
239
					$value['desc'] = '';
240
				}
241
				if ( ! isset( $value['placeholder'] ) ) {
242
					$value['placeholder'] = '';
243
				}
244
245
				// Custom attribute handling
246
				$custom_attributes = array();
247
248
				if ( ! empty( $value['custom_attributes'] ) && is_array( $value['custom_attributes'] ) ) {
249
					foreach ( $value['custom_attributes'] as $attribute => $attribute_value ) {
250
						$custom_attributes[] = esc_attr( $attribute ) . '="' . esc_attr( $attribute_value ) . '"';
251
					}
252
				}
253
254
				// Description handling
255
				if ( ! empty( $value['desc'] ) ) {
256
					$description = $value['desc'];
257
				}
258
259
				if ( $description && in_array( $value['type'], array( 'textarea', 'radio' ), true ) ) {
260
					$description = '<p style="margin-top:0">' . wp_kses_post( $description ) . '</p>';
0 ignored issues
show
The variable $description does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
261
				} elseif ( $description && in_array( $value['type'], array( 'checkbox' ), true ) ) {
262
					$description = wp_kses_post( $description );
263
				} elseif ( $description ) {
264
					$description = '<p class="description">' . wp_kses_post( $description ) . '</p>';
265
				}
266
267
				// Switch based on type
268
				switch( $value['type'] ) {
269
270
					// Section Titles
271
					case 'title':
272
						if ( ! empty( $value['title'] ) ) {
273
							echo '<h2>' . esc_html( $value['title'] ) . '</h2>';
274
						}
275
						if ( ! empty( $value['desc'] ) ) {
276
							echo '<div id="' . esc_attr( sanitize_title( $value['id'] ) ) . '-description">';
277
							echo wp_kses_post( wpautop( wptexturize( $value['desc'] ) ) );
278
							echo '</div>';
279
						}
280
						echo '<table class="form-table">'."\n\n";
281
						if ( ! empty( $value['id'] ) ) {
282
							do_action( 'auto_load_next_post_settings_' . sanitize_title( $value['id'] ) );
283
						}
284
285
						break;
286
287
					// Section Ends
288
					case 'sectionend':
289 View Code Duplication
						if ( ! empty( $value['id'] ) ) {
290
							do_action( 'auto_load_next_post_settings_' . sanitize_title( $value['id'] ) . '_end' );
291
						}
292
						echo '</table>';
293 View Code Duplication
						if ( ! empty( $value['id'] ) ) {
294
							do_action( 'auto_load_next_post_settings_' . sanitize_title( $value['id'] ) . '_after' );
295
						}
296
						break;
297
298
					// Standard text inputs and subtypes like 'number'
299
					case 'text':
300
					case 'number':
301
					case 'password':
302
					case 'date':
303
					case 'month':
304
					case 'time':
305
					case 'week':
306 View Code Duplication
					case 'email':
307
						$option_value = self::get_option( $value['id'], $value['default'] );
308
309
						?><tr valign="top">
310
							<th scope="row" class="titledesc">
311
								<label for="<?php echo esc_attr( $value['id'] ); ?>"><?php echo esc_html( $value['title'] ); ?></label>
312
							</th>
313
							<td class="forminp forminp-<?php echo esc_attr( sanitize_title( $value['type'] ) ); ?>">
314
								<input
315
									name="<?php echo esc_attr( $value['id'] ); ?>"
316
									id="<?php echo esc_attr( $value['id'] ); ?>"
317
									type="<?php echo esc_attr( $value['type'] ); ?>"
318
									style="<?php echo esc_attr( $value['css'] ); ?>"
319
									value="<?php echo esc_attr( $option_value ); ?>"
320
									class="<?php echo esc_attr( $value['class'] ); ?>"
321
									placeholder="<?php echo esc_attr( $value['placeholder'] ); ?>"
322
									<?php echo implode(' ', $custom_attributes ); ?>
323
								/><?php echo $description; ?>
324
							</td>
325
						</tr><?php
326
						break;
327
328
					// Textarea.
329 View Code Duplication
					case 'textarea':
330
						$option_value = self::get_option( $value['id'], $value['default'] );
331
						?>
332
						<tr valign="top">
333
							<th scope="row" class="titledesc">
334
								<label for="<?php echo esc_attr( $value['id'] ); ?>"><?php echo esc_html( $value['title'] ); ?></label>
335
							</th>
336
							<td class="forminp forminp-<?php echo esc_attr( sanitize_title( $value['type'] ) ); ?>">
337
								<?php echo $description; ?>
338
339
								<textarea
340
									name="<?php echo esc_attr( $value['id'] ); ?>"
341
									id="<?php echo esc_attr( $value['id'] ); ?>"
342
									style="<?php echo esc_attr( $value['css'] ); ?>"
343
									class="<?php echo esc_attr( $value['class'] ); ?>"
344
									placeholder="<?php echo esc_attr( $value['placeholder'] ); ?>"
345
									<?php echo implode( ' ', $custom_attributes ); ?>
346
									><?php echo esc_textarea( $option_value ); ?></textarea>
347
							</td>
348
						</tr>
349
						<?php
350
						break;
351
352
					// Select boxes.
353
					case 'select':
354
					case 'multiselect':
355
						$option_value = self::get_option( $value['id'], $value['default'] );
356
						?>
357
						<tr valign="top">
358
							<th scope="row" class="titledesc">
359
								<label for="<?php echo esc_attr( $value['id'] ); ?>"><?php echo esc_html( $value['title'] ); ?></label>
360
							</th>
361
							<td class="forminp forminp-<?php echo esc_attr( sanitize_title( $value['type'] ) ); ?>">
362
								<select
363
									name="<?php echo esc_attr( $value['id'] ); ?><?php echo ( 'multiselect' === $value['type'] ) ? '[]' : ''; ?>"
364
									id="<?php echo esc_attr( $value['id'] ); ?>"
365
									style="<?php echo esc_attr( $value['css'] ); ?>"
366
									class="<?php echo esc_attr( $value['class'] ); ?>"
367
									data-placeholder="<?php echo esc_attr( $value['placeholder'] ); ?>"
368
									<?php echo implode( ' ', $custom_attributes ); ?>
369
									<?php echo 'multiselect' === $value['type'] ? 'multiple="multiple"' : ''; ?>
370
									>
371
									<?php
372
									foreach ( $value['options'] as $key => $val ) {
373
										?>
374
										<option value="<?php echo esc_attr( $key ); ?>"
375
											<?php
376
											if ( is_array( $option_value ) ) {
377
												selected( in_array( (string) $key, $option_value, true ), true );
378
											} else {
379
												selected( $option_value, (string) $key );
380
											}
381
											?>
382
											>
383
											<?php echo esc_html( $val ); ?></option>
384
											<?php
385
									}
386
									?>
387
								</select> <?php echo $description; ?>
388
							</td>
389
						</tr>
390
						<?php
391
						break;
392
393
					// Radio inputs.
394
					case 'radio':
395
						$option_value = self::get_option( $value['id'], $value['default'] );
396
						?>
397
						<tr valign="top">
398
							<th scope="row" class="titledesc">
399
								<label for="<?php echo esc_attr( $value['id'] ); ?>"><?php echo esc_html( $value['title'] ); ?></label>
400
							</th>
401
							<td class="forminp forminp-<?php echo esc_attr( sanitize_title( $value['type'] ) ); ?>">
402
								<fieldset>
403
									<?php echo $description; ?>
404
									<ul>
405
									<?php
406
									foreach ( $value['options'] as $key => $val ) {
407
										?>
408
										<li>
409
											<label><input
410
													name="<?php echo esc_attr( $value['id'] ); ?>"
411
													value="<?php echo esc_attr( $key ); ?>"
412
													type="radio"
413
													style="<?php echo esc_attr( $value['css'] ); ?>"
414
													class="<?php echo esc_attr( $value['class'] ); ?>"
415
													<?php echo implode( ' ', $custom_attributes ); // WPCS: XSS ok. ?>
416
													<?php checked( $key, $option_value ); ?>
417
													/> <?php echo esc_html( $val ); ?></label>
418
										</li>
419
										<?php
420
									}
421
									?>
422
									</ul>
423
								</fieldset>
424
							</td>
425
						</tr>
426
						<?php
427
						break;
428
429
					// Checkbox input.
430
					case 'checkbox':
431
						$option_value     = self::get_option( $value['id'], $value['default'] );
432
						$visibility_class = array();
433
434
						if ( ! isset( $value['hide_if_checked'] ) ) {
435
							$value['hide_if_checked'] = false;
436
						}
437
						if ( ! isset( $value['show_if_checked'] ) ) {
438
							$value['show_if_checked'] = false;
439
						}
440
						if ( 'yes' === $value['hide_if_checked'] || 'yes' === $value['show_if_checked'] ) {
441
							$visibility_class[] = 'hidden_option';
442
						}
443
						if ( 'option' === $value['hide_if_checked'] ) {
444
							$visibility_class[] = 'hide_options_if_checked';
445
						}
446
						if ( 'option' === $value['show_if_checked'] ) {
447
							$visibility_class[] = 'show_options_if_checked';
448
						}
449
450
						if ( ! isset( $value['checkboxgroup'] ) || 'start' === $value['checkboxgroup'] ) {
451
							?>
452
								<tr valign="top" class="<?php echo esc_attr( implode( ' ', $visibility_class ) ); ?>">
453
									<th scope="row" class="titledesc"><?php echo esc_html( $value['title'] ); ?></th>
454
									<td class="forminp forminp-checkbox">
455
										<fieldset>
456
							<?php
457
						} else {
458
							?>
459
								<fieldset class="<?php echo esc_attr( implode( ' ', $visibility_class ) ); ?>">
460
							<?php
461
						}
462
463
						if ( ! empty( $value['title'] ) ) {
464
							?>
465
								<legend class="screen-reader-text"><span><?php echo esc_html( $value['title'] ); ?></span></legend>
466
							<?php
467
						}
468
						?>
469
								<label for="<?php echo esc_attr( $value['id'] ); ?>">
470
									<input
471
										name="<?php echo esc_attr( $value['id'] ); ?>"
472
										id="<?php echo esc_attr( $value['id'] ); ?>"
473
										type="checkbox"
474
										class="<?php echo esc_attr( isset( $value['class'] ) ? $value['class'] : '' ); ?>"
475
										value="1"
476
										<?php checked( $option_value, 'yes' ); ?>
477
										<?php echo implode( ' ', $custom_attributes ); ?>
478
									/> <?php echo $description; ?>
479
								</label>
480
								<?php
481
482
								if ( ! isset( $value['checkboxgroup'] ) || 'end' === $value['checkboxgroup'] ) {
483
									?>
484
										</fieldset>
485
									</td>
486
								</tr>
487
							<?php
488
						} else {
489
							?>
490
								</fieldset>
491
							<?php
492
						}
493
						break;
494
495
					// Default: run an action
496
					default:
497
						do_action( 'auto_load_next_post_admin_field_' . $value['type'], $value );
498
499
						break;
500
				} // end switch()
501
			} // END foreach()
502
		} // END output_fields()
503
504
		/**
505
		 * Save admin fields.
506
		 *
507
		 * Loops though the plugin options array and outputs each field.
508
		 *
509
		 * @access  public
510
		 * @static
511
		 * @since   1.0.0
512
		 * @version 1.5.0
513
		 * @param   array $options Opens array to output
514
		 * @return  bool
515
		 */
516
		public static function save_fields( $options ) {
517
			if ( empty( $_POST ) ) {
518
				return false;
519
			}
520
521
			// Options to update will be stored here
522
			$update_options   = array();
523
			$autoload_options = array();
524
525
			// Loop options and get values to save
526
			foreach ( $options as $option ) {
527
				if ( ! isset( $option['id'] ) || ! isset( $option['type'] ) ) {
528
					continue;
529
				}
530
531
				// Get posted value.
532
				if ( strstr( $option['id'], '[' ) ) {
533
					parse_str( $option['id'], $option_name_array );
534
					$option_name  = current( array_keys( $option_name_array ) );
535
					$setting_name = key( $option_name_array[ $option_name ] );
536
					$raw_value    = isset( $_POST[ $option_name ][ $setting_name ] ) ? wp_unslash( $_POST[ $option_name ][ $setting_name ] ) : null;
537
				} else {
538
					$option_name  = $option['id'];
539
					$setting_name = '';
540
					$raw_value    = isset( $_POST[ $option['id'] ] ) ? wp_unslash( $_POST[ $option['id'] ] ) : null;
541
				}
542
543
				switch ( $option['type'] ) {
544
					case "checkbox" :
545
						$value = '1' === $raw_value || 'yes' === $raw_value ? 'yes' : 'no';
546
						break;
547
548
					case "textarea" :
549
						$value = wp_kses_post( trim( stripslashes( $_POST[$option['id']] ) ) );
550
						break;
551
552
					case "multiselect" :
553
						$value = array_filter( array_map( 'auto_load_next_post_clean', (array) $raw_value ) );
554
						break;
555
556
					case 'select' :
557
						$allowed_values = empty( $option['options'] ) ? array() : array_map( 'strval', array_keys( $option['options'] ) );
558
						if ( empty( $option['default'] ) && empty( $allowed_values ) ) {
559
							$value = null;
560
							break;
561
						}
562
						$default = ( empty( $option['default'] ) ? $allowed_values[0] : $option['default'] );
563
						$value   = in_array( $raw_value, $allowed_values, true ) ? $raw_value : $default;
564
						break;
565
566
					default :
567
						$value = auto_load_next_post_clean( $raw_value );
568
						break;
569
				} // END switch()
570
571
				/**
572
				 * Fire an action when a certain 'type' of field is being saved.
573
				 *
574
				 * @deprecated 1.5.0 - doesn't allow manipulation of values!
575
				 */
576
				if ( has_action( 'auto_load_next_post_update_option_' . sanitize_title( $option['type'] ) ) ) {
577
					if ( is_ajax() ) {
578
						error_log( 'auto_load_next_post_update_option_' . sanitize_title( $option['type'] ) . ' is deprecated since version 1.5.0' );
579
					} else {
580
						_deprecated_hook( 'auto_load_next_post_update_option_' . sanitize_title( $option['type'] ), '1.5.0' );
581
					}
582
583
					do_action( 'auto_load_next_post_update_option_' . sanitize_title( $option['type'] ), $option );
584
					continue;
585
				}
586
587
				if ( is_null( $value ) ) {
588
					continue;
589
				}
590
591
				// Check if option is an array and handle that differently to single values.
592
				if ( $option_name && $setting_name ) {
593
					if ( ! isset( $update_options[ $option_name ] ) ) {
594
						$update_options[ $option_name ] = get_option( $option_name, array() );
595
					}
596
					if ( ! is_array( $update_options[ $option_name ] ) ) {
597
						$update_options[ $option_name ] = array();
598
					}
599
					$update_options[ $option_name ][ $setting_name ] = $value;
600
				} else {
601
					$update_options[ $option_name ] = $value;
602
				}
603
604
				$autoload_options[ $option_name ] = isset( $option['autoload'] ) ? (bool) $option['autoload'] : true;
605
606
				/**
607
				 * Fire an action before saved.
608
				 *
609
				 * @deprecated 1.5.0 - doesn't allow manipulation of values!
610
				 */
611
				if ( has_action( 'auto_load_next_post_update_option' ) ) {
612
					if ( is_ajax() ) {
613
						error_log( 'auto_load_next_post_update_option is deprecated since version 1.5.0' );
614
					} else {
615
						_deprecated_hook( 'auto_load_next_post_update_option', '1.5.0' );
616
					}
617
618
					do_action( 'auto_load_next_post_update_option', $option );
619
				}
620
			}
621
622
			// Now save the options
623
			foreach ( $update_options as $name => $value ) {
624
				update_option( $name, $value, $autoload_options[ $name ] ? 'yes' : 'no' );
625
			}
626
627
			// Save all options as an array. Ready for export.
628
			update_option( 'auto_load_next_post_options', $update_options );
629
630
			return true;
631
		} // END save_fields()
632
633
	} // END class.
634
635
} // END if class exists.
636