Completed
Push — master ( d51ce1...80c0ca )
by Dwain
05:52
created

Sensei_Settings_API::setup_settings()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 4

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 5
rs 9.4286
cc 1
eloc 4
nc 1
nop 0
1
<?php
2
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
3
4
/**
5
 * Sensei Settings API Class
6
 *
7
 * A settings API (wrapping the WordPress Settings API).
8
 *
9
 * @package WordPress
10
 * @subpackage Sensei
11
 * @category Settings
12
 * @author WooThemes
13
 * @since 1.0.0
14
 */
15
class Sensei_Settings_API {
16
	public $token;
17
	public $page_slug;
18
	public $name;
19
	public $menu_label;
20
	public $settings;
21
	public $sections;
22
	public $fields;
23
	public $errors;
24
25
	public $has_range;
26
	public $has_imageselector;
27
	public $has_tabs;
28
	private $tabs;
29
	public $settings_version;
30
31
	/**
32
	 * Constructor.
33
	 * @access public
34
	 * @since  1.0.0
35
	 * @return void
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
36
	 */
37
	public function __construct () {
38
		$this->token = 'woothemes-sensei-settings';
39
		$this->page_slug = 'woothemes-sensei-settings-api';
40
41
		$this->sections = array();
42
		$this->fields = array();
43
		$this->remaining_fields = array();
0 ignored issues
show
Bug introduced by
The property remaining_fields does not seem to exist. Did you mean fields?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
44
		$this->errors = array();
45
46
		$this->has_range = false;
47
		$this->has_imageselector = false;
48
		$this->has_tabs = false;
49
		$this->tabs = array();
50
		$this->settings_version = '';
51
52
	} // End __construct()
53
54
	/**
55
	 * Setup the settings screen and necessary functions.
56
	 * @access public
57
	 * @since  1.0.0
58
	 * @return void
59
	 */
60
	public function register_hook_listener() {
61
62
        add_action( 'admin_menu', array( $this, 'register_settings_screen' ), 60 );
63
		add_action( 'admin_init', array( $this, 'settings_fields' ) );
64
		add_action( 'init', array( $this, 'general_init' ) );
65
66
	} // End setup_settings()
67
68
	/**
69
	 * Initialise settings sections, settings fields and create tabs, if applicable.
70
	 * @access  public
71
	 * @since   1.0.3
72
	 * @return  void
73
	 */
74
	public function general_init() {
75
		$this->init_sections();
76
		$this->init_fields();
77
		$this->get_settings();
78
		if ( $this->has_tabs == true ) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
79
			$this->create_tabs();
80
		} // End If Statement
81
	} // End general_init()
82
83
	/**
84
	 * Register the settings sections.
85
	 * @access public
86
	 * @since  1.0.0
87
	 * @return void
88
	 */
89
	public function init_sections () {
90
		// Override this function in your class and assign the array of sections to $this->sections.
91
		_e( 'Override init_sections() in your class.', 'woothemes-sensei' );
92
	} // End init_sections()
93
94
	/**
95
	 * Register the settings fields.
96
	 * @access public
97
	 * @since  1.0.0
98
	 * @return void
99
	 */
100
	public function init_fields () {
101
		// Override this function in your class and assign the array of sections to $this->fields.
102
		_e( 'Override init_fields() in your class.', 'woothemes-sensei' );
103
	} // End init_fields()
104
105
	/**
106
	 * Construct and output HTML markup for the settings tabs.
107
	 * @access public
108
	 * @since  1.1.0
109
	 * @return void
110
	 */
111
	public function settings_tabs () {
112
		if ( ! $this->has_tabs ) { return; }
113
114
		if ( count( $this->tabs ) > 0 ) {
115
			$html = '';
116
117
			$html .= '<ul id="settings-sections" class="subsubsub hide-if-no-js">' . "\n";
118
119
			$sections = array(
120
						'all' => array( 'href' => '#all', 'name' => __( 'All', 'woothemes-sensei' ), 'class' => 'current all tab' )
121
					);
122
123
			foreach ( $this->tabs as $k => $v ) {
124
				$sections[$k] = array( 'href' => '#' . esc_attr( $k ), 'name' => esc_attr( $v['name'] ), 'class' => 'tab' );
125
			}
126
127
			$count = 1;
128
			foreach ( $sections as $k => $v ) {
129
				$count++;
130
				$html .= '<li><a href="' . $v['href'] . '"';
131 View Code Duplication
				if ( isset( $v['class'] ) && ( $v['class'] != '' ) ) { $html .= ' class="' . esc_attr( $v['class'] ) . '"'; }
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
132
				$html .= '>' . esc_attr( $v['name'] ) . '</a>';
133
				if ( $count <= count( $sections ) ) { $html .= ' | '; }
134
				$html .= '</li>' . "\n";
135
			}
136
137
			$html .= '</ul><div class="clear"></div>' . "\n";
138
139
			echo $html;
140
		}
141
	} // End settings_tabs()
