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