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