PluginProbe ʕ •ᴥ•ʔ
Secure Custom Fields / 6.6.0
Secure Custom Fields v6.6.0
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-relationship.php
secure-custom-fields / includes / fields Last commit date
FlexibleContent 8 months ago class-acf-field-accordion.php 1 year ago class-acf-field-button-group.php 8 months ago class-acf-field-checkbox.php 8 months ago class-acf-field-clone.php 10 months ago class-acf-field-color_picker.php 8 months 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 8 months ago class-acf-field-flexible-content.php 8 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 8 months ago class-acf-field-image.php 8 months 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 8 months ago class-acf-field-range.php 1 year ago class-acf-field-relationship.php 10 months ago class-acf-field-repeater.php 8 months 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 8 months 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-relationship.php
891 lines
1 <?php
2
3 if ( ! class_exists( 'acf_field_relationship' ) ) :
4
5 class acf_field_relationship 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 public function initialize() {
17 $this->name = 'relationship';
18 $this->label = __( 'Relationship', 'secure-custom-fields' );
19 $this->category = 'relational';
20 $this->description = __( 'A dual-column interface to select one or more posts, pages, or custom post type items to create a relationship with the item that you\'re currently editing. Includes options to search and filter.', 'secure-custom-fields' );
21 $this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-relationship.png';
22 $this->doc_url = 'https://developer.wordpress.org/secure-custom-fields/features/fields/relationship/';
23 $this->tutorial_url = 'https://developer.wordpress.org/secure-custom-fields/features/fields/relationship/relationship-tutorial/';
24 $this->defaults = array(
25 'post_type' => array(),
26 'taxonomy' => array(),
27 'min' => 0,
28 'max' => 0,
29 'filters' => array( 'search', 'post_type', 'taxonomy' ),
30 'elements' => array(),
31 'return_format' => 'object',
32 'bidirectional_target' => array(),
33 );
34 add_filter( 'acf/conditional_logic/choices', array( $this, 'render_field_relation_conditional_choices' ), 10, 3 );
35
36 // extra
37 add_action( 'wp_ajax_acf/fields/relationship/query', array( $this, 'ajax_query' ) );
38 add_action( 'wp_ajax_nopriv_acf/fields/relationship/query', array( $this, 'ajax_query' ) );
39 }
40
41 /**
42 * Filters choices in relation conditions.
43 *
44 * @since ACF 6.3
45 *
46 * @param array $choices The selected choice.
47 * @param array $conditional_field The conditional field settings object.
48 * @param string $rule_value The rule value.
49 * @return array
50 */
51 public function render_field_relation_conditional_choices( $choices, $conditional_field, $rule_value ) {
52 if ( ! is_array( $conditional_field ) || $conditional_field['type'] !== 'relationship' ) {
53 return $choices;
54 }
55 if ( ! empty( $rule_value ) ) {
56 $post_title = esc_html( get_the_title( $rule_value ) );
57 $choices = array( $rule_value => $post_title );
58 }
59 return $choices;
60 }
61
62 /**
63 * description
64 *
65 * @type function
66 * @date 16/12/2015
67 * @since ACF 5.3.2
68 *
69 * @param $post_id (int)
70 * @return $post_id (int)
71 */
72 function input_admin_enqueue_scripts() {
73
74 // localize
75 acf_localize_text(
76 array(
77 // 'Minimum values reached ( {min} values )' => __('Minimum values reached ( {min} values )', 'secure-custom-fields'),
78 'Maximum values reached ( {max} values )' => __( 'Maximum values reached ( {max} values )', 'secure-custom-fields' ),
79 'Loading' => __( 'Loading', 'secure-custom-fields' ),
80 'No matches found' => __( 'No matches found', 'secure-custom-fields' ),
81 )
82 );
83 }
84
85 /**
86 * Returns AJAX results for the Relationship field.
87 *
88 * @since ACF 5.0.0
89 *
90 * @return void
91 */
92 public function ajax_query() {
93 $nonce = acf_request_arg( 'nonce', '' );
94 $key = acf_request_arg( 'field_key', '' );
95 $conditional_logic = (bool) acf_request_arg( 'conditional_logic', false );
96
97 if ( $conditional_logic ) {
98 if ( ! acf_current_user_can_admin() ) {
99 die();
100 }
101
102 // Use the standard ACF admin nonce.
103 $nonce = '';
104 $key = '';
105 }
106
107 if ( ! acf_verify_ajax( $nonce, $key ) ) {
108 die();
109 }
110
111 acf_send_ajax_results( $this->get_ajax_query( $_POST ) );
112 }
113
114 /**
115 * This function will return an array of data formatted for use in a select2 AJAX response
116 *
117 * @since ACF 5.0.9
118 *
119 * @param array $options An array of options for the query.
120 * @return array
121 */
122 public function get_ajax_query( $options = array() ) {
123 // defaults
124 $options = wp_parse_args(
125 $options,
126 array(
127 'post_id' => 0,
128 's' => '',
129 'field_key' => '',
130 'paged' => 1,
131 'post_type' => '',
132 'include' => '',
133 'taxonomy' => '',
134 )
135 );
136
137 // load field
138 $field = acf_get_field( $options['field_key'] );
139 if ( ! $field ) {
140 return false;
141 }
142
143 // vars
144 $results = array();
145 $args = array();
146 $s = false;
147 $is_search = false;
148
149 // paged
150 $args['posts_per_page'] = 20;
151 $args['paged'] = intval( $options['paged'] );
152
153 // search
154 if ( $options['s'] !== '' && empty( $options['include'] ) ) {
155 // strip slashes (search may be integer)
156 $s = wp_unslash( strval( $options['s'] ) );
157
158 // update vars
159 $args['s'] = $s;
160 $is_search = true;
161 }
162
163 // post_type
164 if ( ! empty( $options['post_type'] ) ) {
165 $args['post_type'] = acf_get_array( $options['post_type'] );
166 } elseif ( ! empty( $field['post_type'] ) ) {
167 $args['post_type'] = acf_get_array( $field['post_type'] );
168 } else {
169 $args['post_type'] = acf_get_post_types();
170 }
171
172 // post status
173 if ( ! empty( $options['post_status'] ) ) {
174 $args['post_status'] = acf_get_array( $options['post_status'] );
175 } elseif ( ! empty( $field['post_status'] ) ) {
176 $args['post_status'] = acf_get_array( $field['post_status'] );
177 }
178
179 // taxonomy
180 if ( ! empty( $options['taxonomy'] ) ) {
181
182 // vars
183 $term = acf_decode_taxonomy_term( $options['taxonomy'] );
184
185 // tax query
186 $args['tax_query'] = array();
187
188 // append
189 $args['tax_query'][] = array(
190 'taxonomy' => $term['taxonomy'],
191 'field' => 'slug',
192 'terms' => $term['term'],
193 );
194 } elseif ( ! empty( $field['taxonomy'] ) ) {
195
196 // vars
197 $terms = acf_decode_taxonomy_terms( $field['taxonomy'] );
198
199 // append to $args
200 $args['tax_query'] = array(
201 'relation' => 'OR',
202 );
203
204 // now create the tax queries
205 foreach ( $terms as $k => $v ) {
206 $args['tax_query'][] = array(
207 'taxonomy' => $k,
208 'field' => 'slug',
209 'terms' => $v,
210 );
211 }
212 }
213
214 if ( ! empty( $options['include'] ) ) {
215 // If we have an include, we need to return only the selected posts.
216 $args['post__in'] = array( $options['include'] );
217 }
218
219 // filters
220 $args = apply_filters( 'acf/fields/relationship/query', $args, $field, $options['post_id'] );
221 $args = apply_filters( 'acf/fields/relationship/query/name=' . $field['name'], $args, $field, $options['post_id'] );
222 $args = apply_filters( 'acf/fields/relationship/query/key=' . $field['key'], $args, $field, $options['post_id'] );
223
224 // get posts grouped by post type
225 $groups = acf_get_grouped_posts( $args );
226
227 // bail early if no posts
228 if ( empty( $groups ) ) {
229 return false;
230 }
231
232 // loop
233 foreach ( array_keys( $groups ) as $group_title ) {
234
235 // vars
236 $posts = acf_extract_var( $groups, $group_title );
237
238 // data
239 $data = array(
240 'text' => $group_title,
241 'children' => array(),
242 );
243
244 // convert post objects to post titles
245 foreach ( array_keys( $posts ) as $post_id ) {
246 $posts[ $post_id ] = $this->get_post_title( $posts[ $post_id ], $field, $options['post_id'] );
247 }
248
249 // order posts by search
250 if ( $is_search && empty( $args['orderby'] ) && isset( $args['s'] ) ) {
251 $posts = acf_order_by_search( $posts, $args['s'] );
252 }
253
254 // append to $data
255 foreach ( array_keys( $posts ) as $post_id ) {
256 $data['children'][] = $this->get_post_result( $post_id, $posts[ $post_id ] );
257 }
258
259 // append to $results
260 $results[] = $data;
261 }
262
263 // add as optgroup or results
264 if ( count( $args['post_type'] ) == 1 ) {
265 $results = $results[0]['children'];
266 }
267
268 // vars
269 $response = array(
270 'results' => $results,
271 'limit' => $args['posts_per_page'],
272 );
273
274 // return
275 return $response;
276 }
277
278 /**
279 * This function will return an array containing id, text and maybe description data
280 *
281 * @type function
282 * @date 7/07/2016
283 * @since ACF 5.4.0
284 *
285 * @param $id (mixed)
286 * @param $text (string)
287 * @return (array)
288 */
289 function get_post_result( $id, $text ) {
290
291 // vars
292 $result = array(
293 'id' => $id,
294 'text' => $text,
295 );
296
297 // return
298 return $result;
299 }
300
301
302 /**
303 * This function returns the HTML for a result
304 *
305 * @type function
306 * @date 1/11/2013
307 * @since ACF 5.0.0
308 *
309 * @param $post (object)
310 * @param $field (array)
311 * @param $post_id (int) the post_id to which this value is saved to
312 * @return (string)
313 */
314 function get_post_title( $post, $field, $post_id = 0, $is_search = 0 ) {
315
316 // get post_id
317 if ( ! $post_id ) {
318 $post_id = acf_get_form_data( 'post_id' );
319 }
320
321 // vars
322 $title = esc_html( acf_get_post_title( $post, $is_search ) );
323
324 // featured_image
325 if ( acf_in_array( 'featured_image', $field['elements'] ) ) {
326
327 // vars
328 $class = 'thumbnail';
329 $thumbnail = acf_get_post_thumbnail( $post->ID, array( 17, 17 ) );
330
331 // icon
332 if ( $thumbnail['type'] == 'icon' ) {
333 $class .= ' -' . $thumbnail['type'];
334 }
335
336 // append
337 $title = '<div class="' . $class . '">' . $thumbnail['html'] . '</div>' . $title;
338 }
339
340 // filters
341 $title = apply_filters( 'acf/fields/relationship/result', $title, $post, $field, $post_id );
342 $title = apply_filters( 'acf/fields/relationship/result/name=' . $field['_name'], $title, $post, $field, $post_id );
343 $title = apply_filters( 'acf/fields/relationship/result/key=' . $field['key'], $title, $post, $field, $post_id );
344
345 // return
346 return $title;
347 }
348
349
350 /**
351 * Create the HTML interface for your field
352 *
353 * @param $field - an array holding all the field's data
354 *
355 * @type action
356 * @since ACF 3.6
357 * @date 23/01/13
358 */
359 function render_field( $field ) {
360
361 // vars
362 $post_type = acf_get_array( $field['post_type'] );
363 $taxonomy = acf_get_array( $field['taxonomy'] );
364 $filters = acf_get_array( $field['filters'] );
365
366 // filters
367 $filter_count = count( $filters );
368 $filter_post_type_choices = array();
369 $filter_taxonomy_choices = array();
370
371 // post_type filter
372 if ( in_array( 'post_type', $filters ) ) {
373 $filter_post_type_choices = array(
374 '' => __( 'Select post type', 'secure-custom-fields' ),
375 ) + acf_get_pretty_post_types( $post_type );
376 }
377
378 // taxonomy filter
379 if ( in_array( 'taxonomy', $filters ) ) {
380 $term_choices = array();
381 $filter_taxonomy_choices = array(
382 '' => __( 'Select taxonomy', 'secure-custom-fields' ),
383 );
384
385 // check for specific taxonomy setting
386 if ( $taxonomy ) {
387 $terms = acf_get_encoded_terms( $taxonomy );
388 $term_choices = acf_get_choices_from_terms( $terms, 'slug' );
389
390 // if no terms were specified, find all terms
391 } else {
392
393 // restrict taxonomies by the post_type selected
394 $term_args = array();
395 if ( $post_type ) {
396 $term_args['taxonomy'] = acf_get_taxonomies(
397 array(
398 'post_type' => $post_type,
399 )
400 );
401 }
402
403 // get terms
404 $terms = acf_get_grouped_terms( $term_args );
405 $term_choices = acf_get_choices_from_grouped_terms( $terms, 'slug' );
406 }
407
408 // append term choices
409 $filter_taxonomy_choices = $filter_taxonomy_choices + $term_choices;
410 }
411
412 // div attributes
413 $atts = array(
414 'id' => $field['id'],
415 'class' => "acf-relationship {$field['class']}",
416 'data-min' => $field['min'],
417 'data-max' => $field['max'],
418 'data-s' => '',
419 'data-paged' => 1,
420 'data-post_type' => '',
421 'data-taxonomy' => '',
422 'data-nonce' => wp_create_nonce( $field['key'] ),
423 );
424
425 ?>
426 <div <?php echo acf_esc_attrs( $atts ); ?>>
427
428 <?php
429 acf_hidden_input(
430 array(
431 'name' => $field['name'],
432 'value' => '',
433 )
434 );
435 ?>
436
437 <?php
438
439 /* filters */
440 if ( $filter_count ) :
441 ?>
442 <div class="filters -f<?php echo esc_attr( $filter_count ); ?>">
443 <?php
444
445 /* search */
446 if ( in_array( 'search', $filters ) ) :
447 ?>
448 <div class="filter -search">
449 <?php
450 acf_text_input(
451 array(
452 'placeholder' => __( 'Search...', 'secure-custom-fields' ),
453 'data-filter' => 's',
454 )
455 );
456 ?>
457 </div>
458 <?php
459 endif;
460
461 /* post_type */
462 if ( in_array( 'post_type', $filters ) ) :
463 ?>
464 <div class="filter -post_type">
465 <?php
466 acf_select_input(
467 array(
468 'choices' => $filter_post_type_choices,
469 'data-filter' => 'post_type',
470 )
471 );
472 ?>
473 </div>
474 <?php
475 endif;
476
477 /* post_type */
478 if ( in_array( 'taxonomy', $filters ) ) :
479 ?>
480 <div class="filter -taxonomy">
481 <?php
482 acf_select_input(
483 array(
484 'choices' => $filter_taxonomy_choices,
485 'data-filter' => 'taxonomy',
486 )
487 );
488 ?>
489 </div>
490 <?php endif; ?>
491 </div>
492 <?php endif; ?>
493
494 <div class="selection">
495 <div class="choices">
496 <ul class="acf-bl list choices-list"></ul>
497 </div>
498 <div class="values">
499 <ul class="acf-bl list values-list">
500 <?php
501 if ( ! empty( $field['value'] ) ) :
502
503 // get posts
504 $posts = acf_get_posts(
505 array(
506 'post__in' => $field['value'],
507 'post_type' => $field['post_type'],
508 )
509 );
510
511 // loop
512 foreach ( $posts as $post ) :
513 ?>
514 <li>
515 <?php
516 acf_hidden_input(
517 array(
518 'name' => $field['name'] . '[]',
519 'value' => $post->ID,
520 )
521 );
522 ?>
523 <span tabindex="0" data-id="<?php echo esc_attr( $post->ID ); ?>" class="acf-rel-item acf-rel-item-remove">
524 <?php echo acf_esc_html( $this->get_post_title( $post, $field ) ); ?>
525 <a href="#" class="acf-icon -minus small dark" data-name="remove_item"></a>
526 </span>
527 </li>
528 <?php endforeach; ?>
529 <?php endif; ?>
530 </ul>
531 </div>
532 </div>
533 </div>
534 <?php
535 }
536
537
538 /**
539 * Create extra options for your field. This is rendered when editing a field.
540 * The value of $field['name'] can be used (like bellow) to save extra data to the $field
541 *
542 * @type action
543 * @since ACF 3.6
544 * @date 23/01/13
545 *
546 * @param $field - an array holding all the field's data
547 */
548 function render_field_settings( $field ) {
549 acf_render_field_setting(
550 $field,
551 array(
552 'label' => __( 'Filter by Post Type', 'secure-custom-fields' ),
553 'instructions' => '',
554 'type' => 'select',
555 'name' => 'post_type',
556 'choices' => acf_get_pretty_post_types(),
557 'multiple' => 1,
558 'ui' => 1,
559 'allow_null' => 1,
560 'placeholder' => __( 'All post types', 'secure-custom-fields' ),
561 )
562 );
563
564 acf_render_field_setting(
565 $field,
566 array(
567 'label' => __( 'Filter by Post Status', 'secure-custom-fields' ),
568 'instructions' => '',
569 'type' => 'select',
570 'name' => 'post_status',
571 'choices' => acf_get_pretty_post_statuses(),
572 'multiple' => 1,
573 'ui' => 1,
574 'allow_null' => 1,
575 'placeholder' => __( 'Any post status', 'secure-custom-fields' ),
576 )
577 );
578
579 acf_render_field_setting(
580 $field,
581 array(
582 'label' => __( 'Filter by Taxonomy', 'secure-custom-fields' ),
583 'instructions' => '',
584 'type' => 'select',
585 'name' => 'taxonomy',
586 'choices' => acf_get_taxonomy_terms(),
587 'multiple' => 1,
588 'ui' => 1,
589 'allow_null' => 1,
590 'placeholder' => __( 'All taxonomies', 'secure-custom-fields' ),
591 )
592 );
593
594 acf_render_field_setting(
595 $field,
596 array(
597 'label' => __( 'Filters', 'secure-custom-fields' ),
598 'instructions' => '',
599 'type' => 'checkbox',
600 'name' => 'filters',
601 'choices' => array(
602 'search' => __( 'Search', 'secure-custom-fields' ),
603 'post_type' => __( 'Post Type', 'secure-custom-fields' ),
604 'taxonomy' => __( 'Taxonomy', 'secure-custom-fields' ),
605 ),
606 )
607 );
608
609 acf_render_field_setting(
610 $field,
611 array(
612 'label' => __( 'Return Format', 'secure-custom-fields' ),
613 'instructions' => '',
614 'type' => 'radio',
615 'name' => 'return_format',
616 'choices' => array(
617 'object' => __( 'Post Object', 'secure-custom-fields' ),
618 'id' => __( 'Post ID', 'secure-custom-fields' ),
619 ),
620 'layout' => 'horizontal',
621 )
622 );
623 }
624
625 /**
626 * Renders the field settings used in the "Validation" tab.
627 *
628 * @since ACF 6.0
629 *
630 * @param array $field The field settings array.
631 * @return void
632 */
633 function render_field_validation_settings( $field ) {
634 $field['min'] = empty( $field['min'] ) ? '' : $field['min'];
635 $field['max'] = empty( $field['max'] ) ? '' : $field['max'];
636
637 acf_render_field_setting(
638 $field,
639 array(
640 'label' => __( 'Minimum Posts', 'secure-custom-fields' ),
641 'instructions' => '',
642 'type' => 'number',
643 'name' => 'min',
644 )
645 );
646
647 acf_render_field_setting(
648 $field,
649 array(
650 'label' => __( 'Maximum Posts', 'secure-custom-fields' ),
651 'instructions' => '',
652 'type' => 'number',
653 'name' => 'max',
654 )
655 );
656 }
657
658 /**
659 * Renders the field settings used in the "Presentation" tab.
660 *
661 * @since ACF 6.0
662 *
663 * @param array $field The field settings array.
664 * @return void
665 */
666 function render_field_presentation_settings( $field ) {
667 acf_render_field_setting(
668 $field,
669 array(
670 'label' => __( 'Elements', 'secure-custom-fields' ),
671 'instructions' => __( 'Selected elements will be displayed in each result', 'secure-custom-fields' ),
672 'type' => 'checkbox',
673 'name' => 'elements',
674 'choices' => array(
675 'featured_image' => __( 'Featured Image', 'secure-custom-fields' ),
676 ),
677 )
678 );
679 }
680
681 /**
682 * Renders the field settings used in the "Advanced" tab.
683 *
684 * @since ACF 6.2
685 *
686 * @param array $field The field settings array.
687 * @return void
688 */
689 public function render_field_advanced_settings( $field ) {
690 acf_render_bidirectional_field_settings( $field );
691 }
692
693 /**
694 * This filter is applied to the $value after it is loaded from the db and before it is returned to the template
695 *
696 * @type filter
697 * @since ACF 3.6
698 * @date 23/01/13
699 *
700 * @param $value (mixed) the value which was loaded from the database
701 * @param $post_id (mixed) the post_id from which the value was loaded
702 * @param $field (array) the field array holding all the field options
703 *
704 * @return $value (mixed) the modified value
705 */
706 function format_value( $value, $post_id, $field ) {
707
708 // bail early if no value
709 if ( empty( $value ) ) {
710 return $value;
711 }
712
713 // force value to array
714 $value = acf_get_array( $value );
715
716 // convert to int
717 $value = array_map( 'intval', $value );
718
719 // load posts if needed
720 if ( $field['return_format'] == 'object' ) {
721
722 // get posts
723 $value = acf_get_posts(
724 array(
725 'post__in' => $value,
726 'post_type' => $field['post_type'],
727 )
728 );
729 }
730
731 // return
732 return $value;
733 }
734
735
736 /**
737 * description
738 *
739 * @type function
740 * @date 11/02/2014
741 * @since ACF 5.0.0
742 *
743 * @param $post_id (int)
744 * @return $post_id (int)
745 */
746 function validate_value( $valid, $value, $field, $input ) {
747
748 // default
749 if ( empty( $value ) || ! is_array( $value ) ) {
750 $value = array();
751 }
752
753 // min
754 if ( count( $value ) < $field['min'] ) {
755 /* translators: %1$s: field label, %2$s: minimum number of selections */
756 $valid = _n( '%1$s requires at least %2$s selection', '%1$s requires at least %2$s selections', $field['min'], 'secure-custom-fields' );
757 $valid = sprintf( $valid, $field['label'], $field['min'] );
758 }
759
760 // return
761 return $valid;
762 }
763
764
765 /**
766 * Filters the field value before it is saved into the database.
767 *
768 * @since ACF 3.6
769 *
770 * @param mixed $value The value which will be saved in the database.
771 * @param integer $post_id The post_id of which the value will be saved.
772 * @param array $field The field array holding all the field options.
773 *
774 * @return mixed $value The modified value.
775 */
776 public function update_value( $value, $post_id, $field ) {
777
778 // Bail early if no value.
779 if ( empty( $value ) ) {
780 acf_update_bidirectional_values( array(), $post_id, $field );
781 return $value;
782 }
783
784 // Format array of values.
785 // - ensure each value is an id.
786 // - Parse each id as string for SQL LIKE queries.
787 if ( acf_is_sequential_array( $value ) ) {
788 $value = array_map( 'acf_idval', $value );
789 $value = array_map( 'strval', $value );
790
791 // Parse single value for id.
792 } else {
793 $value = acf_idval( $value );
794 }
795
796 acf_update_bidirectional_values( acf_get_array( $value ), $post_id, $field );
797
798 // Return value.
799 return $value;
800 }
801
802 /**
803 * Validates relationship fields updated via the REST API.
804 *
805 * @param boolean $valid The current validity boolean.
806 * @param integer $value The value of the field.
807 * @param array $field The field array.
808 * @return boolean|WP_Error
809 */
810 public function validate_rest_value( $valid, $value, $field ) {
811 return acf_get_field_type( 'post_object' )->validate_rest_value( $valid, $value, $field );
812 }
813
814 /**
815 * Return the schema array for the REST API.
816 *
817 * @param array $field
818 * @return array
819 */
820 public function get_rest_schema( array $field ) {
821 $schema = array(
822 'type' => array( 'integer', 'array', 'null' ),
823 'required' => ! empty( $field['required'] ),
824 'items' => array(
825 'type' => 'integer',
826 ),
827 );
828
829 if ( empty( $field['allow_null'] ) ) {
830 $schema['minItems'] = 1;
831 }
832
833 if ( ! empty( $field['min'] ) ) {
834 $schema['minItems'] = (int) $field['min'];
835 }
836
837 if ( ! empty( $field['max'] ) ) {
838 $schema['maxItems'] = (int) $field['max'];
839 }
840
841 return $schema;
842 }
843
844 /**
845 * @see \acf_field::get_rest_links()
846 * @param mixed $value The raw (unformatted) field value.
847 * @param integer|string $post_id
848 * @param array $field
849 * @return array
850 */
851 public function get_rest_links( $value, $post_id, array $field ) {
852 $links = array();
853
854 if ( empty( $value ) ) {
855 return $links;
856 }
857
858 foreach ( (array) $value as $object_id ) {
859 if ( ! $post_type = get_post_type( $object_id ) or ! $post_type = get_post_type_object( $post_type ) ) {
860 continue;
861 }
862 $rest_base = acf_get_object_type_rest_base( $post_type );
863 $links[] = array(
864 'rel' => $post_type->name === 'attachment' ? 'acf:attachment' : 'acf:post',
865 'href' => rest_url( sprintf( '/wp/v2/%s/%s', $rest_base, $object_id ) ),
866 'embeddable' => true,
867 );
868 }
869
870 return $links;
871 }
872
873 /**
874 * Apply basic formatting to prepare the value for default REST output.
875 *
876 * @param mixed $value
877 * @param string|integer $post_id
878 * @param array $field
879 * @return mixed
880 */
881 public function format_value_for_rest( $value, $post_id, array $field ) {
882 return acf_format_numerics( $value );
883 }
884 }
885
886
887 // initialize
888 acf_register_field_type( 'acf_field_relationship' );
889 endif; // class_exists check
890
891 ?>