PluginProbe ʕ •ᴥ•ʔ
Secure Custom Fields / 6.4.0-beta2
Secure Custom Fields v6.4.0-beta2
6.9.5 6.9.4 6.9.3 6.9.2 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-checkbox.php
secure-custom-fields / includes / fields Last commit date
class-acf-field-accordion.php 1 year ago class-acf-field-button-group.php 1 year ago class-acf-field-checkbox.php 1 year ago class-acf-field-color_picker.php 1 year ago class-acf-field-date_picker.php 1 year ago class-acf-field-date_time_picker.php 1 year ago class-acf-field-email.php 1 year ago class-acf-field-file.php 1 year ago class-acf-field-google-map.php 1 year ago class-acf-field-group.php 1 year ago class-acf-field-icon_picker.php 1 year 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-number.php 1 year ago class-acf-field-oembed.php 1 year ago class-acf-field-output.php 1 year ago class-acf-field-page_link.php 1 year ago class-acf-field-password.php 1 year ago class-acf-field-post_object.php 1 year ago class-acf-field-radio.php 1 year ago class-acf-field-range.php 1 year ago class-acf-field-relationship.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 1 year ago index.php 1 year ago
class-acf-field-checkbox.php
593 lines
1 <?php
2
3 if ( ! class_exists( 'acf_field_checkbox' ) ) :
4
5 class acf_field_checkbox extends acf_field {
6
7
8 /**
9 * This function will setup the field type data
10 *
11 * @type function
12 * @date 5/03/2014
13 * @since 5.0.0
14 *
15 * @param n/a
16 * @return n/a
17 */
18 function initialize() {
19
20 // vars
21 $this->name = 'checkbox';
22 $this->label = __( 'Checkbox', 'acf' );
23 $this->category = 'choice';
24 $this->description = __( 'A group of checkbox inputs that allow the user to select one, or multiple values that you specify.', 'acf' );
25 $this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-checkbox.png';
26 $this->doc_url = 'https://www.advancedcustomfields.com/resources/checkbox/';
27 $this->defaults = array(
28 'layout' => 'vertical',
29 'choices' => array(),
30 'default_value' => '',
31 'allow_custom' => 0,
32 'save_custom' => 0,
33 'toggle' => 0,
34 'return_format' => 'value',
35 'custom_choice_button_text' => __( 'Add new choice', 'acf' ),
36 );
37 }
38
39
40 /**
41 * Create the HTML interface for your field
42 *
43 * @param $field (array) the $field being rendered
44 *
45 * @type action
46 * @since 3.6
47 * @date 23/01/13
48 *
49 * @param $field (array) the $field being edited
50 * @return n/a
51 */
52 function render_field( $field ) {
53
54 // reset vars
55 $this->_values = array();
56 $this->_all_checked = true;
57
58 // ensure array
59 $field['value'] = acf_get_array( $field['value'] );
60 $field['choices'] = acf_get_array( $field['choices'] );
61
62 // hiden input
63 acf_hidden_input( array( 'name' => $field['name'] ) );
64
65 // vars
66 $li = '';
67 $ul = array(
68 'class' => 'acf-checkbox-list',
69 );
70
71 // append to class
72 $ul['class'] .= ' ' . ( $field['layout'] == 'horizontal' ? 'acf-hl' : 'acf-bl' );
73 $ul['class'] .= ' ' . $field['class'];
74
75 // checkbox saves an array
76 $field['name'] .= '[]';
77
78 // choices
79 if ( ! empty( $field['choices'] ) ) {
80
81 // choices
82 $li .= $this->render_field_choices( $field );
83
84 // toggle
85 if ( $field['toggle'] ) {
86 $li = $this->render_field_toggle( $field ) . $li;
87 }
88 }
89
90 // custom
91 if ( $field['allow_custom'] ) {
92 $li .= $this->render_field_custom( $field );
93 }
94
95 // return
96 echo '<ul ' . acf_esc_attrs( $ul ) . '>' . "\n" . $li . '</ul>' . "\n"; //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- escaped by specific render methods above.
97 }
98
99
100 /**
101 * description
102 *
103 * @type function
104 * @date 15/7/17
105 * @since 5.6.0
106 *
107 * @param $post_id (int)
108 * @return $post_id (int)
109 */
110 function render_field_choices( $field ) {
111
112 // walk
113 return $this->walk( $field['choices'], $field );
114 }
115
116 /**
117 * Validates values for the checkbox field
118 *
119 * @since 6.0.0
120 *
121 * @param boolean $valid If the field is valid.
122 * @param mixed $value The value to validate.
123 * @param array $field The main field array.
124 * @param string $input The input element's name attribute.
125 * @return boolean
126 */
127 public function validate_value( $valid, $value, $field, $input ) {
128 if ( ! is_array( $value ) || empty( $field['allow_custom'] ) ) {
129 return $valid;
130 }
131
132 foreach ( $value as $value ) {
133 if ( empty( $value ) && $value !== '0' ) {
134 return __( 'Checkbox custom values cannot be empty. Uncheck any empty values.', 'acf' );
135 }
136 }
137
138 return $valid;
139 }
140
141 /**
142 * description
143 *
144 * @type function
145 * @date 15/7/17
146 * @since 5.6.0
147 *
148 * @param $post_id (int)
149 * @return $post_id (int)
150 */
151 function render_field_toggle( $field ) {
152
153 // vars
154 $atts = array(
155 'type' => 'checkbox',
156 'class' => 'acf-checkbox-toggle',
157 'label' => __( 'Toggle All', 'acf' ),
158 );
159
160 // custom label
161 if ( is_string( $field['toggle'] ) ) {
162 $atts['label'] = $field['toggle'];
163 }
164
165 // checked
166 if ( $this->_all_checked ) {
167 $atts['checked'] = 'checked';
168 }
169
170 // return
171 return '<li>' . acf_get_checkbox_input( $atts ) . '</li>' . "\n";
172 }
173
174
175 /**
176 * description
177 *
178 * @type function
179 * @date 15/7/17
180 * @since 5.6.0
181 *
182 * @param $post_id (int)
183 * @return $post_id (int)
184 */
185 function render_field_custom( $field ) {
186
187 // vars
188 $html = '';
189
190 // loop
191 foreach ( $field['value'] as $value ) {
192
193 // ignore if already eixsts
194 if ( isset( $field['choices'][ $value ] ) ) {
195 continue;
196 }
197
198 // vars
199 $esc_value = esc_attr( $value );
200 $text_input = array(
201 'name' => $field['name'],
202 'value' => $value,
203 );
204
205 // bail early if choice already exists
206 if ( in_array( $esc_value, $this->_values ) ) {
207 continue;
208 }
209
210 // append
211 $html .= '<li><input class="acf-checkbox-custom" type="checkbox" checked="checked" />' . acf_get_text_input( $text_input ) . '</li>' . "\n";
212 }
213
214 // append button
215 $html .= '<li><a href="#" class="button acf-add-checkbox">' . esc_attr( $field['custom_choice_button_text'] ) . '</a></li>' . "\n";
216
217 // return
218 return $html;
219 }
220
221
222 function walk( $choices = array(), $args = array(), $depth = 0 ) {
223
224 // bail early if no choices
225 if ( empty( $choices ) ) {
226 return '';
227 }
228
229 // defaults
230 $args = wp_parse_args(
231 $args,
232 array(
233 'id' => '',
234 'type' => 'checkbox',
235 'name' => '',
236 'value' => array(),
237 'disabled' => array(),
238 )
239 );
240
241 // vars
242 $html = '';
243
244 // sanitize values for 'selected' matching
245 if ( $depth == 0 ) {
246 $args['value'] = array_map( 'esc_attr', $args['value'] );
247 $args['disabled'] = array_map( 'esc_attr', $args['disabled'] );
248 }
249
250 // loop
251 foreach ( $choices as $value => $label ) {
252
253 // open
254 $html .= '<li>';
255
256 // optgroup
257 if ( is_array( $label ) ) {
258 $html .= '<ul>' . "\n";
259 $html .= $this->walk( $label, $args, $depth + 1 );
260 $html .= '</ul>';
261
262 // option
263 } else {
264
265 // vars
266 $esc_value = esc_attr( $value );
267 $atts = array(
268 'id' => $args['id'] . '-' . str_replace( ' ', '-', $value ),
269 'type' => $args['type'],
270 'name' => $args['name'],
271 'value' => $value,
272 'label' => $label,
273 );
274
275 // selected
276 if ( in_array( $esc_value, $args['value'] ) ) {
277 $atts['checked'] = 'checked';
278 } else {
279 $this->_all_checked = false;
280 }
281
282 // disabled
283 if ( in_array( $esc_value, $args['disabled'] ) ) {
284 $atts['disabled'] = 'disabled';
285 }
286
287 // store value added
288 $this->_values[] = $esc_value;
289
290 // append
291 $html .= acf_get_checkbox_input( $atts );
292 }
293
294 // close
295 $html .= '</li>' . "\n";
296 }
297
298 // return
299 return $html;
300 }
301
302
303
304 /**
305 * Create extra options for your field. This is rendered when editing a field.
306 * The value of $field['name'] can be used (like bellow) to save extra data to the $field
307 *
308 * @type action
309 * @since 3.6
310 * @date 23/01/13
311 *
312 * @param $field - an array holding all the field's data
313 */
314 function render_field_settings( $field ) {
315 // Encode choices (convert from array).
316 $field['choices'] = acf_encode_choices( $field['choices'] );
317 $field['default_value'] = acf_encode_choices( $field['default_value'], false );
318
319 acf_render_field_setting(
320 $field,
321 array(
322 'label' => __( 'Choices', 'acf' ),
323 'instructions' => __( 'Enter each choice on a new line.', 'acf' ) . '<br />' . __( 'For more control, you may specify both a value and label like this:', 'acf' ) . '<br /><span class="acf-field-setting-example">' . __( 'red : Red', 'acf' ) . '</span>',
324 'type' => 'textarea',
325 'name' => 'choices',
326 )
327 );
328
329 acf_render_field_setting(
330 $field,
331 array(
332 'label' => __( 'Default Value', 'acf' ),
333 'instructions' => __( 'Enter each default value on a new line', 'acf' ),
334 'type' => 'textarea',
335 'name' => 'default_value',
336 )
337 );
338
339 acf_render_field_setting(
340 $field,
341 array(
342 'label' => __( 'Return Value', 'acf' ),
343 'instructions' => __( 'Specify the returned value on front end', 'acf' ),
344 'type' => 'radio',
345 'name' => 'return_format',
346 'layout' => 'horizontal',
347 'choices' => array(
348 'value' => __( 'Value', 'acf' ),
349 'label' => __( 'Label', 'acf' ),
350 'array' => __( 'Both (Array)', 'acf' ),
351 ),
352 )
353 );
354 }
355
356 /**
357 * Renders the field settings used in the "Validation" tab.
358 *
359 * @since 6.0
360 *
361 * @param array $field The field settings array.
362 * @return void
363 */
364 function render_field_validation_settings( $field ) {
365 acf_render_field_setting(
366 $field,
367 array(
368 'label' => __( 'Allow Custom Values', 'acf' ),
369 'name' => 'allow_custom',
370 'type' => 'true_false',
371 'ui' => 1,
372 'instructions' => __( "Allow 'custom' values to be added", 'acf' ),
373 )
374 );
375
376 acf_render_field_setting(
377 $field,
378 array(
379 'label' => __( 'Save Custom Values', 'acf' ),
380 'name' => 'save_custom',
381 'type' => 'true_false',
382 'ui' => 1,
383 'instructions' => __( "Save 'custom' values to the field's choices", 'acf' ),
384 'conditions' => array(
385 'field' => 'allow_custom',
386 'operator' => '==',
387 'value' => 1,
388 ),
389 )
390 );
391 }
392
393 /**
394 * Renders the field settings used in the "Presentation" tab.
395 *
396 * @since 6.0
397 *
398 * @param array $field The field settings array.
399 * @return void
400 */
401 function render_field_presentation_settings( $field ) {
402 acf_render_field_setting(
403 $field,
404 array(
405 'label' => __( 'Layout', 'acf' ),
406 'instructions' => '',
407 'type' => 'radio',
408 'name' => 'layout',
409 'layout' => 'horizontal',
410 'choices' => array(
411 'vertical' => __( 'Vertical', 'acf' ),
412 'horizontal' => __( 'Horizontal', 'acf' ),
413 ),
414 )
415 );
416
417 acf_render_field_setting(
418 $field,
419 array(
420 'label' => __( 'Add Toggle All', 'acf' ),
421 'instructions' => __( 'Prepend an extra checkbox to toggle all choices', 'acf' ),
422 'name' => 'toggle',
423 'type' => 'true_false',
424 'ui' => 1,
425 )
426 );
427 }
428
429 /**
430 * This filter is appied to the $field before it is saved to the database
431 *
432 * @type filter
433 * @since 3.6
434 * @date 23/01/13
435 *
436 * @param $field - the field array holding all the field options
437 * @param $post_id - the field group ID (post_type = acf)
438 *
439 * @return $field - the modified field
440 */
441 function update_field( $field ) {
442
443 // Decode choices (convert to array).
444 $field['choices'] = acf_decode_choices( $field['choices'] );
445 $field['default_value'] = acf_decode_choices( $field['default_value'], true );
446 return $field;
447 }
448
449
450 /**
451 * This filter is appied to the $value before it is updated in the db
452 *
453 * @type filter
454 * @since 3.6
455 * @date 23/01/13
456 *
457 * @param $value - the value which will be saved in the database
458 * @param $post_id - the post_id of which the value will be saved
459 * @param $field - the field array holding all the field options
460 *
461 * @return $value - the modified value
462 */
463 function update_value( $value, $post_id, $field ) {
464
465 // bail early if is empty
466 if ( empty( $value ) ) {
467 return $value;
468 }
469
470 // select -> update_value()
471 $value = acf_get_field_type( 'select' )->update_value( $value, $post_id, $field );
472
473 // save_other_choice
474 if ( $field['save_custom'] ) {
475
476 // get raw $field (may have been changed via repeater field)
477 // if field is local, it won't have an ID
478 $selector = $field['ID'] ? $field['ID'] : $field['key'];
479 $field = acf_get_field( $selector );
480 if ( ! $field ) {
481 return false;
482 }
483
484 // bail early if no ID (JSON only)
485 if ( ! $field['ID'] ) {
486 return $value;
487 }
488
489 // loop
490 foreach ( $value as $v ) {
491
492 // ignore if already eixsts
493 if ( isset( $field['choices'][ $v ] ) ) {
494 continue;
495 }
496
497 // unslash (fixes serialize single quote issue)
498 $v = wp_unslash( $v );
499
500 // sanitize (remove tags)
501 $v = sanitize_text_field( $v );
502
503 // append
504 $field['choices'][ $v ] = $v;
505 }
506
507 // save
508 acf_update_field( $field );
509 }
510
511 // return
512 return $value;
513 }
514
515
516 /**
517 * This function will translate field settings
518 *
519 * @type function
520 * @date 8/03/2016
521 * @since 5.3.2
522 *
523 * @param $field (array)
524 * @return $field
525 */
526 function translate_field( $field ) {
527
528 return acf_get_field_type( 'select' )->translate_field( $field );
529 }
530
531
532 /**
533 * This filter is appied to the $value after it is loaded from the db and before it is returned to the template
534 *
535 * @type filter
536 * @since 3.6
537 * @date 23/01/13
538 *
539 * @param $value (mixed) the value which was loaded from the database
540 * @param $post_id (mixed) the post_id from which the value was loaded
541 * @param $field (array) the field array holding all the field options
542 *
543 * @return $value (mixed) the modified value
544 */
545 function format_value( $value, $post_id, $field ) {
546
547 // Bail early if is empty.
548 if ( acf_is_empty( $value ) ) {
549 return array();
550 }
551
552 // Always convert to array of items.
553 $value = acf_array( $value );
554
555 // Return.
556 return acf_get_field_type( 'select' )->format_value( $value, $post_id, $field );
557 }
558
559 /**
560 * Return the schema array for the REST API.
561 *
562 * @param array $field
563 * @return array
564 */
565 public function get_rest_schema( array $field ) {
566 $schema = array(
567 'type' => array( 'integer', 'string', 'array', 'null' ),
568 'required' => isset( $field['required'] ) && $field['required'],
569 'items' => array(
570 'type' => array( 'string', 'integer' ),
571 ),
572 );
573
574 if ( isset( $field['default_value'] ) && '' !== $field['default_value'] ) {
575 $schema['default'] = $field['default_value'];
576 }
577
578 // If we allow custom values, nothing else to do here.
579 if ( ! empty( $field['allow_custom'] ) ) {
580 return $schema;
581 }
582
583 $schema['items']['enum'] = acf_get_field_type( 'select' )->format_rest_choices( $field['choices'] );
584
585 return $schema;
586 }
587 }
588
589
590 // initialize
591 acf_register_field_type( 'acf_field_checkbox' );
592 endif; // class_exists check
593