Passed
Pull Request — master (#465)
by Brian
12:30
created

validate_setting_checkbox_field()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 2
rs 10
c 1
b 0
f 0
1
<?php
2
/**
3
 * REST API Setting Options controller
4
 *
5
 * Handles requests to the /settings and /settings/$setting_id endpoints.
6
 *
7
 * @package GetPaid
8
 * @subpackage REST API
9
 * @since   2.0.0
10
 */
11
12
defined( 'ABSPATH' ) || exit;
13
14
/**
15
 * GetPaid REST Setting controller class.
16
 *
17
 * @package Invoicing
18
 */
19
class GetPaid_REST_Settings_Controller extends GetPaid_REST_Controller {
20
21
	/**
22
	 * An array of available settings.
23
	 *
24
	 * @var string
25
	 */
26
	protected $settings;
27
28
	/**
29
	 * Route base.
30
	 *
31
	 * @var string
32
	 */
33
	protected $rest_base = 'settings';
34
35
	/**
36
	 * Registers the routes for the objects of the controller.
37
	 *
38
	 * @since 2.0.0
39
	 *
40
	 * @see register_rest_route()
41
	 */
42
	public function register_namespace_routes( $namespace ) {
43
44
		// List all registered tabs.
45
		register_rest_route(
46
			$namespace,
47
			$this->rest_base,
48
			array(
49
				array(
50
					'methods'             => WP_REST_Server::READABLE,
51
					'callback'            => array( $this, 'get_tabs' ),
52
					'permission_callback' => array( $this, 'get_items_permissions_check' ),
53
				),
54
				'schema' => '__return_empty_array',
55
			)
56
		);
57
58
		// View/Update a single setting.
59
		register_rest_route(
60
			$namespace,
61
			$this->rest_base . '/setting/(?P<id>[\w-]+)',
62
			array(
63
				'args'   => array(
64
					'id'    => array(
65
						'description' => __( 'Unique identifier for the setting.', 'invoicing' ),
66
						'type'        => 'string',
67
						'required'    => true,
68
					),
69
				),
70
				array(
71
					'methods'             => WP_REST_Server::READABLE,
72
					'callback'            => array( $this, 'get_item' ),
73
					'permission_callback' => array( $this, 'get_items_permissions_check' ),
74
				),
75
				array(
76
					'methods'             => WP_REST_Server::EDITABLE,
77
					'callback'            => array( $this, 'update_item' ),
78
					'permission_callback' => array( $this, 'update_items_permissions_check' ),
79
					'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
80
				),
81
				'schema' => array( $this, 'get_public_item_schema' ),
82
			)
83
		);
84
85
		// List registered sections for a given tab.
86
		register_rest_route(
87
			$namespace,
88
			$this->rest_base . '/(?P<tab>[\w-]+)',
89
			array(
90
				'args'   => array(
91
					'tab'    => array(
92
						'description' => __( 'Unique identifier for the tab whose sections should be retrieved.', 'invoicing' ),
93
						'type'        => 'string',
94
						'required'    => true,
95
						'enum'        => array_keys( wpinv_get_settings_tabs() ),
96
					),
97
				),
98
				array(
99
					'methods'             => WP_REST_Server::READABLE,
100
					'callback'            => array( $this, 'get_sections' ),
101
					'permission_callback' => array( $this, 'get_items_permissions_check' ),
102
				),
103
				'schema' => '__return_empty_array',
104
			)
105
		);
106
107
		// List all registered settings for a given tab.
108
		register_rest_route(
109
			$namespace,
110
			$this->rest_base . '/(?P<tab>[\w-]+)/(?P<section>[\w-]+)',
111
			array(
112
				'args'   => array(
113
					'tab'    => array(
114
						'description' => __( 'Unique identifier for the tab whose settings should be retrieved.', 'invoicing' ),
115
						'type'        => 'string',
116
						'required'    => true,
117
						'enum'        => array_keys( wpinv_get_settings_tabs() ),
118
					),
119
					'section'    => array(
120
						'description' => __( 'The section in the tab whose settings should be retrieved.', 'invoicing' ),
121
						'type'        => 'string',
122
						'required'    => true,
123
					),
124
				),
125
				array(
126
					'methods'             => WP_REST_Server::READABLE,
127
					'callback'            => array( $this, 'get_items' ),
128
					'permission_callback' => array( $this, 'get_items_permissions_check' ),
129
				),
130
				'schema' => array( $this, 'get_public_item_schema' ),
131
			)
132
		);
133
134
		register_rest_route(
135
			$namespace,
136
			'/' . $this->rest_base . '/batch',
137
			array(
138
				'args'   => array(
139
					'id'              => array(
140
						'description' => __( 'Setting ID.', 'invoicing' ),
141
						'type'        => 'string',
142
					),
143
				),
144
				array(
145
					'methods'             => WP_REST_Server::EDITABLE,
146
					'callback'            => array( $this, 'batch_items' ),
147
					'permission_callback' => array( $this, 'batch_items_permissions_check' ),
148
					'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
149
				),
150
				'schema' => array( $this, 'get_public_batch_schema' ),
151
			)
152
		);
153
154
	}
155
	
156
	/**
157
	 * Return all settings.
158
	 *
159
	 * @since  2.0.0
160
	 * @param  WP_REST_Request $request Request data.
161
	 * @return WP_Error|WP_REST_Response
162
	 */
163
	public function get_items( $request ) {
164
165
		$settings = $this->get_settings();
166
167
		if ( ! isset( $settings[ $request['tab'] ] ) ) {
168
			return new WP_Error( 'rest_invalid_tab', __( 'Invalid tab.', 'invoicing' ), array( 'status' => 400 ) );
169
		}
170
171
		if ( ! isset( $settings[ $request['tab'] ][ $request['section'] ] ) ) {
172
			return new WP_Error( 'rest_invalid_section', __( 'Invalid section.', 'invoicing' ), array( 'status' => 400 ) );
173
		}
174
175
		$settings = $settings[ $request['tab'] ][ $request['section'] ];
176
		$prepared = array();
177
178
		foreach ( $settings as $setting ) {
179
180
			$setting      = $this->sanitize_setting( $setting );
181
			$setting_data = $this->prepare_item_for_response( $setting, $request );
182
			$setting_data = $this->prepare_response_for_collection( $setting_data );
183
184
			if ( $this->is_setting_type_valid( $setting['type'] ) ) {
185
				$prepared[]   = $setting_data;
186
			}
187
188
		}
189
190
		return rest_ensure_response( $prepared );
191
	}
192
193
	/**
194
	 * Return a single setting.
195
	 *
196
	 * @since  2.0.0
197
	 * @param  WP_REST_Request $request Request data.
198
	 * @return WP_Error|WP_REST_Response
199
	 */
200
	public function get_item( $request ) {
201
		$setting  = $this->get_setting( $request['id'] );
202
203
		if ( is_wp_error( $setting ) ) {
204
			return $setting;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $setting also could return the type array which is incompatible with the documented return type WP_Error|WP_REST_Response.
Loading history...
205
		}
206
207
		$setting  = $this->sanitize_setting( $setting );
0 ignored issues
show
Bug introduced by
It seems like $setting can also be of type WP_Error; however, parameter $setting of GetPaid_REST_Settings_Co...ler::sanitize_setting() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

207
		$setting  = $this->sanitize_setting( /** @scrutinizer ignore-type */ $setting );
Loading history...
208
		$response = $this->prepare_item_for_response( $setting, $request );
209
		return rest_ensure_response( $response );
210
	}
211
212
	/**
213
	 * Update a single setting.
214
	 *
215
	 * @since  2.0.0
216
	 * @param  WP_REST_Request $request Request data.
217
	 * @return WP_Error|WP_REST_Response
218
	 */
219
	public function update_item( $request ) {
220
		$setting = $this->get_setting( $request['id'] );
221
222
		if ( is_wp_error( $setting ) ) {
223
			return $setting;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $setting also could return the type array which is incompatible with the documented return type WP_Error|WP_REST_Response.
Loading history...
224
		}
225
226
		if ( is_callable( array( $this, 'validate_setting_' . $setting['type'] . '_field' ) ) ) {
227
			$value = $this->{'validate_setting_' . $setting['type'] . '_field'}( $request['value'], $setting );
228
		} else {
229
			$value = $this->validate_setting_text_field( $request['value'], $setting );
0 ignored issues
show
Unused Code introduced by
The call to GetPaid_REST_Settings_Co...te_setting_text_field() has too many arguments starting with $setting. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

229
			/** @scrutinizer ignore-call */ 
230
   $value = $this->validate_setting_text_field( $request['value'], $setting );

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
230
		}
231
232
		if ( is_wp_error( $value ) ) {
233
			return $value;
234
		}
235
236
		wpinv_update_option( $request['id'], $value );
237
		$setting['value'] = $value;
238
		$setting          = $this->sanitize_setting( $setting );
0 ignored issues
show
Bug introduced by
It seems like $setting can also be of type WP_Error; however, parameter $setting of GetPaid_REST_Settings_Co...ler::sanitize_setting() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

238
		$setting          = $this->sanitize_setting( /** @scrutinizer ignore-type */ $setting );
Loading history...
239
		$response         = $this->prepare_item_for_response( $setting, $request );
240
241
		return rest_ensure_response( $response );
242
	}
243
244
	/**
245
	 * Makes sure the current user has access to READ the settings APIs.
246
	 *
247
	 * @since  2.0.0
248
	 * @param WP_REST_Request $request Full data about the request.
249
	 * @return WP_Error|boolean
250
	 */
251
	public function get_items_permissions_check( $request ) {
252
		if ( ! wpinv_current_user_can_manage_invoicing() ) {
253
			return new WP_Error( 'rest_cannot_view', __( 'Sorry, you cannot list resources.', 'invoicing' ), array( 'status' => rest_authorization_required_code() ) );
254
		}
255
256
		return true;
257
	}
258
259
	/**
260
	 * Makes sure the current user has access to WRITE the settings APIs.
261
	 *
262
	 * @since  2.0.0
263
	 * @param WP_REST_Request $request Full data about the request.
264
	 * @return WP_Error|boolean
265
	 */
266
	public function update_items_permissions_check( $request ) {
267
		if ( ! wpinv_current_user_can_manage_invoicing() ) {
268
			return new WP_Error( 'rest_cannot_edit', __( 'Sorry, you cannot edit this resource.', 'invoicing' ), array( 'status' => rest_authorization_required_code() ) );
269
		}
270
271
		return true;
272
	}
273
274
	/**
275
	 * Check if a given request has access batch create, update and delete items.
276
	 *
277
	 * @param  WP_REST_Request $request Full details about the request.
278
	 *
279
	 * @return boolean|WP_Error
280
	 */
281
	public function batch_items_permissions_check( $request ) {
282
		return wpinv_current_user_can_manage_invoicing() ? true : new WP_Error( 'rest_cannot_batch', __( 'Sorry, you are not allowed to batch manipulate this resource.', 'invoicing' ), array( 'status' => rest_authorization_required_code() ) );
283
	}
284
285
	/**
286
	 * Prepare links for the request.
287
	 *
288
	 * @param string $setting_id Setting ID.
289
	 * @return array Links for the given setting.
290
	 */
291
	protected function prepare_links( $setting_id ) {
292
293
		$links = array(
294
			'self'       => array(
295
				'href'   => rest_url( sprintf( '/%s/%s/setting/%s', $this->namespace, $this->rest_base, $setting_id ) ),
296
			),
297
			'collection' => array(
298
				'href'   => rest_url( sprintf( '/%s/%s', $this->namespace, $this->rest_base ) ),
299
			),
300
		);
301
302
		return $links;
303
	}
304
305
	/**
306
	 * Prepare a settings object for serialization.
307
	 *
308
	 * @since  2.0.0
309
	 * @param array           $item Setting object.
310
	 * @param WP_REST_Request $request Request object.
311
	 * @return WP_REST_Response $response Response data.
312
	 */
313
	public function prepare_item_for_response( $item, $request ) {
314
		$context = empty( $request['context'] ) ? 'view' : $request['context'];
315
		$data    = $this->add_additional_fields_to_object( $item, $request );
316
		$data    = $this->filter_response_by_context( $data, $context );
317
318
		$response = rest_ensure_response( $data );
319
320
		$response->add_links( $this->prepare_links( $item['id'] ) );
321
322
		return $response;
323
	}
324
325
	/**
326
	 * Filters out bad values from the settings array/filter so we
327
	 * only return known values via the API.
328
	 *
329
	 * @since 2.0.0
330
	 * @param  array $setting Setting.
331
	 * @return array
332
	 */
333
	public function filter_setting( $setting ) {
334
		return array_intersect_key(
335
			$setting,
336
			array_flip( array_filter( array_keys( $setting ), array( $this, 'allowed_setting_keys' ) ) )
337
		);
338
	}
339
340
	/**
341
	 * Callback for allowed keys for each setting response.
342
	 *
343
	 * @param  string $key Key to check.
344
	 * @return boolean
345
	 */
346
	public function allowed_setting_keys( $key ) {
347
		return in_array( $key, array_keys( $this->setting_defaults() ), true );
348
	}
349
350
	/**
351
	 * Returns default options for a setting. null means the field is required.
352
	 *
353
	 * @since  2.0.0
354
	 * @return array
355
	 */
356
	protected function setting_defaults() {
357
		return array(
358
			'id'          => null,
359
			'name'        => null,
360
			'desc'        => '',
361
			'options'     => array(),
362
			'std'         => false,
363
			'value'       => false,
364
			'placeholder' => '',
365
			'readonly'    => false,
366
			'faux'        => false,
367
			'section'     => 'main',
368
			'tab'         => 'general',
369
			'type'        => 'text',
370
		);
371
	}
372
373
	/**
374
	 * Sanitizes a setting's field.
375
	 *
376
	 * @param  array $setting The setting to sanitize.
377
	 * @return array
378
	 */
379
	public function sanitize_setting( $setting ) {
380
		
381
		$setting          = wp_parse_args( $setting, $this->setting_defaults() );
382
		$setting['value'] = wpinv_get_option( $setting['id'], $setting['std'] );
383
		return $this->filter_setting( $setting );
384
385
	}
386
387
	/**
388
	 * Get setting data.
389
	 *
390
	 * @since  2.0.0
391
	 * @param string $setting_id Setting ID.
392
	 * @return array|WP_Error
393
	 */
394
	public function get_setting( $setting_id ) {
395
396
		if ( empty( $setting_id ) ) {
397
			return new WP_Error( 'rest_setting_setting_invalid', __( 'Invalid setting.', 'invoicing' ), array( 'status' => 404 ) );
398
		}
399
400
		$settings  = $this->get_settings();
401
402
		foreach ( $settings as $tabs ) {
403
404
			foreach ( $tabs as $sections ) {
405
406
				if ( isset( $sections[ $setting_id ] ) ) {
407
					if ( ! $this->is_setting_type_valid( $sections[ $setting_id ]['type'] ) ) {
408
						return new WP_Error( 'rest_setting_setting_type_invalid', __( 'Invalid setting type.', 'invoicing' ), array( 'status' => 404 ) );
409
					}
410
411
					return $sections[ $setting_id ];
412
				}
413
414
			}
415
416
		}
417
418
		return new WP_Error( 'rest_setting_setting_invalid', __( 'Invalid setting.', 'invoicing' ), array( 'status' => 404 ) );
419
	}
420
421
	/**
422
	 * Get all tabs.
423
	 *
424
	 * @param  WP_REST_Request $request Request data.
425
	 * @return array
426
	 */
427
	public function get_tabs( $request ) {
428
		$tabs     = wpinv_get_settings_tabs();
429
		$prepared = array();
430
431
		foreach ( $tabs as $id => $tab ) {
432
433
			$_request        = $request;
434
			$_request['tab'] = sanitize_title( $id );
435
			$data            = array(
436
				'id'       => sanitize_title( $id ),
437
				'label'    => sanitize_text_field( $tab ),
438
				'sections' => $this->get_sections( $_request ),
439
			);
440
441
			$data     = $this->add_additional_fields_to_object( $data, $request );
442
			$response = rest_ensure_response( $data );
443
444
			if ( ! is_wp_error( $response ) ) {
445
				$links = array(
446
					'sections'   => array(
447
						'href'   => rest_url( sprintf( '/%s/%s/%s', $this->namespace, $this->rest_base, $id ) ),
448
					),
449
					'collection' => array(
450
						'href'   => rest_url( sprintf( '/%s/%s', $this->namespace, $this->rest_base ) ),
451
					),
452
				);
453
				$response->add_links( $links );
454
				$response = $this->prepare_response_for_collection( $response );
455
			}
456
457
			$prepared[] = $response;
458
459
		}
460
461
		return rest_ensure_response( $prepared );
0 ignored issues
show
Bug Best Practice introduced by
The expression return rest_ensure_response($prepared) returns the type WP_REST_Response which is incompatible with the documented return type array.
Loading history...
462
	}
463
464
	/**
465
	 * Get all sections.
466
	 *
467
	 * @param  WP_REST_Request $request Request data.
468
	 * @return array
469
	 */
470
	public function get_sections( $request ) {
471
472
		$tab      = sanitize_title( $request['tab'] );
473
		$sections = wpinv_get_settings_tab_sections( $tab );
474
		$prepared = array();
475
476
		foreach ( $sections as $id => $section ) {
477
478
			$data            = array(
479
				'id'       => sanitize_title( $id ),
480
				'label'    => sanitize_text_field( $section ),
481
			);
482
483
			$data     = $this->add_additional_fields_to_object( $data, $request );
484
			$response = rest_ensure_response( $data );
485
486
			if ( ! is_wp_error( $response ) ) {
487
				$links = array(
488
					'settings'   => array(
489
						'href'   => rest_url( sprintf( '/%s/%s/%s/%s', $this->namespace, $this->rest_base, $tab, $id ) ),
490
					),
491
					'collection' => array(
492
						'href'   => rest_url( sprintf( '/%s/%s/%s', $this->namespace, $this->rest_base, $tab ) ),
493
					),
494
					'tabs'       => array(
495
						'href'   => rest_url( sprintf( '/%s/%s', $this->namespace, $this->rest_base ) ),
496
					),
497
				);
498
				$response->add_links( $links );
499
				$response = $this->prepare_response_for_collection( $response );
500
			}
501
502
			$prepared[] = $response;
503
504
		}
505
506
		return rest_ensure_response( $prepared );
0 ignored issues
show
Bug Best Practice introduced by
The expression return rest_ensure_response($prepared) returns the type WP_REST_Response which is incompatible with the documented return type array.
Loading history...
507
	}
508
509
	/**
510
	 * Get all settings.
511
	 *
512
	 * @return array
513
	 */
514
	public function get_settings() {
515
516
		if ( empty( $this->settings ) ) {
517
			$this->settings = wpinv_get_registered_settings();
0 ignored issues
show
Documentation Bug introduced by
It seems like wpinv_get_registered_settings() of type array is incompatible with the declared type string of property $settings.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
518
		}
519
520
		return $this->settings;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->settings also could return the type string which is incompatible with the documented return type array.
Loading history...
521
522
	}
523
524
	/**
525
	 * Boolean for if a setting type is a valid supported setting type.
526
	 *
527
	 * @since  2.0.0
528
	 * @param  string $type Type.
529
	 * @return bool
530
	 */
531
	public function is_setting_type_valid( $type ) {
532
533
		return in_array(
534
			$type, array(
535
				'text',         // Validates with validate_setting_text_field.
536
				'email',        // Validates with validate_setting_text_field.
537
				'number',       // Validates with validate_setting_text_field.
538
				'color',        // Validates with validate_setting_text_field.
539
				'password',     // Validates with validate_setting_text_field.
540
				'textarea',     // Validates with validate_setting_textarea_field.
541
				'select',       // Validates with validate_setting_select_field.
542
				'multiselect',  // Validates with validate_setting_multiselect_field.
543
				'radio',        // Validates with validate_setting_radio_field (-> validate_setting_select_field).
544
				'checkbox',     // Validates with validate_setting_checkbox_field.
545
				'header',       // Validates with validate_setting_text_field.
546
			)
547
		);
548
549
	}
550
551
	/**
552
	 * Get the settings schema, conforming to JSON Schema.
553
	 *
554
	 * @return array
555
	 */
556
	public function get_item_schema() {
557
558
		// Maybe retrieve the schema from cache.
559
		if ( ! empty( $this->schema ) ) {
560
			return $this->add_additional_fields_schema( $this->schema );
561
		}
562
563
		$schema = array(
564
			'$schema'    => 'http://json-schema.org/draft-04/schema#',
565
			'title'      => 'setting',
566
			'type'       => 'object',
567
			'properties' => array(
568
				'id'          => array(
569
					'description' => __( 'A unique identifier for the setting.', 'invoicing' ),
570
					'type'        => 'string',
571
					'arg_options' => array(
572
						'sanitize_callback' => 'sanitize_title',
573
					),
574
					'context'     => array( 'view', 'edit' ),
575
					'readonly'    => true,
576
				),
577
				'tab'         => array(
578
					'description' => __( 'An identifier for the tab this setting belongs to.', 'invoicing' ),
579
					'type'        => 'string',
580
					'arg_options' => array(
581
						'sanitize_callback' => 'sanitize_title',
582
					),
583
					'context'     => array( 'view', 'edit' ),
584
					'readonly'    => true,
585
				),
586
				'section'     => array(
587
					'description' => __( 'An identifier for the section this setting belongs to.', 'invoicing' ),
588
					'type'        => 'string',
589
					'arg_options' => array(
590
						'sanitize_callback' => 'sanitize_title',
591
					),
592
					'context'     => array( 'view', 'edit' ),
593
					'readonly'    => true,
594
				),
595
				'name'       => array(
596
					'description' => __( 'A human readable label for the setting used in interfaces.', 'invoicing' ),
597
					'type'        => 'string',
598
					'arg_options' => array(
599
						'sanitize_callback' => 'sanitize_text_field',
600
					),
601
					'context'     => array( 'view', 'edit' ),
602
					'readonly'    => true,
603
				),
604
				'desc'        => array(
605
					'description' => __( 'A human readable description for the setting used in interfaces.', 'invoicing' ),
606
					'type'        => 'string',
607
					'context'     => array( 'view', 'edit' ),
608
					'readonly'    => true,
609
				),
610
				'value'       => array(
611
					'description' => __( 'The current value of this setting.', 'invoicing' ),
612
					'type'        => 'mixed',
613
					'context'     => array( 'view', 'edit' ),
614
				),
615
				'default'     => array(
616
					'description' => __( 'Default value for the setting.', 'invoicing' ),
617
					'type'        => 'mixed',
618
					'context'     => array( 'view', 'edit' ),
619
					'readonly'    => true,
620
				),
621
				'placeholder' => array(
622
					'description' => __( 'Placeholder text to be displayed in text inputs.', 'invoicing' ),
623
					'type'        => 'string',
624
					'arg_options' => array(
625
						'sanitize_callback' => 'sanitize_text_field',
626
					),
627
					'context'     => array( 'view', 'edit' ),
628
					'readonly'    => true,
629
				),
630
				'type'        => array(
631
					'description' => __( 'Type of setting.', 'invoicing' ),
632
					'type'        => 'string',
633
					'arg_options' => array(
634
						'sanitize_callback' => 'sanitize_text_field',
635
					),
636
					'context'     => array( 'view', 'edit' ),
637
					'enum'        => array( 'text', 'email', 'number', 'color', 'password', 'textarea', 'select', 'multiselect', 'radio', 'image_width', 'checkbox', 'raw_html' ),
638
					'readonly'    => true,
639
				),
640
				'options'     => array(
641
					'description' => __( 'Array of options (key value pairs) for inputs such as select, multiselect, and radio buttons.', 'invoicing' ),
642
					'type'        => 'object',
643
					'context'     => array( 'view', 'edit' ),
644
					'readonly'    => true,
645
				),
646
				'readonly'        => array(
647
					'description' => __( 'Whether or not this setting is readonly', 'invoicing' ),
648
					'type'        => 'string',
649
					'context'     => array( 'view' ),
650
					'readonly'    => true,
651
				),
652
				'faux'            => array(
653
					'description' => __( 'Whether or not this setting is readonly/faux', 'invoicing' ),
654
					'type'        => 'string',
655
					'context'     => array( 'view' ),
656
					'readonly'    => true,
657
				),
658
			),
659
		);
660
661
		// Filters the settings schema for the REST API.
662
        $schema = apply_filters( 'getpaid_rest_settings_schema', $schema );
663
664
		// Cache the settings schema.
665
		$this->schema = $schema;
666
667
		return $this->add_additional_fields_schema( $this->schema );
668
669
	}
670
671
	/**
672
	 * Validate a text value for a text based setting.
673
	 *
674
	 * @since 2.0.0
675
	 * @param string $value Value.
676
	 * @param array  $setting Setting.
677
	 * @return string
678
	 */
679
	public function validate_setting_text_field( $value ) {
680
		$value = is_null( $value ) ? '' : $value;
0 ignored issues
show
introduced by
The condition is_null($value) is always false.
Loading history...
681
		return wp_kses_post( trim( stripslashes( $value ) ) );
682
	}
683
684
	/**
685
	 * Validate select based settings.
686
	 *
687
	 * @since 2.0.0
688
	 * @param string $value Value.
689
	 * @param array  $setting Setting.
690
	 * @return string|WP_Error
691
	 */
692
	public function validate_setting_select_field( $value, $setting ) {
693
		if ( array_key_exists( $value, $setting['options'] ) ) {
694
			return $value;
695
		} else {
696
			return new WP_Error( 'rest_setting_value_invalid', __( 'An invalid setting value was passed.', 'invoicing' ), array( 'status' => 400 ) );
697
		}
698
	}
699
700
	/**
701
	 * Validate multiselect based settings.
702
	 *
703
	 * @since 2.0.0
704
	 * @param array $values Values.
705
	 * @param array $setting Setting.
706
	 * @return array|WP_Error
707
	 */
708
	public function validate_setting_multiselect_field( $values, $setting ) {
709
		if ( empty( $values ) ) {
710
			return array();
711
		}
712
713
		if ( ! is_array( $values ) ) {
0 ignored issues
show
introduced by
The condition is_array($values) is always true.
Loading history...
714
			return new WP_Error( 'rest_setting_value_invalid', __( 'An invalid setting value was passed.', 'invoicing' ), array( 'status' => 400 ) );
715
		}
716
717
		$final_values = array();
718
		foreach ( $values as $value ) {
719
			if ( array_key_exists( $value, $setting['options'] ) ) {
720
				$final_values[] = $value;
721
			}
722
		}
723
724
		return $final_values;
725
	}
726
727
	/**
728
	 * Validate radio based settings.
729
	 *
730
	 * @since 2.0.0
731
	 * @param string $value Value.
732
	 * @param array  $setting Setting.
733
	 * @return string|WP_Error
734
	 */
735
	public function validate_setting_radio_field( $value, $setting ) {
736
		return $this->validate_setting_select_field( $value, $setting );
737
	}
738
739
	/**
740
	 * Validate checkbox based settings.
741
	 *
742
	 * @since 2.0.0
743
	 * @param string $value Value.
744
	 * @return int
745
	 */
746
	public function validate_setting_checkbox_field( $value ) {
747
		return (int) ! empty( $value );
748
	}
749
750
	/**
751
	 * Validate textarea based settings.
752
	 *
753
	 * @since 2.0.0
754
	 * @param string $value Value.
755
	 * @return string
756
	 */
757
	public function validate_setting_textarea_field( $value ) {
758
		$value = is_null( $value ) ? '' : $value;
0 ignored issues
show
introduced by
The condition is_null($value) is always false.
Loading history...
759
		return wp_kses(
760
			trim( stripslashes( $value ) ),
761
			array_merge(
762
				array(
763
					'iframe' => array(
764
						'src'   => true,
765
						'style' => true,
766
						'id'    => true,
767
						'class' => true,
768
					),
769
				),
770
				wp_kses_allowed_html( 'post' )
771
			)
772
		);
773
	}
774
775
}
776