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