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