PluginProbe
Advanced Custom Fields (ACF®) / 4.1.2
Advanced Custom Fields (ACF®) v4.1.2
6.8.9 6.8.8 6.8.7 6.8.6 6.8.5 6.8.4 6.8.3 6.8.2 6.8.1 5.8.5 5.8.6 5.8.7 5.8.8 5.8.9 5.9.0 5.9.1 5.9.2 5.9.3 5.9.4 5.9.5 5.9.6 5.9.7 5.9.8 5.9.9 6.0.0 All 230 releases
advanced-custom-fields / core / fields / relationship.php
relationship.php
775 lines 16.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 class acf_field_relationship extends acf_field
4 {
5 // vars
6 var $defaults;
7
8
9 /*
10 * __construct
11 *
12 * Set name / label needed for actions / filters
13 *
14 * @since 3.6
15 * @date 23/01/13
16 */
17
18 function __construct()
19 {
20 // vars
21 $this->name = 'relationship';
22 $this->label = __("Relationship",'acf');
23 $this->category = __("Relational",'acf');
24 $this->defaults = array(
25 'post_type' => array('all'),
26 'max' => '',
27 'taxonomy' => array('all'),
28 'filters' => array('search'),
29 'result_elements' => array('post_title', 'post_type')
30 );
31
32
33 // do not delete!
34 parent::__construct();
35
36
37 // extra
38 add_action('wp_ajax_acf/fields/relationship/query_posts', array($this, 'query_posts'));
39 add_action('wp_ajax_nopriv_acf/fields/relationship/query_posts', array($this, 'query_posts'));
40 }
41
42
43 /*
44 * posts_where
45 *
46 * @description:
47 * @created: 3/09/12
48 */
49
50 function posts_where( $where, &$wp_query )
51 {
52 global $wpdb;
53
54 if ( $title = $wp_query->get('like_title') )
55 {
56 $where .= " AND " . $wpdb->posts . ".post_title LIKE '%" . esc_sql( like_escape( $title ) ) . "%'";
57 }
58
59 return $where;
60 }
61
62
63 /*
64 * query_posts
65 *
66 * @description:
67 * @since: 3.6
68 * @created: 27/01/13
69 */
70
71 function query_posts()
72 {
73 // vars
74 $options = array(
75 'post_type' => 'all',
76 'taxonomy' => 'all',
77 'posts_per_page' => 10,
78 'paged' => 0,
79 'orderby' => 'title',
80 'order' => 'ASC',
81 'post_status' => array('publish', 'private', 'draft', 'inherit', 'future'),
82 'suppress_filters' => false,
83 's' => '',
84 'lang' => false,
85 'update_post_meta_cache' => false,
86 'field_key' => '',
87 'nonce' => '',
88 'ancestor' => false,
89 );
90
91 $options = array_merge( $options, $_POST );
92
93
94 // validate
95 if( !wp_verify_nonce($options['nonce'], 'acf_nonce') )
96 {
97 die(0);
98 }
99
100
101 // WPML
102 if( $options['lang'] )
103 {
104 global $sitepress;
105
106 $sitepress->switch_lang( $options['lang'] );
107 }
108
109
110 // convert types
111 $options['post_type'] = explode(',', $options['post_type']);
112 $options['taxonomy'] = explode(',', $options['taxonomy']);
113
114
115 // load all post types by default
116 if( in_array('all', $options['post_type']) )
117 {
118 $options['post_type'] = apply_filters('acf/get_post_types', array());
119 }
120
121
122 // attachment doesn't work if it is the only item in an array???
123 if( is_array($options['post_type']) && count($options['post_type']) == 1 )
124 {
125 $options['post_type'] = $options['post_type'][0];
126 }
127
128
129 // create tax queries
130 if( ! in_array('all', $options['taxonomy']) )
131 {
132 // vars
133 $taxonomies = array();
134 $options['tax_query'] = array();
135
136 foreach( $options['taxonomy'] as $v )
137 {
138
139 // find term (find taxonomy!)
140 // $term = array( 0 => $taxonomy, 1 => $term_id )
141 $term = explode(':', $v);
142
143
144 // validate
145 if( !is_array($term) || !isset($term[1]) )
146 {
147 continue;
148 }
149
150
151 // add to tax array
152 $taxonomies[ $term[0] ][] = $term[1];
153
154 }
155
156
157 // now create the tax queries
158 foreach( $taxonomies as $k => $v )
159 {
160 $options['tax_query'][] = array(
161 'taxonomy' => $k,
162 'field' => 'id',
163 'terms' => $v,
164 );
165 }
166 }
167
168 unset( $options['taxonomy'] );
169
170
171 // search
172 if( $options['s'] )
173 {
174 $options['like_title'] = $options['s'];
175
176 add_filter( 'posts_where', array($this, 'posts_where'), 10, 2 );
177 }
178
179 unset( $options['s'] );
180
181
182 // load field
183 $field = array();
184 if( $options['ancestor'] )
185 {
186 $ancestor = apply_filters('acf/load_field', array(), $options['ancestor'] );
187 $field = acf_get_child_field_from_parent_field( $options['field_key'], $ancestor );
188 }
189 else
190 {
191 $field = apply_filters('acf/load_field', array(), $options['field_key'] );
192 }
193
194 $field = array_merge( $this->defaults, $field );
195
196 $the_post = get_post( $options['post_id'] );
197
198
199 // filters
200 $options = apply_filters('acf/fields/relationship/query', $options, $field, $the_post);
201 $options = apply_filters('acf/fields/relationship/query/name=' . $field['name'], $options, $field, $the_post );
202 $options = apply_filters('acf/fields/relationship/query/key=' . $field['key'], $options, $field, $the_post );
203
204
205 $results = '';
206
207
208 // load the posts
209 $posts = get_posts( $options );
210
211 if( $posts )
212 {
213 foreach( $posts as $post )
214 {
215 // right aligned info
216 $title = '<span class="relationship-item-info">';
217
218 if( in_array('post_type', $field['result_elements']) )
219 {
220 $title .= $post->post_type;
221 }
222
223 // WPML
224 if( $options['lang'] )
225 {
226 $title .= ' (' . $options['lang'] . ')';
227 }
228
229 $title .= '</span>';
230
231
232 // featured_image
233 if( in_array('featured_image', $field['result_elements']) )
234 {
235 $image = get_the_post_thumbnail( $post->ID, array(21, 21) );
236
237 $title .= '<div class="result-thumbnail">' . $image . '</div>';
238 }
239
240
241 // find title. Could use get_the_title, but that uses get_post(), so I think this uses less Memory
242 $title .= apply_filters( 'the_title', $post->post_title, $post->ID );
243
244 // status
245 if($post->post_status != "publish")
246 {
247 $title .= " ($post->post_status)";
248 }
249
250 // filters
251 $title = apply_filters('acf/fields/relationship/result', $title, $post, $field, $the_post);
252 $title = apply_filters('acf/fields/relationship/result/name=' . $field['name'] , $title, $post, $field, $the_post);
253 $title = apply_filters('acf/fields/relationship/result/key=' . $field['key'], $title, $post, $field, $the_post);
254
255
256 $results .= '<li><a href="' . get_permalink($post->ID) . '" data-post_id="' . $post->ID . '">' . $title . '<span class="acf-button-add"></span></a></li>';
257 }
258 }
259
260
261 echo $results;
262 die();
263
264 }
265
266
267 /*
268 * create_field()
269 *
270 * Create the HTML interface for your field
271 *
272 * @param $field - an array holding all the field's data
273 *
274 * @type action
275 * @since 3.6
276 * @date 23/01/13
277 */
278
279 function create_field( $field )
280 {
281 // temp store the_post
282 global $post;
283 $the_post = $post;
284
285
286 // vars
287 $field = array_merge($this->defaults, $field);
288
289
290 // no row limit?
291 if( !$field['max'] || $field['max'] < 1 )
292 {
293 $field['max'] = 9999;
294 }
295
296
297 // validate post_type
298 if( !$field['post_type'] || !is_array($field['post_type']) || in_array('', $field['post_type']) )
299 {
300 $field['post_type'] = array( 'all' );
301 }
302
303
304 // validate taxonomy
305 if( !$field['taxonomy'] || !is_array($field['taxonomy']) || in_array('', $field['taxonomy']) )
306 {
307 $field['taxonomy'] = array( 'all' );
308 }
309
310
311 // class
312 $class = '';
313 if( $field['filters'] )
314 {
315 foreach( $field['filters'] as $filter )
316 {
317 $class .= ' has-' . $filter;
318 }
319 }
320
321 $attributes = array(
322 'max' => $field['max'],
323 's' => '',
324 'paged' => 1,
325 'post_type' => implode(',', $field['post_type']),
326 'taxonomy' => implode(',', $field['taxonomy']),
327 'field_key' => $field['key']
328 );
329
330
331 // Lang
332 if( defined('ICL_LANGUAGE_CODE') )
333 {
334 $attributes['lang'] = ICL_LANGUAGE_CODE;
335 }
336
337
338 // parent
339 preg_match('/\[(field_.*?)\]/', $field['name'], $ancestor);
340 if( isset($ancestor[1]) && $ancestor[1] != $field['key'])
341 {
342 $attributes['ancestor'] = $ancestor[1];
343 }
344
345 ?>
346 <div class="acf_relationship<?php echo $class; ?>"<?php foreach( $attributes as $k => $v ): ?> data-<?php echo $k; ?>="<?php echo $v; ?>"<?php endforeach; ?>>
347
348 <!-- Hidden Blank default value -->
349 <input type="hidden" name="<?php echo $field['name']; ?>" value="" />
350
351 <!-- Template for value -->
352 <script type="text/html" class="tmpl-li">
353 <li>
354 <a href="#" data-post_id="{post_id}">{title}<span class="acf-button-remove"></span></a>
355 <input type="hidden" name="<?php echo $field['name']; ?>[]" value="{post_id}" />
356 </li>
357 </script>
358 <!-- / Template for value -->
359
360 <!-- Left List -->
361 <div class="relationship_left">
362 <table class="widefat">
363 <thead>
364 <?php if(in_array( 'search', $field['filters']) ): ?>
365 <tr>
366 <th>
367 <label class="relationship_label" for="relationship_<?php echo $field['name']; ?>"><?php _e("Search",'acf'); ?>...</label>
368 <input class="relationship_search" type="text" id="relationship_<?php echo $field['name']; ?>" />
369 <!-- <div class="clear_relationship_search"></div> -->
370 </th>
371 </tr>
372 <?php endif; ?>
373 <?php if(in_array( 'post_type', $field['filters']) ): ?>
374 <tr>
375 <th>
376 <?php
377
378 // vars
379 $choices = array(
380 'all' => 'Filter by post type'
381 );
382
383
384 if( in_array('all', $field['post_type']) )
385 {
386 $post_types = apply_filters( 'acf/get_post_types', array() );
387 $choices = array_merge( $choices, $post_types);
388 }
389 else
390 {
391 foreach( $field['post_type'] as $post_type )
392 {
393 $choices[ $post_type ] = $post_type;
394 }
395 }
396
397
398 // create field
399 do_action('acf/create_field', array(
400 'type' => 'select',
401 'name' => '',
402 'class' => 'select-post_type',
403 'value' => '',
404 'choices' => $choices,
405 ));
406
407 ?>
408 </th>
409 </tr>
410 <?php endif; ?>
411 </thead>
412 </table>
413 <ul class="bl relationship_list">
414 <li class="load-more">
415 <div class="acf-loading"></div>
416 </li>
417 </ul>
418 </div>
419 <!-- /Left List -->
420
421 <!-- Right List -->
422 <div class="relationship_right">
423 <ul class="bl relationship_list">
424 <?php
425
426 if( $field['value'] )
427 {
428 foreach( $field['value'] as $post )
429 {
430 // right aligned info
431 $title = '<span class="relationship-item-info">';
432
433 if( in_array('post_type', $field['result_elements']) )
434 {
435 $title .= $post->post_type;
436 }
437
438 // WPML
439 if( defined('ICL_LANGUAGE_CODE') )
440 {
441 $title .= ' (' . ICL_LANGUAGE_CODE . ')';
442 }
443
444 $title .= '</span>';
445
446
447 // featured_image
448 if( in_array('featured_image', $field['result_elements']) )
449 {
450 $image = get_the_post_thumbnail( $post->ID, array(21, 21) );
451
452 $title .= '<div class="result-thumbnail">' . $image . '</div>';
453 }
454
455
456 // find title. Could use get_the_title, but that uses get_post(), so I think this uses less Memory
457 $title .= apply_filters( 'the_title', $post->post_title, $post->ID );
458
459 // status
460 if($post->post_status != "publish")
461 {
462 $title .= " ($post->post_status)";
463 }
464
465
466 // filters
467 $title = apply_filters('acf/fields/relationship/result', $title, $post, $field, $the_post);
468 $title = apply_filters('acf/fields/relationship/result/name=' . $field['name'] , $title, $post, $field, $the_post);
469 $title = apply_filters('acf/fields/relationship/result/key=' . $field['key'], $title, $post, $field, $the_post);
470
471
472 echo '<li>
473 <a href="' . get_permalink($post->ID) . '" class="" data-post_id="' . $post->ID . '">' . $title . '<span class="acf-button-remove"></span></a>
474 <input type="hidden" name="' . $field['name'] . '[]" value="' . $post->ID . '" />
475 </li>';
476
477
478 }
479 }
480
481 ?>
482 </ul>
483 </div>
484 <!-- / Right List -->
485
486 </div>
487 <?php
488 }
489
490
491 /*
492 * create_options()
493 *
494 * Create extra options for your field. This is rendered when editing a field.
495 * The value of $field['name'] can be used (like bellow) to save extra data to the $field
496 *
497 * @type action
498 * @since 3.6
499 * @date 23/01/13
500 *
501 * @param $field - an array holding all the field's data
502 */
503
504 function create_options( $field )
505 {
506 // vars
507 $field = array_merge($this->defaults, $field);
508 $key = $field['name'];
509
510
511
512 // validate taxonomy
513 if( !is_array($field['taxonomy']) )
514 {
515 $field['taxonomy'] = array('all');
516 }
517
518
519 // validate result_elements
520 if( !is_array( $field['result_elements'] ) )
521 {
522 $field['result_elements'] = array();
523 }
524
525 if( !in_array('post_title', $field['result_elements']) )
526 {
527 $field['result_elements'][] = 'post_title';
528 }
529
530 ?>
531 <tr class="field_option field_option_<?php echo $this->name; ?>">
532 <td class="label">
533 <label for=""><?php _e("Post Type",'acf'); ?></label>
534 </td>
535 <td>
536 <?php
537
538 $choices = array(
539 'all' => __("All",'acf')
540 );
541 $choices = apply_filters('acf/get_post_types', $choices);
542
543
544 do_action('acf/create_field', array(
545 'type' => 'select',
546 'name' => 'fields['.$key.'][post_type]',
547 'value' => $field['post_type'],
548 'choices' => $choices,
549 'multiple' => 1,
550 ));
551
552 ?>
553 </td>
554 </tr>
555 <tr class="field_option field_option_<?php echo $this->name; ?>">
556 <td class="label">
557 <label><?php _e("Filter from Taxonomy",'acf'); ?></label>
558 </td>
559 <td>
560 <?php
561 $choices = array(
562 '' => array(
563 'all' => __("All",'acf')
564 )
565 );
566 $simple_value = false;
567 $choices = apply_filters('acf/get_taxonomies_for_select', $choices, $simple_value);
568
569
570 do_action('acf/create_field', array(
571 'type' => 'select',
572 'name' => 'fields['.$key.'][taxonomy]',
573 'value' => $field['taxonomy'],
574 'choices' => $choices,
575 'multiple' => 1,
576 ));
577 ?>
578 </td>
579 </tr>
580 <tr class="field_option field_option_<?php echo $this->name; ?>">
581 <td class="label">
582 <label><?php _e("Filters",'acf'); ?></label>
583 </td>
584 <td>
585 <?php
586 do_action('acf/create_field', array(
587 'type' => 'checkbox',
588 'name' => 'fields['.$key.'][filters]',
589 'value' => $field['filters'],
590 'choices' => array(
591 'search' => __("Search",'acf'),
592 'post_type' => __("Post Type Select",'acf'),
593 )
594 ));
595 ?>
596 </td>
597 </tr>
598 <tr class="field_option field_option_<?php echo $this->name; ?>">
599 <td class="label">
600 <label><?php _e("Elements",'acf'); ?></label>
601 <p><?php _e("Selected elements will be displayed in each result",'acf') ?></p>
602 </td>
603 <td>
604 <?php
605 do_action('acf/create_field', array(
606 'type' => 'checkbox',
607 'name' => 'fields['.$key.'][result_elements]',
608 'value' => $field['result_elements'],
609 'choices' => array(
610 'featured_image' => 'Featured Image',
611 'post_title' => __("Post Title",'acf'),
612 'post_type' => __("Post Type",'acf'),
613 ),
614 'disabled' => array(
615 'post_title'
616 )
617 ));
618 ?>
619 </td>
620 </tr>
621 <tr class="field_option field_option_<?php echo $this->name; ?>">
622 <td class="label">
623 <label><?php _e("Maximum posts",'acf'); ?></label>
624 </td>
625 <td>
626 <?php
627 do_action('acf/create_field', array(
628 'type' => 'text',
629 'name' => 'fields['.$key.'][max]',
630 'value' => $field['max'],
631 ));
632 ?>
633 </td>
634 </tr>
635 <?php
636
637 }
638
639
640 /*
641 * format_value()
642 *
643 * This filter is appied to the $value after it is loaded from the db and before it is passed to the create_field action
644 *
645 * @type filter
646 * @since 3.6
647 * @date 23/01/13
648 *
649 * @param $value - the value which was loaded from the database
650 * @param $post_id - the $post_id from which the value was loaded
651 * @param $field - the field array holding all the field options
652 *
653 * @return $value - the modified value
654 */
655
656 function format_value( $value, $post_id, $field )
657 {
658 // empty?
659 if( !$value )
660 {
661 return $value;
662 }
663
664
665 // Pre 3.3.3, the value is a string coma seperated
666 if( !is_array($value) )
667 {
668 $value = explode(',', $value);
669 }
670
671
672 // empty?
673 if( empty($value) )
674 {
675 return $value;
676 }
677
678
679 // find posts (DISTINCT POSTS)
680 $posts = get_posts(array(
681 'numberposts' => -1,
682 'post__in' => $value,
683 'post_type' => apply_filters('acf/get_post_types', array()),
684 'post_status' => array('publish', 'private', 'draft', 'inherit', 'future'),
685 ));
686
687
688 $ordered_posts = array();
689 foreach( $posts as $post )
690 {
691 // create array to hold value data
692 $ordered_posts[ $post->ID ] = $post;
693 }
694
695
696 // override value array with attachments
697 foreach( $value as $k => $v)
698 {
699 // check that post exists (my have been trashed)
700 if( !isset($ordered_posts[ $v ]) )
701 {
702 unset( $value[ $k ] );
703 }
704 else
705 {
706 $value[ $k ] = $ordered_posts[ $v ];
707 }
708 }
709
710
711 // return value
712 return $value;
713 }
714
715
716 /*
717 * format_value_for_api()
718 *
719 * This filter is appied to the $value after it is loaded from the db and before it is passed back to the api functions such as the_field
720 *
721 * @type filter
722 * @since 3.6
723 * @date 23/01/13
724 *
725 * @param $value - the value which was loaded from the database
726 * @param $post_id - the $post_id from which the value was loaded
727 * @param $field - the field array holding all the field options
728 *
729 * @return $value - the modified value
730 */
731
732 function format_value_for_api( $value, $post_id, $field )
733 {
734 return $this->format_value( $value, $post_id, $field );
735 }
736
737
738 /*
739 * update_value()
740 *
741 * This filter is appied to the $value before it is updated in the db
742 *
743 * @type filter
744 * @since 3.6
745 * @date 23/01/13
746 *
747 * @param $value - the value which will be saved in the database
748 * @param $post_id - the $post_id of which the value will be saved
749 * @param $field - the field array holding all the field options
750 *
751 * @return $value - the modified value
752 */
753
754 function update_value( $value, $post_id, $field )
755 {
756 // array?
757 if( is_array($value) ){ foreach( $value as $k => $v ){
758
759 // object?
760 if( is_object($v) && isset($v->ID) )
761 {
762 $value[ $k ] = $v->ID;
763 }
764
765 }}
766
767
768 return $value;
769 }
770
771 }
772
773 new acf_field_relationship();
774
775 ?>