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