PluginProbe ʕ •ᴥ•ʔ
Secure Custom Fields / 6.4.1-beta7
Secure Custom Fields v6.4.1-beta7
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-taxonomy.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-clone.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-flexible-content.php 1 year ago class-acf-field-gallery.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-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 1 year ago class-acf-repeater-table.php 1 year ago index.php 1 year ago
class-acf-field-taxonomy.php
963 lines
1 <?php
2
3 if ( ! class_exists( 'acf_field_taxonomy' ) ) :
4
5 class acf_field_taxonomy extends acf_field {
6
7
8 // vars
9 var $save_post_terms = array();
10
11
12 /**
13 * This function will setup the field type data
14 *
15 * @type function
16 * @date 5/03/2014
17 * @since ACF 5.0.0
18 */
19 public function initialize() {
20 $this->name = 'taxonomy';
21 $this->label = __( 'Taxonomy', 'secure-custom-fields' );
22 $this->category = 'relational';
23 $this->description = __( 'Allows the selection of one or more taxonomy terms based on the criteria and options specified in the fields settings.', 'secure-custom-fields' );
24 $this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-taxonomy.png';
25 $this->doc_url = 'https://developer.wordpress.org/secure-custom-fields/features/fields/taxonomy/';
26 $this->tutorial_url = 'https://developer.wordpress.org/secure-custom-fields/features/fields/taxonomy/taxonomy-tutorial/';
27 $this->defaults = array(
28 'taxonomy' => 'category',
29 'field_type' => 'checkbox',
30 'multiple' => 0,
31 'allow_null' => 0,
32 'return_format' => 'id',
33 'add_term' => 1, // 5.2.3
34 'load_terms' => 0, // 5.2.7
35 'save_terms' => 0, // 5.2.7
36 'bidirectional_target' => array(),
37 );
38
39 // Register filter variations.
40 acf_add_filter_variations( 'acf/fields/taxonomy/query', array( 'name', 'key' ), 1 );
41 acf_add_filter_variations( 'acf/fields/taxonomy/result', array( 'name', 'key' ), 2 );
42
43 // ajax
44 add_action( 'wp_ajax_acf/fields/taxonomy/query', array( $this, 'ajax_query' ) );
45 add_action( 'wp_ajax_nopriv_acf/fields/taxonomy/query', array( $this, 'ajax_query' ) );
46 add_action( 'wp_ajax_acf/fields/taxonomy/add_term', array( $this, 'ajax_add_term' ) );
47 add_filter( 'acf/conditional_logic/choices', array( $this, 'render_field_taxonomy_conditional_choices' ), 10, 3 );
48
49 // actions
50 add_action( 'acf/save_post', array( $this, 'save_post' ), 15, 1 );
51 }
52
53 /**
54 * Returns AJAX results for the Taxonomy field.
55 *
56 * @since ACF 5.0.0
57 *
58 * @return void
59 */
60 public function ajax_query() {
61 $nonce = acf_request_arg( 'nonce', '' );
62 $key = acf_request_arg( 'field_key', '' );
63 $conditional_logic = (bool) acf_request_arg( 'conditional_logic', false );
64
65 if ( $conditional_logic ) {
66 if ( ! acf_current_user_can_admin() ) {
67 die();
68 }
69
70 // Use the standard ACF admin nonce.
71 $nonce = '';
72 $key = '';
73 }
74
75 if ( ! acf_verify_ajax( $nonce, $key ) ) {
76 die();
77 }
78
79 acf_send_ajax_results( $this->get_ajax_query( $_POST ) );
80 }
81
82 /**
83 * This function will return an array of data formatted for use in a select2 AJAX response
84 *
85 * @type function
86 * @date 15/10/2014
87 * @since ACF 5.0.9
88 *
89 * @param $options (array)
90 * @return (array)
91 */
92 function get_ajax_query( $options = array() ) {
93 $options = acf_parse_args(
94 $options,
95 array(
96 'post_id' => 0,
97 's' => '',
98 'field_key' => '',
99 'term_id' => '',
100 'include' => '',
101 'paged' => 1,
102 )
103 );
104
105 $field = acf_get_field( $options['field_key'] );
106 if ( ! $field ) {
107 return false;
108 }
109
110 // if options include isset, then we are loading a specific term.
111 if ( ! empty( $options['include'] ) ) {
112 $options['term_id'] = $options['include'];
113 // paged should be 1.
114 $options['paged'] = 1;
115 }
116
117 // Bail early if taxonomy does not exist.
118 if ( ! taxonomy_exists( $field['taxonomy'] ) ) {
119 return false;
120 }
121
122 $results = array();
123 $is_hierarchical = is_taxonomy_hierarchical( $field['taxonomy'] );
124 $is_pagination = ( $options['paged'] > 0 );
125 $is_search = false;
126 $limit = 20;
127 $offset = 20 * ( $options['paged'] - 1 );
128
129 $args = array(
130 'taxonomy' => $field['taxonomy'],
131 'hide_empty' => false,
132 );
133
134 // Don't bother for hierarchial terms, we will need to load all terms anyway.
135 if ( $is_pagination && ! $is_hierarchical ) {
136 $args['number'] = $limit;
137 $args['offset'] = $offset;
138 }
139
140 // search
141 if ( $options['s'] !== '' ) {
142
143 // strip slashes (search may be integer)
144 $s = wp_unslash( strval( $options['s'] ) );
145
146 $args['search'] = isset( $options['term_id'] ) && $options['term_id'] ? '' : $s;
147 $is_search = true;
148 }
149
150 $args = apply_filters( 'acf/fields/taxonomy/query', $args, $field, $options['post_id'] );
151
152 if ( ! empty( $options['include'] ) ) {
153 // Limit search to a specific id if one is provided.
154 $args['include'] = $options['include'];
155 }
156
157 $terms = acf_get_terms( $args );
158
159 // Sort hierachial.
160 if ( $is_hierarchical ) {
161 $limit = acf_maybe_get( $args, 'number', $limit );
162 $offset = acf_maybe_get( $args, 'offset', $offset );
163
164 $parent = acf_maybe_get( $args, 'parent', 0 );
165 $parent = acf_maybe_get( $args, 'child_of', $parent );
166
167 // This will fail if a search has taken place because parents wont exist.
168 if ( ! $is_search ) {
169 $ordered_terms = _get_term_children( $parent, $terms, $field['taxonomy'] );
170 // Check for empty array. Possible if parent did not exist within original data.
171 if ( ! empty( $ordered_terms ) ) {
172 $terms = $ordered_terms;
173 }
174 }
175
176 // Fake pagination.
177 if ( $is_pagination && ! $options['include'] ) {
178 $terms = array_slice( $terms, $offset, $limit );
179 }
180 }
181
182 // Append to r.
183 foreach ( $terms as $term ) {
184
185 // Add to json.
186 $results[] = array(
187 'id' => $term->term_id,
188 'text' => $this->get_term_title( $term, $field, $options['post_id'], true ),
189 );
190 }
191
192 $response = array(
193 'results' => $results,
194 'limit' => $limit,
195 );
196
197 return $response;
198 }
199
200 /**
201 * Returns the Term's title displayed in the field UI.
202 *
203 * @since ACF 5.0.0
204 *
205 * @param WP_Term $term The term object.
206 * @param array $field The field settings.
207 * @param mixed $post_id The post_id being edited.
208 * @param boolean $unescape Should we return an unescaped post title.
209 * @return string
210 */
211 function get_term_title( $term, $field, $post_id = 0, $unescape = false ) {
212 $title = acf_get_term_title( $term );
213
214 // Default $post_id to current post being edited.
215 $post_id = $post_id ? $post_id : acf_get_form_data( 'post_id' );
216
217 // unescape for select2 output which handles the escaping.
218 if ( $unescape ) {
219 $title = html_entity_decode( $title );
220 }
221
222 /**
223 * Filters the term title.
224 *
225 * @date 1/11/2013
226 * @since ACF 5.0.0
227 *
228 * @param string $title The term title.
229 * @param WP_Term $term The term object.
230 * @param array $field The field settings.
231 * @param (int|string) $post_id The post_id being edited.
232 */
233 return apply_filters( 'acf/fields/taxonomy/result', $title, $term, $field, $post_id );
234 }
235
236
237 /**
238 * This function will return an array of terms for a given field value
239 *
240 * @type function
241 * @date 13/06/2014
242 * @since ACF 5.0.0
243 *
244 * @param $value (array)
245 * @return $value
246 */
247 function get_terms( $value, $taxonomy = 'category' ) {
248
249 // load terms in 1 query to save multiple DB calls from following code
250 if ( count( $value ) > 1 ) {
251 $terms = acf_get_terms(
252 array(
253 'taxonomy' => $taxonomy,
254 'include' => $value,
255 'hide_empty' => false,
256 )
257 );
258 }
259
260 // update value to include $post
261 foreach ( array_keys( $value ) as $i ) {
262 $value[ $i ] = get_term( $value[ $i ], $taxonomy );
263 }
264
265 // filter out null values
266 $value = array_filter( $value );
267
268 // return
269 return $value;
270 }
271
272
273 /**
274 * This filter is appied to the $value after it is loaded from the db
275 *
276 * @type filter
277 * @since ACF 3.6
278 * @date 23/01/13
279 *
280 * @param $value - the value found in the database
281 * @param $post_id - the post_id from which the value was loaded from
282 * @param $field - the field array holding all the field options
283 *
284 * @return $value - the value to be saved in te database
285 */
286 function load_value( $value, $post_id, $field ) {
287
288 // get valid terms
289 $value = acf_get_valid_terms( $value, $field['taxonomy'] );
290
291 // load_terms
292 if ( $field['load_terms'] ) {
293
294 // Decode $post_id for $type and $id.
295 $decoded = acf_decode_post_id( $post_id );
296 $type = $decoded['type'];
297 $id = $decoded['id'];
298
299 if ( $type === 'block' ) {
300 // Get parent block...
301 }
302
303 // get terms
304 $term_ids = wp_get_object_terms(
305 $id,
306 $field['taxonomy'],
307 array(
308 'fields' => 'ids',
309 'orderby' => 'none',
310 )
311 );
312
313 // bail early if no terms
314 if ( empty( $term_ids ) || is_wp_error( $term_ids ) ) {
315 return false;
316 }
317
318 // sort
319 if ( ! empty( $value ) ) {
320 $order = array();
321
322 foreach ( $term_ids as $i => $v ) {
323 $order[ $i ] = array_search( $v, $value );
324 }
325
326 array_multisort( $order, $term_ids );
327 }
328
329 // update value
330 $value = $term_ids;
331 }
332
333 // convert back from array if neccessary
334 if ( $field['field_type'] == 'select' || $field['field_type'] == 'radio' ) {
335 $value = array_shift( $value );
336 }
337
338 // return
339 return $value;
340 }
341
342
343 /**
344 * Filters the field value before it is saved into the database.
345 *
346 * @since ACF 3.6
347 *
348 * @param mixed $value The value which will be saved in the database.
349 * @param integer $post_id The post_id of which the value will be saved.
350 * @param array $field The field array holding all the field options.
351 * @return mixed $value The modified value.
352 */
353 public function update_value( $value, $post_id, $field ) {
354
355 if ( is_array( $value ) ) {
356 $value = array_filter( $value );
357 }
358
359 acf_update_bidirectional_values( acf_get_array( $value ), $post_id, $field, 'term' );
360
361 // save_terms if enabled.
362 if ( $field['save_terms'] ) {
363
364 // vars
365 $taxonomy = $field['taxonomy'];
366
367 // force value to array.
368 $term_ids = acf_get_array( $value );
369
370 // convert to int.
371 $term_ids = array_map( 'intval', $term_ids );
372
373 // get existing term id's (from a previously saved field).
374 $old_term_ids = isset( $this->save_post_terms[ $taxonomy ] ) ? $this->save_post_terms[ $taxonomy ] : array();
375
376 // append
377 $this->save_post_terms[ $taxonomy ] = array_merge( $old_term_ids, $term_ids );
378
379 // if called directly from frontend update_field().
380 if ( ! did_action( 'acf/save_post' ) ) {
381 $this->save_post( $post_id );
382 return $value;
383 }
384 }
385
386 return $value;
387 }
388
389 /**
390 * This function will save any terms in the save_post_terms array
391 *
392 * @since ACF 5.0.9
393 *
394 * @param mixed $post_id The ACF post ID to save to.
395 * @return void
396 */
397 public function save_post( $post_id ) {
398 // Check for saved terms.
399 if ( ! empty( $this->save_post_terms ) ) {
400 /**
401 * Determine object ID allowing for non "post" $post_id (user, taxonomy, etc).
402 * Although not fully supported by WordPress, non "post" objects may use the term relationships table.
403 * Sharing taxonomies across object types is discouraged, but unique taxonomies work well.
404 * Note: Do not attempt to restrict to "post" only. This has been attempted in 5.8.9 and later reverted.
405 */
406 $decoded = acf_decode_post_id( $post_id );
407 $type = $decoded['type'];
408 $id = $decoded['id'];
409
410 if ( $type === 'block' ) {
411 // Get parent block...
412 }
413
414 // Loop over taxonomies and save terms.
415 foreach ( $this->save_post_terms as $taxonomy => $term_ids ) {
416 wp_set_object_terms( $id, $term_ids, $taxonomy, false );
417 }
418
419 // Reset storage.
420 $this->save_post_terms = array();
421 }
422 }
423
424 /**
425 * This filter is appied to the $value after it is loaded from the db and before it is returned to the template
426 *
427 * @type filter
428 * @since ACF 3.6
429 * @date 23/01/13
430 *
431 * @param $value (mixed) the value which was loaded from the database
432 * @param $post_id (mixed) the post_id from which the value was loaded
433 * @param $field (array) the field array holding all the field options
434 *
435 * @return $value (mixed) the modified value
436 */
437 function format_value( $value, $post_id, $field ) {
438
439 // bail early if no value
440 if ( empty( $value ) ) {
441 return false;
442 }
443
444 // force value to array
445 $value = acf_get_array( $value );
446
447 // load posts if needed
448 if ( $field['return_format'] == 'object' ) {
449
450 // get posts
451 $value = $this->get_terms( $value, $field['taxonomy'] );
452 }
453
454 // convert back from array if neccessary
455 if ( $field['field_type'] == 'select' || $field['field_type'] == 'radio' ) {
456 $value = array_shift( $value );
457 }
458
459 // return
460 return $value;
461 }
462
463 /**
464 * Renders the Taxonomy field.
465 *
466 * @since ACF 3.6
467 *
468 * @param array $field The field settings array.
469 * @return void
470 */
471 public function render_field( $field ) {
472 // force value to array
473 $field['value'] = acf_get_array( $field['value'] );
474
475 // vars
476 $div = array(
477 'class' => 'acf-taxonomy-field',
478 'data-save' => $field['save_terms'],
479 'data-ftype' => $field['field_type'],
480 'data-taxonomy' => $field['taxonomy'],
481 'data-allow_null' => $field['allow_null'],
482 'data-nonce' => wp_create_nonce( $field['key'] ),
483 );
484 // get taxonomy
485 $taxonomy = get_taxonomy( $field['taxonomy'] );
486
487 // bail early if taxonomy does not exist
488 if ( ! $taxonomy ) {
489 return;
490 }
491
492 ?>
493 <div <?php echo acf_esc_attrs( $div ); ?>>
494 <?php if ( $field['add_term'] && current_user_can( $taxonomy->cap->manage_terms ) ) : ?>
495 <div class="acf-actions -hover">
496 <a href="#" class="acf-icon -plus acf-js-tooltip small" data-name="add" title="<?php echo esc_attr( $taxonomy->labels->add_new_item ); ?>"></a>
497 </div>
498 <?php
499 endif;
500
501 if ( $field['field_type'] == 'select' ) {
502 $field['multiple'] = 0;
503
504 $this->render_field_select( $field );
505 } elseif ( $field['field_type'] == 'multi_select' ) {
506 $field['multiple'] = 1;
507
508 $this->render_field_select( $field );
509 } elseif ( $field['field_type'] == 'radio' ) {
510 $this->render_field_checkbox( $field );
511 } elseif ( $field['field_type'] == 'checkbox' ) {
512 $this->render_field_checkbox( $field );
513 }
514
515 ?>
516 </div>
517 <?php
518 }
519
520 /**
521 * Create the HTML interface for your field
522 *
523 * @type action
524 * @since ACF 3.6
525 * @date 23/01/13
526 *
527 * @param $field - an array holding all the field's data
528 */
529 function render_field_select( $field ) {
530
531 // Change Field into a select
532 $field['type'] = 'select';
533 $field['ui'] = 1;
534 $field['ajax'] = 1;
535 $field['choices'] = array();
536
537 // value
538 if ( ! empty( $field['value'] ) ) {
539
540 // get terms
541 $terms = $this->get_terms( $field['value'], $field['taxonomy'] );
542
543 // set choices
544 if ( ! empty( $terms ) ) {
545 foreach ( array_keys( $terms ) as $i ) {
546
547 // vars
548 $term = acf_extract_var( $terms, $i );
549
550 // append to choices
551 $field['choices'][ $term->term_id ] = $this->get_term_title( $term, $field );
552 }
553 }
554 }
555
556 // render select
557 acf_render_field( $field );
558 }
559
560
561 /**
562 * Create the HTML interface for your field
563 *
564 * @since ACF 3.6
565 *
566 * @param array $field an array holding all the field's data.
567 */
568 public function render_field_checkbox( $field ) {
569
570 // hidden input.
571 acf_hidden_input(
572 array(
573 'type' => 'hidden',
574 'name' => $field['name'],
575 )
576 );
577
578 // checkbox saves an array.
579 if ( $field['field_type'] == 'checkbox' ) {
580 $field['name'] .= '[]';
581 }
582
583 // taxonomy.
584 $taxonomy_obj = get_taxonomy( $field['taxonomy'] );
585
586 // include walker.
587 acf_include( 'includes/walkers/class-acf-walker-taxonomy-field.php' );
588
589 // vars.
590 $args = array(
591 'taxonomy' => $field['taxonomy'],
592 /* translators: %s: Taxonomy name */
593 'show_option_none' => sprintf( _x( 'No %s', 'No Terms', 'secure-custom-fields' ), $taxonomy_obj->labels->name ),
594 'hide_empty' => false,
595 'style' => 'none',
596 'walker' => new ACF_Taxonomy_Field_Walker( $field ),
597 );
598
599 // filter for 3rd party customization.
600 $args = apply_filters( 'acf/fields/taxonomy/wp_list_categories', $args, $field );
601 $args = apply_filters( 'acf/fields/taxonomy/wp_list_categories/name=' . $field['_name'], $args, $field );
602 $args = apply_filters( 'acf/fields/taxonomy/wp_list_categories/key=' . $field['key'], $args, $field );
603
604 ?>
605 <div class="categorychecklist-holder">
606 <ul class="acf-checkbox-list acf-bl">
607 <?php wp_list_categories( $args ); ?>
608 </ul>
609 </div>
610 <?php
611 }
612
613
614 /**
615 * Create extra options for your field. This is rendered when editing a field.
616 * The value of $field['name'] can be used (like bellow) to save extra data to the $field
617 *
618 * @type action
619 * @since ACF 3.6
620 * @date 23/01/13
621 *
622 * @param $field - an array holding all the field's data
623 */
624 function render_field_settings( $field ) {
625 acf_render_field_setting(
626 $field,
627 array(
628 'label' => __( 'Taxonomy', 'secure-custom-fields' ),
629 'instructions' => __( 'Select the taxonomy to be displayed', 'secure-custom-fields' ),
630 'type' => 'select',
631 'name' => 'taxonomy',
632 'choices' => acf_get_taxonomy_labels(),
633 )
634 );
635
636 acf_render_field_setting(
637 $field,
638 array(
639 'label' => __( 'Create Terms', 'secure-custom-fields' ),
640 'instructions' => __( 'Allow new terms to be created whilst editing', 'secure-custom-fields' ),
641 'name' => 'add_term',
642 'type' => 'true_false',
643 'ui' => 1,
644 )
645 );
646
647 acf_render_field_setting(
648 $field,
649 array(
650 'label' => __( 'Save Terms', 'secure-custom-fields' ),
651 'instructions' => __( 'Connect selected terms to the post', 'secure-custom-fields' ),
652 'name' => 'save_terms',
653 'type' => 'true_false',
654 'ui' => 1,
655 )
656 );
657
658 acf_render_field_setting(
659 $field,
660 array(
661 'label' => __( 'Load Terms', 'secure-custom-fields' ),
662 'instructions' => __( 'Load value from posts terms', 'secure-custom-fields' ),
663 'name' => 'load_terms',
664 'type' => 'true_false',
665 'ui' => 1,
666 )
667 );
668
669 acf_render_field_setting(
670 $field,
671 array(
672 'label' => __( 'Return Value', 'secure-custom-fields' ),
673 'instructions' => '',
674 'type' => 'radio',
675 'name' => 'return_format',
676 'choices' => array(
677 'object' => __( 'Term Object', 'secure-custom-fields' ),
678 'id' => __( 'Term ID', 'secure-custom-fields' ),
679 ),
680 'layout' => 'horizontal',
681 )
682 );
683
684 acf_render_field_setting(
685 $field,
686 array(
687 'label' => __( 'Appearance', 'secure-custom-fields' ),
688 'instructions' => __( 'Select the appearance of this field', 'secure-custom-fields' ),
689 'type' => 'select',
690 'name' => 'field_type',
691 'optgroup' => true,
692 'choices' => array(
693 __( 'Multiple Values', 'secure-custom-fields' ) => array(
694 'checkbox' => __( 'Checkbox', 'secure-custom-fields' ),
695 'multi_select' => __( 'Multi Select', 'secure-custom-fields' ),
696 ),
697 __( 'Single Value', 'secure-custom-fields' ) => array(
698 'radio' => __( 'Radio Buttons', 'secure-custom-fields' ),
699 'select' => _x( 'Select', 'noun', 'secure-custom-fields' ),
700 ),
701 ),
702 )
703 );
704
705 acf_render_field_setting(
706 $field,
707 array(
708 'label' => __( 'Allow Null', 'secure-custom-fields' ),
709 'instructions' => '',
710 'name' => 'allow_null',
711 'type' => 'true_false',
712 'ui' => 1,
713 'conditions' => array(
714 'field' => 'field_type',
715 'operator' => '!=',
716 'value' => 'checkbox',
717 ),
718 )
719 );
720 }
721
722 /**
723 * Renders the field settings used in the "Advanced" tab.
724 *
725 * @since ACF 6.2
726 *
727 * @param array $field The field settings array.
728 * @return void
729 */
730 public function render_field_advanced_settings( $field ) {
731 acf_render_bidirectional_field_settings( $field );
732 }
733
734 /**
735 * Filters choices in taxonomy conditions.
736 *
737 * @since ACF 6.3
738 *
739 * @param array $choices The selected choice.
740 * @param array $conditional_field The conditional field settings object.
741 * @param string $rule_value The rule value.
742 * @return mixed
743 */
744 public function render_field_taxonomy_conditional_choices( $choices, $conditional_field, $rule_value ) {
745 if ( is_array( $conditional_field ) && $conditional_field['type'] === 'taxonomy' ) {
746 if ( ! empty( $rule_value ) ) {
747 $term = get_term( $rule_value );
748 $choices = array( $rule_value => $term->name );
749 }
750 }
751 return $choices;
752 }
753
754
755 /**
756 * AJAX handler for adding Taxonomy field terms.
757 *
758 * @since ACF 5.2.3
759 *
760 * @return void
761 */
762 public function ajax_add_term() {
763 $args = acf_request_args(
764 array(
765 'nonce' => '',
766 'field_key' => '',
767 'term_name' => '',
768 'term_parent' => '',
769 )
770 );
771
772 if ( ! acf_verify_ajax( $args['nonce'], $args['field_key'] ) ) {
773 die();
774 }
775
776 // load field
777 $field = acf_get_field( $args['field_key'] );
778 if ( ! $field ) {
779 die();
780 }
781
782 // vars
783 $taxonomy_obj = get_taxonomy( $field['taxonomy'] );
784 $taxonomy_label = $taxonomy_obj->labels->singular_name;
785
786 // validate cap
787 // note: this situation should never occur due to condition of the add new button
788 if ( ! current_user_can( $taxonomy_obj->cap->manage_terms ) ) {
789 wp_send_json_error(
790 array(
791 /* translators: %s: Taxonomy name */
792 'error' => sprintf( __( 'User unable to add new %s', 'secure-custom-fields' ), $taxonomy_label ),
793 )
794 );
795 }
796
797 // save?
798 if ( $args['term_name'] ) {
799
800 // exists
801 if ( term_exists( $args['term_name'], $field['taxonomy'], $args['term_parent'] ) ) {
802 wp_send_json_error(
803 array(
804 /* translators: %s: Taxonomy name */
805 'error' => sprintf( __( '%s already exists', 'secure-custom-fields' ), $taxonomy_label ),
806 )
807 );
808 }
809
810 // vars
811 $extra = array();
812 if ( $args['term_parent'] ) {
813 $extra['parent'] = (int) $args['term_parent'];
814 }
815
816 // insert
817 $data = wp_insert_term( $args['term_name'], $field['taxonomy'], $extra );
818
819 // error
820 if ( is_wp_error( $data ) ) {
821 wp_send_json_error(
822 array(
823 'error' => $data->get_error_message(),
824 )
825 );
826 }
827
828 // load term
829 $term = get_term( $data['term_id'] );
830
831 // prepend ancenstors count to term name
832 $prefix = '';
833 $ancestors = get_ancestors( $term->term_id, $term->taxonomy );
834 if ( ! empty( $ancestors ) ) {
835 $prefix = str_repeat( '- ', count( $ancestors ) );
836 }
837
838 // success
839 wp_send_json_success(
840 array(
841 /* translators: %s: Taxonomy name */
842 'message' => sprintf( __( '%s added', 'secure-custom-fields' ), $taxonomy_label ),
843 'term_id' => $term->term_id,
844 'term_name' => $term->name,
845 'term_label' => $prefix . $term->name,
846 'term_parent' => $term->parent,
847 )
848 );
849 }
850
851 ?>
852 <form method="post">
853 <?php
854
855 acf_render_field_wrap(
856 array(
857 'label' => __( 'Name', 'secure-custom-fields' ),
858 'name' => 'term_name',
859 'type' => 'text',
860 )
861 );
862
863 if ( is_taxonomy_hierarchical( $field['taxonomy'] ) ) {
864 $choices = array();
865 $response = $this->get_ajax_query( $args );
866
867 if ( $response ) {
868 foreach ( $response['results'] as $v ) {
869 $choices[ $v['id'] ] = $v['text'];
870 }
871 }
872
873 acf_render_field_wrap(
874 array(
875 'label' => __( 'Parent', 'secure-custom-fields' ),
876 'name' => 'term_parent',
877 'type' => 'select',
878 'allow_null' => 1,
879 'ui' => 0,
880 'choices' => $choices,
881 )
882 );
883 }
884
885 ?>
886 <p class="acf-submit">
887 <button class="acf-submit-button button button-primary" type="submit"><?php esc_html_e( 'Add', 'secure-custom-fields' ); ?></button>
888 </p>
889 </form><?php
890
891 // die
892 die;
893 }
894
895 /**
896 * Return the schema array for the REST API.
897 *
898 * @param array $field
899 * @return array
900 */
901 public function get_rest_schema( array $field ) {
902 $schema = array(
903 'type' => array( 'integer', 'array', 'null' ),
904 'required' => ! empty( $field['required'] ),
905 'items' => array(
906 'type' => 'integer',
907 ),
908 );
909
910 if ( empty( $field['allow_null'] ) ) {
911 $schema['minItems'] = 1;
912 }
913
914 if ( in_array( $field['field_type'], array( 'radio', 'select' ) ) ) {
915 $schema['maxItems'] = 1;
916 }
917
918 return $schema;
919 }
920
921 /**
922 * @see \acf_field::get_rest_links()
923 * @param mixed $value The raw (unformatted) field value.
924 * @param integer|string $post_id
925 * @param array $field
926 * @return array
927 */
928 public function get_rest_links( $value, $post_id, array $field ) {
929 $links = array();
930
931 if ( empty( $value ) ) {
932 return $links;
933 }
934
935 foreach ( (array) $value as $object_id ) {
936 $term = get_term( $object_id );
937 if ( ! $term instanceof WP_Term ) {
938 continue;
939 }
940
941 $rest_base = acf_get_object_type_rest_base( get_taxonomy( $term->taxonomy ) );
942 if ( ! $rest_base ) {
943 continue;
944 }
945
946 $links[] = array(
947 'rel' => 'acf:term',
948 'href' => rest_url( sprintf( '/wp/v2/%s/%s', $rest_base, $object_id ) ),
949 'embeddable' => true,
950 'taxonomy' => $term->taxonomy,
951 );
952 }
953
954 return $links;
955 }
956 }
957
958
959 // initialize
960 acf_register_field_type( 'acf_field_taxonomy' );
961 endif; // class_exists check
962
963 ?>