PluginProbe ʕ •ᴥ•ʔ
Pods – Custom Content Types and Fields / 3.1.4.2
Pods – Custom Content Types and Fields v3.1.4.2
2.7.31.4 2.8.23.5 2.9.19.5 3.0.10.5 3.1.4.3 3.2.8.4 3.3.9.2 2.8.23.4 2.9.19.4 3.0.10.4 3.1.4.2 3.2.8.3 3.3.9.1 trunk 1.14.8 2.7.31.3 2.8.23.3 2.9.19.3 3.0.10.3 3.1.4.1 3.2.0 3.2.1 3.2.1.1 3.2.2 3.2.4 3.2.5 3.2.6 3.2.7 3.2.7.1 3.2.8 3.2.8.1 3.2.8.2 3.3.0 3.3.1 3.3.2 3.3.3 3.3.4 3.3.5 3.3.6 3.3.7 3.3.8 3.3.9
pods / classes / fields / pick.php
pods / classes / fields Last commit date
avatar.php 2 weeks ago boolean.php 2 weeks ago code.php 2 weeks ago color.php 2 weeks ago comment.php 2 weeks ago currency.php 2 weeks ago date.php 2 weeks ago datetime.php 2 weeks ago email.php 2 weeks ago file.php 2 weeks ago heading.php 2 weeks ago html.php 2 weeks ago link.php 2 weeks ago number.php 2 weeks ago oembed.php 2 weeks ago paragraph.php 2 weeks ago password.php 2 weeks ago phone.php 2 weeks ago pick.php 2 weeks ago slug.php 2 weeks ago taxonomy.php 2 weeks ago text.php 2 weeks ago time.php 2 weeks ago website.php 2 weeks ago wysiwyg.php 2 weeks ago
pick.php
4280 lines
1 <?php
2
3 use Pods\Static_Cache;
4 use Pods\Whatsit\Pod;
5 use Pods\Whatsit\Field;
6 use Pods\Whatsit\Object_Field;
7 use Pods\API\Whatsit\Value_Field;
8 use Pods\Whatsit\Store;
9
10 /**
11 * @package Pods\Fields
12 */
13 class PodsField_Pick extends PodsField {
14
15 /**
16 * {@inheritdoc}
17 */
18 public static $group = 'Relationships / Media';
19
20 /**
21 * {@inheritdoc}
22 */
23 public static $type = 'pick';
24
25 /**
26 * {@inheritdoc}
27 */
28 public static $label = 'Relationship';
29
30 /**
31 * {@inheritdoc}
32 */
33 protected static $api = false;
34
35 /**
36 * Available Related Objects.
37 *
38 * @var array
39 * @since 2.3.0
40 */
41 public static $related_objects = array();
42
43 /**
44 * Custom Related Objects
45 *
46 * @var array
47 * @since 2.3.0
48 */
49 public static $custom_related_objects = array();
50
51 /**
52 * Data used during validate / save to avoid extra queries.
53 *
54 * @var array
55 * @since 2.3.0
56 */
57 public static $related_data = array();
58
59 /**
60 * Data used during input method (mainly for autocomplete).
61 *
62 * @var array
63 * @since 2.3.0
64 */
65 public static $field_data = array();
66
67 /**
68 * Saved array of simple relationship names.
69 *
70 * @var array
71 * @since 2.5.0
72 */
73 private static $names_simple = null;
74
75 /**
76 * Saved array of relationship names
77 *
78 * @var array
79 * @since 2.5.0
80 */
81 private static $names_related = null;
82
83 /**
84 * Saved array of bidirectional relationship names
85 *
86 * @var array
87 * @since 2.5.0
88 */
89 private static $names_bidirectional = null;
90
91 /**
92 * {@inheritdoc}
93 */
94 public function setup() {
95
96 static::$group = __( 'Relationships / Media', 'pods' );
97 static::$label = __( 'Relationship', 'pods' );
98 }
99
100 /**
101 * {@inheritdoc}
102 */
103 public function admin_init() {
104
105 // AJAX for Relationship lookups.
106 add_action( 'wp_ajax_pods_relationship', array( $this, 'admin_ajax_relationship' ) );
107 add_action( 'wp_ajax_nopriv_pods_relationship', array( $this, 'admin_ajax_relationship' ) );
108
109 // Handle modal input.
110 add_action( 'pods_meta_box_pre', array( $this, 'admin_modal_input' ) );
111 add_action( 'edit_form_top', array( $this, 'admin_modal_input' ) );
112 add_action( 'show_user_profile', array( $this, 'admin_modal_input' ) );
113 add_action( 'edit_user_profile', array( $this, 'admin_modal_input' ) );
114
115 // Hook into every taxonomy form.
116 $taxonomies = get_taxonomies();
117
118 foreach ( $taxonomies as $taxonomy ) {
119 if ( $taxonomy instanceof WP_Term ) {
120 $taxonomy = $taxonomy->name;
121 }
122
123 add_action( $taxonomy . '_add_form', array( $this, 'admin_modal_input' ) );
124 add_action( $taxonomy . '_edit_form', array( $this, 'admin_modal_input' ) );
125 }
126
127 // Handle modal saving.
128 add_filter( 'redirect_post_location', array( $this, 'admin_modal_bail_post_redirect' ), 10, 2 );
129 add_action( 'load-edit-tags.php', array( $this, 'admin_modal_bail_term_action' ) );
130 add_action( 'load-categories.php', array( $this, 'admin_modal_bail_term_action' ) );
131 add_action( 'load-edit-link-categories.php', array( $this, 'admin_modal_bail_term_action' ) );
132 add_action( 'personal_options_update', array( $this, 'admin_modal_bail_user_action' ) );
133 add_action( 'user_register', array( $this, 'admin_modal_bail_user_action' ) );
134 add_action( 'pods_api_processed_form', array( $this, 'admin_modal_bail_pod' ), 10, 3 );
135
136 }
137
138 /**
139 * {@inheritdoc}
140 */
141 public function options() {
142 // translators: %s: is the Documentation linked text.
143 $fallback_help = __( 'More details on our %s.', 'pods' );
144
145 $fallback_help_link = sprintf(
146 '<a href="%1$s" target="_blank" rel="noopener noreferrer">%2$s</a>',
147 esc_url( 'https://docs.pods.io/fields/relationship/' ),
148 __( 'Field Type Documentation', 'pods' )
149 );
150
151 $fallback_help = sprintf( $fallback_help, $fallback_help_link );
152
153 $simple_objects = $this->simple_objects();
154
155 $slow_text = __( '(may be slow for large data sets)', 'pods' );
156
157 $options = [
158 static::$type . '_format_type' => [
159 'label' => __( 'Selection Type', 'pods' ),
160 'help' => $fallback_help,
161 'default' => 'single',
162 'required' => true,
163 'type' => 'pick',
164 'data' => [
165 'single' => __( 'Single Select', 'pods' ),
166 'multi' => __( 'Multiple Select', 'pods' ),
167 ],
168 'pick_format_single' => 'dropdown',
169 'pick_show_select_text' => 0,
170 'dependency' => true,
171 ],
172 static::$type . '_format_single' => [
173 'label' => __( 'Input Type', 'pods' ),
174 'help' => $fallback_help,
175 'depends-on' => [
176 static::$type . '_format_type' => 'single',
177 ],
178 'default' => 'dropdown',
179 'required' => true,
180 'type' => 'pick',
181 'data' => apply_filters( 'pods_form_ui_field_pick_format_single_options', [
182 'dropdown' => __( 'Drop Down', 'pods' ) . ' ' . $slow_text,
183 'radio' => __( 'Radio Buttons', 'pods' ) . ' ' . $slow_text,
184 'autocomplete' => __( 'Autocomplete', 'pods' ),
185 'list' => __( 'List View (single value)', 'pods' ),
186 ] ),
187 'pick_format_single' => 'dropdown',
188 'pick_show_select_text' => 0,
189 'dependency' => true,
190 ],
191 static::$type . '_format_single_help' => [
192 'label' => '',
193 'type' => 'html',
194 'default' => 0,
195 'html_content' => '<p><em>' . esc_html__( 'Please note: When relating to dynamic content with large amounts of data, Drop Down or Radio Buttons can cause the edit screen to load very slowly because it loads all data at once. Consider using the Autocomplete or List View instead.', 'pods' ) . '</em></p>',
196 'dependency' => true,
197 'wildcard-on' => [
198 static::$type . '_format_single' => [
199 '^dropdown$',
200 '^radio$',
201 ],
202 static::$type . '_object' => [
203 '^post_type-(?!(custom_css|customize_changeset)).*$',
204 '^taxonomy-.*$',
205 '^user$',
206 '^pod-.*$',
207 ],
208 ],
209 ],
210 static::$type . '_format_multi' => [
211 'label' => __( 'Input Type', 'pods' ),
212 'help' => $fallback_help,
213 'depends-on' => [
214 static::$type . '_format_type' => 'multi',
215 ],
216 'default' => 'list',
217 'required' => true,
218 'type' => 'pick',
219 'data' => apply_filters( 'pods_form_ui_field_pick_format_multi_options', [
220 'checkbox' => __( 'Checkboxes', 'pods' ) . ' ' . $slow_text,
221 'multiselect' => __( 'Multi Select (basic selection)', 'pods' ) . ' ' . $slow_text,
222 'autocomplete' => __( 'Autocomplete', 'pods' ),
223 'list' => __( 'List View (with reordering)', 'pods' ),
224 ] ),
225 'pick_format_single' => 'dropdown',
226 'pick_show_select_text' => 0,
227 'dependency' => true,
228 ],
229 static::$type . '_format_multi_help' => [
230 'label' => '',
231 'type' => 'html',
232 'default' => 0,
233 'html_content' => '<p><em>' . esc_html__( 'Please note: When relating to dynamic content with large amounts of data, Checkboxes or Multi Select can cause the edit screen to load very slowly because it loads all data at once. Consider using the Autocomplete or List View instead.', 'pods' ) . '</em></p>',
234 'dependency' => true,
235 'wildcard-on' => [
236 static::$type . '_format_multi' => [
237 '^checkbox$',
238 '^multiselect$',
239 ],
240 static::$type . '_object' => [
241 '^post_type-(?!(custom_css|customize_changeset)).*$',
242 '^taxonomy-.*$',
243 '^user$',
244 '^pod-.*$',
245 ],
246 ],
247 ],
248 static::$type . '_display_format_multi' => [
249 'label' => __( 'Display Format', 'pods' ),
250 'help' => __( 'Used as format for front-end display', 'pods' ) . ' ' . $fallback_help,
251 'depends-on' => [
252 static::$type . '_format_type' => 'multi',
253 ],
254 'default' => 'default',
255 'required' => true,
256 'type' => 'pick',
257 'data' => [
258 'default' => __( 'Item 1, Item 2, and Item 3', 'pods' ),
259 'non_serial' => __( 'Item 1, Item 2 and Item 3', 'pods' ),
260 'br' => __( 'One per line (br HTML tags)', 'pods' ),
261 'ul' => __( 'Unordered HTML list', 'pods' ),
262 'ol' => __( 'Ordered HTML list', 'pods' ),
263 'custom' => __( 'Custom separator (without "and")', 'pods' ),
264 ],
265 'pick_format_single' => 'dropdown',
266 'pick_show_select_text' => 0,
267 'dependency' => true,
268 ],
269 static::$type . '_display_format_separator' => [
270 'label' => __( 'Display Format Separator', 'pods' ),
271 'help' => __( 'Used as separator for front-end display. This also turns off the "and" portion of the formatting.', 'pods' ) . ' ' . $fallback_help,
272 'depends-on' => [
273 static::$type . '_display_format_multi' => 'custom',
274 static::$type . '_format_type' => 'multi',
275 ],
276 'default' => ', ',
277 'type' => 'text',
278 ],
279 static::$type . '_allow_add_new' => [
280 'label' => __( 'Allow Add New', 'pods' ),
281 'help' => __( 'Allow new related records to be created in a modal window', 'pods' ) . ' ' . $fallback_help,
282 'wildcard-on' => [
283 static::$type . '_object' => [
284 '^post_type-(?!(custom_css|customize_changeset)).*$',
285 //'^taxonomy-.*$', @todo We need to finish adding support for add new on term form.
286 '^user$',
287 '^pod-.*$',
288 ],
289 ],
290 'type' => 'boolean',
291 'default' => 1,
292 ],
293 static::$type . '_add_new_label' => array(
294 'label' => __( 'Add New Label', 'pods' ),
295 'placeholder' => __( 'Add New', 'pods' ),
296 'default' => '',
297 'type' => 'text',
298 'depends-on' => [ static::$type . '_allow_add_new' => true ]
299 ),
300 static::$type . '_taggable' => [
301 'label' => __( 'Taggable', 'pods' ),
302 'help' => __( 'Allow new values to be inserted when using an Autocomplete field', 'pods' ) . ' ' . $fallback_help,
303 'depends-on-any' => [
304 static::$type . '_format_single' => 'autocomplete',
305 static::$type . '_format_multi' => 'autocomplete',
306 ],
307 'excludes-on' => [
308 static::$type . '_object' => array_merge( [
309 'site',
310 'network',
311 ], $simple_objects ),
312 static::$type . '_allow_add_new' => false,
313 ],
314 'type' => 'boolean',
315 'default' => 0,
316 ],
317 static::$type . '_show_icon' => [
318 'label' => __( 'Show Icons', 'pods' ),
319 'help' => $fallback_help,
320 'depends-on-any' => [
321 static::$type . '_format_single' => 'list',
322 static::$type . '_format_multi' => 'list',
323 ],
324 'excludes-on' => [
325 static::$type . '_object' => array_merge( [ 'site', 'network' ], $simple_objects ),
326 ],
327 'type' => 'boolean',
328 'default' => 1,
329 ],
330 static::$type . '_show_edit_link' => [
331 'label' => __( 'Show Edit Links', 'pods' ),
332 'help' => $fallback_help,
333 'depends-on-any' => [
334 static::$type . '_format_single' => 'list',
335 static::$type . '_format_multi' => 'list',
336 ],
337 'excludes-on' => [
338 static::$type . '_object' => array_merge( [ 'site', 'network' ], $simple_objects ),
339 ],
340 'type' => 'boolean',
341 'default' => 1,
342 ],
343 static::$type . '_show_view_link' => [
344 'label' => __( 'Show View Links', 'pods' ),
345 'help' => $fallback_help,
346 'depends-on-any' => [
347 static::$type . '_format_single' => 'list',
348 static::$type . '_format_multi' => 'list',
349 ],
350 'excludes-on' => [
351 static::$type . '_object' => array_merge( [ 'site', 'network' ], $simple_objects ),
352 ],
353 'type' => 'boolean',
354 'default' => 1,
355 ],
356 static::$type . '_select_text' => [
357 'label' => __( 'Default Select Text', 'pods' ),
358 'help' => __( 'This is the text used for the default "no selection" dropdown item. If left empty, it will default to "-- Select One --"', 'pods' ) . ' ' . $fallback_help,
359 'depends-on' => [
360 static::$type . '_format_type' => 'single',
361 static::$type . '_format_single' => 'dropdown',
362 ],
363 'default' => '',
364 'text_placeholder' => __( '-- Select One --', 'pods' ),
365 'type' => 'text',
366 ],
367 static::$type . '_limit' => [
368 'label' => __( 'Selection Limit', 'pods' ),
369 'help' => __( 'Default is "0" for no limit, but you can enter 1 or more to limit the number of items that can be selected.', 'pods' ) . ' ' . $fallback_help,
370 'depends-on' => [
371 static::$type . '_format_type' => 'multi',
372 ],
373 'default' => 0,
374 'type' => 'number',
375 ],
376 static::$type . '_table_id' => [
377 'label' => __( 'Table ID Column', 'pods' ),
378 'help' => __( 'You must provide the ID column name for the table, this will be used to keep track of the relationship', 'pods' ) . ' ' . $fallback_help,
379 'depends-on' => [
380 static::$type . '_object' => 'table',
381 ],
382 'required' => 1,
383 'default' => '',
384 'type' => 'text',
385 ],
386 static::$type . '_table_index' => [
387 'label' => __( 'Table Index Column', 'pods' ),
388 'help' => __( 'You must provide the index column name for the table, this may optionally also be the ID column name', 'pods' ) . ' ' . $fallback_help,
389 'depends-on' => [
390 static::$type . '_object' => 'table',
391 ],
392 'required' => 1,
393 'default' => '',
394 'type' => 'text',
395 ],
396 static::$type . '_display' => [
397 'label' => __( 'Display Field in Selection List', 'pods' ),
398 'help' => __( 'Provide the name of a field on the related object to reference, example: {@post_title}', 'pods' ) . ' ' . $fallback_help,
399 'excludes-on' => [
400 static::$type . '_object' => array_merge( [ 'site', 'network' ], $simple_objects ),
401 ],
402 'default' => '',
403 'type' => 'text',
404 ],
405 static::$type . '_user_role' => [
406 'label' => __( 'Limit list by Role(s)', 'pods' ),
407 'help' => __( 'You can choose to limit Users available for selection by specific role(s).', 'pods' ) . ' ' . $fallback_help,
408 'default' => '',
409 'type' => 'pick',
410 'pick_object' => 'role',
411 'pick_format_type' => 'multi',
412 'pick_format_multi' => 'autocomplete',
413 'depends-on' => [
414 static::$type . '_object' => 'user',
415 ],
416 ],
417 static::$type . '_where' => [
418 'label' => __( 'Customized <em>WHERE</em>', 'pods' ),
419 'help' => $fallback_help,
420 'excludes-on' => [
421 static::$type . '_object' => array_merge( [ 'site', 'network' ], $simple_objects ),
422 ],
423 'default' => '',
424 'type' => 'text',
425 ],
426 static::$type . '_orderby' => [
427 'label' => __( 'Customized <em>ORDER BY</em>', 'pods' ),
428 'help' => $fallback_help,
429 'excludes-on' => [
430 static::$type . '_object' => array_merge( [ 'site', 'network' ], $simple_objects ),
431 ],
432 'default' => '',
433 'type' => 'text',
434 ],
435 static::$type . '_groupby' => [
436 'label' => __( 'Customized <em>GROUP BY</em>', 'pods' ),
437 'help' => $fallback_help,
438 'excludes-on' => [
439 static::$type . '_object' => array_merge( [ 'site', 'network' ], $simple_objects ),
440 ],
441 'default' => '',
442 'type' => 'text',
443 ],
444 ];
445
446 $post_type_pick_objects = array();
447
448 foreach ( get_post_types( '', 'names' ) as $post_type ) {
449 $post_type_pick_objects[] = 'post_type-' . $post_type;
450 }
451
452 $options[ static::$type . '_post_status' ] = [
453 'label' => __( 'Limit list by Post Status', 'pods' ),
454 'help' => __( 'You can choose to limit Posts available for selection by one or more specific post status.', 'pods' ),
455 'type' => 'pick',
456 'pick_object' => 'post-status-with-any',
457 'pick_format_type' => 'multi',
458 'default' => 'publish',
459 'depends-on' => [
460 static::$type . '_object' => $post_type_pick_objects,
461 ],
462 ];
463
464 $options[ static::$type . '_post_author' ] = [
465 'label' => __( 'Limit list to the same Post Author', 'pods' ),
466 'help' => __( 'You can choose to limit Posts available for selection to those created by the same Post Author. This only works if this pod is a Post Type and this field is related to a Post Type.', 'pods' ),
467 'type' => 'boolean',
468 'default' => 0,
469 'depends-on' => [
470 // @todo Support being able to depend on the current pod type like _pod_type => post_type or something.
471 static::$type . '_object' => $post_type_pick_objects,
472 ],
473 ];
474
475 return $options;
476
477 }
478
479 /**
480 * {@inheritdoc}
481 */
482 public function prepare( $options = null ) {
483 $format = static::$prepare;
484
485 // Maybe use number format for storage if not a simple relationship and limit is one.
486 if ( $options instanceof Field && ! $options->is_simple_relationship() && 1 === $options->get_limit() ) {
487 $format = '%d';
488 }
489
490 return $format;
491 }
492
493 /**
494 * Register a related object.
495 *
496 * @param string $name Object name.
497 * @param string $label Object label.
498 * @param array $options Object options.
499 *
500 * @return array|boolean Object array or false if unsuccessful
501 * @since 2.3.0
502 */
503 public function register_related_object( $name, $label, $options = null ) {
504
505 if ( empty( $name ) || empty( $label ) ) {
506 return false;
507 }
508
509 $related_object = array(
510 'label' => $label,
511 'group' => 'Custom Relationships',
512 'simple' => true,
513 'bidirectional' => false,
514 'data' => array(),
515 'data_callback' => null,
516 );
517
518 $related_object = array_merge( $related_object, $options );
519
520 if ( $related_object['data_callback'] instanceof Closure ) {
521 return pods_error( 'Pods does not support closures for data callbacks' );
522 }
523
524 self::$custom_related_objects[ $name ] = $related_object;
525
526 return true;
527
528 }
529
530 /**
531 * Setup related objects.
532 *
533 * @param boolean $force Whether to force refresh of related objects.
534 *
535 * @return bool True when data has been loaded
536 * @since 2.3.0
537 */
538 public function setup_related_objects( $force = false ) {
539
540 $new_data_loaded = false;
541
542 if ( ! $force && empty( self::$related_objects ) ) {
543 // Only load transient if we aren't forcing a refresh.
544 self::$related_objects = pods_transient_get( 'pods_related_objects' );
545
546 if ( false !== self::$related_objects ) {
547 $new_data_loaded = true;
548 }
549 } elseif ( $force ) {
550 // If we are rebuilding, make sure we start with a clean slate.
551 self::$related_objects = [];
552 }
553
554 if ( ! is_array( self::$related_objects ) ) {
555 self::$related_objects = [];
556 }
557
558 if ( empty( self::$related_objects ) ) {
559 // Do a complete build of related_objects.
560 $new_data_loaded = true;
561
562 // Custom simple relationship lists.
563 self::$related_objects['custom-simple'] = array(
564 'label' => __( 'Simple (custom defined list)', 'pods' ),
565 'group' => __( 'Custom', 'pods' ),
566 'simple' => true,
567 );
568
569 // Pods options.
570 $pod_options = array();
571
572 // Include PodsMeta if not already included.
573 pods_meta();
574
575 // Advanced Content Types for relationships.
576 $_pods = PodsMeta::$advanced_content_types;
577
578 foreach ( $_pods as $pod ) {
579 $pod_options[ $pod['name'] ] = $pod['label'] . ' (' . $pod['name'] . ')';
580 }
581
582 /**
583 * Allow filtering the list of Pods to show in the list of relationship objects.
584 *
585 * @since 2.8.0
586 *
587 * @param array $pod_options List of Pods to show in the list of relationship objects.
588 */
589 $pod_options = apply_filters( 'pods_field_pick_setup_related_objects_pods', $pod_options );
590
591 asort( $pod_options );
592
593 foreach ( $pod_options as $pod => $label ) {
594 self::$related_objects[ 'pod-' . $pod ] = array(
595 'label' => $label,
596 'group' => __( 'Advanced Content Types', 'pods' ),
597 'bidirectional' => true,
598 );
599 }
600
601 /**
602 * Prevent ability to extend core Pods content types.
603 *
604 * @param bool $ignore_internal Default is true, when set to false Pods internal content types can not be extended.
605 *
606 * @since 2.3.19
607 */
608 $ignore_internal = apply_filters( 'pods_pick_ignore_internal', true );
609
610 $pods_meta = pods_meta();
611
612 // Public Post Types for relationships.
613 $post_types = get_post_types( [ 'public' => true ] );
614 asort( $post_types );
615
616 foreach ( $post_types as $post_type => $label ) {
617 if (
618 empty( $post_type )
619 || 'attachment' === $post_type
620 || (
621 $pods_meta
622 && ! $pods_meta->is_type_covered( 'post_type', $post_type )
623 )
624 ) {
625 unset( $post_types[ $post_type ] );
626
627 continue;
628 } elseif ( $ignore_internal && 0 === strpos( $post_type, '_pods_' ) ) {
629 unset( $post_types[ $post_type ] );
630
631 continue;
632 }
633
634 $post_type = get_post_type_object( $post_type );
635
636 self::$related_objects[ 'post_type-' . $post_type->name ] = array(
637 'label' => $post_type->label . ' (' . $post_type->name . ')',
638 'group' => __( 'Post Types', 'pods' ),
639 'bidirectional' => true,
640 );
641 }
642
643 // Post Types for relationships.
644 $post_types = get_post_types( [ 'public' => false ] );
645 asort( $post_types );
646
647 foreach ( $post_types as $post_type => $label ) {
648 if (
649 empty( $post_type )
650 || 'attachment' === $post_type
651 || (
652 $pods_meta
653 && ! $pods_meta->is_type_covered( 'post_type', $post_type )
654 )
655 ) {
656 unset( $post_types[ $post_type ] );
657
658 continue;
659 } elseif ( $ignore_internal && 0 === strpos( $post_type, '_pods_' ) ) {
660 unset( $post_types[ $post_type ] );
661
662 continue;
663 }
664
665 $post_type = get_post_type_object( $post_type );
666
667 self::$related_objects[ 'post_type-' . $post_type->name ] = array(
668 'label' => $post_type->label . ' (' . $post_type->name . ')',
669 'group' => __( 'Post Types (Private)', 'pods' ),
670 'bidirectional' => true,
671 );
672 }
673
674 // Taxonomies for relationships.
675 $taxonomies = get_taxonomies();
676 asort( $taxonomies );
677
678 foreach ( $taxonomies as $taxonomy => $label ) {
679 if (
680 empty( $taxonomy )
681 || (
682 $pods_meta
683 && ! $pods_meta->is_type_covered( 'taxonomy', $taxonomy )
684 )
685 ) {
686 unset( $taxonomies[ $taxonomy ] );
687
688 continue;
689 } elseif ( $ignore_internal && 0 === strpos( $taxonomy, '_pods_' ) ) {
690 unset( $taxonomies[ $taxonomy ] );
691
692 continue;
693 }
694
695 $taxonomy = get_taxonomy( $taxonomy );
696
697 self::$related_objects[ 'taxonomy-' . $taxonomy->name ] = array(
698 'label' => $taxonomy->label . ' (' . $taxonomy->name . ')',
699 'group' => __( 'Taxonomies', 'pods' ),
700 'bidirectional' => true,
701 );
702 }//end foreach
703
704 // Other WP Objects for relationships.
705 self::$related_objects['user'] = array(
706 'label' => __( 'Users', 'pods' ),
707 'group' => __( 'Other WP Objects', 'pods' ),
708 'bidirectional' => true,
709 );
710
711 self::$related_objects['role'] = array(
712 'label' => __( 'User Roles', 'pods' ),
713 'group' => __( 'Other WP Objects', 'pods' ),
714 'simple' => true,
715 'data_callback' => array( $this, 'data_roles' ),
716 );
717
718 self::$related_objects['capability'] = array(
719 'label' => __( 'User Capabilities', 'pods' ),
720 'group' => __( 'Other WP Objects', 'pods' ),
721 'simple' => true,
722 'data_callback' => array( $this, 'data_capabilities' ),
723 );
724
725 self::$related_objects['media'] = array(
726 'label' => __( 'Media', 'pods' ),
727 'group' => __( 'Other WP Objects', 'pods' ),
728 'bidirectional' => true,
729 );
730
731 self::$related_objects['comment'] = array(
732 'label' => __( 'Comments', 'pods' ),
733 'group' => __( 'Other WP Objects', 'pods' ),
734 'bidirectional' => true,
735 );
736
737 self::$related_objects['image-size'] = array(
738 'label' => __( 'Image Sizes', 'pods' ),
739 'group' => __( 'Other WP Objects', 'pods' ),
740 'simple' => true,
741 'data_callback' => array( $this, 'data_image_sizes' ),
742 );
743
744 self::$related_objects['nav_menu'] = array(
745 'label' => __( 'Navigation Menus', 'pods' ),
746 'group' => __( 'Other WP Objects', 'pods' ),
747 );
748
749 self::$related_objects['post_format'] = array(
750 'label' => __( 'Post Formats', 'pods' ),
751 'group' => __( 'Other WP Objects', 'pods' ),
752 );
753
754 self::$related_objects['post-status'] = array(
755 'label' => __( 'Post Status', 'pods' ),
756 'group' => __( 'Other WP Objects', 'pods' ),
757 'simple' => true,
758 'data_callback' => array( $this, 'data_post_stati' ),
759 );
760
761 self::$related_objects['post-status-with-any'] = array(
762 'label' => __( 'Post Status (with any)', 'pods' ),
763 'group' => __( 'Other WP Objects', 'pods' ),
764 'simple' => true,
765 'data_callback' => array( $this, 'data_post_stati_with_any' ),
766 );
767
768 self::$related_objects['post-types'] = [
769 'label' => __( 'Post Type Objects', 'pods' ),
770 'group' => __( 'Other WP Objects', 'pods' ),
771 'simple' => true,
772 'data_callback' => [ $this, 'data_post_types' ],
773 ];
774
775 self::$related_objects['taxonomies'] = [
776 'label' => __( 'Taxonomy Objects', 'pods' ),
777 'group' => __( 'Other WP Objects', 'pods' ),
778 'simple' => true,
779 'data_callback' => [ $this, 'data_taxonomies' ],
780 ];
781
782 do_action( 'pods_form_ui_field_pick_related_objects_other' );
783
784 self::$related_objects['country'] = array(
785 'label' => __( 'Countries', 'pods' ),
786 'group' => __( 'Predefined Lists', 'pods' ),
787 'simple' => true,
788 'data_callback' => array( $this, 'data_countries' ),
789 );
790
791 self::$related_objects['us_state'] = array(
792 'label' => __( 'US States', 'pods' ),
793 'group' => __( 'Predefined Lists', 'pods' ),
794 'simple' => true,
795 'data_callback' => array( $this, 'data_us_states' ),
796 );
797
798 self::$related_objects['ca_province'] = array(
799 'label' => __( 'CA Provinces', 'pods' ),
800 'group' => __( 'Predefined Lists', 'pods' ),
801 'simple' => true,
802 'data_callback' => array( $this, 'data_ca_provinces' ),
803 );
804
805 self::$related_objects['days_of_week'] = array(
806 'label' => __( 'Calendar - Days of Week', 'pods' ),
807 'group' => __( 'Predefined Lists', 'pods' ),
808 'simple' => true,
809 'data_callback' => array( $this, 'data_days_of_week' ),
810 );
811
812 self::$related_objects['months_of_year'] = array(
813 'label' => __( 'Calendar - Months of Year', 'pods' ),
814 'group' => __( 'Predefined Lists', 'pods' ),
815 'simple' => true,
816 'data_callback' => array( $this, 'data_months_of_year' ),
817 );
818
819 do_action( 'pods_form_ui_field_pick_related_objects_predefined' );
820
821 if ( did_action( 'init' ) ) {
822 pods_transient_set( 'pods_related_objects', self::$related_objects, WEEK_IN_SECONDS );
823 }
824 }//end if
825
826 /**
827 * Allow custom related objects to be defined
828 */
829 do_action( 'pods_form_ui_field_pick_related_objects_custom' );
830
831 foreach ( self::$custom_related_objects as $object => $related_object ) {
832 if ( ! isset( self::$related_objects[ $object ] ) ) {
833 $new_data_loaded = true;
834
835 self::$related_objects[ $object ] = $related_object;
836 }
837 }
838
839 if ( $new_data_loaded ) {
840 /**
841 * Allow hooking in when new data has been loaded.
842 *
843 * @since 2.8.0
844 */
845 do_action( 'pods_form_ui_field_pick_related_objects_new_data_loaded' );
846 }
847
848 return true;
849
850 }
851
852 /**
853 * Return available related objects
854 *
855 * @param boolean $force Whether to force refresh of related objects.
856 *
857 * @return array Field selection array
858 * @since 2.3.0
859 */
860 public function related_objects( $force = false ) {
861 if ( null !== self::$names_related ) {
862 return self::$names_related;
863 }
864
865 $this->setup_related_objects( $force );
866
867 $related_objects = array();
868
869 foreach ( self::$related_objects as $related_object_name => $related_object ) {
870 if ( ! isset( $related_objects[ $related_object['group'] ] ) ) {
871 $related_objects[ $related_object['group'] ] = array();
872 }
873
874 $related_objects[ $related_object['group'] ][ $related_object_name ] = $related_object['label'];
875 }
876
877 self::$names_related = (array) apply_filters( 'pods_form_ui_field_pick_related_objects', $related_objects );
878
879 return self::$names_related;
880 }
881
882 /**
883 * Return available simple object names
884 *
885 * @return array Simple object names
886 * @since 2.3.0
887 */
888 public function simple_objects() {
889 if ( null !== self::$names_simple ) {
890 return self::$names_simple;
891 }
892
893 $this->setup_related_objects();
894
895 $simple_objects = array();
896
897 foreach ( self::$related_objects as $object => $related_object ) {
898 if ( ! isset( $related_object['simple'] ) || ! $related_object['simple'] ) {
899 continue;
900 }
901
902 $simple_objects[] = $object;
903 }
904
905 self::$names_simple = (array) apply_filters( 'pods_form_ui_field_pick_simple_objects', $simple_objects );
906
907 return self::$names_simple;
908 }
909
910 /**
911 * Return available bidirectional object names
912 *
913 * @return array Bidirectional object names
914 * @since 2.3.4
915 */
916 public function bidirectional_objects() {
917 if ( null !== self::$names_bidirectional ) {
918 return self::$names_bidirectional;
919 }
920
921 $this->setup_related_objects();
922
923 $bidirectional_objects = array();
924
925 foreach ( self::$related_objects as $object => $related_object ) {
926 if ( ! isset( $related_object['bidirectional'] ) || ! $related_object['bidirectional'] ) {
927 continue;
928 }
929
930 $bidirectional_objects[] = $object;
931 }
932
933 self::$names_bidirectional = (array) apply_filters( 'pods_form_ui_field_pick_bidirectional_objects', $bidirectional_objects );
934
935 return self::$names_bidirectional;
936 }
937
938 /**
939 * {@inheritdoc}
940 */
941 public function schema( $options = null ) {
942 $field = pods_config_for_field( $options );
943
944 if ( $field && $field->is_simple_relationship() ) {
945 return 'LONGTEXT';
946 }
947
948 return false;
949 }
950
951 /**
952 * {@inheritdoc}
953 */
954 public function display( $value = null, $name = null, $options = null, $pod = null, $id = null ) {
955
956 $fields = null;
957
958 if ( is_object( $pod ) && isset( $pod->fields ) ) {
959 /**
960 * @var $pod Pods Pods object.
961 */
962 $fields = pods_config_get_all_fields( $pod );
963 } elseif ( is_array( $pod ) && isset( $pod['fields'] ) ) {
964 $fields = pods_config_get_all_fields( $pod );
965 }
966
967 $args = array(
968 'field' => $name,
969 'fields' => $fields,
970 );
971
972 $display_format = pods_v( static::$type . '_display_format_multi', $options, 'default' );
973
974 switch ( $display_format ) {
975 case 'ul':
976 case 'ol':
977 $value = '<' . $display_format . '><li>' . implode( '</li><li>', (array) $value ) . '</li></' . $display_format . '>';
978 break;
979 case 'br':
980 $value = implode( '<br />', $value );
981 break;
982 case 'non_serial':
983 $args['serial'] = false;
984 $value = pods_serial_comma( $value, $args );
985 break;
986 case 'custom':
987 $args['serial'] = false;
988
989 $separator = pods_v( static::$type . '_display_format_separator', $options, ', ' );
990 if ( ! empty( $separator ) ) {
991 $args['separator'] = $separator;
992
993 // Replicate separator behavior.
994 $args['and'] = $args['separator'];
995 }
996 $value = pods_serial_comma( $value, $args );
997 break;
998 default:
999 $value = pods_serial_comma( $value, $args );
1000 break;
1001 }
1002
1003 return $value;
1004 }
1005
1006 /**
1007 * {@inheritdoc}
1008 */
1009 public function input( $name, $value = null, $options = null, $pod = null, $id = null ) {
1010 $options = ( is_array( $options ) || is_object( $options ) ) ? $options : (array) $options;
1011
1012 // Do anything we need to do here with options setup / enforcement.
1013
1014 // Default labels.
1015 if ( empty( $options[ static::$type . '_add_new_label' ] ) ) {
1016 $options[ static::$type . '_add_new_label' ] = __( 'Add New', 'pods' );
1017 }
1018
1019 parent::input( $name, $value, $options, $pod, $id );
1020 }
1021
1022 /**
1023 * {@inheritdoc}
1024 */
1025 public function build_dfv_field_options( $options, $args ) {
1026 // Use field object if it was provided.
1027 if ( isset( $options['_field_object'] ) ) {
1028 $field = $options['_field_object'];
1029
1030 unset( $options['_field_object'] );
1031
1032 $options = pods_config_merge_data( $field, $options );
1033 }
1034
1035 $field_options = $options instanceof \Pods\Whatsit ? $options->export() : $options;
1036
1037 if ( ! isset( $field_options['id'] ) ) {
1038 $field_options['id'] = 0;
1039 }
1040
1041 // Enforce defaults.
1042 $all_options = static::options();
1043
1044 foreach ( $all_options as $option_name => $option ) {
1045 $default = pods_v( 'default', $option, '' );
1046
1047 $field_options[ $option_name ] = pods_v( $option_name, $field_options, $default );
1048
1049 if ( '' === $field_options[ $option_name ] ) {
1050 $field_options[ $option_name ] = $default;
1051 }
1052 }
1053
1054 $field_options['grouped'] = 1;
1055
1056 if ( empty( $field_options[ $args->type . '_object' ] ) ) {
1057 $field_options[ $args->type . '_object' ] = '';
1058 }
1059
1060 if ( empty( $field_options[ $args->type . '_val' ] ) ) {
1061 $field_options[ $args->type . '_val' ] = '';
1062 }
1063
1064 // Unset the table info for now.
1065 $field_options['table_info'] = [];
1066
1067 $custom = pods_v( $args->type . '_custom', $field_options, false );
1068
1069 $custom = apply_filters( 'pods_form_ui_field_pick_custom_values', $custom, $args->name, $args->value, $field_options, $args->pod, $args->id );
1070
1071 $ajax = false;
1072
1073 if ( $this->can_ajax( $args->type, $field_options ) ) {
1074 $ajax = true;
1075
1076 $field_data = pods_static_cache_get( $field_options['name'] . '/' . $field_options['id'], __CLASS__ . '/field_data' ) ?: [];
1077
1078 if ( isset( $field_data['autocomplete'] ) ) {
1079 $ajax = (boolean) $field_data['autocomplete'];
1080 }
1081 }
1082
1083 $ajax = apply_filters( 'pods_form_ui_field_pick_ajax', $ajax, $args->name, $args->value, $field_options, $args->pod, $args->id );
1084
1085 if ( 0 === (int) pods_v( $args->type . '_ajax', $field_options, 1 ) ) {
1086 $ajax = false;
1087 }
1088
1089 $field_options[ $args->type . '_ajax' ] = (int) $ajax;
1090
1091 $format_type = pods_v( $args->type . '_format_type', $field_options, 'single', true );
1092
1093 $limit = 1;
1094
1095 if ( 'single' === $format_type ) {
1096 $format_single = pods_v( $args->type . '_format_single', $field_options, 'dropdown', true );
1097
1098 if ( ! empty( $args->value ) && is_array( $args->value ) ) {
1099 $args->value = reset( $args->value );
1100 }
1101
1102 if ( 'dropdown' === $format_single ) {
1103 $field_options['view_name'] = 'select';
1104 } elseif ( 'radio' === $format_single ) {
1105 $field_options['view_name'] = 'radio';
1106 } elseif ( 'autocomplete' === $format_single ) {
1107 $field_options['view_name'] = 'select2';
1108 } elseif ( 'list' === $format_single ) {
1109 $field_options['view_name'] = 'list';
1110 } else {
1111 $field_options['view_name'] = $format_single;
1112 }
1113 } elseif ( 'multi' === $format_type ) {
1114 $format_multi = pods_v( $args->type . '_format_multi', $field_options, 'checkbox', true );
1115
1116 if ( ! empty( $args->value ) && ! is_array( $args->value ) ) {
1117 $args->value = explode( ',', $args->value );
1118 }
1119
1120 if ( 'checkbox' === $format_multi ) {
1121 $field_options['view_name'] = 'checkbox';
1122 } elseif ( 'multiselect' === $format_multi ) {
1123 $field_options['view_name'] = 'select';
1124 } elseif ( 'autocomplete' === $format_multi ) {
1125 $field_options['view_name'] = 'select2';
1126 } elseif ( 'list' === $format_multi ) {
1127 $field_options['view_name'] = 'list';
1128 } else {
1129 $field_options['view_name'] = $format_multi;
1130 }
1131
1132 $limit = 0;
1133
1134 if ( ! empty( $field_options[ $args->type . '_limit' ] ) ) {
1135 $limit = absint( $field_options[ $args->type . '_limit' ] );
1136 }
1137 } else {
1138 $field_options['view_name'] = $format_type;
1139 }
1140
1141 $field_options[ $args->type . '_limit' ] = $limit;
1142
1143 $field_options['ajax_data'] = $this->build_dfv_autocomplete_ajax_data( $field_options, $args, $ajax );
1144 $field_options['select2_overrides'] = null;
1145
1146 if ( 'select2' === $field_options['view_name'] ) {
1147 // @todo Revisit this, they probably aren't used anymore now since this is DFV.
1148 wp_enqueue_style( 'pods-select2' );
1149 wp_enqueue_script( 'pods-select2' );
1150
1151 /**
1152 * Allow overriding some Select2/SelectWoo options used in the JS init.
1153 *
1154 * @since 2.7.0
1155 *
1156 * @param array|null $select2_overrides Override options for Select2/SelectWoo.
1157 */
1158 $field_options['select2_overrides'] = apply_filters( 'pods_pick_select2_overrides', $field_options['select2_overrides'] );
1159 }
1160
1161 if ( ! empty( $args->build_item_data ) ) {
1162 $field_options['item_data'] = $this->build_dfv_field_item_data( $args );
1163 }
1164
1165 return $field_options;
1166 }
1167
1168 /**
1169 * Build DFV autocomplete AJAX data.
1170 *
1171 * @param array|Field $options DFV options.
1172 * @param object $args {
1173 * Field information arguments.
1174 *
1175 * @type string $name Field name.
1176 * @type string $type Field type.
1177 * @type array $options Field options.
1178 * @type mixed $value Current value.
1179 * @type array $pod Pod information.
1180 * @type int|string $id Current item ID.
1181 * }
1182 * @param bool $ajax True if ajax mode should be used.
1183 *
1184 * @return array
1185 */
1186 public function build_dfv_autocomplete_ajax_data( $options, $args, $ajax = false ) {
1187
1188 if ( is_array( $args->pod ) ) {
1189 $pod_name = $args->pod['name'];
1190 } elseif ( $args->pod instanceof Pods ) {
1191 $pod_name = $args->pod->pod;
1192 } elseif ( $args->pod instanceof Pod ) {
1193 $pod_name = $args->pod->get_name();
1194 } else {
1195 $pod_name = '';
1196 }
1197
1198 if ( is_array( $options ) ) {
1199 $field_name = pods_v( 'name', $options );
1200 } elseif ( $options instanceof Field ) {
1201 $field_name = $options->get_name();
1202 } else {
1203 $field_name = '';
1204 }
1205
1206 $id = (int) $args->id;
1207
1208 if ( is_user_logged_in() ) {
1209 $uid = 'user_' . get_current_user_id();
1210 } else {
1211 $uid = pods_session_id();
1212 }
1213
1214 $uri_hash = wp_create_nonce( 'pods_uri_' . $_SERVER['REQUEST_URI'] );
1215
1216 $nonce_name = 'pods_relationship:' . json_encode( compact( 'pod_name', 'field_name', 'uid', 'uri_hash', 'id' ) );
1217 $field_nonce = wp_create_nonce( $nonce_name );
1218
1219 // Values can be overridden via the `pods_field_dfv_data` filter in $data['fieldConfig']['ajax_data'].
1220 return [
1221 'ajax' => $ajax,
1222 'delay' => 300,
1223 'minimum_input_length' => 1,
1224 'pod_name' => $pod_name,
1225 'field_name' => $field_name,
1226 'id' => $id,
1227 'uri_hash' => $uri_hash,
1228 '_wpnonce' => $field_nonce,
1229 ];
1230 }
1231
1232 /**
1233 * {@inheritdoc}
1234 */
1235 public function build_dfv_field_config( $args ) {
1236 $config = parent::build_dfv_field_config( $args );
1237
1238 // Ensure data is passed in for relationship fields.
1239 if ( ! isset( $config['data'] ) && ! empty( $args->options['data'] ) ) {
1240 $config['data'] = $this->get_raw_data( $args->options );
1241 }
1242
1243 // Default optgroup handling to off.
1244 if ( ! isset( $config['optgroup'] ) ) {
1245 $config['optgroup'] = false;
1246 }
1247
1248 /**
1249 * Filter on whether to allow modals to be used on the front of the site (in an non-admin area).
1250 *
1251 * @param boolean $show_on_front
1252 * @param array $config
1253 * @param array $args
1254 *
1255 * @since 2.7.0
1256 */
1257 $show_on_front = apply_filters( 'pods_ui_dfv_pick_modals_show_on_front', false, $config, $args );
1258
1259 /**
1260 * Filter on whether to allow nested modals to be used (modals within modals).
1261 *
1262 * @param boolean $allow_nested_modals
1263 * @param array $config
1264 * @param array $args
1265 *
1266 * @since 2.7.0
1267 */
1268 $allow_nested_modals = apply_filters( 'pods_ui_dfv_pick_modals_allow_nested', false, $config, $args );
1269
1270 // Disallow add/edit outside the admin and when we're already in a modal
1271 if ( ( ! $show_on_front && ! is_admin() ) || ( ! $allow_nested_modals && pods_is_modal_window() ) ) {
1272 $config[ $args->type . '_allow_add_new' ] = false;
1273 $config[ $args->type . '_show_edit_link' ] = false;
1274 }
1275
1276 $config[ $args->type . '_taggable' ] = filter_var( pods_v( $args->type . '_taggable', $config ), FILTER_VALIDATE_BOOLEAN );
1277 $config[ $args->type . '_allow_add_new' ] = filter_var( pods_v( $args->type . '_allow_add_new', $config ), FILTER_VALIDATE_BOOLEAN );
1278 $config[ $args->type . '_show_edit_link' ] = filter_var( pods_v( $args->type . '_show_edit_link', $config ), FILTER_VALIDATE_BOOLEAN );
1279
1280 $iframe = array(
1281 'src' => '',
1282 'url' => '',
1283 'query_args' => array(),
1284 );
1285
1286 // Set the file name and args based on the content type of the relationship
1287 switch ( $args->options['pick_object'] ) {
1288 case 'post_type':
1289 if ( ! empty( $args->options['pick_val'] ) ) {
1290 $post_type_obj = get_post_type_object( $args->options['pick_val'] );
1291
1292 if ( $post_type_obj && current_user_can( $post_type_obj->cap->create_posts ) ) {
1293 $iframe['url'] = admin_url( 'post-new.php' );
1294 $iframe['query_args'] = array(
1295 'post_type' => $args->options['pick_val'],
1296 );
1297 }
1298 }
1299
1300 // Determine the default icon to use for this post type,
1301 // default to the dashicon for posts
1302 $config[ 'default_icon' ] = 'dashicons-admin-post';
1303
1304 // Any custom specified menu icon gets priority
1305 $post_type = get_post_type_object( $args->options[ 'pick_val' ] );
1306 if ( ! empty( $post_type->menu_icon ) ) {
1307 $config[ 'default_icon' ] = $post_type->menu_icon;
1308
1309 // Page and attachment have their own dashicons
1310 } elseif ( isset( $post_type->name ) ) {
1311 switch ( $post_type->name ) {
1312 case 'page':
1313 // Default for pages.
1314 $config[ 'default_icon' ] = 'dashicons-admin-page';
1315 break;
1316 case 'attachment':
1317 // Default for attachments.
1318 $config[ 'default_icon' ] = 'dashicons-admin-media';
1319 break;
1320 }
1321 }
1322
1323 break;
1324
1325 case 'taxonomy':
1326 /*
1327 * @todo Fix add new modal issues
1328 if ( ! empty( $args->options['pick_val'] ) ) {
1329 $taxonomy_obj = get_taxonomy( $args->options['pick_val'] );
1330
1331 if ( $taxonomy_obj && current_user_can( $taxonomy_obj->cap->edit_terms ) ) {
1332 $iframe['url'] = admin_url( 'edit-tags.php' );
1333 $iframe['query_args'] = array(
1334 'taxonomy' => $args->options['pick_val'],
1335 );
1336 }
1337 }
1338 */
1339
1340 break;
1341
1342 case 'user':
1343 if ( current_user_can( 'create_users' ) ) {
1344 $iframe['url'] = admin_url( 'user-new.php' );
1345 }
1346
1347 break;
1348
1349 case 'pod':
1350 if ( ! empty( $args->options['pick_val'] ) ) {
1351 if ( pods_is_admin( array( 'pods', 'pods_content', 'pods_edit_' . $args->options['pick_val'] ) ) ) {
1352 $iframe['url'] = admin_url( 'admin.php' );
1353 $iframe['query_args'] = array(
1354 'page' => 'pods-manage-' . $args->options['pick_val'],
1355 'action' => 'add',
1356 );
1357
1358 }
1359 }
1360
1361 break;
1362 }//end switch
1363
1364 // Potential valid modal target if we've set the file name
1365 if ( ! empty( $iframe['url'] ) ) {
1366 // @todo: Replace string literal with defined constant
1367 $iframe['query_args']['pods_modal'] = 1;
1368
1369 // Add args we always need
1370 $iframe['src'] = add_query_arg( $iframe['query_args'], $iframe['url'] );
1371 }
1372
1373 $iframe['title_add'] = sprintf( __( '%s: Add New', 'pods' ), $args->options['label'] );
1374 $iframe['title_edit'] = sprintf( __( '%s: Edit', 'pods' ), $args->options['label'] );
1375
1376 /**
1377 * Allow filtering iframe configuration
1378 *
1379 * @param array $iframe
1380 * @param array $config
1381 * @param array $args
1382 *
1383 * @since 2.7.0
1384 */
1385 $iframe = apply_filters( 'pods_ui_dfv_pick_modals_iframe', $iframe, $config, $args );
1386
1387 if ( ! empty( $iframe['src'] ) ) {
1388 // We extend wp.media.view.Modal for modal add/edit, we must ensure we load the template for it
1389 wp_enqueue_media();
1390 }
1391
1392 $config['iframe_src'] = $iframe['src'];
1393 $config['iframe_title_add'] = $iframe['title_add'];
1394 $config['iframe_title_edit'] = $iframe['title_edit'];
1395
1396 return $config;
1397
1398 }
1399
1400 /**
1401 * {@inheritdoc}
1402 */
1403 public function build_dfv_field_item_data( $args ) {
1404 $args->options['supports_thumbnails'] = null;
1405
1406 $item_data = [];
1407 $data = [];
1408
1409 if ( ! empty( $args->options['data'] ) ) {
1410 $data = $this->get_raw_data( $args->options );
1411 } elseif ( ! empty( $args->data ) ) {
1412 $data = $args->data;
1413 } else {
1414 $data = $this->data( $args->name, $args->value, $args->options, $args->pod, $args->id );
1415 }
1416
1417 if ( [] !== $data ) {
1418 $item_data = $this->build_dfv_field_item_data_recurse( $data, $args );
1419 }
1420
1421 return $item_data;
1422
1423 }
1424
1425 /**
1426 * Loop through relationship data and expand item data with additional information for DFV.
1427 *
1428 * @param array $data Item data to expand.
1429 * @param object $args {
1430 * Field information arguments.
1431 *
1432 * @type string $name Field name.
1433 * @type string $type Field type.
1434 * @type array $options Field options.
1435 * @type mixed $value Current value.
1436 * @type array $pod Pod information.
1437 * @type int|string $id Current item ID.
1438 * }
1439 *
1440 * @return array
1441 */
1442 public function build_dfv_field_item_data_recurse( $data, $args ) {
1443
1444 $item_data = array();
1445
1446 foreach ( $data as $item_id => $item_title ) {
1447 if ( is_array( $item_title ) ) {
1448 $args->options['optgroup'] = true;
1449
1450 $item_data[] = array(
1451 'label' => $item_id,
1452 'collection' => $this->build_dfv_field_item_data_recurse( $item_title, $args ),
1453 );
1454 } else {
1455 // Key by item_id temporarily to be able to sort based on $args->value
1456 $item_data[ $item_id ] = $this->build_dfv_field_item_data_recurse_item( $item_id, $item_title, $args );
1457 }
1458 }
1459
1460 // Maintain any saved sort order from $args->value
1461 if ( is_array( $args->value ) && 1 < count( $args->value ) && $this->is_autocomplete( $args->options ) ) {
1462 $new_item_data = [];
1463
1464 foreach ( $args->value as $value_key => $value_item ) {
1465 if ( ! is_int( $value_key ) ) {
1466 if ( isset( $item_data[ $value_key ] ) ) {
1467 $value_item = $item_data[ $value_key ];
1468 }
1469
1470 $new_item_data[ $value_key ] = $value_item;
1471 }
1472 }
1473
1474 $item_data = array_merge( $new_item_data, $item_data );
1475 }
1476
1477 // Convert from associative to numeric array
1478 return array_values( $item_data );
1479
1480 }
1481
1482 /**
1483 * Loop through relationship data and expand item data with additional information for DFV.
1484 *
1485 * @param int|string $item_id Item ID.
1486 * @param string $item_title Item title.
1487 * @param object $args {
1488 * Field information arguments.
1489 *
1490 * @type string $name Field name.
1491 * @type string $type Field type.
1492 * @type array $options Field options.
1493 * @type mixed $value Current value.
1494 * @type array $pod Pod information.
1495 * @type int|string $id Current item ID.
1496 * }
1497 *
1498 * @return array
1499 */
1500 public function build_dfv_field_item_data_recurse_item( $item_id, $item_title, $args ) {
1501
1502 $icon = '';
1503 $img_icon = '';
1504 $edit_link = '';
1505 $link = '';
1506
1507 if ( ! isset( $args->options['supports_thumbnails'] ) ) {
1508 $args->options['supports_thumbnails'] = null;
1509 }
1510
1511 if ( ! isset( $args->options['pick_object'] ) ) {
1512 $args->options['pick_object'] = null;
1513 }
1514
1515 switch ( $args->options['pick_object'] ) {
1516 case 'post_type':
1517 if ( null === $args->options['supports_thumbnails'] && ! empty( $args->options['pick_val'] ) ) {
1518 $args->options['supports_thumbnails'] = post_type_supports( $args->options['pick_val'], 'thumbnail' );
1519 }
1520
1521 if ( true === $args->options['supports_thumbnails'] ) {
1522 $post_thumbnail_id = get_post_thumbnail_id( $item_id );
1523
1524 if ( $post_thumbnail_id ) {
1525 $thumb = wp_get_attachment_image_src( $post_thumbnail_id, 'thumbnail', false );
1526 }
1527
1528 if ( ! empty( $thumb[0] ) ) {
1529 $img_icon = $thumb[0];
1530 }
1531 }
1532
1533 if ( empty( $img_icon ) ) {
1534
1535 // Default icon for posts.
1536 $icon = 'dashicons-admin-post';
1537
1538 // Post type icons.
1539 $post_type = (array) get_post_type_object( get_post_type( $item_id ) );
1540
1541 if ( ! empty( $post_type['menu_icon'] ) ) {
1542 // Post specific icon.
1543 $icon = $post_type['menu_icon'];
1544 } elseif ( isset( $post_type['name'] ) && 'page' ) {
1545 switch ( $post_type['name'] ) {
1546 case 'page':
1547 // Default for pages.
1548 $icon = 'dashicons-admin-page';
1549 break;
1550 case 'attachment':
1551 // Default for attachments.
1552 $icon = 'dashicons-admin-media';
1553 break;
1554 }
1555 }
1556 }//end if
1557
1558 $edit_link = get_edit_post_link( $item_id, 'raw' );
1559
1560 $link = get_permalink( $item_id );
1561
1562 break;
1563
1564 case 'taxonomy':
1565 if ( ! empty( $args->options['pick_val'] ) ) {
1566
1567 // Default icon for taxonomy.
1568 $icon = 'dashicons-category';
1569
1570 // Change icon for non-hierarchical taxonomies.
1571 $taxonomy = get_term( $item_id );
1572 if ( isset( $taxonomy->taxonomy ) ) {
1573 $taxonomy = (array) get_taxonomy( $taxonomy->taxonomy );
1574 if ( isset( $taxonomy['hierarchical'] ) && ! $taxonomy['hierarchical'] ) {
1575 $icon = 'dashicons-tag';
1576 }
1577 }
1578
1579 $edit_link = get_edit_term_link( $item_id, $args->options['pick_val'] );
1580
1581 $link = get_term_link( $item_id, $args->options['pick_val'] );
1582 }
1583
1584 break;
1585
1586 case 'user':
1587 $args->options['supports_thumbnails'] = true;
1588
1589 $icon = 'dashicons-admin-users';
1590 $img_icon = get_avatar_url( $item_id, array( 'size' => 150 ) );
1591
1592 $edit_link = get_edit_user_link( $item_id );
1593
1594 $link = get_author_posts_url( $item_id );
1595
1596 break;
1597
1598 case 'comment':
1599 $args->options['supports_thumbnails'] = true;
1600
1601 $icon = 'dashicons-admin-comments';
1602 $img_icon = get_avatar_url( get_comment( $item_id ), array( 'size' => 150 ) );
1603
1604 $edit_link = get_edit_comment_link( $item_id );
1605
1606 $link = get_comment_link( $item_id );
1607
1608 break;
1609
1610 case 'pod':
1611 if ( ! empty( $args->options['pick_val'] ) ) {
1612
1613 $icon = pods_svg_icon( 'pods' );
1614
1615 if ( pods_is_admin( array( 'pods', 'pods_content', 'pods_edit_' . $args->options['pick_val'] ) ) ) {
1616 $file_name = 'admin.php';
1617 $query_args = array(
1618 'page' => 'pods-manage-' . $args->options['pick_val'],
1619 'action' => 'edit',
1620 'id' => $item_id,
1621 );
1622
1623 $edit_link = add_query_arg( $query_args, admin_url( $file_name ) );
1624 }
1625
1626 // @todo Add $link support
1627 $link = '';
1628 }
1629
1630 break;
1631 }//end switch
1632
1633 // Image icons always overwrite default icons
1634 if ( ! empty( $img_icon ) ) {
1635 $icon = $img_icon;
1636 }
1637
1638 // Parse icon type
1639 if ( 'none' === $icon || 'div' === $icon ) {
1640 $icon = '';
1641 } elseif ( 0 === strpos( $icon, 'dashicons-' ) ) {
1642 $icon = sanitize_html_class( $icon );
1643 }
1644
1645 // #5740 Check for WP_Error object.
1646 if ( ! is_string( $link ) ) {
1647 $link = '';
1648 }
1649
1650 // Support modal editing
1651 if ( ! empty( $edit_link ) ) {
1652 // @todo: Replace string literal with defined constant
1653 $edit_link = add_query_arg( array( 'pods_modal' => '1' ), $edit_link );
1654 }
1655
1656 // Determine if this is a selected item.
1657 // Issue history for setting selected: #4753, #4892, #5014.
1658 $selected = false;
1659
1660 $values = array();
1661
1662 // If we have values, let's cast them.
1663 if ( isset( $args->value ) ) {
1664 // The value may be a single non-array value.
1665 $values = (array) $args->value;
1666 }
1667
1668 // Cast values in array as string.
1669 $values = array_map( static function( $value ) {
1670 if ( ! is_scalar( $value ) ) {
1671 return $value;
1672 }
1673
1674 return (string) $value;
1675 }, $values );
1676
1677 // If the value array has keys as IDs, let's check for matches from the keys first.
1678 if ( ! isset( $values[0] ) ) {
1679 // Get values from keys.
1680 $key_values = array_keys( $values );
1681
1682 // Cast key values in array as string.
1683 $key_values = array_map( static function( $value ) {
1684 if ( ! is_scalar( $value ) ) {
1685 return $value;
1686 }
1687
1688 return (string) $value;
1689 }, $key_values );
1690
1691 // Let's check to see if the current $item_id matches any key values.
1692 if ( in_array( (string) $item_id, $key_values, true ) ) {
1693 $selected = true;
1694 }
1695 }
1696
1697 // If we do not have a key match, the normal values may still match.
1698 if ( ! $selected ) {
1699 // Let's check to see if the current $item_id matches any values.
1700 if ( in_array( (string) $item_id, $values, true ) ) {
1701 $selected = true;
1702 }
1703 }
1704
1705 $item = array(
1706 'id' => html_entity_decode( esc_html( $item_id ) ),
1707 'icon' => esc_attr( $icon ),
1708 'name' => wp_strip_all_tags( html_entity_decode( $item_title ) ),
1709 'edit_link' => html_entity_decode( esc_url( $edit_link ) ),
1710 'link' => html_entity_decode( esc_url( $link ) ),
1711 'selected' => $selected,
1712 );
1713
1714 return $item;
1715
1716 }
1717
1718 /**
1719 * {@inheritdoc}
1720 */
1721 public function validate( $value, $name = null, $options = null, $fields = null, $pod = null, $id = null, $params = null ) {
1722 $validate = parent::validate( $value, $name, $options, $fields, $pod, $id, $params );
1723
1724 $errors = array();
1725
1726 if ( is_array( $validate ) ) {
1727 $errors = $validate;
1728 }
1729
1730 if ( empty( self::$api ) ) {
1731 self::$api = pods_api();
1732 }
1733
1734 $field = pods_config_for_field( $options, $pod );
1735
1736 $related_pick_limit = 0;
1737 $related_field = false;
1738 $related_pod = false;
1739 $current_related_ids = false;
1740
1741 // Bidirectional relationship requirement checks
1742 $related_object = pods_v( static::$type . '_object', $options, '' );
1743 // pod, post_type, taxonomy, etc..
1744 $related_val = pods_v( static::$type . '_val', $options, $related_object, null, true );
1745 // pod name, post type name, taxonomy name, etc..
1746 if ( empty( $related_val ) ) {
1747 $related_val = $related_object;
1748 }
1749
1750 $related_sister_id = pods_v( 'sister_id', $options, 0 );
1751
1752 if ( is_numeric( $related_sister_id ) ) {
1753 $related_sister_id = (int) $related_sister_id;
1754 } else {
1755 $related_sister_id = 0;
1756 }
1757
1758 $options['id'] = (int) $options['id'];
1759
1760 $related_data = pods_static_cache_get( $options['name'] . '/' . $options['id'], __CLASS__ . '/related_data' ) ?: [];
1761
1762 if (
1763 ! empty( $related_sister_id )
1764 && ! empty( $related_object )
1765 && $field
1766 && ! $field->is_simple_relationship()
1767 ) {
1768 $related_pod = self::$api->load_pod( [
1769 'name' => $related_val,
1770 'auto_setup' => true,
1771 ] );
1772
1773 if ( false !== $related_pod && ( 'pod' === $related_object || $related_object === $related_pod['type'] ) ) {
1774 $related_field = false;
1775
1776 // Ensure sister_id exists on related Pod.
1777 foreach ( $related_pod['fields'] as $related_pod_field ) {
1778 if ( 'pick' === $related_pod_field['type'] && $related_sister_id === $related_pod_field['id'] ) {
1779 $related_field = $related_pod_field;
1780
1781 break;
1782 }
1783 }
1784
1785 if ( ! empty( $related_field ) ) {
1786 $current_ids = self::$api->lookup_related_items( $options['id'], $pod['id'], $id, $options, $pod );
1787
1788 $related_data[ 'current_ids_' . $id ] = $current_ids;
1789
1790 $value_ids = $value;
1791
1792 // Convert values from a comma-separated string into an array.
1793 if ( ! is_array( $value_ids ) ) {
1794 $value_ids = explode( ',', $value_ids );
1795 }
1796
1797 $value_ids = array_unique( array_filter( $value_ids ) );
1798
1799 // Get ids to remove.
1800 $remove_ids = array_diff( $current_ids, $value_ids );
1801
1802 $related_data[ 'remove_ids_' . $id ] = $remove_ids;
1803
1804 $related_required = (boolean) pods_v( 'required', $related_field, 0 );
1805 $related_pick_limit = (int) pods_v( static::$type . '_limit', $related_field, 0 );
1806
1807 if ( 'single' === pods_v( static::$type . '_format_type', $related_field ) ) {
1808 $related_pick_limit = 1;
1809 }
1810
1811 // Validate Required fields.
1812 if ( $related_required && ! empty( $remove_ids ) ) {
1813 foreach ( $remove_ids as $related_id ) {
1814 $bidirectional_ids = self::$api->lookup_related_items( $related_field['id'], $related_pod['id'], $related_id, $related_field, $related_pod );
1815
1816 $related_data[ 'related_ids_' . $related_id ] = $bidirectional_ids;
1817
1818 if ( empty( $bidirectional_ids ) || ( in_array( (int) $id, $bidirectional_ids, true ) && 1 === count( $bidirectional_ids ) ) ) {
1819 // Translators: %1$s and %2$s stand for field labels.
1820 $errors[] = sprintf( esc_html__( 'The %1$s field is required and cannot be removed by the %2$s field', 'pods' ), $related_field['label'], $options['label'] );
1821 return $errors;
1822 }
1823 }
1824 }
1825 } else {
1826 $related_pod = false;
1827 }//end if
1828 } else {
1829 $related_pod = false;
1830 }//end if
1831 }//end if
1832
1833 if ( ! empty( $related_data ) ) {
1834 $related_data['related_pod'] = $related_pod;
1835 $related_data['related_field'] = $related_field;
1836 $related_data['related_pick_limit'] = $related_pick_limit;
1837
1838 pods_static_cache_set( $options['name'] . '/' . $options['id'], $related_data, __CLASS__ . '/related_data' );
1839
1840 $pick_limit = (int) pods_v( static::$type . '_limit', $options, 0 );
1841
1842 if ( 'single' === pods_v( static::$type . '_format_type', $options ) ) {
1843 $pick_limit = 1;
1844 }
1845
1846 $related_field['id'] = (int) $related_field['id'];
1847
1848 $bidirectional_related_data = pods_static_cache_get( $related_field['name'] . '/' . $related_field['id'], __CLASS__ . '/related_data' ) ?: [];
1849
1850 if ( empty( $bidirectional_related_data ) ) {
1851 $bidirectional_related_data = [
1852 'related_pod' => $pod,
1853 'related_field' => $options,
1854 'related_pick_limit' => $pick_limit,
1855 ];
1856
1857 pods_static_cache_set( $related_field['name'] . '/' . $related_field['id'], $bidirectional_related_data, __CLASS__ . '/related_data' );
1858 }
1859 }//end if
1860
1861 if ( ! empty( $errors ) ) {
1862 return $errors;
1863 }
1864
1865 return $validate;
1866
1867 }
1868
1869 /**
1870 * {@inheritdoc}
1871 */
1872 public function save( $value, $id = null, $name = null, $options = null, $fields = null, $pod = null, $params = null ) {
1873
1874 if ( empty( self::$api ) ) {
1875 self::$api = pods_api();
1876 }
1877
1878 $options['id'] = (int) $options['id'];
1879
1880 $related_pod = null;
1881 $related_field = null;
1882 $related_pick_limit = 0;
1883 $current_ids = [];
1884 $remove_ids = [];
1885
1886 if ( null === $value ) {
1887 $value = [];
1888 } elseif ( ! is_array( $value ) ) {
1889 $value = [
1890 $value,
1891 ];
1892 }
1893
1894 $current_ids = isset( $params->current_ids ) ? $params->current_ids : null;
1895 $value_ids = isset( $params->value_ids ) ? $params->value_ids : null;
1896 $remove_ids = isset( $params->remove_ids ) ? $params->remove_ids : null;
1897
1898 if ( null === $value_ids ) {
1899 $value_ids = array_unique( array_filter( $value ) );
1900 }
1901
1902 $related_data = pods_static_cache_get( $options['name'] . '/' . $options['id'], __CLASS__ . '/related_data' ) ?: [];
1903
1904 if ( ! empty( $related_data ) && isset( $related_data['current_ids_' . $id ], $related_data['remove_ids_' . $id ] ) ) {
1905 $related_pod = $related_data['related_pod'];
1906 $related_field = $related_data['related_field'];
1907 $related_pick_limit = $related_data['related_pick_limit'];
1908
1909 if ( null === $current_ids ) {
1910 $current_ids = $related_data[ 'current_ids_' . $id ];
1911 }
1912
1913 if ( null === $remove_ids ) {
1914 $remove_ids = $related_data[ 'remove_ids_' . $id ];
1915 }
1916 } elseif ( $options instanceof Field || $options instanceof Value_Field ) {
1917 $related_field = $options->get_bidirectional_field();
1918
1919 if ( ! $related_field ) {
1920 return;
1921 }
1922
1923 $related_pod = $related_field->get_parent_object();
1924 $related_pick_limit = $related_field->get_limit();
1925
1926 if ( null === $current_ids ) {
1927 $current_ids = self::$api->lookup_related_items( $options['id'], $pod['id'], $id, $options, $pod );
1928 }
1929
1930 // Get ids to remove.
1931 if ( null === $remove_ids ) {
1932 $remove_ids = array_diff( $current_ids, $value_ids );
1933 }
1934 }
1935
1936 if ( empty( $related_field ) || empty( $related_pod ) ) {
1937 return;
1938 }
1939
1940 // Handle the bi-directional relationship updates.
1941
1942 $no_conflict = true;
1943
1944 // Only check no conflict mode if this isn't the current pod type.
1945 if ( $related_pod['type'] !== $pod['type'] ) {
1946 $no_conflict = pods_no_conflict_check( $related_pod['type'] );
1947 }
1948
1949 if ( ! $no_conflict ) {
1950 pods_no_conflict_on( $related_pod['type'] );
1951 }
1952
1953 if ( empty( $value_ids ) ) {
1954 // Remove all bidirectional relationships.
1955 if ( ! empty( $remove_ids ) ) {
1956 // Remove this ID from the related IDS.
1957 self::$api->delete_relationships( $remove_ids, $id, $related_pod, $related_field );
1958
1959 // Remove the related IDs from this ID.
1960 self::$api->delete_relationships( $id, $remove_ids, $pod, $options );
1961 }
1962
1963 if ( ! $no_conflict ) {
1964 pods_no_conflict_off( $related_pod['type'] );
1965 }
1966
1967 return;
1968 }
1969
1970 foreach ( $value_ids as $related_id ) {
1971 if ( ! empty( $related_data[ 'related_ids_' . $related_id ] ) ) {
1972 $bidirectional_ids = $related_data[ 'related_ids_' . $related_id ];
1973 } else {
1974 $bidirectional_ids = self::$api->lookup_related_items( $related_field['id'], $related_pod['id'], $related_id, $related_field, $related_pod );
1975 }
1976
1977 $bidirectional_ids = array_filter( $bidirectional_ids );
1978
1979 if ( empty( $bidirectional_ids ) ) {
1980 $bidirectional_ids = array();
1981 }
1982
1983 $bidirectional_remove_ids = array();
1984
1985 if ( 0 < $related_pick_limit && ! empty( $bidirectional_ids ) && ! in_array( $id, $bidirectional_ids, true ) ) {
1986 $total_bidirectional_ids = count( $bidirectional_ids );
1987
1988 while ( $related_pick_limit <= $total_bidirectional_ids ) {
1989 $bidirectional_remove_ids[] = (int) array_pop( $bidirectional_ids );
1990
1991 $total_bidirectional_ids = count( $bidirectional_ids );
1992 }
1993 }
1994
1995 // Remove this item from related items no longer related to.
1996 $bidirectional_remove_ids = array_unique( array_filter( $bidirectional_remove_ids ) );
1997
1998 if ( ! in_array( $id, $bidirectional_ids, true ) ) {
1999 // Add to related items.
2000 $bidirectional_ids[] = $id;
2001 } elseif ( empty( $bidirectional_remove_ids ) ) {
2002 // Nothing to change.
2003 continue;
2004 }
2005
2006 self::$api->save_relationships( $related_id, $bidirectional_ids, $related_pod, $related_field );
2007
2008 if ( ! empty( $bidirectional_remove_ids ) ) {
2009 self::$api->delete_relationships( $bidirectional_remove_ids, $related_id, $pod, $options );
2010 }
2011 }//end foreach
2012
2013 // Remove this ID from the related IDs.
2014 if ( ! empty( $remove_ids ) ) {
2015 self::$api->delete_relationships( $remove_ids, $id, $related_pod, $related_field );
2016 }
2017
2018 if ( ! $no_conflict ) {
2019 pods_no_conflict_off( $related_pod['type'] );
2020 }
2021 }
2022
2023 /**
2024 * Delete the value from the DB
2025 *
2026 * @param int|null $id Item ID.
2027 * @param string|null $name Field name.
2028 * @param array|null $options Field options.
2029 * @param array|null $pod Pod options.
2030 *
2031 * @since 2.3.0
2032 */
2033 public function delete( $id = null, $name = null, $options = null, $pod = null ) {
2034
2035 if ( empty( self::$api ) ) {
2036 self::$api = pods_api();
2037 }
2038
2039 $field = pods_config_for_field( $options, $pod );
2040
2041 // Bidirectional relationship requirement checks.
2042 $related_object = pods_v( static::$type . '_object', $options, '' );
2043
2044 // pod, post_type, taxonomy, etc..
2045 $related_val = pods_v( static::$type . '_val', $options, $related_object, true );
2046
2047 // pod name, post type name, taxonomy name, etc..
2048 $related_sister_id = pods_v( 'sister_id', $options, 0 );
2049
2050 if ( is_numeric( $related_sister_id ) ) {
2051 $related_sister_id = (int) $related_sister_id;
2052 } else {
2053 $related_sister_id = 0;
2054 }
2055
2056 if (
2057 ! empty( $related_sister_id )
2058 && ! empty( $related_object )
2059 && $field
2060 && ! $field->is_simple_relationship()
2061 ) {
2062 $related_pod = self::$api->load_pod( [
2063 'name' => $related_val,
2064 'auto_setup' => true,
2065 ] );
2066
2067 if ( false !== $related_pod && ( 'pod' === $related_object || $related_object === $related_pod['type'] ) ) {
2068 $related_field = false;
2069
2070 // Ensure sister_id exists on related Pod.
2071 foreach ( $related_pod['fields'] as $related_pod_field ) {
2072 if ( 'pick' === $related_pod_field['type'] && (int) $related_sister_id === (int) $related_pod_field['id'] ) {
2073 $related_field = $related_pod_field;
2074
2075 break;
2076 }
2077 }
2078
2079 if ( ! empty( $related_field ) ) {
2080 $values = self::$api->lookup_related_items( $options['id'], $pod['id'], $id, $options, $pod );
2081
2082 if ( ! empty( $values ) ) {
2083 $no_conflict = pods_no_conflict_check( $related_pod['type'] );
2084
2085 if ( ! $no_conflict ) {
2086 pods_no_conflict_on( $related_pod['type'] );
2087 }
2088
2089 self::$api->delete_relationships( $values, $id, $related_pod, $related_field );
2090
2091 if ( ! $no_conflict ) {
2092 pods_no_conflict_off( $related_pod['type'] );
2093 }
2094 }
2095 }
2096 }//end if
2097 }//end if
2098
2099 }
2100
2101 /**
2102 * {@inheritdoc}
2103 */
2104 public function ui( $id, $value, $name = null, $options = null, $fields = null, $pod = null ) {
2105
2106 $value = $this->simple_value( $name, $value, $options, $pod, $id );
2107
2108 return $this->display( $value, $name, $options, $pod, $id );
2109
2110 }
2111
2112 /**
2113 * Get the raw data from the field data provided.
2114 *
2115 * @since 2.9.9
2116 *
2117 * @param array|Field $field The field data.
2118 *
2119 * @return array|mixed
2120 */
2121 public function get_raw_data( $field ) {
2122 $data = pods_v( 'data', $field, null, true );
2123
2124 if ( null !== $data ) {
2125 // Support late-initializing the data from a callback function passed in.
2126 if ( ! is_array( $data ) && ! is_string( $data ) && is_callable( $data ) ) {
2127 $data = $data();
2128 }
2129
2130 $data = (array) $data;
2131 }
2132
2133 return $data;
2134 }
2135
2136 /**
2137 * {@inheritdoc}
2138 */
2139 public function data( $name, $value = null, $options = null, $pod = null, $id = null, $in_form = true ) {
2140 $data = $this->get_raw_data( $options );
2141
2142 $object_params = array(
2143 // The name of the field.
2144 'name' => $name,
2145 // The value of the field.
2146 'value' => $value,
2147 // Field options.
2148 'options' => $options,
2149 // Pod data.
2150 'pod' => $pod,
2151 // Item ID.
2152 'id' => $id,
2153 // Data context.
2154 'context' => 'data',
2155 );
2156
2157 if ( null !== $data ) {
2158 $data = (array) $data;
2159 } else {
2160 $data = (array) $this->get_object_data( $object_params );
2161 }
2162
2163 /**
2164 * Allow filtering whether to always show default select text for the Single select Dropdown field even if
2165 * the field is required.
2166 *
2167 * @since 2.8.9
2168 *
2169 * @param bool $always_show_default_select_text Whether to always show default select text.
2170 * @param array $data The object data.
2171 * @param string|null $name Field name.
2172 * @param mixed|null $value Current value.
2173 * @param array|null $options Field options.
2174 * @param array|null $pod Pod information.
2175 * @param int|string|null $id Current item ID.
2176 */
2177 $always_show_default_select_text = (bool) apply_filters( 'pods_field_pick_always_show_default_select_text', false, $data, $name, $value, $options, $pod, $id );
2178
2179 if (
2180 'single' === pods_v( static::$type . '_format_type', $options, 'single' )
2181 && 'dropdown' === pods_v( static::$type . '_format_single', $options, 'dropdown' )
2182 //&& 0 !== (int) pods_v( static::$type . '_show_select_text', $options, 1 )
2183 && (
2184 $always_show_default_select_text
2185 || empty( $value )
2186 || 0 === (int) pods_v( 'required', $options, 0 )
2187 )
2188 ) {
2189 $default_select = [
2190 '' => pods_v( static::$type . '_select_text', $options, __( '-- Select One --', 'pods' ), true ),
2191 ];
2192
2193 // Unset to prevent conflict.
2194 if ( isset( $data[''] ) ) {
2195 unset( $data[''] );
2196 }
2197
2198 // Prevent resetting the numeric ID keys when adding the empty option via array_merge, use union instead.
2199 $data = $default_select + $data;
2200 }
2201
2202 $data = apply_filters( 'pods_field_pick_data', $data, $name, $value, $options, $pod, $id );
2203
2204 return $data;
2205
2206 }
2207
2208 /**
2209 * Convert a simple value to the correct value
2210 *
2211 * @param string $name The name of the field.
2212 * @param string|array|null $value The value of the field.
2213 * @param array|null $options Field options.
2214 * @param array|null $pod Pod data.
2215 * @param int|null $id Item ID.
2216 * @param boolean $raw Whether to return the raw list of keys (true) or convert to key=>value (false).
2217 *
2218 * @return mixed Corrected value
2219 */
2220 public function simple_value( $name, $value = null, $options = null, $pod = null, $id = null, $raw = false ) {
2221
2222 if ( in_array( pods_v( static::$type . '_object', $options ), $this->simple_objects(), true ) ) {
2223 if ( ! is_array( $value ) && 0 < strlen( (string) $value ) ) {
2224 $simple = @json_decode( $value, true );
2225
2226 if ( is_array( $simple ) ) {
2227 $value = (array) $simple;
2228 }
2229 }
2230
2231 $data = $this->get_raw_data( $options );
2232
2233 $object_params = array(
2234 // The name of the field.
2235 'name' => $name,
2236 // The value of the field.
2237 'value' => $value,
2238 // Field options.
2239 'options' => $options,
2240 // Pod data.
2241 'pod' => $pod,
2242 // Item ID.
2243 'id' => $id,
2244 // Data context.
2245 'context' => 'simple_value',
2246 );
2247
2248 if ( null !== $data ) {
2249 $data = (array) $data;
2250 } else {
2251 $data = (array) $this->get_object_data( $object_params );
2252 }
2253
2254 $key = 0;
2255
2256 if ( is_array( $value ) ) {
2257 if ( ! empty( $data ) ) {
2258 $val = array();
2259
2260 foreach ( $value as $k => $v ) {
2261 if ( is_scalar( $v ) && isset( $data[ $v ] ) ) {
2262 if ( false === $raw ) {
2263 $k = $v;
2264 $v = $data[ $v ];
2265 }
2266
2267 $val[ $k ] = $v;
2268 }
2269 }
2270
2271 $value = $val;
2272 }
2273 } elseif ( isset( $data[ $value ] ) && false === $raw ) {
2274 $key = $value;
2275 $value = $data[ $value ];
2276 }//end if
2277
2278 $single_multi = pods_v( static::$type . '_format_type', $options, 'single' );
2279
2280 if ( 'multi' === $single_multi ) {
2281 $limit = (int) pods_v( static::$type . '_limit', $options, 0 );
2282 } else {
2283 $limit = 1;
2284 }
2285
2286 if ( is_array( $value ) && 0 < $limit ) {
2287 if ( 1 === $limit ) {
2288 $value = current( $value );
2289 } else {
2290 $value = array_slice( $value, 0, $limit, true );
2291 }
2292 } elseif ( ! is_array( $value ) && null !== $value && 0 < strlen( (string) $value ) ) {
2293 if ( 1 !== $limit || ( true === $raw && 'multi' === $single_multi ) ) {
2294 $value = array(
2295 $key => $value,
2296 );
2297 }
2298 }
2299 }//end if
2300
2301 return $value;
2302
2303 }
2304
2305 /**
2306 * Get the label from a pick value.
2307 *
2308 * @param string $name The name of the field.
2309 * @param string|array|null $value The value of the field.
2310 * @param array|null $options Field options.
2311 * @param array|null $pod Pod data.
2312 * @param int|null $id Item ID.
2313 *
2314 * @return string
2315 *
2316 * @since 2.2.0
2317 */
2318 public function value_to_label( $name, $value = null, $options = null, $pod = null, $id = null ) {
2319 $data = $this->get_raw_data( $options );
2320
2321 $object_params = array(
2322 // The name of the field.
2323 'name' => $name,
2324 // The value of the field.
2325 'value' => $value,
2326 // Field options.
2327 'options' => $options,
2328 // Pod data.
2329 'pod' => $pod,
2330 // Item ID.
2331 'id' => $id,
2332 // Data context.
2333 'context' => 'value_to_label',
2334 );
2335
2336 if ( null !== $data ) {
2337 $data = (array) $data;
2338 } else {
2339 $data = (array) $this->get_object_data( $object_params );
2340 }
2341
2342 $labels = array();
2343
2344 foreach ( $data as $v => $l ) {
2345 if ( ! in_array( (string) $l, $labels, true ) && ( (string) $value === (string) $v || ( is_array( $value ) && in_array( (string) $v, $value, true ) ) ) ) {
2346 $labels[] = (string) $l;
2347 }
2348 }
2349
2350 $labels = apply_filters( 'pods_field_pick_value_to_label', $labels, $name, $value, $options, $pod, $id );
2351
2352 $labels = pods_serial_comma( $labels );
2353
2354 return $labels;
2355
2356 }
2357
2358 /**
2359 * Get available items from a relationship field.
2360 *
2361 * @param array|string $field Field array or field name.
2362 * @param array $deprecated Field options array overrides.
2363 * @param array $object_params Additional get_object_data options.
2364 *
2365 * @return array An array of available items from a relationship field
2366 */
2367 public function get_field_data( $field, $deprecated = null, $object_params = array() ) {
2368 $options = array();
2369
2370 $is_field_object = $field instanceof Field;
2371
2372 if ( is_array( $field ) || $is_field_object ) {
2373 $options = $field;
2374 }
2375
2376 // Get field name from array.
2377 $field = pods_v( 'name', $options, $field, true );
2378
2379 // Field name or options not set.
2380 if ( empty( $field ) || empty( $options ) ) {
2381 return array();
2382 }
2383
2384 // Setup object params.
2385 $object_params = array_merge(
2386 array(
2387 // The name of the field.
2388 'name' => $field,
2389 // Field options.
2390 'options' => $options,
2391 ), $object_params
2392 );
2393
2394 // Get data override.
2395 $data = $this->get_raw_data( $options );
2396
2397 if ( null !== $data ) {
2398 // Return data override.
2399 $data = (array) $data;
2400 } else {
2401 // Get object data.
2402 $data = $this->get_object_data( $object_params );
2403 }
2404
2405 return $data;
2406
2407 }
2408
2409 /**
2410 * Get data from relationship objects.
2411 *
2412 * @param array $object_params Object data parameters.
2413 *
2414 * @return array|bool Object data
2415 */
2416 public function get_object_data( $object_params = null ) {
2417
2418 /**
2419 * @var $wpdb wpdb
2420 */
2421 global $wpdb;
2422
2423 $object_params = array_merge(
2424 array(
2425 // The name of the field.
2426 'name' => '',
2427 // The value of the field.
2428 'value' => '',
2429 // Field options.
2430 'options' => array(),
2431 // Pod data.
2432 'pod' => '',
2433 // Item ID.
2434 'id' => '',
2435 // Data context.
2436 'context' => '',
2437 // Data parameters.
2438 'data_params' => array(
2439 // Query being searched.
2440 'query' => '',
2441 ),
2442 // Page number of results to get.
2443 'page' => 1,
2444 // How many data items to limit to (autocomplete defaults to 30, set to -1 or 1+ to override).
2445 'limit' => 0,
2446 ), $object_params
2447 );
2448
2449 /**
2450 * Overwrite parameters used by PodsField_Pick::get_object_data.
2451 *
2452 * @since 2.7.21
2453 *
2454 * @param array $object_params {
2455 * Get object parameters
2456 *
2457 * @type string $name Field name.
2458 * @type mixed $value Current value.
2459 * @type array $options Field options.
2460 * @type array $pod Pod data.
2461 * @type int|string $id Current item ID.
2462 * @type string $context Data context.
2463 * @type array $data_params Data parameters.
2464 * @type int $page Page number of results to get.
2465 * @type int $limit How many data items to limit to (autocomplete defaults to 30, set to -1 or 1+ to override).
2466 * }
2467 */
2468 $object_params = apply_filters( 'pods_field_pick_object_data_params', $object_params );
2469
2470 $object_params['data_params'] = (array) $object_params['data_params'];
2471
2472 $name = $object_params['name'];
2473 $value = $object_params['value'];
2474 $options = $object_params['options'];
2475 $pod = $object_params['pod'];
2476 $id = $object_params['id'];
2477 $context = $object_params['context'];
2478 $data_params = $object_params['data_params'];
2479 $page = min( 1, (int) $object_params['page'] );
2480 $limit = (int) $object_params['limit'];
2481 $autocomplete = false;
2482
2483 // Use field object if it was provided.
2484 if ( isset( $options['_field_object'] ) ) {
2485 $options = $options['_field_object'];
2486
2487 $name = $options->get_name();
2488 }
2489
2490 $data = apply_filters( 'pods_field_pick_object_data', null, $name, $value, $options, $pod, $id, $object_params );
2491 $items = array();
2492
2493 if ( ! isset( $options[ static::$type . '_object' ] ) ) {
2494 $data = $this->get_raw_data( $options );
2495 }
2496
2497 $simple = false;
2498
2499 if ( null === $data ) {
2500 $data = array();
2501
2502 $pick_object = pods_v( static::$type . '_object', $options, null, true );
2503
2504 // No pick object means this has no configuration to work from.
2505 if ( empty( $pick_object ) ) {
2506 return $data;
2507 }
2508
2509 if ( 'custom-simple' === $pick_object ) {
2510 $custom = pods_v( static::$type . '_custom', $options, '' );
2511
2512 $custom = apply_filters( 'pods_form_ui_field_pick_custom_values', $custom, $name, $value, $options, $pod, $id, $object_params );
2513
2514 if ( ! empty( $custom ) ) {
2515 if ( ! is_array( $custom ) ) {
2516 $data = array();
2517
2518 $custom = explode( "\n", trim( $custom ) );
2519
2520 foreach ( $custom as $custom_value ) {
2521 $custom_value = trim( trim( $custom_value, '|' ) );
2522 $custom_label = explode( '|', $custom_value );
2523
2524 if ( empty( $custom_label ) ) {
2525 continue;
2526 }
2527
2528 if ( 1 === count( $custom_label ) ) {
2529 $custom_label = $custom_value;
2530 } else {
2531 $custom_value = $custom_label[0];
2532 $custom_label = $custom_label[1];
2533 }
2534
2535 $custom_value = trim( (string) $custom_value );
2536 $custom_label = trim( (string) $custom_label );
2537
2538 $data[ $custom_value ] = $custom_label;
2539 }
2540 } else {
2541 $data = $custom;
2542 }//end if
2543
2544 $simple = true;
2545 }//end if
2546 } elseif (
2547 $pick_object
2548 && $this->setup_related_objects()
2549 && isset( self::$related_objects[ $pick_object ] )
2550 && ! empty( self::$related_objects[$pick_object ]['data'] )
2551 ) {
2552 $data = self::$related_objects[ $options[ static::$type . '_object' ] ]['data'];
2553
2554 $simple = true;
2555 } elseif (
2556 $pick_object
2557 && $this->setup_related_objects()
2558 && isset( self::$related_objects[ $pick_object ] )
2559 && isset( self::$related_objects[ $pick_object ]['data_callback'] )
2560 && is_callable( self::$related_objects[ $pick_object ]['data_callback'] )
2561 ) {
2562 $data = call_user_func_array(
2563 self::$related_objects[ $options[ static::$type . '_object' ] ]['data_callback'], [
2564 $name,
2565 $value,
2566 $options,
2567 $pod,
2568 $id,
2569 ]
2570 );
2571
2572 if ( 'data' === $context ) {
2573 pods_static_cache_set( $name . '/' . $options['id'], [
2574 'autocomplete' => false,
2575 ], __CLASS__ . '/field_data' );
2576 }
2577
2578 $simple = true;
2579
2580 // Cache data from callback.
2581 if ( ! empty( $data ) ) {
2582 self::$related_objects[ $options[ static::$type . '_object' ] ]['data'] = $data;
2583 }
2584 } elseif ( 'simple_value' !== $context ) {
2585 $pick_val = pods_v( static::$type . '_val', $options );
2586
2587 if ( 'table' === $pick_object ) {
2588 $pick_val = pods_v( static::$type . '_table', $options, $pick_val, true );
2589 }
2590
2591 $current_pod = null;
2592
2593 if ( $pod instanceof Pod ) {
2594 $current_pod = $pod;
2595 } elseif ( $pod instanceof Pods ) {
2596 $current_pod = $pod->pod_data;
2597 } elseif ( is_array( $pod ) ) {
2598 $current_pod = $pod;
2599 }
2600
2601 $related_pod = null;
2602
2603 if ( '__current__' === $pick_val ) {
2604 if ( $pod instanceof Pod ) {
2605 $pick_val = $pod->get_name();
2606
2607 $related_pod = $pod;
2608 } elseif ( $pod instanceof Pods ) {
2609 $pick_val = $pod->pod_data->get_name();
2610
2611 $related_pod = $pod->pod_data;
2612 } elseif ( is_array( $pod ) ) {
2613 $pick_val = $pod['name'];
2614 } elseif ( is_string( $pod ) && 0 < strlen( $pod ) ) {
2615 $pick_val = $pod;
2616 }
2617 }
2618
2619 $table_info = pods_v( 'table_info', $options );
2620
2621 if ( empty( $table_info ) && ! empty( $pick_object ) ) {
2622 $table_info = pods_api()->get_table_info( $pick_object, $pick_val, null, null, $options );
2623 }
2624
2625 // If the ACT was not found, return nothing.
2626 if ( 'pod' === $pick_object && $table_info && ! $table_info['pod'] ) {
2627 return [];
2628 }
2629
2630 if ( null === $related_pod && $table_info && $table_info['pod'] ) {
2631 $related_pod = $table_info['pod'];
2632 }
2633
2634 $search_data = pods_data( $related_pod );
2635 $search_data->table( $table_info );
2636
2637 $default_field_index = $search_data->field_index;
2638
2639 $params = array(
2640 'select' => "`t`.`{$search_data->field_id}`, `t`.`{$search_data->field_index}`",
2641 'table' => $search_data->table,
2642 'where' => pods_v( static::$type . '_where', $options, (array) $table_info['where_default'], true ),
2643 'orderby' => pods_v( static::$type . '_orderby', $options, null, true ),
2644 'having' => pods_v( static::$type . '_having', $options, null, true ),
2645 'groupby' => pods_v( static::$type . '_groupby', $options, null, true ),
2646 'pagination' => false,
2647 'search' => false,
2648 );
2649
2650 if ( in_array( $options[ static::$type . '_object' ], array( 'site', 'network' ), true ) ) {
2651 $params['select'] .= ', `t`.`path`';
2652 }
2653
2654 if ( ! empty( $params['where'] ) && (array) $table_info['where_default'] !== $params['where'] ) {
2655 $params['where'] = pods_evaluate_tags( $params['where'], true );
2656 }
2657
2658 if ( ! empty( $params['having'] ) ) {
2659 $params['having'] = pods_evaluate_tags( $params['having'], true );
2660 }
2661
2662 if ( empty( $params['where'] ) || ( ! is_array( $params['where'] ) && '' === trim( $params['where'] ) ) ) {
2663 $params['where'] = array();
2664 }
2665
2666 $params['where'] = (array) $params['where'];
2667
2668 if ( 'value_to_label' === $context ) {
2669 $params['where'][] = "`t`.`{$search_data->field_id}` = " . number_format( $value, 0, '', '' );
2670 }
2671
2672 // Check if we need to limit by the current post author.
2673 if (
2674 1 === (int) pods_v( static::$type . '_post_author', $options, 0 )
2675 && $current_pod
2676 && 'post_type' === $current_pod['type']
2677 && 'post_type' === $options[ static::$type . '_object' ]
2678 ) {
2679 $post_author_id = 0;
2680
2681 if ( empty( $id ) ) {
2682 if ( is_user_logged_in() ) {
2683 $post_author_id = get_current_user_id();
2684 }
2685 } else {
2686 $post = get_post( $id );
2687
2688 if ( $post ) {
2689 $post_author_id = $post->post_author;
2690 }
2691 }
2692
2693 $params['where'][] = '`t`.`post_author` = ' . (int) $post_author_id;
2694 }
2695
2696 $display = trim( (string) pods_v( static::$type . '_display', $options ), ' {@}' );
2697
2698 $display_field = "`t`.`{$search_data->field_index}`";
2699 $display_field_name = $search_data->field_index;
2700 $display_field_alias = false;
2701
2702 if ( is_string( $display ) && 0 < strlen( $display ) ) {
2703 if ( ! empty( $table_info['pod'] ) ) {
2704 /** @var Pod $related_pod */
2705 $related_pod = $table_info['pod'];
2706
2707 $related_storage = $related_pod->get_storage();
2708 $related_type = $related_pod->get_type();
2709 $found_display_field = $related_pod->get_field( $display );
2710
2711 if ( $found_display_field ) {
2712 $display_field_name = $found_display_field->get_name();
2713 }
2714
2715 if ( $found_display_field instanceof Object_Field ) {
2716 $display_field = "`t`.`{$display_field_name}`";
2717 } elseif (
2718 'table' === $related_storage
2719 && ! in_array(
2720 $related_type, array(
2721 'pod',
2722 'table',
2723 ), true
2724 )
2725 ) {
2726 $display_field = "`d`.`{$display_field_name}`";
2727 } elseif ( 'meta' === $related_storage ) {
2728 $display_field = "`{$display_field_name}`.`meta_value`";
2729
2730 $display_field_alias = true;
2731 } else {
2732 $display_field = "`t`.`{$display_field_name}`";
2733 }
2734 } elseif ( isset( $table_info['object_fields'] ) && isset( $table_info['object_fields'][ $display ]['name'] ) ) {
2735 $display_field_name = $table_info['object_fields'][ $display ]['name'];
2736
2737 $display_field = "`t`.`{$display_field_name}`";
2738 }//end if
2739 }//end if
2740
2741 if ( false === strpos( $params['select'], $display_field ) ) {
2742 $params['select'] .= ', ' . $display_field . ( $display_field_alias ? " AS `{$display_field_name}`" : '' );
2743 }
2744
2745 $autocomplete = $this->is_autocomplete( $options );
2746
2747 $hierarchy = false;
2748
2749 if ( 'data' === $context && ! $autocomplete ) {
2750 if ( 'single' === pods_v( static::$type . '_format_type', $options, 'single' ) && in_array(
2751 pods_v( static::$type . '_format_single', $options, 'dropdown' ), array(
2752 'dropdown',
2753 'radio',
2754 ), true
2755 )
2756 ) {
2757 $hierarchy = true;
2758 } elseif ( 'multi' === pods_v( static::$type . '_format_type', $options, 'single' ) && in_array(
2759 pods_v( static::$type . '_format_multi', $options, 'checkbox' ), array(
2760 'multiselect',
2761 'checkbox',
2762 ), true
2763 )
2764 ) {
2765 $hierarchy = true;
2766 }
2767 }
2768
2769 if ( $hierarchy && $table_info['object_hierarchical'] && ! empty( $table_info['field_parent'] ) ) {
2770 if ( false === strpos( $params['select'], $table_info['field_parent_select'] ) ) {
2771 $params['select'] .= ', ' . $table_info['field_parent_select'];
2772 }
2773 }
2774
2775 if ( $autocomplete ) {
2776 if ( 0 === $limit ) {
2777 $limit = 30;
2778 }
2779
2780 $params['limit'] = apply_filters( 'pods_form_ui_field_pick_autocomplete_limit', $limit, $name, $value, $options, $pod, $id, $object_params );
2781
2782 if ( -1 !== (int) $params['limit'] && is_array( $value ) && $params['limit'] < count( $value ) ) {
2783 $params['limit'] = count( $value );
2784 }
2785
2786 $params['page'] = $page;
2787
2788 if ( 'admin_ajax_relationship' === $context ) {
2789 $lookup_where = array(
2790 $search_data->field_index => "`t`.`{$search_data->field_index}` LIKE '%" . pods_sanitize_like( $data_params['query'] ) . "%'",
2791 );
2792
2793 if ( $display_field_name !== $search_data->field_index ) {
2794 $lookup_where[ $display_field_name ] = "{$display_field} LIKE '%" . pods_sanitize_like( $data_params['query'] ) . "%'";
2795 }
2796
2797 // @todo Hook into WPML for each table
2798 if ( $wpdb->users === $search_data->table ) {
2799 $lookup_where['display_name'] = "`t`.`display_name` LIKE '%" . pods_sanitize_like( $data_params['query'] ) . "%'";
2800 $lookup_where['user_login'] = "`t`.`user_login` LIKE '%" . pods_sanitize_like( $data_params['query'] ) . "%'";
2801 $lookup_where['user_email'] = "`t`.`user_email` LIKE '%" . pods_sanitize_like( $data_params['query'] ) . "%'";
2802 } elseif ( $wpdb->posts === $search_data->table ) {
2803 $lookup_where['post_title'] = "`t`.`post_title` LIKE '%" . pods_sanitize_like( $data_params['query'] ) . "%'";
2804 $lookup_where['post_name'] = "`t`.`post_name` LIKE '%" . pods_sanitize_like( $data_params['query'] ) . "%'";
2805 $lookup_where['post_content'] = "`t`.`post_content` LIKE '%" . pods_sanitize_like( $data_params['query'] ) . "%'";
2806 $lookup_where['post_excerpt'] = "`t`.`post_excerpt` LIKE '%" . pods_sanitize_like( $data_params['query'] ) . "%'";
2807 } elseif ( $wpdb->terms === $search_data->table ) {
2808 $lookup_where['name'] = "`t`.`name` LIKE '%" . pods_sanitize_like( $data_params['query'] ) . "%'";
2809 $lookup_where['slug'] = "`t`.`slug` LIKE '%" . pods_sanitize_like( $data_params['query'] ) . "%'";
2810 } elseif ( $wpdb->comments === $search_data->table ) {
2811 $lookup_where['comment_content'] = "`t`.`comment_content` LIKE '%" . pods_sanitize_like( $data_params['query'] ) . "%'";
2812 $lookup_where['comment_author'] = "`t`.`comment_author` LIKE '%" . pods_sanitize_like( $data_params['query'] ) . "%'";
2813 $lookup_where['comment_author_email'] = "`t`.`comment_author_email` LIKE '%" . pods_sanitize_like( $data_params['query'] ) . "%'";
2814 }
2815
2816 $lookup_where = apply_filters( 'pods_form_ui_field_pick_autocomplete_lookup', $lookup_where, $data_params['query'], $name, $value, $options, $pod, $id, $object_params, $search_data );
2817
2818 if ( ! empty( $lookup_where ) ) {
2819 $params['where'][] = implode( ' OR ', $lookup_where );
2820 }
2821
2822 $orderby = array();
2823 $orderby[] = "( {$display_field} LIKE '%" . pods_sanitize_like( $data_params['query'] ) . "%' ) DESC";
2824
2825 $pick_orderby = pods_v( static::$type . '_orderby', $options, null, true );
2826
2827 if ( is_string( $pick_orderby ) && 0 < strlen( $pick_orderby ) ) {
2828 $orderby[] = $pick_orderby;
2829 }
2830
2831 if ( ! in_array( $search_data->field_index, $orderby, true ) ) {
2832 $orderby[] = "`t`.`{$search_data->field_index}`";
2833 }
2834
2835 if ( ! in_array( $search_data->field_id, $orderby, true ) ) {
2836 $orderby[] = "`t`.`{$search_data->field_id}`";
2837 }
2838
2839 $params['orderby'] = $orderby;
2840 }//end if
2841 } elseif ( 0 < $limit ) {
2842 $params['limit'] = $limit;
2843 $params['page'] = $page;
2844 }//end if
2845
2846 $extra = '';
2847
2848 if ( $wpdb->posts === $search_data->table ) {
2849 $extra = '`t`.`post_type`, `t`.`menu_order`, `t`.`post_date`';
2850 } elseif ( $wpdb->terms === $search_data->table ) {
2851 $extra = '`tt`.`taxonomy`';
2852 } elseif ( $wpdb->comments === $search_data->table ) {
2853 $extra = '`t`.`comment_type`';
2854 } elseif ( $wpdb->site === $search_data->table ) {
2855 $extra = '`t`.`path`';
2856 } elseif ( $wpdb->blogs === $search_data->table ) {
2857 $extra = '`t`.`path`';
2858 }
2859
2860 if ( '' !== $extra && false === strpos( $params['select'], $extra ) ) {
2861 $params['select'] .= ', ' . $extra;
2862 }
2863
2864 if ( 'user' === pods_v( static::$type . '_object', $options ) ) {
2865 $roles = pods_v( static::$type . '_user_role', $options );
2866
2867 if ( ! empty( $roles ) ) {
2868 $where = array();
2869
2870 foreach ( (array) $roles as $role ) {
2871 if ( empty( $role ) || ( pods_clean_name( $role ) !== $role && sanitize_title( $role ) !== $role ) ) {
2872 continue;
2873 }
2874
2875 $where[] = $wpdb->prefix . 'capabilities.meta_value LIKE "%\"' . pods_sanitize_like( $role ) . '\"%"';
2876 }
2877
2878 if ( ! empty( $where ) ) {
2879 $params['where'][] = implode( ' OR ', $where );
2880 }
2881 }//end if
2882 }//end if
2883
2884 if ( empty( $params['where'] ) ) {
2885 $params['where'] = null;
2886 }
2887
2888 try {
2889 $results = $search_data->select( $params );
2890 } catch ( Exception $exception ) {
2891 if ( pods_is_debug_display() ) {
2892 pods_error_exception( $exception );
2893 }
2894
2895 $results = [];
2896 }
2897
2898 if ( $autocomplete && 0 < $params['limit'] && $params['limit'] < $search_data->total_found() ) {
2899 if ( ! empty( $value ) ) {
2900 $ids = $value;
2901
2902 if ( is_array( $ids ) ) {
2903 if ( isset( $ids[0] ) && is_array( $ids[0] ) ) {
2904 $ids = wp_list_pluck( $ids, $search_data->field_id );
2905 }
2906
2907 if ( $params['limit'] < count( $ids ) ) {
2908 $params['limit'] = count( $ids );
2909 }
2910
2911 $ids = array_map( 'absint', $ids );
2912 $ids = implode( ', ', $ids );
2913 } else {
2914 $ids = (int) $ids;
2915 }
2916
2917 if ( is_array( $params['where'] ) ) {
2918 $params['where'] = implode( ' AND ', $params['where'] );
2919 }
2920 if ( ! empty( $params['where'] ) ) {
2921 $params['where'] = '(' . $params['where'] . ') AND ';
2922 }
2923
2924 $params['where'] .= "`t`.`{$search_data->field_id}` IN ( {$ids} )";
2925
2926 try {
2927 $results = array_merge( $results, $search_data->select( $params ) );
2928 } catch ( Exception $exception ) {
2929 if ( pods_is_debug_display() ) {
2930 pods_error_exception( $exception );
2931 }
2932
2933 $results = [];
2934 }
2935 }//end if
2936 } else {
2937 $autocomplete = false;
2938 }//end if
2939
2940 if ( 'data' === $context ) {
2941 pods_static_cache_set( $name . '/' . $options['id'], [
2942 'autocomplete' => $autocomplete,
2943 ], __CLASS__ . '/field_data' );
2944 }
2945
2946 if ( $hierarchy && ! $autocomplete && ! empty( $results ) && $table_info['object_hierarchical'] && ! empty( $table_info['field_parent'] ) ) {
2947 $select_args = array(
2948 'id' => $table_info['field_id'],
2949 'index' => $display_field_name,
2950 'parent' => $table_info['field_parent'],
2951 );
2952
2953 $results = pods_hierarchical_select( $results, $select_args );
2954 }
2955
2956 $ids = array();
2957
2958 if ( ! empty( $results ) ) {
2959 foreach ( $results as $result ) {
2960 $result = get_object_vars( $result );
2961 $field_id = $search_data->field_id;
2962 $field_index = $display_field_name;
2963
2964 if ( ! isset( $result[ $field_index ] ) ) {
2965 $field_index = $default_field_index;
2966 }
2967
2968 if ( ! isset( $result[ $field_id ], $result[ $field_index ] ) ) {
2969 continue;
2970 }
2971
2972 $result[ $field_index ] = trim( $result[ $field_index ] );
2973
2974 $object = '';
2975 $object_type = '';
2976
2977 if ( $wpdb->posts === $search_data->table && isset( $result['post_type'] ) ) {
2978 $object = $result['post_type'];
2979 $object_type = 'post_type';
2980 } elseif ( $wpdb->terms === $search_data->table && isset( $result['taxonomy'] ) ) {
2981 $object = $result['taxonomy'];
2982 $object_type = 'taxonomy';
2983 }
2984
2985 $field_index_data_to_use = pods_v( $field_index, $search_data->object_fields );
2986
2987 $display_filter = pods_v( 'display_filter', $field_index_data_to_use );
2988
2989 if ( is_string( $display_filter ) && 0 < strlen( $display_filter ) ) {
2990 $display_filter_args = pods_v( 'display_filter_args', $field_index_data_to_use );
2991
2992 $filter_args = array(
2993 $display_filter,
2994 $result[ $field_index ],
2995 );
2996
2997 if ( ! empty( $display_filter_args ) ) {
2998 foreach ( (array) $display_filter_args as $display_filter_arg ) {
2999 // Manual solution to a problem that won't map correctly.
3000 if ( 'post_ID' === $display_filter_arg ) {
3001 $display_filter_arg = 'ID';
3002 }
3003
3004 if ( isset( $result[ $display_filter_arg ] ) ) {
3005 $filter_args[] = $result[ $display_filter_arg ];
3006 }
3007 }
3008 }
3009
3010 $result[ $field_index ] = call_user_func_array( 'apply_filters', $filter_args );
3011 }
3012
3013 if ( in_array( $options[ static::$type . '_object' ], array( 'site', 'network' ), true ) ) {
3014 $result[ $field_index ] = $result[ $field_index ] . $result['path'];
3015 } elseif ( '' === $result[ $field_index ] ) {
3016 $result[ $field_index ] = '(No Title)';
3017 }
3018
3019 if ( 'admin_ajax_relationship' === $context ) {
3020 $items[] = $this->build_dfv_field_item_data_recurse_item( $result[ $field_id ], $result[ $field_index ], (object) $object_params );
3021 } else {
3022 $data[ $result[ $field_id ] ] = $result[ $field_index ];
3023 }
3024
3025 $ids[] = $result[ $field_id ];
3026 }//end foreach
3027 }//end if
3028 }//end if
3029
3030 if ( $simple && 'admin_ajax_relationship' === $context ) {
3031 $found_data = array();
3032
3033 foreach ( $data as $k => $v ) {
3034 if ( false !== stripos( $v, $data_params['query'] ) || false !== stripos( $k, $data_params['query'] ) ) {
3035 $found_data[ $k ] = $v;
3036 }
3037 }
3038
3039 $data = $found_data;
3040 }
3041 }//end if
3042
3043 if ( 'admin_ajax_relationship' === $context ) {
3044 if ( empty( $items ) && ! empty( $data ) ) {
3045 foreach ( $data as $k => $v ) {
3046 $items[] = array(
3047 'id' => $k,
3048 'text' => $v,
3049 );
3050 }
3051 }
3052
3053 $data = $items;
3054 }
3055
3056 return $data;
3057
3058 }
3059
3060 /**
3061 * Check if field is autocomplete enabled.
3062 *
3063 * @param array $options Field options.
3064 *
3065 * @return bool
3066 *
3067 * @since 2.7.0
3068 */
3069 private function is_autocomplete( $options ) {
3070
3071 $autocomplete = false;
3072
3073 if ( 'single' === pods_v( static::$type . '_format_type', $options, 'single' ) ) {
3074 if ( in_array( pods_v( static::$type . '_format_single', $options, 'dropdown' ), array( 'autocomplete', 'list' ), true ) ) {
3075 $autocomplete = true;
3076 }
3077 } elseif ( 'multi' === pods_v( static::$type . '_format_type', $options, 'single' ) ) {
3078 if ( in_array( pods_v( static::$type . '_format_multi', $options, 'checkbox' ), array( 'autocomplete', 'list' ), true ) ) {
3079 $autocomplete = true;
3080 }
3081 }
3082
3083 return $autocomplete;
3084 }
3085
3086 /**
3087 * Check if a field type is a tableless text field type.
3088 *
3089 * @since 2.7.4
3090 *
3091 * @param string $type Field type.
3092 * @param array $options Field options.
3093 * @return bool True if the field type is a tableless text field type, false otherwise.
3094 */
3095 private function is_simple_tableless( $type, array $options ) {
3096 $field_object = pods_v( $type . '_object', $options );
3097
3098 return in_array( $field_object, PodsForm::simple_tableless_objects(), true );
3099 }
3100
3101 /**
3102 * Check if a field supports AJAX mode
3103 *
3104 * @param string $type Field type.
3105 * @param array $options Field options.
3106 *
3107 * @return bool
3108 * @since 2.7.4
3109 */
3110 private function can_ajax( $type, $options ) {
3111 return $this->is_autocomplete( $options ) && ! $this->is_simple_tableless( $type, $options );
3112 }
3113
3114
3115 /**
3116 * Handle autocomplete AJAX.
3117 *
3118 * @since 2.3.0
3119 */
3120 public function admin_ajax_relationship() {
3121
3122 pods_session_start();
3123
3124 // Sanitize input.
3125 // @codingStandardsIgnoreLine
3126 $params = pods_unslash( (array) $_POST );
3127
3128 foreach ( $params as $key => $value ) {
3129 if ( 'action' === $key ) {
3130 continue;
3131 }
3132
3133 unset( $params[ $key ] );
3134
3135 $params[ str_replace( '_podsfix_', '', $key ) ] = $value;
3136 }
3137
3138 $params = (object) $params;
3139
3140 if ( ! isset( $params->_wpnonce, $params->pod_name, $params->field_name, $params->uri_hash, $params->id ) ) {
3141 return pods_error( __( 'Unauthorized request', 'pods' ), PodsInit::$admin );
3142 }
3143
3144 if ( ! isset( $params->query ) || '' === trim( $params->query ) ) {
3145 return pods_error( __( 'Invalid field request', 'pods' ), PodsInit::$admin );
3146 }
3147
3148 $_wpnonce = $params->_wpnonce;
3149 $pod_name = $params->pod_name;
3150 $field_name = $params->field_name;
3151 $uri_hash = $params->uri_hash;
3152 $id = (int) $params->id;
3153
3154 $query = $params->query;
3155 $limit = pods_v( 'limit', $params, 15, true );
3156 $page = pods_v( 'page', $params, 1, true );
3157
3158 $uid = pods_session_id();
3159
3160 if ( is_user_logged_in() ) {
3161 $uid = 'user_' . get_current_user_id();
3162 }
3163
3164 $nonce_name = 'pods_relationship:' . json_encode( compact( 'pod_name', 'field_name', 'uid', 'uri_hash', 'id' ) );
3165
3166 if ( false === wp_verify_nonce( $_wpnonce, $nonce_name ) ) {
3167 return pods_error( __( 'Unauthorized request', 'pods' ), PodsInit::$admin );
3168 }
3169
3170 if ( empty( self::$api ) ) {
3171 self::$api = pods_api();
3172 }
3173
3174 $pod = self::$api->load_pod( [
3175 'name' => $pod_name,
3176 ] );
3177
3178 if ( ! $pod ) {
3179 return pods_error( __( 'Invalid Pod configuration', 'pods' ), PodsInit::$admin );
3180 }
3181
3182 $field = $pod->get_field( $field_name );
3183
3184 if ( ! $field ) {
3185 return pods_error( __( 'Invalid Field configuration', 'pods' ), PodsInit::$admin );
3186 }
3187
3188 if ( ! $field->is_autocomplete_relationship() ) {
3189 return pods_error( __( 'Invalid field', 'pods' ), PodsInit::$admin );
3190 }
3191
3192 $object_params = array(
3193 // The name of the field.
3194 'name' => $field['name'],
3195 // The value of the field.
3196 'value' => null,
3197 // Field options.
3198 'options' => $field,
3199 // Pod data.
3200 'pod' => $pod,
3201 // Item ID.
3202 'id' => $id,
3203 // Data context.
3204 'context' => 'admin_ajax_relationship',
3205 'data_params' => $params,
3206 'page' => $page,
3207 'limit' => $limit,
3208 );
3209
3210 $pick_data = apply_filters( 'pods_field_pick_data_ajax', null, $field['name'], null, $field, $pod, $id );
3211
3212 if ( null !== $pick_data ) {
3213 $items = $pick_data;
3214 } else {
3215 $items = $this->get_object_data( $object_params );
3216 }
3217
3218 if ( ! empty( $items ) && isset( $items[0] ) && ! is_array( $items[0] ) ) {
3219 $new_items = array();
3220
3221 foreach ( $items as $id => $text ) {
3222 $new_items[] = array(
3223 'id' => $id,
3224 'text' => $text,
3225 'image' => '',
3226 );
3227 }
3228
3229 $items = $new_items;
3230 }
3231
3232 $items = apply_filters( 'pods_field_pick_data_ajax_items', $items, $field['name'], null, $field, $pod, $id );
3233
3234 $items = array(
3235 'results' => $items,
3236 );
3237
3238 wp_send_json( $items );
3239
3240 die();
3241 // KBAI!
3242 }
3243
3244 /**
3245 * Data callback for Post Stati.
3246 *
3247 * @param string|null $name The name of the field.
3248 * @param string|array|null $value The value of the field.
3249 * @param array|null $options Field options.
3250 * @param array|null $pod Pod data.
3251 * @param int|null $id Item ID.
3252 *
3253 * @return array
3254 *
3255 * @since 2.3.0
3256 */
3257 public function data_post_stati( $name = null, $value = null, $options = null, $pod = null, $id = null ) {
3258 $data = [];
3259
3260 $post_stati = get_post_stati( [], 'objects' );
3261
3262 foreach ( $post_stati as $post_status ) {
3263 $data[ $post_status->name ] = $post_status->label;
3264 }
3265
3266 return (array) apply_filters( 'pods_form_ui_field_pick_data_post_stati', $data, $name, $value, $options, $pod, $id );
3267 }
3268
3269 /**
3270 * Data callback for Post Stati (with any).
3271 *
3272 * @param string|null $name The name of the field.
3273 * @param string|array|null $value The value of the field.
3274 * @param array|null $options Field options.
3275 * @param array|null $pod Pod data.
3276 * @param int|null $id Item ID.
3277 *
3278 * @return array
3279 *
3280 * @since 2.9.10
3281 */
3282 public function data_post_stati_with_any( $name = null, $value = null, $options = null, $pod = null, $id = null ) {
3283 $data = [
3284 '_pods_any' => esc_html__( 'Any Status (excluding Auto-Draft and Trashed)', 'pods' ),
3285 ];
3286
3287 $data = array_merge( $data, $this->data_post_stati( $name, $value, $options, $pod, $id ) );
3288
3289 /**
3290 * Allow filtering the list of post stati with any.
3291 *
3292 * @since 2.9.10
3293 *
3294 * @param array $data The list of post stati with any.
3295 * @param string|null $name The name of the field.
3296 * @param string|array|null $value The value of the field.
3297 * @param array|null $options Field options.
3298 * @param array|null $pod Pod data.
3299 * @param int|null $id Item ID.
3300 */
3301 return (array) apply_filters( 'pods_form_ui_field_pick_data_post_stati_with_any', $data, $name, $value, $options, $pod, $id );
3302 }
3303
3304 /**
3305 * Data callback for User Roles.
3306 *
3307 * @param string|null $name The name of the field.
3308 * @param string|array|null $value The value of the field.
3309 * @param array|null $options Field options.
3310 * @param array|null $pod Pod data.
3311 * @param int|null $id Item ID.
3312 *
3313 * @return array
3314 *
3315 * @since 2.3.0
3316 */
3317 public function data_roles( $name = null, $value = null, $options = null, $pod = null, $id = null ) {
3318
3319 $data = array();
3320
3321 global $wp_roles;
3322
3323 foreach ( $wp_roles->role_objects as $key => $role ) {
3324 $data[ $key ] = $wp_roles->role_names[ $key ];
3325 }
3326
3327 return apply_filters( 'pods_form_ui_field_pick_data_roles', $data, $name, $value, $options, $pod, $id );
3328
3329 }
3330
3331 /**
3332 * Data callback for User Capabilities.
3333 *
3334 * @param string|null $name The name of the field.
3335 * @param string|array|null $value The value of the field.
3336 * @param array|null $options Field options.
3337 * @param array|null $pod Pod data.
3338 * @param int|null $id Item ID.
3339 *
3340 * @return array
3341 *
3342 * @since 2.3.0
3343 */
3344 public function data_capabilities( $name = null, $value = null, $options = null, $pod = null, $id = null ) {
3345
3346 $data = array();
3347
3348 global $wp_roles;
3349
3350 $default_caps = array(
3351 'activate_plugins',
3352 'add_users',
3353 'create_users',
3354 'delete_others_pages',
3355 'delete_others_posts',
3356 'delete_pages',
3357 'delete_plugins',
3358 'delete_posts',
3359 'delete_private_pages',
3360 'delete_private_posts',
3361 'delete_published_pages',
3362 'delete_published_posts',
3363 'delete_users',
3364 'edit_dashboard',
3365 'edit_files',
3366 'edit_others_pages',
3367 'edit_others_posts',
3368 'edit_pages',
3369 'edit_plugins',
3370 'edit_posts',
3371 'edit_private_pages',
3372 'edit_private_posts',
3373 'edit_published_pages',
3374 'edit_published_posts',
3375 'edit_theme_options',
3376 'edit_themes',
3377 'edit_users',
3378 'import',
3379 'install_plugins',
3380 'install_themes',
3381 'list_users',
3382 'manage_categories',
3383 'manage_links',
3384 'manage_options',
3385 'moderate_comments',
3386 'promote_users',
3387 'publish_pages',
3388 'publish_posts',
3389 'read',
3390 'read_private_pages',
3391 'read_private_posts',
3392 'remove_users',
3393 'switch_themes',
3394 'unfiltered_html',
3395 'unfiltered_upload',
3396 'update_core',
3397 'update_plugins',
3398 'update_themes',
3399 'upload_files',
3400 );
3401
3402 $role_caps = array();
3403
3404 foreach ( $wp_roles->role_objects as $key => $role ) {
3405 if ( is_array( $role->capabilities ) ) {
3406 foreach ( $role->capabilities as $cap => $grant ) {
3407 $role_caps[ $cap ] = $cap;
3408 }
3409 }
3410 }
3411
3412 $role_caps = array_unique( $role_caps );
3413
3414 $capabilities = array_merge( $default_caps, $role_caps );
3415
3416 // To support Members filters.
3417 $capabilities = apply_filters( 'members_get_capabilities', $capabilities );
3418
3419 $capabilities = apply_filters( 'pods_roles_get_capabilities', $capabilities );
3420
3421 sort( $capabilities );
3422
3423 $capabilities = array_unique( $capabilities );
3424
3425 global $wp_roles;
3426
3427 foreach ( $capabilities as $capability ) {
3428 $data[ $capability ] = $capability;
3429 }
3430
3431 return apply_filters( 'pods_form_ui_field_pick_data_capabilities', $data, $name, $value, $options, $pod, $id );
3432
3433 }
3434
3435 /**
3436 * Data callback for Image Sizes.
3437 *
3438 * @param string|null $name The name of the field.
3439 * @param string|array|null $value The value of the field.
3440 * @param array|null $options Field options.
3441 * @param array|null $pod Pod data.
3442 * @param int|null $id Item ID.
3443 *
3444 * @return array
3445 *
3446 * @since 2.3.0
3447 */
3448 public function data_image_sizes( $name = null, $value = null, $options = null, $pod = null, $id = null ) {
3449
3450 $data = array();
3451
3452 $image_sizes = get_intermediate_image_sizes();
3453
3454 foreach ( $image_sizes as $image_size ) {
3455 $data[ $image_size ] = ucwords( str_replace( '-', ' ', $image_size ) );
3456 }
3457
3458 return apply_filters( 'pods_form_ui_field_pick_data_image_sizes', $data, $name, $value, $options, $pod, $id );
3459
3460 }
3461
3462 /**
3463 * Data callback for Post Types
3464 *
3465 * @param string $name The name of the field
3466 * @param string|array $value The value of the field
3467 * @param array $options Field options
3468 * @param array $pod Pod data
3469 * @param int $id Item ID
3470 *
3471 * @return array
3472 *
3473 * @since 2.3.0
3474 */
3475 public function data_post_types( $name = null, $value = null, $options = null, $pod = null, $id = null ) {
3476
3477 $data = array();
3478
3479 $post_types = get_post_types( array(), 'objects' );
3480
3481 $ignore = [
3482 'revision',
3483 'nav_menu_item',
3484 'custom_css',
3485 'customize_changeset',
3486 'attachment',
3487 'oembed_cache',
3488 'user_request',
3489 'wp_block',
3490 'wp_template',
3491 'wp_template_part',
3492 'wp_global_styles',
3493 'wp_navigation',
3494 ];
3495
3496 foreach ( $post_types as $post_type ) {
3497 if ( in_array( $post_type->name, $ignore, true ) || 0 === strpos( $post_type->name, '_pods_' ) ) {
3498 continue;
3499 }
3500
3501 $data[ $post_type->name ] = $post_type->label;
3502 }
3503
3504 return apply_filters( 'pods_form_ui_field_pick_data_post_types', $data, $name, $value, $options, $pod, $id );
3505 }
3506
3507 /**
3508 * Data callback for Taxonomies
3509 *
3510 * @param string $name The name of the field
3511 * @param string|array $value The value of the field
3512 * @param array $options Field options
3513 * @param array $pod Pod data
3514 * @param int $id Item ID
3515 *
3516 * @return array
3517 *
3518 * @since 2.3.0
3519 */
3520 public function data_taxonomies( $name = null, $value = null, $options = null, $pod = null, $id = null ) {
3521
3522 $data = array();
3523
3524 $taxonomies = get_taxonomies( array(), 'objects' );
3525
3526 $ignore = array( 'nav_menu', 'post_format' );
3527
3528 foreach ( $taxonomies as $taxonomy ) {
3529 if ( in_array( $taxonomy->name, $ignore, true ) ) {
3530 continue;
3531 }
3532
3533 $data[ $taxonomy->name ] = $taxonomy->label;
3534 }
3535
3536 return apply_filters( 'pods_form_ui_field_pick_data_taxonomies', $data, $name, $value, $options, $pod, $id );
3537 }
3538
3539 /**
3540 * Data callback for Countries.
3541 *
3542 * @param string|null $name The name of the field.
3543 * @param string|array|null $value The value of the field.
3544 * @param array|null $options Field options.
3545 * @param array|null $pod Pod data.
3546 * @param int|null $id Item ID.
3547 *
3548 * @return array
3549 *
3550 * @since 2.3.0
3551 */
3552 public function data_countries( $name = null, $value = null, $options = null, $pod = null, $id = null ) {
3553
3554 $data = array(
3555 'AF' => __( 'Afghanistan' ),
3556 'AL' => __( 'Albania' ),
3557 'DZ' => __( 'Algeria' ),
3558 'AS' => __( 'American Samoa' ),
3559 'AD' => __( 'Andorra' ),
3560 'AO' => __( 'Angola' ),
3561 'AI' => __( 'Anguilla' ),
3562 'AQ' => __( 'Antarctica' ),
3563 'AG' => __( 'Antigua and Barbuda' ),
3564 'AR' => __( 'Argentina' ),
3565 'AM' => __( 'Armenia' ),
3566 'AW' => __( 'Aruba' ),
3567 'AU' => __( 'Australia' ),
3568 'AT' => __( 'Austria' ),
3569 'AZ' => __( 'Azerbaijan' ),
3570 'BS' => __( 'Bahamas' ),
3571 'BH' => __( 'Bahrain' ),
3572 'BD' => __( 'Bangladesh' ),
3573 'BB' => __( 'Barbados' ),
3574 'BY' => __( 'Belarus' ),
3575 'BE' => __( 'Belgium' ),
3576 'BZ' => __( 'Belize' ),
3577 'BJ' => __( 'Benin' ),
3578 'BM' => __( 'Bermuda' ),
3579 'BT' => __( 'Bhutan' ),
3580 'BO' => __( 'Bolivia' ),
3581 'BA' => __( 'Bosnia and Herzegovina' ),
3582 'BW' => __( 'Botswana' ),
3583 'BV' => __( 'Bouvet Island' ),
3584 'BR' => __( 'Brazil' ),
3585 'BQ' => __( 'British Antarctic Territory' ),
3586 'IO' => __( 'British Indian Ocean Territory' ),
3587 'VG' => __( 'British Virgin Islands' ),
3588 'BN' => __( 'Brunei' ),
3589 'BG' => __( 'Bulgaria' ),
3590 'BF' => __( 'Burkina Faso' ),
3591 'BI' => __( 'Burundi' ),
3592 'KH' => __( 'Cambodia' ),
3593 'CM' => __( 'Cameroon' ),
3594 'CA' => __( 'Canada' ),
3595 'CT' => __( 'Canton and Enderbury Islands' ),
3596 'CV' => __( 'Cape Verde' ),
3597 'KY' => __( 'Cayman Islands' ),
3598 'CF' => __( 'Central African Republic' ),
3599 'TD' => __( 'Chad' ),
3600 'CL' => __( 'Chile' ),
3601 'CN' => __( 'China' ),
3602 'CX' => __( 'Christmas Island' ),
3603 'CC' => __( 'Cocos [Keeling] Islands' ),
3604 'CO' => __( 'Colombia' ),
3605 'KM' => __( 'Comoros' ),
3606 'CG' => __( 'Congo - Brazzaville' ),
3607 'CD' => __( 'Congo - Kinshasa' ),
3608 'CK' => __( 'Cook Islands' ),
3609 'CR' => __( 'Costa Rica' ),
3610 'HR' => __( 'Croatia' ),
3611 'CU' => __( 'Cuba' ),
3612 'CY' => __( 'Cyprus' ),
3613 'CZ' => __( 'Czech Republic' ),
3614 'CI' => __( 'Côte d’Ivoire' ),
3615 'DK' => __( 'Denmark' ),
3616 'DJ' => __( 'Djibouti' ),
3617 'DM' => __( 'Dominica' ),
3618 'DO' => __( 'Dominican Republic' ),
3619 'NQ' => __( 'Dronning Maud Land' ),
3620 'DD' => __( 'East Germany' ),
3621 'EC' => __( 'Ecuador' ),
3622 'EG' => __( 'Egypt' ),
3623 'SV' => __( 'El Salvador' ),
3624 'GQ' => __( 'Equatorial Guinea' ),
3625 'ER' => __( 'Eritrea' ),
3626 'EE' => __( 'Estonia' ),
3627 'ET' => __( 'Ethiopia' ),
3628 'FK' => __( 'Falkland Islands' ),
3629 'FO' => __( 'Faroe Islands' ),
3630 'FJ' => __( 'Fiji' ),
3631 'FI' => __( 'Finland' ),
3632 'FR' => __( 'France' ),
3633 'GF' => __( 'French Guiana' ),
3634 'PF' => __( 'French Polynesia' ),
3635 'TF' => __( 'French Southern Territories' ),
3636 'FQ' => __( 'French Southern and Antarctic Territories' ),
3637 'GA' => __( 'Gabon' ),
3638 'GM' => __( 'Gambia' ),
3639 'GE' => __( 'Georgia' ),
3640 'DE' => __( 'Germany' ),
3641 'GH' => __( 'Ghana' ),
3642 'GI' => __( 'Gibraltar' ),
3643 'GR' => __( 'Greece' ),
3644 'GL' => __( 'Greenland' ),
3645 'GD' => __( 'Grenada' ),
3646 'GP' => __( 'Guadeloupe' ),
3647 'GU' => __( 'Guam' ),
3648 'GT' => __( 'Guatemala' ),
3649 'GG' => __( 'Guernsey' ),
3650 'GN' => __( 'Guinea' ),
3651 'GW' => __( 'Guinea-Bissau' ),
3652 'GY' => __( 'Guyana' ),
3653 'HT' => __( 'Haiti' ),
3654 'HM' => __( 'Heard Island and McDonald Islands' ),
3655 'HN' => __( 'Honduras' ),
3656 'HK' => __( 'Hong Kong SAR China' ),
3657 'HU' => __( 'Hungary' ),
3658 'IS' => __( 'Iceland' ),
3659 'IN' => __( 'India' ),
3660 'ID' => __( 'Indonesia' ),
3661 'IR' => __( 'Iran' ),
3662 'IQ' => __( 'Iraq' ),
3663 'IE' => __( 'Ireland' ),
3664 'IM' => __( 'Isle of Man' ),
3665 'IL' => __( 'Israel' ),
3666 'IT' => __( 'Italy' ),
3667 'JM' => __( 'Jamaica' ),
3668 'JP' => __( 'Japan' ),
3669 'JE' => __( 'Jersey' ),
3670 'JT' => __( 'Johnston Island' ),
3671 'JO' => __( 'Jordan' ),
3672 'KZ' => __( 'Kazakhstan' ),
3673 'KE' => __( 'Kenya' ),
3674 'KI' => __( 'Kiribati' ),
3675 'KW' => __( 'Kuwait' ),
3676 'KG' => __( 'Kyrgyzstan' ),
3677 'LA' => __( 'Laos' ),
3678 'LV' => __( 'Latvia' ),
3679 'LB' => __( 'Lebanon' ),
3680 'LS' => __( 'Lesotho' ),
3681 'LR' => __( 'Liberia' ),
3682 'LY' => __( 'Libya' ),
3683 'LI' => __( 'Liechtenstein' ),
3684 'LT' => __( 'Lithuania' ),
3685 'LU' => __( 'Luxembourg' ),
3686 'MO' => __( 'Macau SAR China' ),
3687 'MK' => __( 'Macedonia' ),
3688 'MG' => __( 'Madagascar' ),
3689 'MW' => __( 'Malawi' ),
3690 'MY' => __( 'Malaysia' ),
3691 'MV' => __( 'Maldives' ),
3692 'ML' => __( 'Mali' ),
3693 'MT' => __( 'Malta' ),
3694 'MH' => __( 'Marshall Islands' ),
3695 'MQ' => __( 'Martinique' ),
3696 'MR' => __( 'Mauritania' ),
3697 'MU' => __( 'Mauritius' ),
3698 'YT' => __( 'Mayotte' ),
3699 'FX' => __( 'Metropolitan France' ),
3700 'MX' => __( 'Mexico' ),
3701 'FM' => __( 'Micronesia' ),
3702 'MI' => __( 'Midway Islands' ),
3703 'MD' => __( 'Moldova' ),
3704 'MC' => __( 'Monaco' ),
3705 'MN' => __( 'Mongolia' ),
3706 'ME' => __( 'Montenegro' ),
3707 'MS' => __( 'Montserrat' ),
3708 'MA' => __( 'Morocco' ),
3709 'MZ' => __( 'Mozambique' ),
3710 'MM' => __( 'Myanmar [Burma]' ),
3711 'NA' => __( 'Namibia' ),
3712 'NR' => __( 'Nauru' ),
3713 'NP' => __( 'Nepal' ),
3714 'NL' => __( 'Netherlands' ),
3715 'AN' => __( 'Netherlands Antilles' ),
3716 'NT' => __( 'Neutral Zone' ),
3717 'NC' => __( 'New Caledonia' ),
3718 'NZ' => __( 'New Zealand' ),
3719 'NI' => __( 'Nicaragua' ),
3720 'NE' => __( 'Niger' ),
3721 'NG' => __( 'Nigeria' ),
3722 'NU' => __( 'Niue' ),
3723 'NF' => __( 'Norfolk Island' ),
3724 'KP' => __( 'North Korea' ),
3725 'VD' => __( 'North Vietnam' ),
3726 'MP' => __( 'Northern Mariana Islands' ),
3727 'NO' => __( 'Norway' ),
3728 'OM' => __( 'Oman' ),
3729 'PC' => __( 'Pacific Islands Trust Territory' ),
3730 'PK' => __( 'Pakistan' ),
3731 'PW' => __( 'Palau' ),
3732 'PS' => __( 'Palestinian Territories' ),
3733 'PA' => __( 'Panama' ),
3734 'PZ' => __( 'Panama Canal Zone' ),
3735 'PG' => __( 'Papua New Guinea' ),
3736 'PY' => __( 'Paraguay' ),
3737 'YD' => __( "People's Democratic Republic of Yemen" ),
3738 'PE' => __( 'Peru' ),
3739 'PH' => __( 'Philippines' ),
3740 'PN' => __( 'Pitcairn Islands' ),
3741 'PL' => __( 'Poland' ),
3742 'PT' => __( 'Portugal' ),
3743 'PR' => __( 'Puerto Rico' ),
3744 'QA' => __( 'Qatar' ),
3745 'RO' => __( 'Romania' ),
3746 'RU' => __( 'Russia' ),
3747 'RW' => __( 'Rwanda' ),
3748 'RE' => __( 'Réunion' ),
3749 'BL' => __( 'Saint Barthélemy' ),
3750 'SH' => __( 'Saint Helena' ),
3751 'KN' => __( 'Saint Kitts and Nevis' ),
3752 'LC' => __( 'Saint Lucia' ),
3753 'MF' => __( 'Saint Martin' ),
3754 'PM' => __( 'Saint Pierre and Miquelon' ),
3755 'VC' => __( 'Saint Vincent and the Grenadines' ),
3756 'WS' => __( 'Samoa' ),
3757 'SM' => __( 'San Marino' ),
3758 'SA' => __( 'Saudi Arabia' ),
3759 'SN' => __( 'Senegal' ),
3760 'RS' => __( 'Serbia' ),
3761 'CS' => __( 'Serbia and Montenegro' ),
3762 'SC' => __( 'Seychelles' ),
3763 'SL' => __( 'Sierra Leone' ),
3764 'SG' => __( 'Singapore' ),
3765 'SK' => __( 'Slovakia' ),
3766 'SI' => __( 'Slovenia' ),
3767 'SB' => __( 'Solomon Islands' ),
3768 'SO' => __( 'Somalia' ),
3769 'ZA' => __( 'South Africa' ),
3770 'GS' => __( 'South Georgia and the South Sandwich Islands' ),
3771 'KR' => __( 'South Korea' ),
3772 'ES' => __( 'Spain' ),
3773 'LK' => __( 'Sri Lanka' ),
3774 'SD' => __( 'Sudan' ),
3775 'SR' => __( 'Suriname' ),
3776 'SJ' => __( 'Svalbard and Jan Mayen' ),
3777 'SZ' => __( 'Swaziland' ),
3778 'SE' => __( 'Sweden' ),
3779 'CH' => __( 'Switzerland' ),
3780 'SY' => __( 'Syria' ),
3781 'ST' => __( 'São Tomé and Príncipe' ),
3782 'TW' => __( 'Taiwan' ),
3783 'TJ' => __( 'Tajikistan' ),
3784 'TZ' => __( 'Tanzania' ),
3785 'TH' => __( 'Thailand' ),
3786 'TL' => __( 'Timor-Leste' ),
3787 'TG' => __( 'Togo' ),
3788 'TK' => __( 'Tokelau' ),
3789 'TO' => __( 'Tonga' ),
3790 'TT' => __( 'Trinidad and Tobago' ),
3791 'TN' => __( 'Tunisia' ),
3792 'TR' => __( 'Turkey' ),
3793 'TM' => __( 'Turkmenistan' ),
3794 'TC' => __( 'Turks and Caicos Islands' ),
3795 'TV' => __( 'Tuvalu' ),
3796 'UM' => __( 'U.S. Minor Outlying Islands' ),
3797 'PU' => __( 'U.S. Miscellaneous Pacific Islands' ),
3798 'VI' => __( 'U.S. Virgin Islands' ),
3799 'UG' => __( 'Uganda' ),
3800 'UA' => __( 'Ukraine' ),
3801 'SU' => __( 'Union of Soviet Socialist Republics' ),
3802 'AE' => __( 'United Arab Emirates' ),
3803 'GB' => __( 'United Kingdom' ),
3804 'US' => __( 'United States' ),
3805 'ZZ' => __( 'Unknown or Invalid Region' ),
3806 'UY' => __( 'Uruguay' ),
3807 'UZ' => __( 'Uzbekistan' ),
3808 'VU' => __( 'Vanuatu' ),
3809 'VA' => __( 'Vatican City' ),
3810 'VE' => __( 'Venezuela' ),
3811 'VN' => __( 'Vietnam' ),
3812 'WK' => __( 'Wake Island' ),
3813 'WF' => __( 'Wallis and Futuna' ),
3814 'EH' => __( 'Western Sahara' ),
3815 'YE' => __( 'Yemen' ),
3816 'ZM' => __( 'Zambia' ),
3817 'ZW' => __( 'Zimbabwe' ),
3818 'AX' => __( '�
3819 land Islands' ),
3820 );
3821
3822 return apply_filters( 'pods_form_ui_field_pick_data_countries', $data, $name, $value, $options, $pod, $id );
3823
3824 }
3825
3826 /**
3827 * Data callback for US States.
3828 *
3829 * @param string|null $name The name of the field.
3830 * @param string|array|null $value The value of the field.
3831 * @param array|null $options Field options.
3832 * @param array|null $pod Pod data.
3833 * @param int|null $id Item ID.
3834 *
3835 * @return array
3836 *
3837 * @since 2.3.0
3838 */
3839 public function data_us_states( $name = null, $value = null, $options = null, $pod = null, $id = null ) {
3840
3841 $data = array(
3842 'AL' => __( 'Alabama' ),
3843 'AK' => __( 'Alaska' ),
3844 'AZ' => __( 'Arizona' ),
3845 'AR' => __( 'Arkansas' ),
3846 'CA' => __( 'California' ),
3847 'CO' => __( 'Colorado' ),
3848 'CT' => __( 'Connecticut' ),
3849 'DE' => __( 'Delaware' ),
3850 'DC' => __( 'District Of Columbia' ),
3851 'FL' => __( 'Florida' ),
3852 'GA' => __( 'Georgia' ),
3853 'HI' => __( 'Hawaii' ),
3854 'ID' => __( 'Idaho' ),
3855 'IL' => __( 'Illinois' ),
3856 'IN' => __( 'Indiana' ),
3857 'IA' => __( 'Iowa' ),
3858 'KS' => __( 'Kansas' ),
3859 'KY' => __( 'Kentucky' ),
3860 'LA' => __( 'Louisiana' ),
3861 'ME' => __( 'Maine' ),
3862 'MD' => __( 'Maryland' ),
3863 'MA' => __( 'Massachusetts' ),
3864 'MI' => __( 'Michigan' ),
3865 'MN' => __( 'Minnesota' ),
3866 'MS' => __( 'Mississippi' ),
3867 'MO' => __( 'Missouri' ),
3868 'MT' => __( 'Montana' ),
3869 'NE' => __( 'Nebraska' ),
3870 'NV' => __( 'Nevada' ),
3871 'NH' => __( 'New Hampshire' ),
3872 'NJ' => __( 'New Jersey' ),
3873 'NM' => __( 'New Mexico' ),
3874 'NY' => __( 'New York' ),
3875 'NC' => __( 'North Carolina' ),
3876 'ND' => __( 'North Dakota' ),
3877 'OH' => __( 'Ohio' ),
3878 'OK' => __( 'Oklahoma' ),
3879 'OR' => __( 'Oregon' ),
3880 'PA' => __( 'Pennsylvania' ),
3881 'RI' => __( 'Rhode Island' ),
3882 'SC' => __( 'South Carolina' ),
3883 'SD' => __( 'South Dakota' ),
3884 'TN' => __( 'Tennessee' ),
3885 'TX' => __( 'Texas' ),
3886 'UT' => __( 'Utah' ),
3887 'VT' => __( 'Vermont' ),
3888 'VA' => __( 'Virginia' ),
3889 'WA' => __( 'Washington' ),
3890 'WV' => __( 'West Virginia' ),
3891 'WI' => __( 'Wisconsin' ),
3892 'WY' => __( 'Wyoming' ),
3893 );
3894
3895 return apply_filters( 'pods_form_ui_field_pick_data_us_states', $data, $name, $value, $options, $pod, $id );
3896
3897 }
3898
3899 /**
3900 * Data callback for CA Provinces.
3901 *
3902 * @param string|null $name The name of the field.
3903 * @param string|array|null $value The value of the field.
3904 * @param array|null $options Field options.
3905 * @param array|null $pod Pod data.
3906 * @param int|null $id Item ID.
3907 *
3908 * @return array
3909 *
3910 * @since 2.3.0
3911 */
3912 public function data_ca_provinces( $name = null, $value = null, $options = null, $pod = null, $id = null ) {
3913
3914 $data = array(
3915 'AB' => __( 'Alberta' ),
3916 'BC' => __( 'British Columbia' ),
3917 'MB' => __( 'Manitoba' ),
3918 'NB' => __( 'New Brunswick' ),
3919 'NL' => __( 'Newfoundland and Labrador' ),
3920 'NT' => __( 'Northwest Territories' ),
3921 'NS' => __( 'Nova Scotia' ),
3922 'NU' => __( 'Nunavut' ),
3923 'ON' => __( 'Ontario' ),
3924 'PE' => __( 'Prince Edward Island' ),
3925 'QC' => __( 'Quebec' ),
3926 'SK' => __( 'Saskatchewan' ),
3927 'YT' => __( 'Yukon' ),
3928 );
3929
3930 return apply_filters( 'pods_form_ui_field_pick_data_ca_provinces', $data, $name, $value, $options, $pod, $id );
3931
3932 }
3933
3934 /**
3935 * Data callback for Days of the Week.
3936 *
3937 * @param string|null $name The name of the field.
3938 * @param string|array|null $value The value of the field.
3939 * @param array|null $options Field options.
3940 * @param array|null $pod Pod data.
3941 * @param int|null $id Item ID.
3942 *
3943 * @return array
3944 *
3945 * @since 2.3.0
3946 */
3947 public function data_days_of_week( $name = null, $value = null, $options = null, $pod = null, $id = null ) {
3948
3949 /**
3950 * @var WP_Locale
3951 */
3952 global $wp_locale;
3953
3954 return $wp_locale->weekday;
3955
3956 }
3957
3958 /**
3959 * Data callback for Months of the Year.
3960 *
3961 * @param string|null $name The name of the field.
3962 * @param string|array|null $value The value of the field.
3963 * @param array|null $options Field options.
3964 * @param array|null $pod Pod data.
3965 * @param int|null $id Item ID.
3966 *
3967 * @return array
3968 *
3969 * @since 2.3.0
3970 */
3971 public function data_months_of_year( $name = null, $value = null, $options = null, $pod = null, $id = null ) {
3972
3973 /**
3974 * @var WP_Locale
3975 */
3976 global $wp_locale;
3977
3978 return $wp_locale->month;
3979
3980 }
3981
3982 /**
3983 * Add our modal input to the form so we can track whether we're in our modal during saving or not.
3984 */
3985 public function admin_modal_input() {
3986
3987 if ( ! pods_is_modal_window() ) {
3988 return;
3989 }
3990
3991 echo '<input name="pods_modal" type="hidden" value="1" />';
3992
3993 }
3994
3995 /**
3996 * Bail to send new saved data back to our modal handler.
3997 *
3998 * @param int $item_id Item ID.
3999 * @param string $item_title Item title.
4000 * @param object $field_args Field arguments.
4001 */
4002 public function admin_modal_bail( $item_id, $item_title, $field_args ) {
4003
4004 $model_data = $this->build_dfv_field_item_data_recurse_item( $item_id, $item_title, $field_args );
4005 ?>
4006 <script type="text/javascript">
4007 window.parent.postMessage( {
4008 type: 'PODS_MESSAGE',
4009 data: <?php echo wp_json_encode( $model_data, JSON_HEX_TAG ); ?>,
4010 }, window.location.origin );
4011 </script>
4012 <?php
4013
4014 die();
4015
4016 }
4017
4018 /**
4019 * Bail to send new saved data back to our modal handler.
4020 *
4021 * @param int $item_id Item ID.
4022 * @param string $item_title Item title.
4023 * @param object $field_args Field arguments.
4024 */
4025 public function admin_modal_bail_JSON( $item_id, $item_title, $field_args ) {
4026
4027 $model_data = $this->build_dfv_field_item_data_recurse_item( $item_id, $item_title, $field_args );
4028 echo wp_json_encode( $model_data, JSON_HEX_TAG );
4029
4030 die();
4031 }
4032
4033 /**
4034 * Bail on Post save redirect for Admin modal.
4035 *
4036 * @param string $location The destination URL.
4037 * @param int $post_id The post ID.
4038 *
4039 * @return string
4040 */
4041 public function admin_modal_bail_post_redirect( $location, $post_id ) {
4042
4043 if ( ! pods_is_modal_window() ) {
4044 return $location;
4045 }
4046
4047 $post_title = get_the_title( $post_id );
4048
4049 $field_args = (object) array(
4050 'options' => array(
4051 'pick_object' => 'post_type',
4052 'pick_val' => get_post_type( $post_id ),
4053 ),
4054 'value' => array(
4055 $post_id => $post_title,
4056 ),
4057 );
4058
4059 $this->admin_modal_bail( $post_id, $post_title, $field_args );
4060
4061 return $location;
4062
4063 }
4064
4065 /**
4066 * Hook into term updating process to bail on redirect.
4067 */
4068 public function admin_modal_bail_term_action() {
4069
4070 if ( ! pods_is_modal_window() ) {
4071 return;
4072 }
4073
4074 if ( function_exists( 'get_current_screen' ) ) {
4075 $screen = get_current_screen();
4076
4077 if ( 'edit-tags' === $screen->base ) {
4078 // @todo Need more effort on the solution for add new handling.
4079 //add_action( 'admin_footer', [ $this, 'admin_modal_bail_term_action_add_new' ], 20 );
4080 }
4081 }
4082
4083 add_action( 'created_term', array( $this, 'admin_modal_bail_term' ), 10, 3 );
4084 add_action( 'edited_term', array( $this, 'admin_modal_bail_term' ), 10, 3 );
4085
4086 }
4087
4088 /**
4089 * Hook into term creation process to bail after success.
4090 *
4091 * @todo Try and catch the added tr node on the table tbody.
4092 */
4093 public function admin_modal_bail_term_action_add_new() {
4094 ?>
4095 <script type="text/javascript">
4096 jQuery( function ( $ ) {
4097 /** @var {jQuery.Event} e */
4098 $( '.tags' ).on( 'DOMSubtreeModified', function(e) {
4099 console.log( e );
4100
4101 if ( !== e.target.is( 'tbody#the-list' ) ) {
4102 return;
4103 }
4104
4105 const $theTermRow = $( e.target.innerHTML() );
4106 const titleRow = $theTermRow.find( '.column-name .row-title' );
4107 const actionView = $theTermRow.find( '.row-actions span.view a' );
4108
4109 const termData = {
4110 id : $theTermRow.find( '.check-column input' ).val(),
4111 icon : '',
4112 name : titleRow.text(),
4113 edit_link: titleRow.prop( 'href' ),
4114 link : actionView[0] ? actionView.prop( 'href' ) : '',
4115 selected : true,
4116 };
4117
4118 console.log( termData );
4119
4120 window.parent.postMessage( {
4121 type : 'PODS_MESSAGE',
4122 data : termData,
4123 }, window.location.origin );
4124 } );
4125 } );
4126 </script>
4127 <?php
4128 }
4129
4130 /**
4131 * Bail on Term save redirect for Admin modal.
4132 *
4133 * @param int $term_id Term ID.
4134 * @param int $tt_id Term taxonomy ID.
4135 * @param string $taxonomy Taxonomy slug.
4136 */
4137 public function admin_modal_bail_term( $term_id, $tt_id, $taxonomy ) {
4138
4139 if ( ! pods_is_modal_window() ) {
4140 return;
4141 }
4142
4143 $term = get_term( $term_id );
4144
4145 if ( ! $term || is_wp_error( $term ) ) {
4146 return;
4147 }
4148
4149 $field_args = (object) array(
4150 'options' => array(
4151 'pick_object' => 'taxonomy',
4152 'pick_val' => $term->taxonomy,
4153 ),
4154 'value' => array(
4155 $term->term_id => $term->name,
4156 ),
4157 );
4158
4159 $this->admin_modal_bail( $term->term_id, $term->name, $field_args );
4160
4161 }
4162
4163 /**
4164 * Hook into user updating process to bail on redirect.
4165 */
4166 public function admin_modal_bail_user_action() {
4167
4168 if ( ! pods_is_modal_window() ) {
4169 return;
4170 }
4171
4172 add_filter( 'wp_redirect', array( $this, 'admin_modal_bail_user_redirect' ) );
4173
4174 }
4175
4176 /**
4177 * Bail on User save redirect for Admin modal.
4178 *
4179 * @param string $location The destination URL.
4180 *
4181 * @return string
4182 */
4183 public function admin_modal_bail_user_redirect( $location ) {
4184
4185 if ( ! pods_is_modal_window() ) {
4186 return $location;
4187 }
4188
4189 global $user_id;
4190
4191 $user = get_userdata( $user_id );
4192
4193 if ( ! $user || is_wp_error( $user ) ) {
4194 return $location;
4195 }
4196
4197 $field_args = (object) array(
4198 'options' => array(
4199 'pick_object' => 'user',
4200 'pick_val' => '',
4201 ),
4202 'value' => array(
4203 $user->ID => $user->display_name,
4204 ),
4205 );
4206
4207 $this->admin_modal_bail( $user->ID, $user->display_name, $field_args );
4208
4209 return $location;
4210
4211 }
4212
4213 /**
4214 * Bail on Pod item save for Admin modal.
4215 *
4216 * @param int $id Item ID.
4217 * @param array $params save_pod_item parameters.
4218 * @param null|Pods $obj Pod object (if set).
4219 */
4220 public function admin_modal_bail_pod( $id, $params, $obj ) {
4221
4222 if ( ! pods_is_modal_window() ) {
4223 return;
4224 }
4225
4226 if ( ! $obj ) {
4227 $obj = pods_get_instance( $params['pod'] );
4228 }
4229
4230 if ( ! $obj || ! $obj->fetch( $id ) ) {
4231 return;
4232 }
4233
4234 $item_id = $obj->id();
4235 $item_title = $obj->index();
4236
4237 $field_args = (object) array(
4238 'options' => array(
4239 'pick_object' => $obj->pod_data['type'],
4240 'pick_val' => $obj->pod,
4241 ),
4242 'value' => array(
4243 $obj->id() => $item_title,
4244 ),
4245 );
4246
4247 $this->admin_modal_bail_JSON( $item_id, $item_title, $field_args );
4248
4249 }
4250
4251 /**
4252 * Build field data for Pods DFV.
4253 *
4254 * @param object $args {
4255 * Field information arguments.
4256 *
4257 * @type string $name Field name.
4258 * @type string $type Field type.
4259 * @type array $options Field options.
4260 * @type mixed $value Current value.
4261 * @type array $pod Pod information.
4262 * @type int|string $id Current item ID.
4263 * @type string $form_field_type HTML field type.
4264 * }
4265 *
4266 * @return array
4267 */
4268 public function build_dfv_field_data( $args ) {
4269 $data = parent::build_dfv_field_data( $args );
4270
4271 // Normalize arrays for multiple select.
4272 if ( is_array( $data['fieldValue'] ) ) {
4273 $data['fieldValue'] = array_values( $data['fieldValue'] );
4274 }
4275
4276 return $data;
4277 }
4278
4279 }
4280