PluginProbe ʕ •ᴥ•ʔ
Pods – Custom Content Types and Fields / 3.2.2
Pods – Custom Content Types and Fields v3.2.2
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 3 years ago boolean.php 3 years ago code.php 2 years ago color.php 3 years ago comment.php 4 years ago currency.php 3 years ago date.php 2 years ago datetime.php 2 years ago email.php 3 years ago file.php 2 years ago heading.php 2 years ago html.php 2 years ago link.php 3 years ago number.php 2 years ago oembed.php 2 years ago paragraph.php 2 years ago password.php 3 years ago phone.php 3 years ago pick.php 2 years ago slug.php 3 years ago taxonomy.php 4 years ago text.php 2 years ago time.php 2 years ago website.php 3 years ago wysiwyg.php 2 years ago
pick.php
4284 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 object $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 object $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 object $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' => null !== $item_id ? html_entity_decode( esc_html( $item_id ), ENT_COMPAT ) : '',
1707 'icon' => null !== $icon ? esc_attr( $icon ) : '',
1708 'name' => null !== $item_title ? wp_strip_all_tags( html_entity_decode( $item_title, ENT_COMPAT ) ) : '',
1709 'edit_link' => null !== $edit_link ? html_entity_decode( esc_url( $edit_link ), ENT_COMPAT ) : '',
1710 'link' => null !== $link ? html_entity_decode( esc_url( $link ), ENT_COMPAT ) : '',
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 $query_sanitized_like = pods_sanitize_like( $data_params['query'] );
2790
2791 $lookup_where = array(
2792 $search_data->field_index => "`t`.`{$search_data->field_index}` LIKE '%{$query_sanitized_like}%'",
2793 );
2794
2795 if ( $display_field_name !== $search_data->field_index ) {
2796 $lookup_where[ $display_field_name ] = "{$display_field} LIKE '%{$query_sanitized_like}%'";
2797 }
2798
2799 // @todo Hook into WPML for each table
2800 if ( $wpdb->users === $search_data->table ) {
2801 $lookup_where['display_name'] = "`t`.`display_name` LIKE '%{$query_sanitized_like}%'";
2802 $lookup_where['user_login'] = "`t`.`user_login` LIKE '%{$query_sanitized_like}%'";
2803 $lookup_where['user_email'] = "`t`.`user_email` LIKE '%{$query_sanitized_like}%'";
2804 } elseif ( $wpdb->posts === $search_data->table ) {
2805 $lookup_where['post_title'] = "`t`.`post_title` LIKE '%{$query_sanitized_like}%'";
2806 $lookup_where['post_name'] = "`t`.`post_name` LIKE '%{$query_sanitized_like}%'";
2807 $lookup_where['post_content'] = "`t`.`post_content` LIKE '%{$query_sanitized_like}%'";
2808 $lookup_where['post_excerpt'] = "`t`.`post_excerpt` LIKE '%{$query_sanitized_like}%'";
2809 } elseif ( $wpdb->terms === $search_data->table ) {
2810 $lookup_where['name'] = "`t`.`name` LIKE '%{$query_sanitized_like}%'";
2811 $lookup_where['slug'] = "`t`.`slug` LIKE '%{$query_sanitized_like}%'";
2812 } elseif ( $wpdb->comments === $search_data->table ) {
2813 $lookup_where['comment_content'] = "`t`.`comment_content` LIKE '%{$query_sanitized_like}%'";
2814 $lookup_where['comment_author'] = "`t`.`comment_author` LIKE '%{$query_sanitized_like}%'";
2815 $lookup_where['comment_author_email'] = "`t`.`comment_author_email` LIKE '%{$query_sanitized_like}%'";
2816 }
2817
2818 $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 );
2819
2820 if ( ! empty( $lookup_where ) ) {
2821 $params['where'][] = implode( ' OR ', $lookup_where );
2822 }
2823
2824 $orderby = array();
2825 $orderby[] = "( {$display_field} LIKE '%{$query_sanitized_like}%' ) DESC";
2826
2827 $pick_orderby = pods_v( static::$type . '_orderby', $options, null, true );
2828
2829 if ( is_string( $pick_orderby ) && 0 < strlen( $pick_orderby ) ) {
2830 $orderby[] = $pick_orderby;
2831 }
2832
2833 if ( ! in_array( $search_data->field_index, $orderby, true ) ) {
2834 $orderby[] = "`t`.`{$search_data->field_index}`";
2835 }
2836
2837 if ( ! in_array( $search_data->field_id, $orderby, true ) ) {
2838 $orderby[] = "`t`.`{$search_data->field_id}`";
2839 }
2840
2841 $params['orderby'] = $orderby;
2842 }//end if
2843 } elseif ( 0 < $limit ) {
2844 $params['limit'] = $limit;
2845 $params['page'] = $page;
2846 }//end if
2847
2848 $extra = '';
2849
2850 if ( $wpdb->posts === $search_data->table ) {
2851 $extra = '`t`.`post_type`, `t`.`menu_order`, `t`.`post_date`';
2852 } elseif ( $wpdb->terms === $search_data->table ) {
2853 $extra = '`tt`.`taxonomy`';
2854 } elseif ( $wpdb->comments === $search_data->table ) {
2855 $extra = '`t`.`comment_type`';
2856 } elseif ( $wpdb->site === $search_data->table ) {
2857 $extra = '`t`.`path`';
2858 } elseif ( $wpdb->blogs === $search_data->table ) {
2859 $extra = '`t`.`path`';
2860 }
2861
2862 if ( '' !== $extra && false === strpos( $params['select'], $extra ) ) {
2863 $params['select'] .= ', ' . $extra;
2864 }
2865
2866 if ( 'user' === pods_v( static::$type . '_object', $options ) ) {
2867 $roles = pods_v( static::$type . '_user_role', $options );
2868
2869 if ( ! empty( $roles ) ) {
2870 $where = array();
2871
2872 foreach ( (array) $roles as $role ) {
2873 if ( empty( $role ) || ( pods_clean_name( $role ) !== $role && sanitize_title( $role ) !== $role ) ) {
2874 continue;
2875 }
2876
2877 $role_sanitized_like = pods_sanitize_like( $role );
2878
2879 $where[] = "{$wpdb->prefix}capabilities.meta_value LIKE '%\"{$role_sanitized_like}\"%'";
2880 }
2881
2882 if ( ! empty( $where ) ) {
2883 $params['where'][] = implode( ' OR ', $where );
2884 }
2885 }//end if
2886 }//end if
2887
2888 if ( empty( $params['where'] ) ) {
2889 $params['where'] = null;
2890 }
2891
2892 try {
2893 $results = $search_data->select( $params );
2894 } catch ( Exception $exception ) {
2895 if ( pods_is_debug_display() ) {
2896 pods_error_exception( $exception );
2897 }
2898
2899 $results = [];
2900 }
2901
2902 if ( $autocomplete && 0 < $params['limit'] && $params['limit'] < $search_data->total_found() ) {
2903 if ( ! empty( $value ) ) {
2904 $ids = $value;
2905
2906 if ( is_array( $ids ) ) {
2907 if ( isset( $ids[0] ) && is_array( $ids[0] ) ) {
2908 $ids = wp_list_pluck( $ids, $search_data->field_id );
2909 }
2910
2911 if ( $params['limit'] < count( $ids ) ) {
2912 $params['limit'] = count( $ids );
2913 }
2914
2915 $ids = array_map( 'absint', $ids );
2916 $ids = implode( ', ', $ids );
2917 } else {
2918 $ids = (int) $ids;
2919 }
2920
2921 if ( is_array( $params['where'] ) ) {
2922 $params['where'] = implode( ' AND ', $params['where'] );
2923 }
2924 if ( ! empty( $params['where'] ) ) {
2925 $params['where'] = '(' . $params['where'] . ') AND ';
2926 }
2927
2928 $params['where'] .= "`t`.`{$search_data->field_id}` IN ( {$ids} )";
2929
2930 try {
2931 $results = array_merge( $results, $search_data->select( $params ) );
2932 } catch ( Exception $exception ) {
2933 if ( pods_is_debug_display() ) {
2934 pods_error_exception( $exception );
2935 }
2936
2937 $results = [];
2938 }
2939 }//end if
2940 } else {
2941 $autocomplete = false;
2942 }//end if
2943
2944 if ( 'data' === $context ) {
2945 pods_static_cache_set( $name . '/' . $options['id'], [
2946 'autocomplete' => $autocomplete,
2947 ], __CLASS__ . '/field_data' );
2948 }
2949
2950 if ( $hierarchy && ! $autocomplete && ! empty( $results ) && $table_info['object_hierarchical'] && ! empty( $table_info['field_parent'] ) ) {
2951 $select_args = array(
2952 'id' => $table_info['field_id'],
2953 'index' => $display_field_name,
2954 'parent' => $table_info['field_parent'],
2955 );
2956
2957 $results = pods_hierarchical_select( $results, $select_args );
2958 }
2959
2960 $ids = array();
2961
2962 if ( ! empty( $results ) ) {
2963 foreach ( $results as $result ) {
2964 $result = get_object_vars( $result );
2965 $field_id = $search_data->field_id;
2966 $field_index = $display_field_name;
2967
2968 if ( ! isset( $result[ $field_index ] ) ) {
2969 $field_index = $default_field_index;
2970 }
2971
2972 if ( ! isset( $result[ $field_id ], $result[ $field_index ] ) ) {
2973 continue;
2974 }
2975
2976 $result[ $field_index ] = trim( $result[ $field_index ] );
2977
2978 $object = '';
2979 $object_type = '';
2980
2981 if ( $wpdb->posts === $search_data->table && isset( $result['post_type'] ) ) {
2982 $object = $result['post_type'];
2983 $object_type = 'post_type';
2984 } elseif ( $wpdb->terms === $search_data->table && isset( $result['taxonomy'] ) ) {
2985 $object = $result['taxonomy'];
2986 $object_type = 'taxonomy';
2987 }
2988
2989 $field_index_data_to_use = pods_v( $field_index, $search_data->object_fields );
2990
2991 $display_filter = pods_v( 'display_filter', $field_index_data_to_use );
2992
2993 if ( is_string( $display_filter ) && 0 < strlen( $display_filter ) ) {
2994 $display_filter_args = pods_v( 'display_filter_args', $field_index_data_to_use );
2995
2996 $filter_args = array(
2997 $display_filter,
2998 $result[ $field_index ],
2999 );
3000
3001 if ( ! empty( $display_filter_args ) ) {
3002 foreach ( (array) $display_filter_args as $display_filter_arg ) {
3003 // Manual solution to a problem that won't map correctly.
3004 if ( 'post_ID' === $display_filter_arg ) {
3005 $display_filter_arg = 'ID';
3006 }
3007
3008 if ( isset( $result[ $display_filter_arg ] ) ) {
3009 $filter_args[] = $result[ $display_filter_arg ];
3010 }
3011 }
3012 }
3013
3014 $result[ $field_index ] = call_user_func_array( 'apply_filters', $filter_args );
3015 }
3016
3017 if ( in_array( $options[ static::$type . '_object' ], array( 'site', 'network' ), true ) ) {
3018 $result[ $field_index ] = $result[ $field_index ] . $result['path'];
3019 } elseif ( '' === $result[ $field_index ] ) {
3020 $result[ $field_index ] = '(No Title)';
3021 }
3022
3023 if ( 'admin_ajax_relationship' === $context ) {
3024 $items[] = $this->build_dfv_field_item_data_recurse_item( $result[ $field_id ], $result[ $field_index ], (object) $object_params );
3025 } else {
3026 $data[ $result[ $field_id ] ] = $result[ $field_index ];
3027 }
3028
3029 $ids[] = $result[ $field_id ];
3030 }//end foreach
3031 }//end if
3032 }//end if
3033
3034 if ( $simple && 'admin_ajax_relationship' === $context ) {
3035 $found_data = array();
3036
3037 foreach ( $data as $k => $v ) {
3038 if ( false !== stripos( $v, $data_params['query'] ) || false !== stripos( $k, $data_params['query'] ) ) {
3039 $found_data[ $k ] = $v;
3040 }
3041 }
3042
3043 $data = $found_data;
3044 }
3045 }//end if
3046
3047 if ( 'admin_ajax_relationship' === $context ) {
3048 if ( empty( $items ) && ! empty( $data ) ) {
3049 foreach ( $data as $k => $v ) {
3050 $items[] = array(
3051 'id' => $k,
3052 'text' => $v,
3053 );
3054 }
3055 }
3056
3057 $data = $items;
3058 }
3059
3060 return $data;
3061
3062 }
3063
3064 /**
3065 * Check if field is autocomplete enabled.
3066 *
3067 * @param array $options Field options.
3068 *
3069 * @return bool
3070 *
3071 * @since 2.7.0
3072 */
3073 private function is_autocomplete( $options ) {
3074
3075 $autocomplete = false;
3076
3077 if ( 'single' === pods_v( static::$type . '_format_type', $options, 'single' ) ) {
3078 if ( in_array( pods_v( static::$type . '_format_single', $options, 'dropdown' ), array( 'autocomplete', 'list' ), true ) ) {
3079 $autocomplete = true;
3080 }
3081 } elseif ( 'multi' === pods_v( static::$type . '_format_type', $options, 'single' ) ) {
3082 if ( in_array( pods_v( static::$type . '_format_multi', $options, 'checkbox' ), array( 'autocomplete', 'list' ), true ) ) {
3083 $autocomplete = true;
3084 }
3085 }
3086
3087 return $autocomplete;
3088 }
3089
3090 /**
3091 * Check if a field type is a tableless text field type.
3092 *
3093 * @since 2.7.4
3094 *
3095 * @param string $type Field type.
3096 * @param array $options Field options.
3097 * @return bool True if the field type is a tableless text field type, false otherwise.
3098 */
3099 private function is_simple_tableless( $type, array $options ) {
3100 $field_object = pods_v( $type . '_object', $options );
3101
3102 return in_array( $field_object, PodsForm::simple_tableless_objects(), true );
3103 }
3104
3105 /**
3106 * Check if a field supports AJAX mode
3107 *
3108 * @param string $type Field type.
3109 * @param array $options Field options.
3110 *
3111 * @return bool
3112 * @since 2.7.4
3113 */
3114 private function can_ajax( $type, $options ) {
3115 return $this->is_autocomplete( $options ) && ! $this->is_simple_tableless( $type, $options );
3116 }
3117
3118
3119 /**
3120 * Handle autocomplete AJAX.
3121 *
3122 * @since 2.3.0
3123 */
3124 public function admin_ajax_relationship() {
3125
3126 pods_session_start();
3127
3128 // Sanitize input.
3129 // @codingStandardsIgnoreLine
3130 $params = pods_unslash( (array) $_POST );
3131
3132 foreach ( $params as $key => $value ) {
3133 if ( 'action' === $key ) {
3134 continue;
3135 }
3136
3137 unset( $params[ $key ] );
3138
3139 $params[ str_replace( '_podsfix_', '', $key ) ] = $value;
3140 }
3141
3142 $params = (object) $params;
3143
3144 if ( ! isset( $params->_wpnonce, $params->pod_name, $params->field_name, $params->uri_hash, $params->id ) ) {
3145 pods_error( __( 'Unauthorized request', 'pods' ), PodsInit::$admin );
3146 }
3147
3148 if ( ! isset( $params->query ) || '' === trim( $params->query ) ) {
3149 pods_error( __( 'Invalid field request', 'pods' ), PodsInit::$admin );
3150 }
3151
3152 $_wpnonce = $params->_wpnonce;
3153 $pod_name = $params->pod_name;
3154 $field_name = $params->field_name;
3155 $uri_hash = $params->uri_hash;
3156 $id = (int) $params->id;
3157
3158 $query = $params->query;
3159 $limit = pods_v( 'limit', $params, 15, true );
3160 $page = pods_v( 'page', $params, 1, true );
3161
3162 $uid = pods_session_id();
3163
3164 if ( is_user_logged_in() ) {
3165 $uid = 'user_' . get_current_user_id();
3166 }
3167
3168 $nonce_name = 'pods_relationship:' . json_encode( compact( 'pod_name', 'field_name', 'uid', 'uri_hash', 'id' ) );
3169
3170 if ( false === wp_verify_nonce( $_wpnonce, $nonce_name ) ) {
3171 pods_error( __( 'Unauthorized request', 'pods' ), PodsInit::$admin );
3172 }
3173
3174 if ( empty( self::$api ) ) {
3175 self::$api = pods_api();
3176 }
3177
3178 $pod = self::$api->load_pod( [
3179 'name' => $pod_name,
3180 ] );
3181
3182 if ( ! $pod ) {
3183 pods_error( __( 'Invalid Pod configuration', 'pods' ), PodsInit::$admin );
3184 }
3185
3186 $field = $pod->get_field( $field_name );
3187
3188 if ( ! $field ) {
3189 pods_error( __( 'Invalid Field configuration', 'pods' ), PodsInit::$admin );
3190 }
3191
3192 if ( ! $field->is_autocomplete_relationship() ) {
3193 pods_error( __( 'Invalid field', 'pods' ), PodsInit::$admin );
3194 }
3195
3196 $object_params = array(
3197 // The name of the field.
3198 'name' => $field['name'],
3199 // The value of the field.
3200 'value' => null,
3201 // Field options.
3202 'options' => $field,
3203 // Pod data.
3204 'pod' => $pod,
3205 // Item ID.
3206 'id' => $id,
3207 // Data context.
3208 'context' => 'admin_ajax_relationship',
3209 'data_params' => $params,
3210 'page' => $page,
3211 'limit' => $limit,
3212 );
3213
3214 $pick_data = apply_filters( 'pods_field_pick_data_ajax', null, $field['name'], null, $field, $pod, $id );
3215
3216 if ( null !== $pick_data ) {
3217 $items = $pick_data;
3218 } else {
3219 $items = $this->get_object_data( $object_params );
3220 }
3221
3222 if ( ! empty( $items ) && isset( $items[0] ) && ! is_array( $items[0] ) ) {
3223 $new_items = array();
3224
3225 foreach ( $items as $id => $text ) {
3226 $new_items[] = array(
3227 'id' => $id,
3228 'text' => $text,
3229 'image' => '',
3230 );
3231 }
3232
3233 $items = $new_items;
3234 }
3235
3236 $items = apply_filters( 'pods_field_pick_data_ajax_items', $items, $field['name'], null, $field, $pod, $id );
3237
3238 $items = array(
3239 'results' => $items,
3240 );
3241
3242 wp_send_json( $items );
3243
3244 die();
3245 // KBAI!
3246 }
3247
3248 /**
3249 * Data callback for Post Stati.
3250 *
3251 * @param string|null $name The name of the field.
3252 * @param string|array|null $value The value of the field.
3253 * @param array|null $options Field options.
3254 * @param array|null $pod Pod data.
3255 * @param int|null $id Item ID.
3256 *
3257 * @return array
3258 *
3259 * @since 2.3.0
3260 */
3261 public function data_post_stati( $name = null, $value = null, $options = null, $pod = null, $id = null ) {
3262 $data = [];
3263
3264 $post_stati = get_post_stati( [], 'objects' );
3265
3266 foreach ( $post_stati as $post_status ) {
3267 $data[ $post_status->name ] = $post_status->label;
3268 }
3269
3270 return (array) apply_filters( 'pods_form_ui_field_pick_data_post_stati', $data, $name, $value, $options, $pod, $id );
3271 }
3272
3273 /**
3274 * Data callback for Post Stati (with any).
3275 *
3276 * @param string|null $name The name of the field.
3277 * @param string|array|null $value The value of the field.
3278 * @param array|null $options Field options.
3279 * @param array|null $pod Pod data.
3280 * @param int|null $id Item ID.
3281 *
3282 * @return array
3283 *
3284 * @since 2.9.10
3285 */
3286 public function data_post_stati_with_any( $name = null, $value = null, $options = null, $pod = null, $id = null ) {
3287 $data = [
3288 '_pods_any' => esc_html__( 'Any Status (excluding Auto-Draft and Trashed)', 'pods' ),
3289 ];
3290
3291 $data = array_merge( $data, $this->data_post_stati( $name, $value, $options, $pod, $id ) );
3292
3293 /**
3294 * Allow filtering the list of post stati with any.
3295 *
3296 * @since 2.9.10
3297 *
3298 * @param array $data The list of post stati with any.
3299 * @param string|null $name The name of the field.
3300 * @param string|array|null $value The value of the field.
3301 * @param array|null $options Field options.
3302 * @param array|null $pod Pod data.
3303 * @param int|null $id Item ID.
3304 */
3305 return (array) apply_filters( 'pods_form_ui_field_pick_data_post_stati_with_any', $data, $name, $value, $options, $pod, $id );
3306 }
3307
3308 /**
3309 * Data callback for User Roles.
3310 *
3311 * @param string|null $name The name of the field.
3312 * @param string|array|null $value The value of the field.
3313 * @param array|null $options Field options.
3314 * @param array|null $pod Pod data.
3315 * @param int|null $id Item ID.
3316 *
3317 * @return array
3318 *
3319 * @since 2.3.0
3320 */
3321 public function data_roles( $name = null, $value = null, $options = null, $pod = null, $id = null ) {
3322
3323 $data = array();
3324
3325 global $wp_roles;
3326
3327 foreach ( $wp_roles->role_objects as $key => $role ) {
3328 $data[ $key ] = $wp_roles->role_names[ $key ];
3329 }
3330
3331 return apply_filters( 'pods_form_ui_field_pick_data_roles', $data, $name, $value, $options, $pod, $id );
3332
3333 }
3334
3335 /**
3336 * Data callback for User Capabilities.
3337 *
3338 * @param string|null $name The name of the field.
3339 * @param string|array|null $value The value of the field.
3340 * @param array|null $options Field options.
3341 * @param array|null $pod Pod data.
3342 * @param int|null $id Item ID.
3343 *
3344 * @return array
3345 *
3346 * @since 2.3.0
3347 */
3348 public function data_capabilities( $name = null, $value = null, $options = null, $pod = null, $id = null ) {
3349
3350 $data = array();
3351
3352 global $wp_roles;
3353
3354 $default_caps = array(
3355 'activate_plugins',
3356 'add_users',
3357 'create_users',
3358 'delete_others_pages',
3359 'delete_others_posts',
3360 'delete_pages',
3361 'delete_plugins',
3362 'delete_posts',
3363 'delete_private_pages',
3364 'delete_private_posts',
3365 'delete_published_pages',
3366 'delete_published_posts',
3367 'delete_users',
3368 'edit_dashboard',
3369 'edit_files',
3370 'edit_others_pages',
3371 'edit_others_posts',
3372 'edit_pages',
3373 'edit_plugins',
3374 'edit_posts',
3375 'edit_private_pages',
3376 'edit_private_posts',
3377 'edit_published_pages',
3378 'edit_published_posts',
3379 'edit_theme_options',
3380 'edit_themes',
3381 'edit_users',
3382 'import',
3383 'install_plugins',
3384 'install_themes',
3385 'list_users',
3386 'manage_categories',
3387 'manage_links',
3388 'manage_options',
3389 'moderate_comments',
3390 'promote_users',
3391 'publish_pages',
3392 'publish_posts',
3393 'read',
3394 'read_private_pages',
3395 'read_private_posts',
3396 'remove_users',
3397 'switch_themes',
3398 'unfiltered_html',
3399 'unfiltered_upload',
3400 'update_core',
3401 'update_plugins',
3402 'update_themes',
3403 'upload_files',
3404 );
3405
3406 $role_caps = array();
3407
3408 foreach ( $wp_roles->role_objects as $key => $role ) {
3409 if ( is_array( $role->capabilities ) ) {
3410 foreach ( $role->capabilities as $cap => $grant ) {
3411 $role_caps[ $cap ] = $cap;
3412 }
3413 }
3414 }
3415
3416 $role_caps = array_unique( $role_caps );
3417
3418 $capabilities = array_merge( $default_caps, $role_caps );
3419
3420 // To support Members filters.
3421 $capabilities = apply_filters( 'members_get_capabilities', $capabilities );
3422
3423 $capabilities = apply_filters( 'pods_roles_get_capabilities', $capabilities );
3424
3425 sort( $capabilities );
3426
3427 $capabilities = array_unique( $capabilities );
3428
3429 global $wp_roles;
3430
3431 foreach ( $capabilities as $capability ) {
3432 $data[ $capability ] = $capability;
3433 }
3434
3435 return apply_filters( 'pods_form_ui_field_pick_data_capabilities', $data, $name, $value, $options, $pod, $id );
3436
3437 }
3438
3439 /**
3440 * Data callback for Image Sizes.
3441 *
3442 * @param string|null $name The name of the field.
3443 * @param string|array|null $value The value of the field.
3444 * @param array|null $options Field options.
3445 * @param array|null $pod Pod data.
3446 * @param int|null $id Item ID.
3447 *
3448 * @return array
3449 *
3450 * @since 2.3.0
3451 */
3452 public function data_image_sizes( $name = null, $value = null, $options = null, $pod = null, $id = null ) {
3453
3454 $data = array();
3455
3456 $image_sizes = get_intermediate_image_sizes();
3457
3458 foreach ( $image_sizes as $image_size ) {
3459 $data[ $image_size ] = ucwords( str_replace( '-', ' ', $image_size ) );
3460 }
3461
3462 return apply_filters( 'pods_form_ui_field_pick_data_image_sizes', $data, $name, $value, $options, $pod, $id );
3463
3464 }
3465
3466 /**
3467 * Data callback for Post Types
3468 *
3469 * @param string $name The name of the field
3470 * @param string|array $value The value of the field
3471 * @param array $options Field options
3472 * @param array $pod Pod data
3473 * @param int $id Item ID
3474 *
3475 * @return array
3476 *
3477 * @since 2.3.0
3478 */
3479 public function data_post_types( $name = null, $value = null, $options = null, $pod = null, $id = null ) {
3480
3481 $data = array();
3482
3483 $post_types = get_post_types( array(), 'objects' );
3484
3485 $ignore = [
3486 'revision',
3487 'nav_menu_item',
3488 'custom_css',
3489 'customize_changeset',
3490 'attachment',
3491 'oembed_cache',
3492 'user_request',
3493 'wp_block',
3494 'wp_template',
3495 'wp_template_part',
3496 'wp_global_styles',
3497 'wp_navigation',
3498 ];
3499
3500 foreach ( $post_types as $post_type ) {
3501 if ( in_array( $post_type->name, $ignore, true ) || 0 === strpos( $post_type->name, '_pods_' ) ) {
3502 continue;
3503 }
3504
3505 $data[ $post_type->name ] = $post_type->label;
3506 }
3507
3508 return apply_filters( 'pods_form_ui_field_pick_data_post_types', $data, $name, $value, $options, $pod, $id );
3509 }
3510
3511 /**
3512 * Data callback for Taxonomies
3513 *
3514 * @param string $name The name of the field
3515 * @param string|array $value The value of the field
3516 * @param array $options Field options
3517 * @param array $pod Pod data
3518 * @param int $id Item ID
3519 *
3520 * @return array
3521 *
3522 * @since 2.3.0
3523 */
3524 public function data_taxonomies( $name = null, $value = null, $options = null, $pod = null, $id = null ) {
3525
3526 $data = array();
3527
3528 $taxonomies = get_taxonomies( array(), 'objects' );
3529
3530 $ignore = array( 'nav_menu', 'post_format' );
3531
3532 foreach ( $taxonomies as $taxonomy ) {
3533 if ( in_array( $taxonomy->name, $ignore, true ) ) {
3534 continue;
3535 }
3536
3537 $data[ $taxonomy->name ] = $taxonomy->label;
3538 }
3539
3540 return apply_filters( 'pods_form_ui_field_pick_data_taxonomies', $data, $name, $value, $options, $pod, $id );
3541 }
3542
3543 /**
3544 * Data callback for Countries.
3545 *
3546 * @param string|null $name The name of the field.
3547 * @param string|array|null $value The value of the field.
3548 * @param array|null $options Field options.
3549 * @param array|null $pod Pod data.
3550 * @param int|null $id Item ID.
3551 *
3552 * @return array
3553 *
3554 * @since 2.3.0
3555 */
3556 public function data_countries( $name = null, $value = null, $options = null, $pod = null, $id = null ) {
3557
3558 $data = array(
3559 'AF' => __( 'Afghanistan' ),
3560 'AL' => __( 'Albania' ),
3561 'DZ' => __( 'Algeria' ),
3562 'AS' => __( 'American Samoa' ),
3563 'AD' => __( 'Andorra' ),
3564 'AO' => __( 'Angola' ),
3565 'AI' => __( 'Anguilla' ),
3566 'AQ' => __( 'Antarctica' ),
3567 'AG' => __( 'Antigua and Barbuda' ),
3568 'AR' => __( 'Argentina' ),
3569 'AM' => __( 'Armenia' ),
3570 'AW' => __( 'Aruba' ),
3571 'AU' => __( 'Australia' ),
3572 'AT' => __( 'Austria' ),
3573 'AZ' => __( 'Azerbaijan' ),
3574 'BS' => __( 'Bahamas' ),
3575 'BH' => __( 'Bahrain' ),
3576 'BD' => __( 'Bangladesh' ),
3577 'BB' => __( 'Barbados' ),
3578 'BY' => __( 'Belarus' ),
3579 'BE' => __( 'Belgium' ),
3580 'BZ' => __( 'Belize' ),
3581 'BJ' => __( 'Benin' ),
3582 'BM' => __( 'Bermuda' ),
3583 'BT' => __( 'Bhutan' ),
3584 'BO' => __( 'Bolivia' ),
3585 'BA' => __( 'Bosnia and Herzegovina' ),
3586 'BW' => __( 'Botswana' ),
3587 'BV' => __( 'Bouvet Island' ),
3588 'BR' => __( 'Brazil' ),
3589 'BQ' => __( 'British Antarctic Territory' ),
3590 'IO' => __( 'British Indian Ocean Territory' ),
3591 'VG' => __( 'British Virgin Islands' ),
3592 'BN' => __( 'Brunei' ),
3593 'BG' => __( 'Bulgaria' ),
3594 'BF' => __( 'Burkina Faso' ),
3595 'BI' => __( 'Burundi' ),
3596 'KH' => __( 'Cambodia' ),
3597 'CM' => __( 'Cameroon' ),
3598 'CA' => __( 'Canada' ),
3599 'CT' => __( 'Canton and Enderbury Islands' ),
3600 'CV' => __( 'Cape Verde' ),
3601 'KY' => __( 'Cayman Islands' ),
3602 'CF' => __( 'Central African Republic' ),
3603 'TD' => __( 'Chad' ),
3604 'CL' => __( 'Chile' ),
3605 'CN' => __( 'China' ),
3606 'CX' => __( 'Christmas Island' ),
3607 'CC' => __( 'Cocos [Keeling] Islands' ),
3608 'CO' => __( 'Colombia' ),
3609 'KM' => __( 'Comoros' ),
3610 'CG' => __( 'Congo - Brazzaville' ),
3611 'CD' => __( 'Congo - Kinshasa' ),
3612 'CK' => __( 'Cook Islands' ),
3613 'CR' => __( 'Costa Rica' ),
3614 'HR' => __( 'Croatia' ),
3615 'CU' => __( 'Cuba' ),
3616 'CY' => __( 'Cyprus' ),
3617 'CZ' => __( 'Czech Republic' ),
3618 'CI' => __( 'Côte d’Ivoire' ),
3619 'DK' => __( 'Denmark' ),
3620 'DJ' => __( 'Djibouti' ),
3621 'DM' => __( 'Dominica' ),
3622 'DO' => __( 'Dominican Republic' ),
3623 'NQ' => __( 'Dronning Maud Land' ),
3624 'DD' => __( 'East Germany' ),
3625 'EC' => __( 'Ecuador' ),
3626 'EG' => __( 'Egypt' ),
3627 'SV' => __( 'El Salvador' ),
3628 'GQ' => __( 'Equatorial Guinea' ),
3629 'ER' => __( 'Eritrea' ),
3630 'EE' => __( 'Estonia' ),
3631 'ET' => __( 'Ethiopia' ),
3632 'FK' => __( 'Falkland Islands' ),
3633 'FO' => __( 'Faroe Islands' ),
3634 'FJ' => __( 'Fiji' ),
3635 'FI' => __( 'Finland' ),
3636 'FR' => __( 'France' ),
3637 'GF' => __( 'French Guiana' ),
3638 'PF' => __( 'French Polynesia' ),
3639 'TF' => __( 'French Southern Territories' ),
3640 'FQ' => __( 'French Southern and Antarctic Territories' ),
3641 'GA' => __( 'Gabon' ),
3642 'GM' => __( 'Gambia' ),
3643 'GE' => __( 'Georgia' ),
3644 'DE' => __( 'Germany' ),
3645 'GH' => __( 'Ghana' ),
3646 'GI' => __( 'Gibraltar' ),
3647 'GR' => __( 'Greece' ),
3648 'GL' => __( 'Greenland' ),
3649 'GD' => __( 'Grenada' ),
3650 'GP' => __( 'Guadeloupe' ),
3651 'GU' => __( 'Guam' ),
3652 'GT' => __( 'Guatemala' ),
3653 'GG' => __( 'Guernsey' ),
3654 'GN' => __( 'Guinea' ),
3655 'GW' => __( 'Guinea-Bissau' ),
3656 'GY' => __( 'Guyana' ),
3657 'HT' => __( 'Haiti' ),
3658 'HM' => __( 'Heard Island and McDonald Islands' ),
3659 'HN' => __( 'Honduras' ),
3660 'HK' => __( 'Hong Kong SAR China' ),
3661 'HU' => __( 'Hungary' ),
3662 'IS' => __( 'Iceland' ),
3663 'IN' => __( 'India' ),
3664 'ID' => __( 'Indonesia' ),
3665 'IR' => __( 'Iran' ),
3666 'IQ' => __( 'Iraq' ),
3667 'IE' => __( 'Ireland' ),
3668 'IM' => __( 'Isle of Man' ),
3669 'IL' => __( 'Israel' ),
3670 'IT' => __( 'Italy' ),
3671 'JM' => __( 'Jamaica' ),
3672 'JP' => __( 'Japan' ),
3673 'JE' => __( 'Jersey' ),
3674 'JT' => __( 'Johnston Island' ),
3675 'JO' => __( 'Jordan' ),
3676 'KZ' => __( 'Kazakhstan' ),
3677 'KE' => __( 'Kenya' ),
3678 'KI' => __( 'Kiribati' ),
3679 'KW' => __( 'Kuwait' ),
3680 'KG' => __( 'Kyrgyzstan' ),
3681 'LA' => __( 'Laos' ),
3682 'LV' => __( 'Latvia' ),
3683 'LB' => __( 'Lebanon' ),
3684 'LS' => __( 'Lesotho' ),
3685 'LR' => __( 'Liberia' ),
3686 'LY' => __( 'Libya' ),
3687 'LI' => __( 'Liechtenstein' ),
3688 'LT' => __( 'Lithuania' ),
3689 'LU' => __( 'Luxembourg' ),
3690 'MO' => __( 'Macau SAR China' ),
3691 'MK' => __( 'Macedonia' ),
3692 'MG' => __( 'Madagascar' ),
3693 'MW' => __( 'Malawi' ),
3694 'MY' => __( 'Malaysia' ),
3695 'MV' => __( 'Maldives' ),
3696 'ML' => __( 'Mali' ),
3697 'MT' => __( 'Malta' ),
3698 'MH' => __( 'Marshall Islands' ),
3699 'MQ' => __( 'Martinique' ),
3700 'MR' => __( 'Mauritania' ),
3701 'MU' => __( 'Mauritius' ),
3702 'YT' => __( 'Mayotte' ),
3703 'FX' => __( 'Metropolitan France' ),
3704 'MX' => __( 'Mexico' ),
3705 'FM' => __( 'Micronesia' ),
3706 'MI' => __( 'Midway Islands' ),
3707 'MD' => __( 'Moldova' ),
3708 'MC' => __( 'Monaco' ),
3709 'MN' => __( 'Mongolia' ),
3710 'ME' => __( 'Montenegro' ),
3711 'MS' => __( 'Montserrat' ),
3712 'MA' => __( 'Morocco' ),
3713 'MZ' => __( 'Mozambique' ),
3714 'MM' => __( 'Myanmar [Burma]' ),
3715 'NA' => __( 'Namibia' ),
3716 'NR' => __( 'Nauru' ),
3717 'NP' => __( 'Nepal' ),
3718 'NL' => __( 'Netherlands' ),
3719 'AN' => __( 'Netherlands Antilles' ),
3720 'NT' => __( 'Neutral Zone' ),
3721 'NC' => __( 'New Caledonia' ),
3722 'NZ' => __( 'New Zealand' ),
3723 'NI' => __( 'Nicaragua' ),
3724 'NE' => __( 'Niger' ),
3725 'NG' => __( 'Nigeria' ),
3726 'NU' => __( 'Niue' ),
3727 'NF' => __( 'Norfolk Island' ),
3728 'KP' => __( 'North Korea' ),
3729 'VD' => __( 'North Vietnam' ),
3730 'MP' => __( 'Northern Mariana Islands' ),
3731 'NO' => __( 'Norway' ),
3732 'OM' => __( 'Oman' ),
3733 'PC' => __( 'Pacific Islands Trust Territory' ),
3734 'PK' => __( 'Pakistan' ),
3735 'PW' => __( 'Palau' ),
3736 'PS' => __( 'Palestinian Territories' ),
3737 'PA' => __( 'Panama' ),
3738 'PZ' => __( 'Panama Canal Zone' ),
3739 'PG' => __( 'Papua New Guinea' ),
3740 'PY' => __( 'Paraguay' ),
3741 'YD' => __( "People's Democratic Republic of Yemen" ),
3742 'PE' => __( 'Peru' ),
3743 'PH' => __( 'Philippines' ),
3744 'PN' => __( 'Pitcairn Islands' ),
3745 'PL' => __( 'Poland' ),
3746 'PT' => __( 'Portugal' ),
3747 'PR' => __( 'Puerto Rico' ),
3748 'QA' => __( 'Qatar' ),
3749 'RO' => __( 'Romania' ),
3750 'RU' => __( 'Russia' ),
3751 'RW' => __( 'Rwanda' ),
3752 'RE' => __( 'Réunion' ),
3753 'BL' => __( 'Saint Barthélemy' ),
3754 'SH' => __( 'Saint Helena' ),
3755 'KN' => __( 'Saint Kitts and Nevis' ),
3756 'LC' => __( 'Saint Lucia' ),
3757 'MF' => __( 'Saint Martin' ),
3758 'PM' => __( 'Saint Pierre and Miquelon' ),
3759 'VC' => __( 'Saint Vincent and the Grenadines' ),
3760 'WS' => __( 'Samoa' ),
3761 'SM' => __( 'San Marino' ),
3762 'SA' => __( 'Saudi Arabia' ),
3763 'SN' => __( 'Senegal' ),
3764 'RS' => __( 'Serbia' ),
3765 'CS' => __( 'Serbia and Montenegro' ),
3766 'SC' => __( 'Seychelles' ),
3767 'SL' => __( 'Sierra Leone' ),
3768 'SG' => __( 'Singapore' ),
3769 'SK' => __( 'Slovakia' ),
3770 'SI' => __( 'Slovenia' ),
3771 'SB' => __( 'Solomon Islands' ),
3772 'SO' => __( 'Somalia' ),
3773 'ZA' => __( 'South Africa' ),
3774 'GS' => __( 'South Georgia and the South Sandwich Islands' ),
3775 'KR' => __( 'South Korea' ),
3776 'ES' => __( 'Spain' ),
3777 'LK' => __( 'Sri Lanka' ),
3778 'SD' => __( 'Sudan' ),
3779 'SR' => __( 'Suriname' ),
3780 'SJ' => __( 'Svalbard and Jan Mayen' ),
3781 'SZ' => __( 'Swaziland' ),
3782 'SE' => __( 'Sweden' ),
3783 'CH' => __( 'Switzerland' ),
3784 'SY' => __( 'Syria' ),
3785 'ST' => __( 'São Tomé and Príncipe' ),
3786 'TW' => __( 'Taiwan' ),
3787 'TJ' => __( 'Tajikistan' ),
3788 'TZ' => __( 'Tanzania' ),
3789 'TH' => __( 'Thailand' ),
3790 'TL' => __( 'Timor-Leste' ),
3791 'TG' => __( 'Togo' ),
3792 'TK' => __( 'Tokelau' ),
3793 'TO' => __( 'Tonga' ),
3794 'TT' => __( 'Trinidad and Tobago' ),
3795 'TN' => __( 'Tunisia' ),
3796 'TR' => __( 'Turkey' ),
3797 'TM' => __( 'Turkmenistan' ),
3798 'TC' => __( 'Turks and Caicos Islands' ),
3799 'TV' => __( 'Tuvalu' ),
3800 'UM' => __( 'U.S. Minor Outlying Islands' ),
3801 'PU' => __( 'U.S. Miscellaneous Pacific Islands' ),
3802 'VI' => __( 'U.S. Virgin Islands' ),
3803 'UG' => __( 'Uganda' ),
3804 'UA' => __( 'Ukraine' ),
3805 'SU' => __( 'Union of Soviet Socialist Republics' ),
3806 'AE' => __( 'United Arab Emirates' ),
3807 'GB' => __( 'United Kingdom' ),
3808 'US' => __( 'United States' ),
3809 'ZZ' => __( 'Unknown or Invalid Region' ),
3810 'UY' => __( 'Uruguay' ),
3811 'UZ' => __( 'Uzbekistan' ),
3812 'VU' => __( 'Vanuatu' ),
3813 'VA' => __( 'Vatican City' ),
3814 'VE' => __( 'Venezuela' ),
3815 'VN' => __( 'Vietnam' ),
3816 'WK' => __( 'Wake Island' ),
3817 'WF' => __( 'Wallis and Futuna' ),
3818 'EH' => __( 'Western Sahara' ),
3819 'YE' => __( 'Yemen' ),
3820 'ZM' => __( 'Zambia' ),
3821 'ZW' => __( 'Zimbabwe' ),
3822 'AX' => __( '�
3823 land Islands' ),
3824 );
3825
3826 return apply_filters( 'pods_form_ui_field_pick_data_countries', $data, $name, $value, $options, $pod, $id );
3827
3828 }
3829
3830 /**
3831 * Data callback for US States.
3832 *
3833 * @param string|null $name The name of the field.
3834 * @param string|array|null $value The value of the field.
3835 * @param array|null $options Field options.
3836 * @param array|null $pod Pod data.
3837 * @param int|null $id Item ID.
3838 *
3839 * @return array
3840 *
3841 * @since 2.3.0
3842 */
3843 public function data_us_states( $name = null, $value = null, $options = null, $pod = null, $id = null ) {
3844
3845 $data = array(
3846 'AL' => __( 'Alabama' ),
3847 'AK' => __( 'Alaska' ),
3848 'AZ' => __( 'Arizona' ),
3849 'AR' => __( 'Arkansas' ),
3850 'CA' => __( 'California' ),
3851 'CO' => __( 'Colorado' ),
3852 'CT' => __( 'Connecticut' ),
3853 'DE' => __( 'Delaware' ),
3854 'DC' => __( 'District Of Columbia' ),
3855 'FL' => __( 'Florida' ),
3856 'GA' => __( 'Georgia' ),
3857 'HI' => __( 'Hawaii' ),
3858 'ID' => __( 'Idaho' ),
3859 'IL' => __( 'Illinois' ),
3860 'IN' => __( 'Indiana' ),
3861 'IA' => __( 'Iowa' ),
3862 'KS' => __( 'Kansas' ),
3863 'KY' => __( 'Kentucky' ),
3864 'LA' => __( 'Louisiana' ),
3865 'ME' => __( 'Maine' ),
3866 'MD' => __( 'Maryland' ),
3867 'MA' => __( 'Massachusetts' ),
3868 'MI' => __( 'Michigan' ),
3869 'MN' => __( 'Minnesota' ),
3870 'MS' => __( 'Mississippi' ),
3871 'MO' => __( 'Missouri' ),
3872 'MT' => __( 'Montana' ),
3873 'NE' => __( 'Nebraska' ),
3874 'NV' => __( 'Nevada' ),
3875 'NH' => __( 'New Hampshire' ),
3876 'NJ' => __( 'New Jersey' ),
3877 'NM' => __( 'New Mexico' ),
3878 'NY' => __( 'New York' ),
3879 'NC' => __( 'North Carolina' ),
3880 'ND' => __( 'North Dakota' ),
3881 'OH' => __( 'Ohio' ),
3882 'OK' => __( 'Oklahoma' ),
3883 'OR' => __( 'Oregon' ),
3884 'PA' => __( 'Pennsylvania' ),
3885 'RI' => __( 'Rhode Island' ),
3886 'SC' => __( 'South Carolina' ),
3887 'SD' => __( 'South Dakota' ),
3888 'TN' => __( 'Tennessee' ),
3889 'TX' => __( 'Texas' ),
3890 'UT' => __( 'Utah' ),
3891 'VT' => __( 'Vermont' ),
3892 'VA' => __( 'Virginia' ),
3893 'WA' => __( 'Washington' ),
3894 'WV' => __( 'West Virginia' ),
3895 'WI' => __( 'Wisconsin' ),
3896 'WY' => __( 'Wyoming' ),
3897 );
3898
3899 return apply_filters( 'pods_form_ui_field_pick_data_us_states', $data, $name, $value, $options, $pod, $id );
3900
3901 }
3902
3903 /**
3904 * Data callback for CA Provinces.
3905 *
3906 * @param string|null $name The name of the field.
3907 * @param string|array|null $value The value of the field.
3908 * @param array|null $options Field options.
3909 * @param array|null $pod Pod data.
3910 * @param int|null $id Item ID.
3911 *
3912 * @return array
3913 *
3914 * @since 2.3.0
3915 */
3916 public function data_ca_provinces( $name = null, $value = null, $options = null, $pod = null, $id = null ) {
3917
3918 $data = array(
3919 'AB' => __( 'Alberta' ),
3920 'BC' => __( 'British Columbia' ),
3921 'MB' => __( 'Manitoba' ),
3922 'NB' => __( 'New Brunswick' ),
3923 'NL' => __( 'Newfoundland and Labrador' ),
3924 'NT' => __( 'Northwest Territories' ),
3925 'NS' => __( 'Nova Scotia' ),
3926 'NU' => __( 'Nunavut' ),
3927 'ON' => __( 'Ontario' ),
3928 'PE' => __( 'Prince Edward Island' ),
3929 'QC' => __( 'Quebec' ),
3930 'SK' => __( 'Saskatchewan' ),
3931 'YT' => __( 'Yukon' ),
3932 );
3933
3934 return apply_filters( 'pods_form_ui_field_pick_data_ca_provinces', $data, $name, $value, $options, $pod, $id );
3935
3936 }
3937
3938 /**
3939 * Data callback for Days of the Week.
3940 *
3941 * @param string|null $name The name of the field.
3942 * @param string|array|null $value The value of the field.
3943 * @param array|null $options Field options.
3944 * @param array|null $pod Pod data.
3945 * @param int|null $id Item ID.
3946 *
3947 * @return array
3948 *
3949 * @since 2.3.0
3950 */
3951 public function data_days_of_week( $name = null, $value = null, $options = null, $pod = null, $id = null ) {
3952
3953 /**
3954 * @var WP_Locale
3955 */
3956 global $wp_locale;
3957
3958 return $wp_locale->weekday;
3959
3960 }
3961
3962 /**
3963 * Data callback for Months of the Year.
3964 *
3965 * @param string|null $name The name of the field.
3966 * @param string|array|null $value The value of the field.
3967 * @param array|null $options Field options.
3968 * @param array|null $pod Pod data.
3969 * @param int|null $id Item ID.
3970 *
3971 * @return array
3972 *
3973 * @since 2.3.0
3974 */
3975 public function data_months_of_year( $name = null, $value = null, $options = null, $pod = null, $id = null ) {
3976
3977 /**
3978 * @var WP_Locale
3979 */
3980 global $wp_locale;
3981
3982 return $wp_locale->month;
3983
3984 }
3985
3986 /**
3987 * Add our modal input to the form so we can track whether we're in our modal during saving or not.
3988 */
3989 public function admin_modal_input() {
3990
3991 if ( ! pods_is_modal_window() ) {
3992 return;
3993 }
3994
3995 echo '<input name="pods_modal" type="hidden" value="1" />';
3996
3997 }
3998
3999 /**
4000 * Bail to send new saved data back to our modal handler.
4001 *
4002 * @param int $item_id Item ID.
4003 * @param string $item_title Item title.
4004 * @param object $field_args Field arguments.
4005 */
4006 public function admin_modal_bail( $item_id, $item_title, $field_args ) {
4007
4008 $model_data = $this->build_dfv_field_item_data_recurse_item( $item_id, $item_title, $field_args );
4009 ?>
4010 <script type="text/javascript">
4011 window.parent.postMessage( {
4012 type: 'PODS_MESSAGE',
4013 data: <?php echo wp_json_encode( $model_data, JSON_HEX_TAG ); ?>,
4014 }, window.location.origin );
4015 </script>
4016 <?php
4017
4018 die();
4019
4020 }
4021
4022 /**
4023 * Bail to send new saved data back to our modal handler.
4024 *
4025 * @param int $item_id Item ID.
4026 * @param string $item_title Item title.
4027 * @param object $field_args Field arguments.
4028 */
4029 public function admin_modal_bail_JSON( $item_id, $item_title, $field_args ) {
4030
4031 $model_data = $this->build_dfv_field_item_data_recurse_item( $item_id, $item_title, $field_args );
4032 echo wp_json_encode( $model_data, JSON_HEX_TAG );
4033
4034 die();
4035 }
4036
4037 /**
4038 * Bail on Post save redirect for Admin modal.
4039 *
4040 * @param string $location The destination URL.
4041 * @param int $post_id The post ID.
4042 *
4043 * @return string
4044 */
4045 public function admin_modal_bail_post_redirect( $location, $post_id ) {
4046
4047 if ( ! pods_is_modal_window() ) {
4048 return $location;
4049 }
4050
4051 $post_title = get_the_title( $post_id );
4052
4053 $field_args = (object) array(
4054 'options' => array(
4055 'pick_object' => 'post_type',
4056 'pick_val' => get_post_type( $post_id ),
4057 ),
4058 'value' => array(
4059 $post_id => $post_title,
4060 ),
4061 );
4062
4063 $this->admin_modal_bail( $post_id, $post_title, $field_args );
4064
4065 return $location;
4066
4067 }
4068
4069 /**
4070 * Hook into term updating process to bail on redirect.
4071 */
4072 public function admin_modal_bail_term_action() {
4073
4074 if ( ! pods_is_modal_window() ) {
4075 return;
4076 }
4077
4078 if ( function_exists( 'get_current_screen' ) ) {
4079 $screen = get_current_screen();
4080
4081 if ( 'edit-tags' === $screen->base ) {
4082 // @todo Need more effort on the solution for add new handling.
4083 //add_action( 'admin_footer', [ $this, 'admin_modal_bail_term_action_add_new' ], 20 );
4084 }
4085 }
4086
4087 add_action( 'created_term', array( $this, 'admin_modal_bail_term' ), 10, 3 );
4088 add_action( 'edited_term', array( $this, 'admin_modal_bail_term' ), 10, 3 );
4089
4090 }
4091
4092 /**
4093 * Hook into term creation process to bail after success.
4094 *
4095 * @todo Try and catch the added tr node on the table tbody.
4096 */
4097 public function admin_modal_bail_term_action_add_new() {
4098 ?>
4099 <script type="text/javascript">
4100 jQuery( function ( $ ) {
4101 /** @var {jQuery.Event} e */
4102 $( '.tags' ).on( 'DOMSubtreeModified', function(e) {
4103 console.log( e );
4104
4105 if ( !== e.target.is( 'tbody#the-list' ) ) {
4106 return;
4107 }
4108
4109 const $theTermRow = $( e.target.innerHTML() );
4110 const titleRow = $theTermRow.find( '.column-name .row-title' );
4111 const actionView = $theTermRow.find( '.row-actions span.view a' );
4112
4113 const termData = {
4114 id : $theTermRow.find( '.check-column input' ).val(),
4115 icon : '',
4116 name : titleRow.text(),
4117 edit_link: titleRow.prop( 'href' ),
4118 link : actionView[0] ? actionView.prop( 'href' ) : '',
4119 selected : true,
4120 };
4121
4122 console.log( termData );
4123
4124 window.parent.postMessage( {
4125 type : 'PODS_MESSAGE',
4126 data : termData,
4127 }, window.location.origin );
4128 } );
4129 } );
4130 </script>
4131 <?php
4132 }
4133
4134 /**
4135 * Bail on Term save redirect for Admin modal.
4136 *
4137 * @param int $term_id Term ID.
4138 * @param int $tt_id Term taxonomy ID.
4139 * @param string $taxonomy Taxonomy slug.
4140 */
4141 public function admin_modal_bail_term( $term_id, $tt_id, $taxonomy ) {
4142
4143 if ( ! pods_is_modal_window() ) {
4144 return;
4145 }
4146
4147 $term = get_term( $term_id );
4148
4149 if ( ! $term || is_wp_error( $term ) ) {
4150 return;
4151 }
4152
4153 $field_args = (object) array(
4154 'options' => array(
4155 'pick_object' => 'taxonomy',
4156 'pick_val' => $term->taxonomy,
4157 ),
4158 'value' => array(
4159 $term->term_id => $term->name,
4160 ),
4161 );
4162
4163 $this->admin_modal_bail( $term->term_id, $term->name, $field_args );
4164
4165 }
4166
4167 /**
4168 * Hook into user updating process to bail on redirect.
4169 */
4170 public function admin_modal_bail_user_action() {
4171
4172 if ( ! pods_is_modal_window() ) {
4173 return;
4174 }
4175
4176 add_filter( 'wp_redirect', array( $this, 'admin_modal_bail_user_redirect' ) );
4177
4178 }
4179
4180 /**
4181 * Bail on User save redirect for Admin modal.
4182 *
4183 * @param string $location The destination URL.
4184 *
4185 * @return string
4186 */
4187 public function admin_modal_bail_user_redirect( $location ) {
4188
4189 if ( ! pods_is_modal_window() ) {
4190 return $location;
4191 }
4192
4193 global $user_id;
4194
4195 $user = get_userdata( $user_id );
4196
4197 if ( ! $user ) {
4198 return $location;
4199 }
4200
4201 $field_args = (object) array(
4202 'options' => array(
4203 'pick_object' => 'user',
4204 'pick_val' => '',
4205 ),
4206 'value' => array(
4207 $user->ID => $user->display_name,
4208 ),
4209 );
4210
4211 $this->admin_modal_bail( $user->ID, $user->display_name, $field_args );
4212
4213 return $location;
4214
4215 }
4216
4217 /**
4218 * Bail on Pod item save for Admin modal.
4219 *
4220 * @param int $id Item ID.
4221 * @param array $params save_pod_item parameters.
4222 * @param null|Pods $obj Pod object (if set).
4223 */
4224 public function admin_modal_bail_pod( $id, $params, $obj ) {
4225
4226 if ( ! pods_is_modal_window() ) {
4227 return;
4228 }
4229
4230 if ( ! $obj ) {
4231 $obj = pods_get_instance( $params['pod'] );
4232 }
4233
4234 if ( ! $obj || ! $obj->fetch( $id ) ) {
4235 return;
4236 }
4237
4238 $item_id = $obj->id();
4239 $item_title = $obj->index();
4240
4241 $field_args = (object) array(
4242 'options' => array(
4243 'pick_object' => $obj->pod_data['type'],
4244 'pick_val' => $obj->pod,
4245 ),
4246 'value' => array(
4247 $obj->id() => $item_title,
4248 ),
4249 );
4250
4251 $this->admin_modal_bail_JSON( $item_id, $item_title, $field_args );
4252
4253 }
4254
4255 /**
4256 * Build field data for Pods DFV.
4257 *
4258 * @param object $args {
4259 * Field information arguments.
4260 *
4261 * @type string $name Field name.
4262 * @type string $type Field type.
4263 * @type array $options Field options.
4264 * @type mixed $value Current value.
4265 * @type array $pod Pod information.
4266 * @type int|string $id Current item ID.
4267 * @type string $form_field_type HTML field type.
4268 * }
4269 *
4270 * @return array
4271 */
4272 public function build_dfv_field_data( $args ) {
4273 $data = parent::build_dfv_field_data( $args );
4274
4275 // Normalize arrays for multiple select.
4276 if ( is_array( $data['fieldValue'] ) ) {
4277 $data['fieldValue'] = array_values( $data['fieldValue'] );
4278 }
4279
4280 return $data;
4281 }
4282
4283 }
4284