PluginProbe ʕ •ᴥ•ʔ
Secure Custom Fields / 6.5.7
Secure Custom Fields v6.5.7
6.9.1 6.9.0 6.8.9 6.8.7 6.8.8 6.8.6 6.8.4 6.8.5 trunk 6.4.0-beta1 6.4.0-beta2 6.4.1 6.4.1-beta3 6.4.1-beta4 6.4.1-beta5 6.4.1-beta6 6.4.1-beta7 6.4.2 6.5.0 6.5.1 6.5.2 6.5.3 6.5.4 6.5.5 6.5.6 6.5.7 6.6.0 6.7.0 6.7.1 6.8.0 6.8.1 6.8.2 6.8.3
secure-custom-fields / includes / fields / class-acf-field-select.php
secure-custom-fields / includes / fields Last commit date
FlexibleContent 10 months ago class-acf-field-accordion.php 1 year ago class-acf-field-button-group.php 1 year ago class-acf-field-checkbox.php 10 months ago class-acf-field-clone.php 10 months ago class-acf-field-color_picker.php 1 year ago class-acf-field-date_picker.php 10 months ago class-acf-field-date_time_picker.php 10 months ago class-acf-field-email.php 1 year ago class-acf-field-file.php 1 year ago class-acf-field-flexible-content.php 10 months ago class-acf-field-gallery.php 1 year ago class-acf-field-google-map.php 10 months ago class-acf-field-group.php 10 months ago class-acf-field-icon_picker.php 10 months ago class-acf-field-image.php 1 year ago class-acf-field-link.php 1 year ago class-acf-field-message.php 1 year ago class-acf-field-nav-menu.php 1 year ago class-acf-field-number.php 1 year ago class-acf-field-oembed.php 10 months ago class-acf-field-output.php 1 year ago class-acf-field-page_link.php 10 months ago class-acf-field-password.php 1 year ago class-acf-field-post_object.php 10 months ago class-acf-field-radio.php 1 year ago class-acf-field-range.php 1 year ago class-acf-field-relationship.php 10 months ago class-acf-field-repeater.php 1 year ago class-acf-field-select.php 1 year ago class-acf-field-separator.php 1 year ago class-acf-field-tab.php 1 year ago class-acf-field-taxonomy.php 1 year ago class-acf-field-text.php 1 year ago class-acf-field-textarea.php 1 year ago class-acf-field-time_picker.php 1 year ago class-acf-field-true_false.php 1 year ago class-acf-field-url.php 1 year ago class-acf-field-user.php 1 year ago class-acf-field-wysiwyg.php 1 year ago class-acf-field.php 10 months ago class-acf-repeater-table.php 1 year ago index.php 1 year ago
class-acf-field-select.php
790 lines
1 <?php
2
3 if ( ! class_exists( 'acf_field_select' ) ) :
4
5 class acf_field_select extends acf_field {
6
7
8
9 /**
10 * This function will setup the field type data
11 *
12 * @type function
13 * @date 5/03/2014
14 * @since ACF 5.0.0
15 *
16 * @param n/a
17 * @return n/a
18 */
19 function initialize() {
20
21 // vars
22 $this->name = 'select';
23 $this->label = _x( 'Select', 'noun', 'secure-custom-fields' );
24 $this->category = 'choice';
25 $this->description = __( 'A dropdown list with a selection of choices that you specify.', 'secure-custom-fields' );
26 $this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-select.png';
27 $this->doc_url = 'https://developer.wordpress.org/secure-custom-fields/features/fields/select/';
28 $this->tutorial_url = 'https://developer.wordpress.org/secure-custom-fields/features/fields/select/select-tutorial/';
29 $this->defaults = array(
30 'multiple' => 0,
31 'allow_null' => 0,
32 'choices' => array(),
33 'default_value' => '',
34 'ui' => 0,
35 'ajax' => 0,
36 'placeholder' => '',
37 'return_format' => 'value',
38 'create_options' => 0,
39 'save_options' => 0,
40 );
41
42 // ajax
43 add_action( 'wp_ajax_acf/fields/select/query', array( $this, 'ajax_query' ) );
44 add_action( 'wp_ajax_nopriv_acf/fields/select/query', array( $this, 'ajax_query' ) );
45 }
46
47
48 /**
49 * Enqueues admin scripts for the Select field.
50 *
51 * @since ACF 5.3.2
52 *
53 * @return void
54 */
55 public function input_admin_enqueue_scripts() {
56 // Bail early if not enqueuing select2.
57 if ( ! acf_get_setting( 'enqueue_select2' ) ) {
58 return;
59 }
60
61 global $wp_scripts;
62
63 $min = defined( 'SCF_DEVELOPMENT_MODE' ) && SCF_DEVELOPMENT_MODE ? '' : '.min';
64 $major = acf_get_setting( 'select2_version' );
65
66 // attempt to find 3rd party Select2 version
67 // - avoid including v3 CSS when v4 JS is already enqueued.
68 if ( isset( $wp_scripts->registered['select2'] ) ) {
69 $major = (int) $wp_scripts->registered['select2']->ver;
70 }
71
72 if ( $major === 3 ) {
73 // Use v3 if necessary.
74 $version = '3.5.2';
75 $script = acf_get_url( "assets/inc/select2/3/select2{$min}.js" );
76 $style = acf_get_url( 'assets/inc/select2/3/select2.css' );
77 } else {
78 // Default to v4.
79 $version = '4.0.13';
80 $script = acf_get_url( "assets/inc/select2/4/select2.full{$min}.js" );
81 $style = acf_get_url( "assets/inc/select2/4/select2{$min}.css" );
82 }
83
84 wp_enqueue_script( 'select2', $script, array( 'jquery' ), $version );
85 wp_enqueue_style( 'select2', $style, '', $version );
86
87 acf_localize_data(
88 array(
89 'select2L10n' => array(
90 'matches_1' => _x( 'One result is available, press enter to select it.', 'Select2 JS matches_1', 'secure-custom-fields' ),
91 /* translators: %d - number of results available in select field */
92 'matches_n' => _x( '%d results are available, use up and down arrow keys to navigate.', 'Select2 JS matches_n', 'secure-custom-fields' ),
93 'matches_0' => _x( 'No matches found', 'Select2 JS matches_0', 'secure-custom-fields' ),
94 'input_too_short_1' => _x( 'Please enter 1 or more characters', 'Select2 JS input_too_short_1', 'secure-custom-fields' ),
95 /* translators: %d - number of characters to enter into select field input */
96 'input_too_short_n' => _x( 'Please enter %d or more characters', 'Select2 JS input_too_short_n', 'secure-custom-fields' ),
97 'input_too_long_1' => _x( 'Please delete 1 character', 'Select2 JS input_too_long_1', 'secure-custom-fields' ),
98 /* translators: %d - number of characters that should be removed from select field */
99 'input_too_long_n' => _x( 'Please delete %d characters', 'Select2 JS input_too_long_n', 'secure-custom-fields' ),
100 'selection_too_long_1' => _x( 'You can only select 1 item', 'Select2 JS selection_too_long_1', 'secure-custom-fields' ),
101 /* translators: %d - maximum number of items that can be selected in the select field */
102 'selection_too_long_n' => _x( 'You can only select %d items', 'Select2 JS selection_too_long_n', 'secure-custom-fields' ),
103 'load_more' => _x( 'Loading more results&hellip;', 'Select2 JS load_more', 'secure-custom-fields' ),
104 'searching' => _x( 'Searching&hellip;', 'Select2 JS searching', 'secure-custom-fields' ),
105 'load_fail' => _x( 'Loading failed', 'Select2 JS load_fail', 'secure-custom-fields' ),
106 ),
107 )
108 );
109 }
110
111 /**
112 * AJAX handler for getting Select field choices.
113 *
114 * @since ACF 5.0.0
115 *
116 * @return void
117 */
118 public function ajax_query() {
119 $nonce = acf_request_arg( 'nonce', '' );
120 $key = acf_request_arg( 'field_key', '' );
121
122 // Back-compat for field settings.
123 if ( ! acf_is_field_key( $key ) ) {
124 $nonce = '';
125 $key = '';
126 }
127
128 if ( ! acf_verify_ajax( $nonce, $key ) ) {
129 die();
130 }
131
132 acf_send_ajax_results( $this->get_ajax_query( $_POST ) );
133 }
134
135 /**
136 * This function will return an array of data formatted for use in a select2 AJAX response
137 *
138 * @since ACF 5.0.9
139 *
140 * @param array $options An array of options.
141 * @return array A select2 compatible array of options.
142 */
143 public function get_ajax_query( $options = array() ) {
144 $options = acf_parse_args(
145 $options,
146 array(
147 'post_id' => 0,
148 's' => '',
149 'field_key' => '',
150 'paged' => 1,
151 )
152 );
153
154 $shortcut = apply_filters( 'acf/fields/select/query', array(), $options );
155 $shortcut = apply_filters( 'acf/fields/select/query/key=' . $options['field_key'], $shortcut, $options );
156 if ( ! empty( $shortcut ) ) {
157 return $shortcut;
158 }
159
160 // load field.
161 $field = acf_get_field( $options['field_key'] );
162 if ( ! $field ) {
163 return false;
164 }
165
166 // get choices.
167 $choices = acf_get_array( $field['choices'] );
168 if ( empty( $field['choices'] ) ) {
169 return false;
170 }
171
172 $results = array();
173 $s = null;
174
175 // search.
176 if ( isset( $options['s'] ) && '' !== $options['s'] ) {
177
178 // strip slashes (search may be integer)
179 $s = strval( $options['s'] );
180 $s = wp_unslash( $s );
181 }
182
183 foreach ( $field['choices'] as $k => $v ) {
184
185 // ensure $v is a string.
186 $v = strval( $v );
187
188 // if searching, but doesn't exist.
189 if ( is_string( $s ) && stripos( $v, $s ) === false ) {
190 continue;
191 }
192
193 // append results.
194 $results[] = array(
195 'id' => $k,
196 'text' => $v,
197 );
198 }
199
200 $response = array(
201 'results' => $results,
202 );
203
204 return $response;
205 }
206
207
208 /**
209 * Creates the HTML interface for the field.
210 *
211 * @param array $field An array holding all the field's data.
212 * @return void
213 *
214 * @since ACF 3.6
215 */
216 function render_field( $field ) {
217
218 $value = acf_get_array( $field['value'] );
219 $choices = acf_get_array( $field['choices'] );
220
221 if ( empty( $field['placeholder'] ) ) {
222 $field['placeholder'] = _x( 'Select', 'verb', 'secure-custom-fields' );
223 }
224
225 // Add empty value (allows '' to be selected).
226 if ( empty( $value ) ) {
227 $value = array( '' );
228 }
229
230 // Prepend empty choice
231 // - only for single selects
232 // - have tried array_merge but this causes keys to re-index if is numeric (post ID's)
233 if ( isset( $field['allow_null'] ) && $field['allow_null'] && isset( $field['multiple'] ) && ! $field['multiple'] ) {
234 $choices = array( '' => "- {$field['placeholder']} -" ) + $choices;
235 }
236
237 // Clean up choices if using ajax.
238 if ( isset( $field['ui'] ) && $field['ui'] && isset( $field['ajax'] ) && $field['ajax'] ) {
239 $minimal = array();
240 foreach ( $value as $key ) {
241 if ( isset( $choices[ $key ] ) ) {
242 $minimal[ $key ] = $choices[ $key ];
243 }
244 }
245 $choices = $minimal;
246 }
247
248 $select = array(
249 'id' => acf_maybe_get( $field, 'id', '' ),
250 'class' => acf_maybe_get( $field, 'class', '' ),
251 'name' => acf_maybe_get( $field, 'name', '' ),
252 'data-ui' => acf_maybe_get( $field, 'ui', '' ),
253 'data-ajax' => acf_maybe_get( $field, 'ajax', '' ),
254 'data-multiple' => acf_maybe_get( $field, 'multiple', '' ),
255 'data-placeholder' => acf_maybe_get( $field, 'placeholder', '' ),
256 'data-allow_null' => acf_maybe_get( $field, 'allow_null', '' ),
257 );
258
259 if ( ! empty( $field['aria-label'] ) ) {
260 $select['aria-label'] = $field['aria-label'];
261 }
262
263 if ( isset( $field['multiple'] ) && $field['multiple'] ) {
264 $select['multiple'] = 'multiple';
265 $select['size'] = 5;
266 $select['name'] .= '[]';
267
268 // Reduce size to single line if UI.
269 if ( isset( $field['ui'] ) && $field['ui'] ) {
270 $select['size'] = 1;
271 }
272 }
273
274 if ( ! empty( $field['create_options'] ) && $field['ui'] ) {
275 $select['data-create_options'] = true;
276 }
277
278 // special atts
279 if ( ! empty( $field['readonly'] ) ) {
280 $select['readonly'] = 'readonly';
281 }
282 if ( ! empty( $field['disabled'] ) ) {
283 $select['disabled'] = 'disabled';
284 }
285 if ( ! empty( $field['ajax_action'] ) ) {
286 $select['data-ajax_action'] = $field['ajax_action'];
287 }
288 if ( ! empty( $field['nonce'] ) ) {
289 $select['data-nonce'] = $field['nonce'];
290 }
291 if ( isset( $field['ajax'] ) && $field['ajax'] && empty( $field['nonce'] ) && isset( $field['key'] ) && acf_is_field_key( $field['key'] ) ) {
292 $select['data-nonce'] = wp_create_nonce( $field['key'] );
293 }
294 if ( ! empty( $field['hide_search'] ) ) {
295 $select['data-minimum-results-for-search'] = '-1';
296 }
297
298 // hidden input is needed to allow validation to see <select> element with no selected value
299 if ( ( isset( $field['multiple'] ) && $field['multiple'] ) || ( isset( $field['ui'] ) && $field['ui'] ) ) {
300 acf_hidden_input(
301 array(
302 'id' => $field['id'] . '-input',
303 'name' => $field['name'],
304 )
305 );
306 }
307
308 // append
309 $select['value'] = $value;
310 $select['choices'] = $choices;
311
312 if ( ! empty( $field['create_options'] ) && $field['ui'] && is_array( $field['value'] ) ) {
313 foreach ( $field['value'] as $value ) {
314 // Already exists in choices.
315 if ( isset( $field['choices'][ $value ] ) ) {
316 continue;
317 }
318
319 $option = esc_attr( $value );
320
321 $select['choices'][ $option ] = $option;
322 }
323 }
324
325 // render
326 acf_select_input( $select );
327 }
328
329
330 /**
331 * Renders the field settings used in the "General" tab.
332 *
333 * @since ACF 3.6
334 *
335 * @param array $field An array holding all the field's data.
336 * @return void
337 */
338 public function render_field_settings( $field ) {
339
340 // encode choices (convert from array)
341 $field['choices'] = acf_encode_choices( $field['choices'] );
342 $field['default_value'] = acf_encode_choices( $field['default_value'], false );
343
344 // choices
345 acf_render_field_setting(
346 $field,
347 array(
348 'label' => __( 'Choices', 'secure-custom-fields' ),
349 'instructions' => __( 'Enter each choice on a new line.', 'secure-custom-fields' ) . '<br />' . __( 'For more control, you may specify both a value and label like this:', 'secure-custom-fields' ) . '<br /><span class="acf-field-setting-example">' . __( 'red : Red', 'secure-custom-fields' ) . '</span>',
350 'name' => 'choices',
351 'type' => 'textarea',
352 )
353 );
354
355 // default_value
356 acf_render_field_setting(
357 $field,
358 array(
359 'label' => __( 'Default Value', 'secure-custom-fields' ),
360 'instructions' => __( 'Enter each default value on a new line', 'secure-custom-fields' ),
361 'name' => 'default_value',
362 'type' => 'textarea',
363 )
364 );
365
366 // return_format
367 acf_render_field_setting(
368 $field,
369 array(
370 'label' => __( 'Return Format', 'secure-custom-fields' ),
371 'instructions' => __( 'Specify the value returned', 'secure-custom-fields' ),
372 'type' => 'radio',
373 'name' => 'return_format',
374 'layout' => 'horizontal',
375 'choices' => array(
376 'value' => __( 'Value', 'secure-custom-fields' ),
377 'label' => __( 'Label', 'secure-custom-fields' ),
378 'array' => __( 'Both (Array)', 'secure-custom-fields' ),
379 ),
380 )
381 );
382
383 acf_render_field_setting(
384 $field,
385 array(
386 'label' => __( 'Select Multiple', 'secure-custom-fields' ),
387 'instructions' => 'Allow content editors to select multiple values',
388 'name' => 'multiple',
389 'type' => 'true_false',
390 'ui' => 1,
391 )
392 );
393 }
394
395 /**
396 * Renders the field settings used in the "Validation" tab.
397 *
398 * @since ACF 6.0
399 *
400 * @param array $field The field settings array.
401 * @return void
402 */
403 public function render_field_validation_settings( $field ) {
404 acf_render_field_setting(
405 $field,
406 array(
407 'label' => __( 'Allow Null', 'secure-custom-fields' ),
408 'instructions' => '',
409 'name' => 'allow_null',
410 'type' => 'true_false',
411 'ui' => 1,
412 )
413 );
414 }
415
416 /**
417 * Renders the field settings used in the "Presentation" tab.
418 *
419 * @since ACF 6.0
420 *
421 * @param array $field The field settings array.
422 * @return void
423 */
424 public function render_field_presentation_settings( $field ) {
425 acf_render_field_setting(
426 $field,
427 array(
428 'label' => __( 'Stylized UI', 'secure-custom-fields' ),
429 'instructions' => __( 'Use a stylized checkbox using select2', 'secure-custom-fields' ),
430 'name' => 'ui',
431 'type' => 'true_false',
432 'ui' => 1,
433 )
434 );
435
436 acf_render_field_setting(
437 $field,
438 array(
439 'label' => __( 'Use AJAX to lazy load choices?', 'secure-custom-fields' ),
440 'instructions' => '',
441 'name' => 'ajax',
442 'type' => 'true_false',
443 'ui' => 1,
444 'conditions' => array(
445 'field' => 'ui',
446 'operator' => '==',
447 'value' => 1,
448 ),
449 )
450 );
451
452 acf_render_field_setting(
453 $field,
454 array(
455 'label' => __( 'Create Options', 'secure-custom-fields' ),
456 'instructions' => __( 'Allow content editors to create new options by typing in the Select input. Multiple options can be created from a comma separated string.', 'secure-custom-fields' ),
457 'name' => 'create_options',
458 'type' => 'true_false',
459 'ui' => 1,
460 'conditions' => array(
461 array(
462 'field' => 'ui',
463 'operator' => '==',
464 'value' => 1,
465 ),
466 array(
467 'field' => 'multiple',
468 'operator' => '==',
469 'value' => 1,
470 ),
471 ),
472 )
473 );
474
475 acf_render_field_setting(
476 $field,
477 array(
478 'label' => __( 'Save Options', 'secure-custom-fields' ),
479 'instructions' => __( 'Save created options back to the "Choices" setting in the field definition.', 'secure-custom-fields' ),
480 'name' => 'save_options',
481 'type' => 'true_false',
482 'ui' => 1,
483 'conditions' => array(
484 array(
485 'field' => 'ui',
486 'operator' => '==',
487 'value' => 1,
488 ),
489 array(
490 'field' => 'multiple',
491 'operator' => '==',
492 'value' => 1,
493 ),
494 array(
495 'field' => 'create_options',
496 'operator' => '==',
497 'value' => 1,
498 ),
499 ),
500 )
501 );
502 }
503
504 /**
505 * Filters the $value after it is loaded from the db.
506 *
507 * @since ACF 3.6
508 *
509 * @param mixed $value The value found in the database.
510 * @param integer|string $post_id The post_id from which the value was loaded.
511 * @param array $field The field array holding all the field options.
512 * @return mixed
513 */
514 public function load_value( $value, $post_id, $field ) {
515
516 // Return an array when field is set for multiple.
517 if ( $field['multiple'] ) {
518 if ( acf_is_empty( $value ) ) {
519 return array();
520 }
521 return acf_array( $value );
522 }
523
524 // Otherwise, return a single value.
525 return acf_unarray( $value );
526 }
527
528
529 /**
530 * Filters the $field before it is saved to the database.
531 *
532 * @since ACF 3.6
533 *
534 * @param array $field The field array holding all the field options.
535 * @return array
536 */
537 public function update_field( $field ) {
538
539 // Decode choices (convert to array).
540 $field['choices'] = acf_decode_choices( $field['choices'] );
541 $field['default_value'] = acf_decode_choices( $field['default_value'], true );
542
543 // Convert back to string for single selects.
544 if ( ! $field['multiple'] ) {
545 $field['default_value'] = acf_unarray( $field['default_value'] );
546 }
547
548 return $field;
549 }
550
551
552 /**
553 * Filters the $value before it is updated in the db.
554 *
555 * @since ACF 3.6
556 *
557 * @param mixed $value The value which will be saved in the database.
558 * @param integer|string $post_id The post_id of which the value will be saved.
559 * @param array $field The field array holding all the field options.
560 *
561 * @return mixed
562 */
563 public function update_value( $value, $post_id, $field ) {
564
565 // Bail early if no value.
566 if ( empty( $value ) ) {
567 return $value;
568 }
569
570 // Format array of values.
571 // - Parse each value as string for SQL LIKE queries.
572 if ( is_array( $value ) ) {
573 $value = array_map( 'strval', $value );
574 }
575
576 // Save custom options back to the field definition if configured.
577 if ( ! empty( $field['save_options'] ) && is_array( $value ) ) {
578 // Get the raw field, using the ID if present or the key otherwise (i.e. when using JSON).
579 $selector = $field['ID'] ? $field['ID'] : $field['key'];
580 $field = acf_get_field( $selector );
581
582 // Bail if we don't have a valid field or field ID (JSON only).
583 if ( empty( $field['ID'] ) ) {
584 return $value;
585 }
586
587 foreach ( $value as $v ) {
588 // Ignore if the option already exists.
589 if ( isset( $field['choices'][ $v ] ) ) {
590 continue;
591 }
592
593 // Unslash (fixes serialize single quote issue) and sanitize.
594 $v = wp_unslash( $v );
595 $v = sanitize_text_field( $v );
596
597 // Append to the field choices.
598 $field['choices'][ $v ] = $v;
599 }
600
601 acf_update_field( $field );
602 }
603 return $value;
604 }
605
606
607 /**
608 * Translates the field settings.
609 *
610 * @since ACF 5.3.2
611 *
612 * @param array $field The main field array.
613 * @return array
614 */
615 public function translate_field( $field ) {
616
617 $field['choices'] = acf_translate( $field['choices'] );
618 return $field;
619 }
620
621
622 /**
623 * Filters the $value after it is loaded from the db, and before it is returned to the template.
624 *
625 * @since ACF 3.6
626 *
627 * @param mixed $value The value which was loaded from the database.
628 * @param integer|string $post_id The post_id from which the value was loaded.
629 * @param array $field The field array holding all the field options.
630 *
631 * @return mixed
632 */
633 public function format_value( $value, $post_id, $field ) {
634 if ( is_array( $value ) ) {
635 foreach ( $value as $i => $val ) {
636 $value[ $i ] = $this->format_value_single( $val, $post_id, $field );
637 }
638 } else {
639 $value = $this->format_value_single( $value, $post_id, $field );
640 }
641 return $value;
642 }
643
644 /**
645 * Formats the value when the select is not a multi-select.
646 *
647 * @since 3.6
648 *
649 * @param mixed $value The value to format.
650 * @param integer|string $post_id The post_id from which the value was loaded.
651 * @param array $field The field array holding all the field options.
652 * @return mixed
653 */
654 public function format_value_single( $value, $post_id, $field ) {
655 // Bail early if is empty.
656 if ( acf_is_empty( $value ) ) {
657 return $value;
658 }
659
660 $label = acf_maybe_get( $field['choices'], $value, $value );
661
662 if ( 'label' === $field['return_format'] ) {
663 $value = $label;
664 } elseif ( 'array' === $field['return_format'] ) {
665 $value = array(
666 'value' => $value,
667 'label' => $label,
668 );
669 }
670
671 return $value;
672 }
673
674 /**
675 * Validates select fields updated via the REST API.
676 *
677 * @param boolean $valid The current validity boolean.
678 * @param integer $value The value of the field.
679 * @param array $field The field array.
680 * @return boolean|WP_Error
681 */
682 public function validate_rest_value( $valid, $value, $field ) {
683 // rest_validate_request_arg() handles the other types, we just worry about strings.
684 if ( is_null( $value ) || is_array( $value ) ) {
685 return $valid;
686 }
687
688 if ( ! acf_maybe_get( $field, 'choices' ) ) {
689 return $valid;
690 }
691
692 $option_keys = array_diff(
693 array_keys( $field['choices'] ),
694 array_values( $field['choices'] )
695 );
696
697 $allowed = empty( $option_keys ) ? $field['choices'] : $option_keys;
698
699 if ( ! in_array( $value, $allowed ) ) {
700 $prefix = isset( $field['prefix'] ) ? $field['prefix'] : '';
701 $name = isset( $field['name'] ) ? $field['name'] : '';
702 $param = sprintf( '%s[%s]', $prefix, $name );
703 $data = array(
704 'param' => $param,
705 'value' => $value,
706 );
707 $error = sprintf(
708 /* translators: 1: parameter, 2: allowed values */
709 __( '%1$s is not one of %2$s', 'secure-custom-fields' ),
710 $param,
711 implode( ', ', $allowed )
712 );
713
714 return new WP_Error( 'rest_invalid_param', $error, $data );
715 }
716
717 return $valid;
718 }
719
720 /**
721 * Formats the choices available for the REST API.
722 *
723 * @since ACF 6.2
724 *
725 * @param array $choices The choices for the field.
726 * @return array
727 */
728 public function format_rest_choices( $choices ) {
729 $keys = array_keys( $choices );
730 $values = array_values( $choices );
731 $int_choices = array();
732
733 if ( array_diff( $keys, $values ) ) {
734 // User has specified custom keys.
735 $choices = $keys;
736 } else {
737 // Default keys, same as value.
738 $choices = $values;
739 }
740
741 // Assume everything is a string by default.
742 $choices = array_map( 'strval', $choices );
743
744 // Also allow integers if is_numeric().
745 foreach ( $choices as $choice ) {
746 if ( is_numeric( $choice ) ) {
747 $int_choices[] = (int) $choice;
748 }
749 }
750
751 return array_merge( $choices, $int_choices );
752 }
753
754 /**
755 * Return the schema array for the REST API.
756 *
757 * @param array $field The main field array.
758 * @return array
759 */
760 public function get_rest_schema( array $field ) {
761 $schema = array(
762 'type' => array( 'string', 'array', 'int', 'null' ),
763 'required' => ! empty( $field['required'] ),
764 'items' => array(
765 'type' => array( 'string', 'int' ),
766 'enum' => $this->format_rest_choices( $field['choices'] ),
767 ),
768 );
769
770 if ( empty( $field['allow_null'] ) ) {
771 $schema['minItems'] = 1;
772 }
773
774 if ( empty( $field['multiple'] ) ) {
775 $schema['maxItems'] = 1;
776 }
777
778 if ( isset( $field['default_value'] ) && '' !== $field['default_value'] ) {
779 $schema['default'] = $field['default_value'];
780 }
781
782 return $schema;
783 }
784 }
785
786
787 // initialize
788 acf_register_field_type( 'acf_field_select' );
789 endif; // class_exists check
790