PluginProbe ʕ •ᴥ•ʔ
Advanced Custom Fields: Extended / 0.8
Advanced Custom Fields: Extended v0.8
0.9.2.6 0.9.2.5 0.8.6 0.8.6.1 0.8.6.3 0.8.6.5 0.8.6.6 0.8.6.7 0.8.6.8 0.8.6.9 0.8.7 0.8.7.1 0.8.7.2 0.8.7.3 0.8.7.4 0.8.7.5 0.8.7.6 0.8.8 0.8.8.1 0.8.8.10 0.8.8.11 0.8.8.2 0.8.8.3 0.8.8.4 0.8.8.5 0.8.8.6 0.8.8.7 0.8.8.8 0.8.8.9 0.8.9 0.8.9.1 0.8.9.2 0.8.9.3 0.8.9.4 0.8.9.5 0.9 0.9.0.1 0.9.0.2 0.9.0.3 0.9.0.4 0.9.0.5 0.9.0.6 0.9.0.7 0.9.0.8 0.9.0.9 0.9.1 0.9.1.1 0.9.2 0.9.2.1 0.9.2.2 0.9.2.3 0.9.2.4 trunk 0.5 0.5.1 0.5.2 0.5.2.1 0.5.2.3 0.5.5 0.5.5.1 0.5.8 0.5.8.1 0.6 0.6.0.1 0.6.0.2 0.6.1 0.6.3 0.6.5 0.6.7 0.6.7.2 0.7 0.7.0.3 0.7.5 0.7.5.5 0.7.8 0.7.9 0.7.9.3 0.7.9.4 0.7.9.9.8 0.7.9.9.9 0.8 0.8.1 0.8.2 0.8.3 0.8.3.1 0.8.4 0.8.4.1 0.8.4.5 0.8.4.6 0.8.5 0.8.5.5
acf-extended / includes / fields-settings / bidirectional.php
acf-extended / includes / fields-settings Last commit date
bidirectional.php 6 years ago data.php 6 years ago fields.php 6 years ago permissions.php 6 years ago settings.php 6 years ago validation.php 6 years ago
bidirectional.php
587 lines
1 <?php
2
3 if(!defined('ABSPATH'))
4 exit;
5
6 /**
7 * Field Setting
8 */
9 add_action('acf/render_field_settings/type=relationship', 'acfe_bidirectional_settings');
10 add_action('acf/render_field_settings/type=post_object', 'acfe_bidirectional_settings');
11 add_action('acf/render_field_settings/type=user', 'acfe_bidirectional_settings');
12 add_action('acf/render_field_settings/type=taxonomy', 'acfe_bidirectional_settings');
13 function acfe_bidirectional_settings($field){
14
15 // Settings
16 acf_render_field_setting($field, array(
17 'label' => __('Bidirectional'),
18 'key' => 'acfe_bidirectional',
19 'name' => 'acfe_bidirectional',
20 'instructions' => __('Set the field as bidirectional'),
21 'type' => 'group',
22 'required' => false,
23 'conditional_logic' => false,
24 'wrapper' => array(
25 'width' => '',
26 'class' => '',
27 'id' => '',
28 ),
29 'layout' => 'block',
30 'sub_fields' => array(
31 array(
32 'label' => false,
33 'key' => 'acfe_bidirectional_enabled',
34 'name' => 'acfe_bidirectional_enabled',
35 'type' => 'true_false',
36 'instructions' => '',
37 'required' => false,
38 'wrapper' => array(
39 'width' => '15',
40 'class' => 'acfe_width_auto',
41 'id' => '',
42 ),
43 'message' => '',
44 'default_value' => false,
45 'ui' => true,
46 'ui_on_text' => '',
47 'ui_off_text' => '',
48 'conditional_logic' => false,
49 ),
50 array(
51 'label' => false,
52 'key' => 'acfe_bidirectional_related',
53 'name' => 'acfe_bidirectional_related',
54 'type' => 'select',
55 'instructions' => '',
56 'required' => false,
57 'wrapper' => array(
58 'width' => 50,
59 'class' => '',
60 'id' => '',
61 ),
62 'choices' => array(),
63 'default_value' => array(),
64 'allow_null' => 1,
65 'multiple' => 0,
66 'ui' => 1,
67 'ajax' => 1,
68 'return_format' => 'value',
69 'placeholder' => '',
70 'conditional_logic' => array(
71 array(
72 array(
73 'field' => 'acfe_bidirectional_enabled',
74 'operator' => '==',
75 'value' => '1',
76 ),
77 ),
78 ),
79 ),
80 ),
81 ));
82
83 }
84
85 /**
86 * Field Setting: Ajax Handler
87 */
88 add_action('wp_ajax_acf/fields/select/query', 'acfe_bidirectional_ajax', 0);
89 add_action('wp_ajax_nopriv_acf/fields/select/query', 'acfe_bidirectional_ajax', 0);
90 function acfe_bidirectional_ajax(){
91
92 // Do not die to let ACF handle others ajax requests
93 if(!acf_verify_ajax())
94 return;
95
96 $options = acf_parse_args($_POST, array(
97 'post_id' => 0,
98 's' => '',
99 'field_key' => '',
100 'paged' => 1
101 ));
102
103 // Not our field setting. Stop
104 if($options['field_key'] !== 'acfe_bidirectional_related')
105 return;
106
107 $response = acfe_bidirectional_ajax_query($options);
108
109 acf_send_ajax_results($response);
110
111 }
112
113 /**
114 * Field Setting: Ajax Query
115 */
116 function acfe_bidirectional_ajax_query($options = array()){
117
118 // Current field group
119 $field_group = acf_get_field_group($options['post_id']);
120
121 acf_disable_filters();
122
123 // Get field groups
124 $r_field_groups = acf_get_field_groups();
125 if(empty($r_field_groups))
126 return false;
127
128 $choices = array();
129
130 foreach($r_field_groups as $r_field_group){
131
132 // Bypass current field group
133 if($r_field_group['key'] === $field_group['key'])
134 continue;
135
136 // Bypass ACFE native groups
137 if(in_array($r_field_group['key'], array('group_acfe_author', 'group_acfe_dynamic_post_type', 'group_acfe_dynamic_taxonomy')))
138 continue;
139
140 // Get related fields
141 $r_fields = acf_get_fields($r_field_group['key']);
142 if(empty($r_fields))
143 continue;
144
145 // Filter & find possible related fields
146 foreach($r_fields as $r_field){
147
148 acfe_bidirectional_setting_find_related($r_field, $r_field_group, $choices);
149
150 }
151
152 }
153
154 // vars
155 $results = array();
156 $s = null;
157
158 if(!empty($choices)){
159
160 // search
161 if($options['s'] !== ''){
162
163 // strip slashes (search may be integer)
164 $s = strval($options['s']);
165 $s = wp_unslash($s);
166
167 }
168
169 foreach($choices as $field_group_title => $childs){
170
171 $field_group_title = strval($field_group_title);
172
173 $childrens = array();
174 foreach($childs as $child_key => $child_label){
175
176 $child_label = strval($child_label);
177
178 // if searching, but doesn't exist
179 if(is_string($s) && stripos($child_label, $s) === false && stripos($field_group_title, $s) === false)
180 continue(2);
181
182 $childrens[] = array(
183 'id' => $child_key,
184 'text' => $child_label,
185 );
186
187 }
188
189 $results[] = array(
190 'text' => $field_group_title,
191 'children' => $childrens
192 );
193
194 }
195
196 }
197
198 return array(
199 'results' => $results
200 );
201
202 }
203
204 function acfe_bidirectional_setting_find_related($r_field, $r_field_group, &$choices){
205
206 if(in_array($r_field['type'], array('repeater', 'flexible_content')))
207 return;
208
209 // Recursive search for sub_fields (groups & clones)
210 if(isset($r_field['sub_fields']) && !empty($r_field['sub_fields'])){
211
212 foreach($r_field['sub_fields'] as $r_sub_field){
213
214 // Recursive call
215 return acfe_bidirectional_setting_find_related($r_sub_field, $r_field_group, $choices);
216
217 }
218
219 }
220
221 // Allow only specific fields
222 $allowed_fields_types = array('relationship', 'post_object', 'user', 'taxonomy');
223 if(!in_array($r_field['type'], $allowed_fields_types))
224 return false;
225
226 $choices[$r_field_group['title']][$r_field['key']] = (!empty($r_field['label']) ? $r_field['label'] : $r_field['name']) . ' (' . $r_field['key'] . ')';
227
228 }
229
230 /**
231 * Field Setting: Default Value
232 */
233 add_filter('acf/prepare_field/name=acfe_bidirectional_related', 'acfe_bidirectional_setting_value');
234 function acfe_bidirectional_setting_value($field){
235
236 if(!isset($field['value']) || empty($field['value']))
237 return $field;
238
239 // Get related field
240 $r_field = acf_get_field($field['value']);
241
242 // Related field not found
243 if(!$r_field){
244
245 // Unset & updatevalue
246 $field['value'] = false;
247 acf_update_field($field);
248
249 return $field;
250
251 }
252
253 $r_field_group = acfe_get_field_group_from_field($r_field);
254
255 $field['choices'] = array($r_field['key'] => (!empty($r_field['label']) ? $r_field['label'] : $r_field['name']) . ' (' . $r_field['key'] . ')');
256
257 return $field;
258
259 }
260
261 /**
262 * Field Setting Update
263 */
264 add_filter('acf/update_field/type=relationship', 'acfe_bidirectional_setting_update');
265 add_filter('acf/update_field/type=post_object', 'acfe_bidirectional_setting_update');
266 add_filter('acf/update_field/type=user', 'acfe_bidirectional_setting_update');
267 add_filter('acf/update_field/type=taxonomy', 'acfe_bidirectional_setting_update');
268 function acfe_bidirectional_setting_update($field){
269
270 $do_update = apply_filters('acfe/bidirectional/setting/update', true);
271 if(!$do_update)
272 return $field;
273
274 // Previous setting values
275 $_field = acf_get_field($field['key']);
276
277 // Turning off - Remove related field
278 if(acfe_has_field_bidirectional($_field) && !acfe_has_field_bidirectional($field)){
279
280 // Get related bidirectional related
281 $r_field = acf_get_field($_field['acfe_bidirectional']['acfe_bidirectional_related']);
282
283 // Reset related bidirectional related
284 $r_field['acfe_bidirectional']['acfe_bidirectional_enabled'] = false;
285 $r_field['acfe_bidirectional']['acfe_bidirectional_related'] = false;
286
287 add_filter('acfe/bidirectional/setting/update', '__return_false');
288
289 // Update related bidirectional
290 acf_update_field($r_field);
291
292 remove_filter('acfe/bidirectional/setting/update', '__return_false');
293
294 return $field;
295
296 }
297
298 // Turning on - Add related field
299 elseif(!acfe_has_field_bidirectional($_field) && acfe_has_field_bidirectional($field)){
300
301 // Get related bidirectional related
302 $r_field = acf_get_field($field['acfe_bidirectional']['acfe_bidirectional_related']);
303
304 // Reset related bidirectional related
305 $r_field['acfe_bidirectional']['acfe_bidirectional_enabled'] = true;
306 $r_field['acfe_bidirectional']['acfe_bidirectional_related'] = $field['key'];
307
308 add_filter('acfe/bidirectional/setting/update', '__return_false');
309
310 // Update related bidirectional
311 acf_update_field($r_field);
312
313 remove_filter('acfe/bidirectional/setting/update', '__return_false');
314
315 return $field;
316
317 }
318
319 // Return
320 return $field;
321
322 }
323
324 /**
325 * Field Setting Deleted
326 */
327 add_action('acf/delete_field/type=relationship', 'acfe_bidirectional_setting_delete');
328 add_filter('acf/delete_field/type=post_object', 'acfe_bidirectional_setting_delete');
329 add_filter('acf/delete_field/type=user', 'acfe_bidirectional_setting_delete');
330 add_filter('acf/delete_field/type=taxonomy', 'acfe_bidirectional_setting_delete');
331 function acfe_bidirectional_setting_delete($field){
332
333 if(!acfe_has_field_bidirectional($field))
334 return;
335
336 // Get related bidirectional related
337 $r_field = acf_get_field($field['acfe_bidirectional']['acfe_bidirectional_related']);
338
339 // Reset related bidirectional related
340 $r_field['acfe_bidirectional']['acfe_bidirectional_related'] = false;
341
342 // Update related bidirectional
343 acf_update_field($r_field);
344
345 }
346
347 /**
348 * Update Value
349 */
350 add_filter('acf/update_value/type=relationship', 'acfe_bidirectional_update_value', 11, 3);
351 add_filter('acf/update_value/type=post_object', 'acfe_bidirectional_update_value', 11, 3);
352 add_filter('acf/update_value/type=user', 'acfe_bidirectional_update_value', 11, 3);
353 add_filter('acf/update_value/type=taxonomy', 'acfe_bidirectional_update_value', 11, 3);
354 function acfe_bidirectional_update_value($value, $post_id, $field){
355
356 $ignore = apply_filters('acfe/bidirectional/ignore', false, $value, $post_id, $field);
357 if($ignore)
358 return $value;
359
360 // Check if bidirectional
361 if(!acfe_get_field_bidirectional($field))
362 return $value;
363
364 // Decode current post_id (ie: user_1)
365 $request = acf_decode_post_id($post_id);
366
367 // Values
368 $old_values = acf_get_array(acf_get_metadata($post_id, $field['name']));
369 $new_values = acf_get_array($value);
370
371 // Bail early if no difference
372 // if($old_values === $new_values)
373 // return $value;
374
375 // Values have been removed
376 if(!empty($old_values)){
377 foreach($old_values as $r_id){
378
379 if(in_array($r_id, $new_values))
380 continue;
381
382 acfe_bidirectional_relationship('remove', $r_id, $field, $request['id']);
383
384 }
385 }
386
387 // Values have been added
388 if(!empty($new_values)){
389 foreach($new_values as $r_id){
390
391 if(in_array($r_id, $old_values))
392 continue;
393
394 acfe_bidirectional_relationship('add', $r_id, $field, $request['id']);
395
396 }
397 }
398
399 return $value;
400
401 }
402
403 /**
404 * Establish Relationship
405 *
406 * $type: add|remove
407 * $r_id: the post_id to add the relationship to
408 * $p_field: the parent field
409 * $p_id: the relationship to add
410 */
411 function acfe_bidirectional_relationship($type = 'add', $r_id, $p_field, $p_value){
412
413 // Get Related Field Configuration
414 $r_field = acf_get_field($p_field['acfe_bidirectional']['acfe_bidirectional_related']);
415
416 // Get if bidirectional is active
417 if(!acfe_get_field_bidirectional($r_field))
418 return;
419
420 // Get Related Data Type ({post_id}, user_{id} ...)
421 $r_mtype = '';
422 if($p_field['type'] === 'user')
423 $r_mtype = 'user_';
424 elseif($p_field['type'] === 'taxonomy')
425 $r_mtype = 'term_';
426
427 // Get Related Field Ancestors
428 $r_field_ancestors = acf_get_field_ancestors($r_field);
429
430 // Ancestors - Complexe field (group|clone)
431 if(!empty($r_field_ancestors)){
432
433 // Get ancestors
434 $r_field_ancestors = array_reverse($r_field_ancestors);
435 $r_field_ancestors_fields = array_map('acf_get_field', $r_field_ancestors);
436
437 // Get top ancestor
438 $r_ref_field = $r_field_ancestors_fields[0];
439 $r_ref_values = acf_get_array(acf_get_value($r_mtype.$r_id, $r_ref_field));
440
441 // Get values
442 $r_values = acf_get_array(acfe_get_value_from_ancestor($r_ref_values, $r_field));
443
444 // Unset top ancestor for update (not needed)
445 unset($r_field_ancestors_fields[0]);
446
447 // Add related field to get
448 $r_values_query = array($r_field['key']);
449
450 // If > 1 ancestors, return ancestors keys only
451 if(!empty($r_field_ancestors_fields)){
452
453 $r_field_ancestors_keys = array_map(function($field){
454 return $field['key'];
455 }, $r_field_ancestors_fields);
456
457 // Add ancestors to get
458 $r_values_query = array_merge($r_field_ancestors_keys, $r_values_query);
459
460 }
461
462 }
463
464 // No Ancestors - Simple field
465 else{
466
467 // Refence field
468 $r_ref_field = $r_field;
469
470 // Values
471 $r_values = acf_get_array(acf_get_value($r_mtype.$r_id, $r_field));
472
473 }
474
475 // Convert strings to integers
476 $r_values = acf_parse_types($r_values);
477
478 // Add Value
479 if($type === 'add'){
480
481 if(!in_array($p_value, $r_values))
482 $r_values[] = $p_value;
483
484 }
485
486 // Remove Value
487 elseif($type === 'remove'){
488
489 $r_new_values = array();
490 foreach($r_values as $r_value){
491
492 if($r_value === $p_value)
493 continue;
494
495 $r_new_values[] = $r_value;
496
497 }
498
499 $r_values = $r_new_values;
500
501 }
502
503 /*
504 * Post Object & User 'Allow Multiple' Disabled
505 * Value must not be inside array
506 */
507 if(($r_ref_field['type'] === 'post_object' || $r_ref_field['type'] === 'user') && empty($r_ref_field['multiple']) && isset($r_values[0])){
508
509 // Get latest value
510 $r_values = end($r_values);
511
512 }
513
514 /*
515 * Remove potential empty serialized array in meta value 'a:0:{}'
516 */
517 if(empty($r_values))
518 $r_values = false;
519
520 /*
521 * Construct a value array in case of ancestors. ie:
522 * $related_values = Array(
523 * [field_aaa] => Array(
524 * [field_bbb] => Array(
525 * [0] => xxxx
526 * )
527 * )
528 * )
529 */
530 if(!empty($r_field_ancestors)){
531
532 for($i = count($r_values_query)-1; $i>=0; $i--){
533 $r_values = array($r_values_query[$i] => $r_values);
534 }
535
536 }
537
538 // Filter acf_update_value (to avoid infinite loop)
539 add_filter('acfe/bidirectional/ignore', '__return_true');
540
541 // Update Related Field
542 acf_update_value($r_values, $r_mtype.$r_id, $r_ref_field);
543
544 // Remove acf_update_value filter
545 remove_filter('acfe/bidirectional/ignore', '__return_true');
546
547 }
548
549 function acfe_get_value_from_ancestor($r_ref_values, $r_field){
550
551 foreach($r_ref_values as $r_ref_key => $r_ref_value){
552
553 if($r_ref_key != $r_field['key']){
554
555 if(is_array($r_ref_value))
556 return acfe_get_value_from_ancestor($r_ref_value, $r_field);
557
558 return false;
559
560 }
561
562 return $r_ref_value;
563
564 }
565
566 }
567
568 function acfe_is_field_bidirectional($field){
569
570 return isset($field['acfe_bidirectional']['acfe_bidirectional_enabled']) && !empty($field['acfe_bidirectional']['acfe_bidirectional_enabled']);
571
572 }
573
574 function acfe_has_field_bidirectional($field){
575
576 return isset($field['acfe_bidirectional']['acfe_bidirectional_related']) && !empty($field['acfe_bidirectional']['acfe_bidirectional_related']);
577
578 }
579
580 function acfe_get_field_bidirectional($field){
581
582 if(!acfe_is_field_bidirectional($field) || !acfe_has_field_bidirectional($field))
583 return false;
584
585 return $field['acfe_bidirectional']['acfe_bidirectional_related'];
586
587 }