142
143
	/**
144
	 * Create settings tabs based on the settings sections.
145
	 * @access private
146
	 * @since  1.1.0
147
	 * @return void
148
	 */
149
	private function create_tabs () {
150
		if ( count( $this->sections ) > 0 ) {
151
			$tabs = array();
152
			foreach ( $this->sections as $k => $v ) {
153
				$tabs[$k] = $v;
154
			}
155
156
			$this->tabs = $tabs;
157
		}
158
	} // End create_tabs()
159
160
	/**
161
	 * Create settings sections.
162
	 * @access public
163
	 * @since  1.0.0
164
	 * @return void
165
	 */
166
	public function create_sections () {
167
		if ( count( $this->sections ) > 0 ) {
168
			foreach ( $this->sections as $k => $v ) {
169
				add_settings_section( $k, $v['name'], array( $this, 'section_description' ), $this->token );
170
			}
171
		}
172
	} // End create_sections()
173
174
	/**
175
	 * Create settings fields.
176
	 * @access public
177
	 * @since  1.0.0
178
	 * @return void
179
	 */
180
	public function create_fields () {
181
		if ( count( $this->sections ) > 0 ) {
182
			// $this->parse_fields( $this->fields );
0 ignored issues
show
Unused Code Comprehensibility introduced by
59% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
183
184
			foreach ( $this->fields as $k => $v ) {
185
				$method = $this->determine_method( $v, 'form' );
186
				$name = $v['name'];
187
				if ( $v['type'] == 'info' ) { $name = ''; }
188
				add_settings_field( $k, $name, $method, $this->token, $v['section'], array( 'key' => $k, 'data' => $v ) );
189
190
				// Let the API know that we have a colourpicker field.
191
				if ( $v['type'] == 'range' && $this->has_range == false ) { $this->has_range = true; }
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
192
			}
193
		}
194
	} // End create_fields()
195
196
	/**
197
	 * Determine the method to use for outputting a field, validating a field or checking a field.
198
	 * @access protected
199
	 * @since  1.0.0
200
	 * @param  array $data
201
	 * @return callable,  array or string
0 ignored issues
show
Documentation introduced by
The doc-type callable, could not be parsed: Expected "|" or "end of type", but got "," at position 8. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
202
	 */
203
	protected function determine_method ( $data, $type = 'form' ) {
204
		$method = '';
205
206
		if ( ! in_array( $type, array( 'form', 'validate', 'check' ) ) ) { return; }
207
208
		// Check for custom functions.
209
		if ( isset( $data[$type] ) ) {
210
			if ( function_exists( $data[$type] ) ) {
211
				$method = $data[$type];
212
			}
213
214
			if ( $method == '' && method_exists( $this, $data[$type] ) ) {
215
				if ( $type == 'form' ) {
216
					$method = array( $this, $data[$type] );
217
				} else {
218
					$method = $data[$type];
219
				}
220
			}
221
		}
222
223
		if ( $method == '' && method_exists ( $this, $type . '_field_' . $data['type'] ) ) {
224
			if ( $type == 'form' ) {
225
				$method = array( $this, $type . '_field_' . $data['type'] );
226
			} else {
227
				$method = $type . '_field_' . $data['type'];
228
			}
229
		}
230
231
		if ( $method == '' && function_exists ( $this->token . '_' . $type . '_field_' . $data['type'] ) ) {
232
			$method = $this->token . '_' . $type . '_field_' . $data['type'];
233
		}
234
235
		if ( $method == '' ) {
236
			if ( $type == 'form' ) {
237
				$method = array( $this, $type . '_field_text' );
238
			} else {
239
				$method = $type . '_field_text';
240
			}
241
		}
242
243
		return $method;
244
	} // End determine_method()
