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