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