245
246
	/**
247
	 * Parse the fields into an array index on the sections property.
248
	 * @access public
249
	 * @since  1.0.0
250
	 * @param  array $fields
251
	 * @return void
252
	 */
253
	public function parse_fields ( $fields ) {
254
		foreach ( $fields as $k => $v ) {
255
			if ( isset( $v['section'] ) && ( $v['section'] != '' ) && ( isset( $this->sections[$v['section']] ) ) ) {
256 View Code Duplication
				if ( ! isset( $this->sections[$v['section']]['fields'] ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
257
					$this->sections[$v['section']]['fields'] = array();
258
				}
259
260
				$this->sections[$v['section']]['fields'][$k] = $v;
261
			} else {
262
				$this->remaining_fields[$k] = $v;
0 ignored issues
show
Bug introduced by
The property remaining_fields does not seem to exist. Did you mean fields?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
263
			}
264
		}
265
	} // End parse_fields()
266
267
	/**
268
	 * Register the settings screen within the WordPress admin.
269
	 * @access public
270
	 * @since 1.0.0
271
	 * @return void
272
	 */
273
	public function register_settings_screen () {
274
275
276 View Code Duplication
		if ( current_user_can( 'manage_sensei' ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
277
			$hook = add_submenu_page( 'sensei', $this->name, $this->menu_label, 'manage_sensei', $this->page_slug, array( $this, 'settings_screen' ) );
278
279
			$this->hook = $hook;
0 ignored issues
show
Bug introduced by
The property hook does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
280
		}
281
282
		if ( isset( $_GET['page'] ) && ( $_GET['page'] == $this->page_slug ) ) {
283
			add_action( 'admin_notices', array( $this, 'settings_errors' ) );
284
			add_action( 'admin_print_scripts', array( $this, 'enqueue_scripts' ) );
285
			add_action( 'admin_print_styles', array( $this, 'enqueue_styles' ) );
286
		}
287
	} // End register_settings_screen()
288
289
	/**
290
	 * The markup for the settings screen.
291
	 * @access public
292
	 * @since  1.0.0
293
	 * @return void
294
	 */
295
	public function settings_screen () {
296
297
?>
298
<div id="woothemes-sensei" class="wrap <?php echo esc_attr( $this->token ); ?>">
299
	<?php screen_icon( 'woothemes-sensei' ); ?>
300
	<h2><?php echo esc_html( $this->name ); ?><?php if ( '' != $this->settings_version ) { echo ' <span class="version">' . $this->settings_version . '</span>'; } ?></h2>
301
	<p class="powered-by-woo"><?php _e( 'Powered by', 'woothemes-sensei' ); ?><a href="http://www.woothemes.com/" title="WooThemes"><img src="<?php echo Sensei()->plugin_url; ?>assets/images/woothemes.png" alt="WooThemes" /></a></p>
302
	<?php do_action( 'settings_before_form' ); ?>
303
	<form action="options.php" method="post">
304
		<?php $this->settings_tabs(); ?>
305
		<?php settings_fields( $this->token ); ?>
306
		<?php do_settings_sections( $this->token ); ?>
307
		<?php submit_button(); ?>
308
	</form>
309
	<?php do_action( 'settings_after_form' ); ?>
310
</div><!--/#woothemes-sensei-->
311
<?php
312
	} // End settings_screen()
313
314
	/**
315
	 * Retrieve the settings from the database.
316
	 * @access public
317
	 * @since  1.0.0
318
	 * @return array
319
	 */
320
	public function get_settings () {
321
		if ( ! is_array( $this->settings ) ) {
322
			$this->settings = get_option( $this->token, array() );
323
		}
324
325
		foreach ( $this->fields as $k => $v ) {
326
			if ( ! isset( $this->settings[$k] ) && isset( $v['default'] ) ) {
327
				$this->settings[$k] = $v['default'];
328
			}
329
			if ( $v['type'] == 'checkbox' && $this->settings[$k] != true ) {
330
				$this->settings[$k] = 0;
331
			}
332
		}
333
334
		return $this->settings;
335
	} // End get_settings()
336
337
	/**
338
	 * Register the settings fields.
339
	 * @access public
340
	 * @since  1.0.0
341
	 * @return void
342
	 */
343
	public function settings_fields () {
344
		register_setting( $this->token, $this->token, array( $this, 'validate_fields' ) );
345
		$this->create_sections();
346
		$this->create_fields();
347
	} // End settings_fields()
348
349
	/**
350
	 * Display settings errors.
351
	 * @access public
352
	 * @since  1.0.0
353
	 * @return void
354
	 */
355
	public function settings_errors () {
356
		echo settings_errors( $this->token . '-errors' );
357
	} // End settings_errors()
358
359
	/**
360
	 * Display the description for a settings section.
361
	 * @access public
362
	 * @since  1.0.0
363
	 * @return void
364
	 */
365
	public function section_description ( $section ) {
366 View Code Duplication
		if ( isset( $this->sections[$section['id']]['description'] ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
367
			echo wpautop( $this->sections[$section['id']]['description'] );
368
		}
369
	} // End section_description_main()
370
371
	/**
372
	 * Generate text input field.
373
	 * @access public
374
	 * @since  1.0.0
375
	 * @param  array $args
376
	 * @return void
377
	 */
378 View Code Duplication
	public function form_field_text ( $args ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
379
		$options = $this->get_settings();
380
381
		echo '<input id="' . esc_attr( $args['key'] ) . '" name="' . $this->token . '[' . esc_attr( $args['key'] ) . ']" size="40" type="text" value="' . esc_attr( $options[$args['key']] ) . '" />' . "\n";
382
		if ( isset( $args['data']['description'] ) ) {
383
			echo '<span class="description">' . $args['data']['description'] . '</span>' . "\n";
384
		}
385
	} // End form_field_text()
386
387
	/**
388
	 * Generate color picker field.
389
	 * @access public
390
	 * @since  1.6.0
391
	 * @param  array $args
392
	 * @return void
393
	 */
394 View Code Duplication
	public function form_field_color ( $args ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
395
		$options = $this->get_settings();
396
397
		echo '<input id="' . esc_attr( $args['key'] ) . '" name="' . $this->token . '[' . esc_attr( $args['key'] ) . ']" size="40" type="text" class="color" value="' . esc_attr( $options[$args['key']] ) . '" />' . "\n";
398
		echo '<div style="position:absolute;background:#FFF;z-index:99;border-radius:100%;" class="colorpicker"></div>';
399
		if ( isset( $args['data']['description'] ) ) {
400
			echo '<span class="description">' . $args['data']['description'] . '</span>' . "\n";
401
		}
402
	} // End form_field_text()
403
404
	/**
405
	 * Generate checkbox field.
406
	 * @access public
407
	 * @since  1.0.0
408
	 * @param  array $args
409
	 * @return void
410
	 */
411
	public function form_field_checkbox ( $args ) {
412
		$options = $this->get_settings();
413
414
		$has_description = false;
415
		if ( isset( $args['data']['description'] ) ) {
416
			$has_description = true;
417
			echo '<label for="' . esc_attr( $args['key'] ) . '">' . "\n";
418
		}
419
		echo '<input id="' . $args['key'] . '" name="' . $this->token . '[' . esc_attr( $args['key'] ) . ']" type="checkbox" value="1"' . checked( esc_attr( $options[$args['key']] ), '1', false ) . ' />' . "\n";
420
		if ( $has_description ) {
421
			echo wp_kses( $args['data']['description'], array( 'a' => array(
422
																	        'href' => array(),
423
																	        'title' => array()
424
																	    )
425
															)
426
						) . '</label>' . "\n";
427
		}
428
	} // End form_field_checkbox()
429
430
	/**
431
	 * Generate textarea field.
432
	 * @access public
433
	 * @since  1.0.0
434
	 * @param  array $args
435
	 * @return void
436
	 */
437 View Code Duplication
	public function form_field_textarea ( $args ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
438
		$options = $this->get_settings();
439
440
		echo '<textarea id="' . esc_attr( $args['key'] ) . '" name="' . $this->token . '[' . esc_attr( $args['key'] ) . ']" cols="42" rows="5">' . esc_html( $options[$args['key']] ) . '</textarea>' . "\n";
441
		if ( isset( $args['data']['description'] ) ) {
442
			echo '<p><span class="description">' . esc_html( $args['data']['description'] ) . '</span></p>' . "\n";
443
		}
444
	} // End form_field_textarea()
445
446
	/**
447
	 * Generate select box field.
448
	 * @access public
449
	 * @since  1.0.0
450
	 * @param  array $args
451
	 * @return void
452
	 */
453 View Code Duplication
	public function form_field_select ( $args ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
454
		$options = $this->get_settings();
455
456
		if ( isset( $args['data']['options'] ) && ( count( (array)$args['data']['options'] ) > 0 ) ) {
457
			$html = '';
458
			$html .= '<select class="" id="' . esc_attr( $args['key'] ) . '" name="' . esc_attr( $this->token ) . '[' . esc_attr( $args['key'] ) . ']">' . "\n";
459
				foreach ( $args['data']['options'] as $k => $v ) {
460
					$html .= '<option value="' . esc_attr( $k ) . '"' . selected( esc_attr( $options[$args['key']] ), $k, false ) . '>' . $v . '</option>' . "\n";
461
				}
462
			$html .= '</select>' . "\n";
463
			echo $html;
464
465
			if ( isset( $args['data']['description'] ) ) {
466
				echo '<p><span class="description">' . esc_html( $args['data']['description'] ) . '</span></p>' . "\n";
467
			}
468
		}
469
	} // End form_field_select()
470
471
	/**
472
	 * Generate radio button field.
473
	 * @access public
474
	 * @since  1.0.0
475
	 * @param  array $args
476
	 * @return void
477
	 */
478 View Code Duplication
	public function form_field_radio ( $args ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
479
		$options = $this->get_settings();
480
481
		if ( isset( $args['data']['options'] ) && ( count( (array)$args['data']['options'] ) > 0 ) ) {
482
			$html = '';
483
			foreach ( $args['data']['options'] as $k => $v ) {
484
				$html .= '<input type="radio" name="' . $this->token . '[' . esc_attr( $args['key'] ) . ']" value="' . esc_attr( $k ) . '"' . checked( esc_attr( $options[$args['key']] ), $k, false ) . ' /> ' . $v . '<br />' . "\n";
485
			}
486
			echo $html;
487
488
			if ( isset( $args['data']['description'] ) ) {
489
				echo '<span class="description">' . esc_html( $args['data']['description'] ) . '</span>' . "\n";
490
			}
491
		}
492
	} // End form_field_radio()
493
494
	/**
495
	 * Generate multicheck field.
496
	 * @access public
497
	 * @since  1.0.0
498
	 * @param  array $args
499
	 * @return void
500
	 */
501
	public function form_field_multicheck ( $args ) {
502
		$options = $this->get_settings();
503
504
		if ( isset( $args['data']['options'] ) && ( count( (array)$args['data']['options'] ) > 0 ) ) {
505
			$html = '<div class="multicheck-container" style="margin-bottom:10px;">' . "\n";
506
			foreach ( $args['data']['options'] as $k => $v ) {
507
				$checked = '';
508
509
				if( isset( $options[ $args['key'] ] ) ) {
510
					if ( in_array( $k, (array)$options[ $args['key'] ] ) ) { $checked = ' checked="checked"'; }
511
				} else {
512
					if ( in_array( $k, $args['data']['defaults'] ) ) { $checked = ' checked="checked"'; }
513
				}
514
				$html .= '<label for="checkbox-' . esc_attr( $k ) . '">' . "\n";
515
				$html .= '<input type="checkbox" name="' . esc_attr( $this->token ) . '[' . esc_attr( $args['key'] ) . '][]" class="multicheck multicheck-' . esc_attr( $args['key'] ) . '" value="' . esc_attr( $k ) . '" id="checkbox-' . esc_attr( $k ) . '" ' . $checked . ' /> ' . $v . "\n";
516
				$html .= '</label><br />' . "\n";
517
			}
518
			$html .= '</div>' . "\n";
519
			echo $html;
520
521
			if ( isset( $args['data']['description'] ) ) {
522
				echo '<span class="description">' . esc_html( $args['data']['description'] ) . '</span>' . "\n";
523
			}
524
		}
525
	} // End form_field_multicheck()
526
527
	/**
528
	 * Generate range field.
529
	 * @access public
530
	 * @since  1.0.0
531
	 * @param  array $args
532
	 * @return void
533
	 */
534 View Code Duplication
	public function form_field_range ( $args ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
535
		$options = $this->get_settings();
536
537
		if ( isset( $args['data']['options'] ) && ( count( (array)$args['data']['options'] ) > 0 ) ) {
538
			$html = '';
539
			$html .= '<select id="' . esc_attr( $args['key'] ) . '" name="' . esc_attr( $this->token ) . '[' . esc_attr( $args['key'] ) . ']" class="range-input">' . "\n";
540
				foreach ( $args['data']['options'] as $k => $v ) {
541
					$html .= '<option value="' . esc_attr( $k ) . '"' . selected( esc_attr( $options[$args['key']] ), $k, false ) . '>' . $v . '</option>' . "\n";
542
				}
543
			$html .= '</select>' . "\n";
544
			echo $html;
545
546
			if ( isset( $args['data']['description'] ) ) {
547
				echo '<p><span class="description">' . esc_html( $args['data']['description'] ) . '</span></p>' . "\n";
548
			}
549
		}
550
	} // End form_field_range()
551
552
	/**
553
	 * Generate image-based selector form field.
554
	 * @access public
555
	 * @since  1.0.0
556
	 * @param  array $args
557
	 * @return void
558
	 */
559 View Code Duplication
	public function form_field_images ( $args ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
560
		$options = $this->get_settings();
561
562
		if ( isset( $args['data']['options'] ) && ( count( (array)$args['data']['options'] ) > 0 ) ) {
563
			$html = '';
564
			foreach ( $args['data']['options'] as $k => $v ) {
565
				$html .= '<input type="radio" name="' . esc_attr( $this->token ) . '[' . esc_attr( $args['key'] ) . ']" value="' . esc_attr( $k ) . '"' . checked( esc_attr( $options[$args['key']] ), $k, false ) . ' /> ' . $v . '<br />' . "\n";
566
			}
567
			echo $html;
568
569
			if ( isset( $args['data']['description'] ) ) {
570
				echo '<span class="description">' . esc_html( $args['data']['description'] ) . '</span>' . "\n";
571
			}
572
		}
573
	} // End form_field_images()
574
575
	/**
576
	 * Generate information box field.
577
	 * @access public
578
	 * @since  1.0.0
579
	 * @param  array $args
580
	 * @return void
581
	 */
582
	public function form_field_info ( $args ) {
583
		$class = '';
584 View Code Duplication
		if ( isset( $args['data']['class'] ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
585
			$class = ' ' . esc_attr( $args['data']['class'] );
586
		}
587
		$html = '<div id="' . $args['key'] . '" class="info-box' . $class . '">' . "\n";
588 View Code Duplication
		if ( isset( $args['data']['name'] ) && ( $args['data']['name'] != '' ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
589
			$html .= '<h3 class="title">' . esc_html( $args['data']['name'] ) . '</h3>' . "\n";
590
		}
591 View Code Duplication
		if ( isset( $args['data']['description'] ) && ( $args['data']['description'] != '' ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
592
			$html .= '<p>' . esc_html( $args['data']['description'] ) . '</p>' . "\n";
593
		}
594
		$html .= '</div>' . "\n";
595
596
		echo $html;
597
	} // End form_field_info()
598
599
600
	/**
601
	 * Generate button field.
602
	 * @access public
603
	 * @since  1.9.0
604
	 * @param  array $args
605
	 */
606
	public function form_field_button( $args ) {
607
		$options = $this->get_settings();
0 ignored issues
show
Unused Code introduced by
$options is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
608
609
		if ( isset( $args['data']['target'] ) && isset( $args['data']['label'] ) ) {
610
			printf( '<a href="%s" class="button button-secondary">%s</a> ', esc_url( $args['data']['target'] ), esc_html( $args['data']['label'] ) );
611
612
			if ( isset( $args['data']['description'] ) ) {
613
				echo '<span class="description">' . esc_html( $args['data']['description'] ) . '</span>' . "\n";
614
			}
615
		}
616
	} // End form_field_button()
617
618
619
	/**
620
	 * Validate registered settings fields.
621
	 * @access public
622
	 * @since  1.0.0
623
	 * @param  array $input
624
	 * @uses   $this->parse_errors()
625
	 * @return array $options
626
	 */
627
	public function validate_fields ( $input ) {
628
		$options = $this->get_settings();
629
630
		foreach ( $this->fields as $k => $v ) {
631
			// Make sure checkboxes are present even when false.
632 View Code Duplication
			if ( $v['type'] == 'checkbox' && ! isset( $input[$k] ) ) { $input[$k] = false; }
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
633 View Code Duplication
			if ( $v['type'] == 'multicheck' && ! isset( $input[$k] ) ) { $input[$k] = false; }
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
634
635
			if ( isset( $input[$k] ) ) {
636
				// Perform checks on required fields.
637
				if ( isset( $v['required'] ) && ( $v['required'] == true ) ) {
638
					if ( in_array( $v['type'], $this->get_array_field_types() ) && ( count( (array) $input[$k] ) <= 0 ) ) {
639
						$this->add_error( $k, $v );
640
						continue;
641
					} else {
642
						if ( $input[$k] == '' ) {
643
							$this->add_error( $k, $v );
644
							continue;
645
						}
646
					}
647
				}
648
649
				$value = $input[$k];
650
651
				// Check if the field is valid.
652
				$method = $this->determine_method( $v, 'check' );
653
654 View Code Duplication
				if ( function_exists ( $method ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
655
					$is_valid = $method( $value );
656
				} else {
657
					if ( method_exists( $this, $method ) ) {
658
						$is_valid = $this->$method( $value );
659
					}
660
				}
661
662
				if ( ! $is_valid ) {
0 ignored issues
show
Bug introduced by
The variable $is_valid 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...
663
					$this->add_error( $k, $v );
664
					continue;
665
				}
666
667
				$method = $this->determine_method( $v, 'validate' );
668
669 View Code Duplication
				if ( function_exists ( $method ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
670
					$options[$k] = $method( $value );
671
				} else {
672
					if ( method_exists( $this, $method ) ) {
673
						$options[$k] = $this->$method( $value );
674
					}
675
				}
676
			}
677
		}
678
679
		// Parse error messages into the Settings API.
680
		$this->parse_errors();
681
		return $options;
682
	} // End validate_fields()
683
684
	/**
685
	 * Validate text fields.
686
	 * @access public
687
	 * @since  1.0.0
688
	 * @param  string $input
689
	 * @return string
690
	 */
691
	public function validate_field_text ( $input ) {
692
		return trim( esc_attr( $input ) );
693
	} // End validate_field_text()
694
695
	/**
696
	 * Validate checkbox fields.
697
	 * @access public
698
	 * @since  1.0.0
699
	 * @param  string $input
700
	 * @return string
701
	 */
702
	public function validate_field_checkbox ( $input ) {
703
		if ( ! isset( $input ) ) {
704
			return 0;
705
		} else {
706
			return (bool)$input;
707
		}
708
	} // End validate_field_checkbox()
709
710
	/**
711
	 * Validate multicheck fields.
712
	 * @access public
713
	 * @since  1.0.0
714
	 * @param  string $input
715
	 * @return string
716
	 */
717
	public function validate_field_multicheck ( $input ) {
718
		$input = (array) $input;
719
720
		$input = array_map( 'esc_attr', $input );
721
722
		return $input;
723
	} // End validate_field_multicheck()
724
725
	/**
726
	 * Validate range fields.
727
	 * @access public
728
	 * @since  1.0.0
729
	 * @param  string $input
730
	 * @return string
731
	 */
732
	public function validate_field_range ( $input ) {
733
		$input = number_format( floatval( $input ), 0 );
734
735
		return $input;
736
	} // End validate_field_range()
737
738
	/**
739
	 * Validate URL fields.
740
	 * @access public
741
	 * @since  1.0.0
742
	 * @param  string $input
743
	 * @return string
744
	 */
745
	public function validate_field_url ( $input ) {
746
		return trim( esc_url( $input ) );
747
	} // End validate_field_url()
748
749
	/**
750
	 * Check and validate the input from text fields.
751
	 * @param  string $input String of the value to be validated.
752
	 * @since  1.1.0
753
	 * @return boolean Is the value valid?
754
	 */
755
	public function check_field_text ( $input ) {
0 ignored issues
show
Unused Code introduced by
The parameter $input is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
756
		$is_valid = true;
757
758
		return $is_valid;
759
	} // End check_field_text()
760
761
	/**
762
	 * Log an error internally, for processing later using $this->parse_errors().
763
	 * @access protected
764
	 * @since  1.0.0
765
	 * @param  string $key
766
	 * @param  array $data
767
	 * @return void
768
	 */
769
	protected function add_error ( $key, $data ) {
770
		if ( isset( $data['error_message'] ) ) {
771
			$message = $data['error_message'];
772
		} else {
773
			$message = sprintf( __( '%s is a required field', 'woothemes-sensei' ), $data['name'] );
774
		}
775
		$this->errors[$key] = $message;
776
	} // End add_error()
777
778
	/**
779
	 * Parse logged errors.
780
	 * @access  protected
781
	 * @since   1.0.0
782
	 * @return  void
783
	 */
784
	protected function parse_errors () {
785
		if ( count ( $this->errors ) > 0 ) {
786
			foreach ( $this->errors as $k => $v ) {
787
				add_settings_error( $this->token . '-errors', $k, $v, 'error' );
788
			}
789
		} else {
790
			$message = sprintf( __( '%s updated', 'woothemes-sensei' ), $this->name );
791
			add_settings_error( $this->token . '-errors', $this->token, $message, 'updated' );
792
		}
793
	} // End parse_errors()
794
795
	/**
796
	 * Return an array of field types expecting an array value returned.
797
	 * @access protected
798
	 * @since  1.0.0
799
	 * @return void
800
	 */
801
	protected function get_array_field_types () {
802
		return array( 'multicheck' );
803
	} // End get_array_field_types()
804
805
	/**
806
	 * Load in JavaScripts where necessary.
807
	 * @access public
808
	 * @since  1.0.0
809
	 * @return void
810
	 */
811
	public function enqueue_scripts () {
812
813
814
		$suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
815
816
		wp_enqueue_script( 'farbtastic' );
817
		wp_enqueue_script( 'woothemes-sensei-settings', esc_url( Sensei()->plugin_url . 'assets/js/settings' . $suffix . '.js' ), array( 'jquery', 'farbtastic' ), Sensei()->version );
818
819 View Code Duplication
		if ( $this->has_range ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
820
			wp_enqueue_script( 'woothemes-sensei-settings-ranges', esc_url( Sensei()->plugin_url . 'assets/js/ranges' . $suffix . '.js' ), array( 'jquery-ui-slider' ), Sensei()->version );
821
		}
822
823
		wp_register_script( 'woothemes-sensei-settings-imageselectors', esc_url( Sensei()->plugin_url . 'assets/js/image-selectors' . $suffix . '.js' ), array( 'jquery' ), Sensei()->version );
824
825
		if ( $this->has_imageselector ) {
826
			wp_enqueue_script( 'woothemes-sensei-settings-imageselectors' );
827
		}
828
829
	} // End enqueue_scripts()
830
831
	/**
832
	 * Load in CSS styles where necessary.
833
	 * @access public
834
	 * @since  1.0.0
835
	 * @return void
836
	 */
837
	public function enqueue_styles () {
838
839
		wp_enqueue_style( $this->token . '-admin' );
840
841
		wp_enqueue_style( 'farbtastic' );
842
		wp_enqueue_style( 'woothemes-sensei-settings-api', esc_url( Sensei()->plugin_url . 'assets/css/settings.css' ), array( 'farbtastic' ), Sensei()->version );
843
844
		$this->enqueue_field_styles();
845
	} // End enqueue_styles()
846
847
	/**
848
	 * Load in CSS styles for field types where necessary.
849
	 * @access public
850
	 * @since  1.0.0
851
	 * @return void
852
	 */
853
	public function enqueue_field_styles () {
854
855
856 View Code Duplication
		if ( $this->has_range ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
857
			wp_enqueue_style( 'woothemes-sensei-settings-ranges', esc_url( Sensei()->plugin_url . 'assets/css/ranges.css' ), '', Sensei()->version );
858
		}
859
860
		wp_register_style( 'woothemes-sensei-settings-imageselectors', esc_url( Sensei()->plugin_url . 'assets/css/image-selectors.css' ), '', Sensei()->version );
861
862
		if ( $this->has_imageselector ) {
863
			wp_enqueue_style( 'woothemes-sensei-settings-imageselectors' );
864
		}
865
	} // End enqueue_field_styles()
866
} // End Class
867
868
/**
869
 * Class WooThemes_Sensei_Settings_API
870
 * for backward compatibility
871
 * @since 1.9.0
872
 */
873
class WooThemes_Sensei_Settings_API extends Sensei_Settings_API{}
874