Completed
Pull Request — 2.x (#4370)
by
unknown
05:02
created

PodsField_Pick::bidirectional_objects()   B

Complexity

Conditions 6
Paths 2

Size

Total Lines 19
Code Lines 9

Duplication

Lines 16
Ratio 84.21 %

Importance

Changes 0
Metric Value
cc 6
eloc 9
nc 2
nop 0
dl 16
loc 19
rs 8.8571
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * @package Pods\Fields
5
 */
6
class PodsField_Pick extends PodsField {
7
8
	/**
9
	 * {@inheritdoc}
10
	 */
11
	public static $group = 'Relationships / Media';
12
13
	/**
14
	 * {@inheritdoc}
15
	 */
16
	public static $type = 'pick';
17
18
	/**
19
	 * {@inheritdoc}
20
	 */
21
	public static $label = 'Relationship';
22
23
	/**
24
	 * Available Related Objects.
25
	 *
26
	 * @var array
27
	 * @since 2.3
28
	 */
29
	public static $related_objects = array();
30
31
	/**
32
	 * Custom Related Objects
33
	 *
34
	 * @var array
35
	 * @since 2.3
36
	 */
37
	public static $custom_related_objects = array();
38
39
	/**
40
	 * Data used during validate / save to avoid extra queries.
41
	 *
42
	 * @var array
43
	 * @since 2.3
44
	 */
45
	public static $related_data = array();
46
47
	/**
48
	 * Data used during input method (mainly for autocomplete).
49
	 *
50
	 * @var array
51
	 * @since 2.3
52
	 */
53
	public static $field_data = array();
54
55
	/**
56
	 * API caching for fields that need it during validate/save.
57
	 *
58
	 * @var \PodsAPI
59
	 * @since 2.3
60
	 */
61
	protected static $api = false;
62
63
	/**
64
	 * Saved array of simple relationship names.
65
	 *
66
	 * @var array
67
	 * @since 2.5
68
	 */
69
	private static $names_simple = null;
70
71
	/**
72
	 * Saved array of relationship names
73
	 *
74
	 * @var array
75
	 * @since 2.5
76
	 */
77
	private static $names_related = null;
78
79
	/**
80
	 * Saved array of bidirectional relationship names
81
	 *
82
	 * @var array
83
	 * @since 2.5
84
	 */
85
	private static $names_bidirectional = null;
86
87
	/**
88
	 * {@inheritdoc}
89
	 */
90
	public function __construct() {
91
92
		self::$label = __( 'Relationship', 'pods' );
93
	}
94
95
	/**
96
	 * Add admin_init actions.
97
	 *
98
	 * @since 2.3
99
	 */
100
	public function admin_init() {
101
102
		// AJAX for Relationship lookups.
103
		add_action( 'wp_ajax_pods_relationship', array( $this, 'admin_ajax_relationship' ) );
104
		add_action( 'wp_ajax_nopriv_pods_relationship', array( $this, 'admin_ajax_relationship' ) );
105
106
		// Handle modal input.
107
		add_action( 'edit_form_top', array( $this, 'admin_modal_input' ) );
108
		add_action( 'show_user_profile', array( $this, 'admin_modal_input' ) );
109
		add_action( 'edit_user_profile', array( $this, 'admin_modal_input' ) );
110
		add_action( 'edit_category_form', array( $this, 'admin_modal_input' ) );
111
		add_action( 'edit_link_category_form', array( $this, 'admin_modal_input' ) );
112
		add_action( 'edit_tag_form', array( $this, 'admin_modal_input' ) );
113
		add_action( 'add_tag_form', array( $this, 'admin_modal_input' ) );
114
		add_action( 'pods_meta_box_pre', array( $this, 'admin_modal_input' ) );
115
116
		// Handle modal saving.
117
		add_filter( 'redirect_post_location', array( $this, 'admin_modal_bail_post_redirect' ), 10, 2 );
118
		add_action( 'load-edit-tags.php', array( $this, 'admin_modal_bail_term_action' ) );
119
		add_action( 'load-categories.php', array( $this, 'admin_modal_bail_term_action' ) );
120
		add_action( 'load-edit-link-categories.php', array( $this, 'admin_modal_bail_term_action' ) );
121
		add_action( 'personal_options_update', array( $this, 'admin_modal_bail_user_action' ) );
122
		add_action( 'user_register', array( $this, 'admin_modal_bail_user_action' ) );
123
		add_action( 'pods_api_processed_form', array( $this, 'admin_modal_bail_pod' ), 10, 3 );
124
125
	}
126
127
	/**
128
	 * {@inheritdoc}
129
	 */
130
	public function options() {
131
132
		$options = array(
133
			self::$type . '_format_type'    => array(
134
				'label'      => __( 'Selection Type', 'pods' ),
135
				'help'       => __( 'help', 'pods' ),
136
				'default'    => 'single',
137
				'type'       => 'pick',
138
				'data'       => array(
139
					'single' => __( 'Single Select', 'pods' ),
140
					'multi'  => __( 'Multiple Select', 'pods' ),
141
				),
142
				'dependency' => true,
143
			),
144
			self::$type . '_format_single'  => array(
145
				'label'      => __( 'Format', 'pods' ),
146
				'help'       => __( 'help', 'pods' ),
147
				'depends-on' => array( self::$type . '_format_type' => 'single' ),
148
				'default'    => 'dropdown',
149
				'type'       => 'pick',
150
				'data'       => apply_filters( 'pods_form_ui_field_pick_format_single_options', array(
151
						'dropdown'     => __( 'Drop Down', 'pods' ),
152
						'radio'        => __( 'Radio Buttons', 'pods' ),
153
						'autocomplete' => __( 'Autocomplete', 'pods' ),
154
						'list'         => __( 'List view', 'pods' ),
155
					)
156
				),
157
				'dependency' => true,
158
			),
159
			self::$type . '_format_multi'   => array(
160
				'label'      => __( 'Format', 'pods' ),
161
				'help'       => __( 'help', 'pods' ),
162
				'depends-on' => array( self::$type . '_format_type' => 'multi' ),
163
				'default'    => 'checkbox',
164
				'type'       => 'pick',
165
				'data'       => apply_filters( 'pods_form_ui_field_pick_format_multi_options', array(
166
						'checkbox'     => __( 'Checkboxes', 'pods' ),
167
						'multiselect'  => __( 'Multi Select', 'pods' ),
168
						'autocomplete' => __( 'Autocomplete', 'pods' ),
169
						'list'         => __( 'List view', 'pods' ),
170
					)
171
				),
172
				'dependency' => true,
173
			),
174
			self::$type . '_allow_add_new' => array(
175
				'label'       => __( 'Allow Add New', 'pods' ),
176
				'help'        => __( 'Allow new related records to be created in a modal window', 'pods' ),
177
				'wildcard-on' => array(
178
					self::$type . '_object' => array( '^post-type-(?!(custom-css|customize-changeset)).*$', '^taxonomy-.*$', '^user$', '^pod-.*$' )
179
				),
180
				'type'        => 'boolean',
181
				'default'     => 1
182
			),
183
			self::$type . '_taggable'       => array(
184
				'label'       => __( 'Taggable', 'pods' ),
185
				'help'        => __( 'Allow new values to be inserted when using an Autocomplete field', 'pods' ),
186
				'excludes-on' => array(
187
					self::$type . '_format_single' => array( 'dropdown', 'radio', 'list' ),
188
					self::$type . '_format_multi'  => array( 'checkbox', 'multiselect', 'list' ),
189
					self::$type . '_object'        => array_merge( array( 'site', 'network' ), self::simple_objects() ),
190
				),
191
				'type'        => 'boolean',
192
				'default'     => 0,
193
			),
194
			self::$type . '_show_icon'      => array(
195
				'label'       => __( 'Show Icons', 'pods' ),
196
				'excludes-on' => array(
197
					self::$type . '_format_single' => array( 'dropdown', 'radio', 'autocomplete' ),
198
					self::$type . '_format_multi'  => array( 'checkbox', 'multiselect', 'autocomplete' ),
199
					self::$type . '_object'        => array_merge( array( 'site', 'network' ), self::simple_objects() ),
200
				),
201
				'type'        => 'boolean',
202
				'default'     => 1,
203
			),
204
			self::$type . '_show_edit_link' => array(
205
				'label'       => __( 'Show Edit Links', 'pods' ),
206
				'excludes-on' => array(
207
					self::$type . '_format_single' => array( 'dropdown', 'radio', 'autocomplete' ),
208
					self::$type . '_format_multi'  => array( 'checkbox', 'multiselect', 'autocomplete' ),
209
					self::$type . '_object'        => array_merge( array( 'site', 'network' ), self::simple_objects() ),
210
				),
211
				'type'        => 'boolean',
212
				'default'     => 1,
213
			),
214
			self::$type . '_show_view_link' => array(
215
				'label'       => __( 'Show View Links', 'pods' ),
216
				'excludes-on' => array(
217
					self::$type . '_format_single' => array( 'dropdown', 'radio', 'autocomplete' ),
218
					self::$type . '_format_multi'  => array( 'checkbox', 'multiselect', 'autocomplete' ),
219
					self::$type . '_object'        => array_merge( array( 'site', 'network' ), self::simple_objects() ),
220
				),
221
				'type'        => 'boolean',
222
				'default'     => 1,
223
			),
224
			self::$type . '_select_text'    => array(
225
				'label'      => __( 'Default Select Text', 'pods' ),
226
				'help'       => __( 'This is the text use for the default "no selection" dropdown item, if empty, it will default to "-- Select One --"', 'pods' ),
227
				'depends-on' => array(
228
					self::$type . '_format_type'   => 'single',
229
					self::$type . '_format_single' => 'dropdown',
230
				),
231
				'default'    => '',
232
				'type'       => 'text',
233
			),
234
			self::$type . '_limit'          => array(
235
				'label'      => __( 'Selection Limit', 'pods' ),
236
				'help'       => __( 'help', 'pods' ),
237
				'depends-on' => array( self::$type . '_format_type' => 'multi' ),
238
				'default'    => 0,
239
				'type'       => 'number',
240
			),
241
			self::$type . '_table_id'       => array(
242
				'label'      => __( 'Table ID Column', 'pods' ),
243
				'help'       => __( 'You must provide the ID column name for the table, this will be used to keep track of the relationship', 'pods' ),
244
				'depends-on' => array( self::$type . '_object' => 'table' ),
245
				'required'   => 1,
246
				'default'    => '',
247
				'type'       => 'text',
248
			),
249
			self::$type . '_table_index'    => array(
250
				'label'      => __( 'Table Index Column', 'pods' ),
251
				'help'       => __( 'You must provide the index column name for the table, this may optionally also be the ID column name', 'pods' ),
252
				'depends-on' => array( self::$type . '_object' => 'table' ),
253
				'required'   => 1,
254
				'default'    => '',
255
				'type'       => 'text',
256
			),
257
			self::$type . '_display'        => array(
258
				'label'       => __( 'Display Field in Selection List', 'pods' ),
259
				'help'        => __( 'Provide the name of a field on the related object to reference, example: {@post_title}', 'pods' ),
260
				'excludes-on' => array(
261
					self::$type . '_object' => array_merge( array( 'site', 'network' ), self::simple_objects() ),
262
				),
263
				'default'     => '',
264
				'type'        => 'text',
265
			),
266
			self::$type . '_user_role'      => array(
267
				'label'            => __( 'Limit list to Role(s)', 'pods' ),
268
				'help'             => __( 'help', 'pods' ),
269
				'depends-on'       => array( self::$type . '_object' => 'user' ),
270
				'default'          => '',
271
				'type'             => 'pick',
272
				'pick_object'      => 'role',
273
				'pick_format_type' => 'multi',
274
			),
275
			/*
0 ignored issues
show
Unused Code Comprehensibility introduced by
54% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
276
            self::$type . '_user_site' => array(
277
                'label' => __( 'Limit list to Site(s)', 'pods' ),
278
                'help' => __( 'help', 'pods' ),
279
                'depends-on' => array( self::$type . '_object' => 'user' ),
280
                'default' => '',
281
                'type' => 'pick',
282
                'pick_object' => 'site',
283
                'pick_format_type' => 'multi',
284
            ),
285
			*/
286
			self::$type . '_where'          => array(
287
				'label'       => __( 'Customized <em>WHERE</em>', 'pods' ),
288
				'help'        => __( 'help', 'pods' ),
289
				'excludes-on' => array(
290
					self::$type . '_object' => array_merge( array( 'site', 'network' ), self::simple_objects() ),
291
				),
292
				'default'     => '',
293
				'type'        => 'text',
294
			),
295
			self::$type . '_orderby'        => array(
296
				'label'       => __( 'Customized <em>ORDER BY</em>', 'pods' ),
297
				'help'        => __( 'help', 'pods' ),
298
				'excludes-on' => array(
299
					self::$type . '_object' => array_merge( array( 'site', 'network' ), self::simple_objects() ),
300
				),
301
				'default'     => '',
302
				'type'        => 'text',
303
			),
304
			self::$type . '_groupby'        => array(
305
				'label'       => __( 'Customized <em>GROUP BY</em>', 'pods' ),
306
				'help'        => __( 'help', 'pods' ),
307
				'excludes-on' => array(
308
					self::$type . '_object' => array_merge( array( 'site', 'network' ), self::simple_objects() ),
309
				),
310
				'default'     => '',
311
				'type'        => 'text',
312
			),
313
			/*
0 ignored issues
show
Unused Code Comprehensibility introduced by
53% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
314
			self::$type . '_size' => array(
315
				'label' => __( 'Field Size', 'pods' ),
316
				'default' => 'medium',
317
				'type' => 'pick',
318
				'data' => array(
319
					'small' => __( 'Small', 'pods' ),
320
					'medium' => __( 'Medium', 'pods' ),
321
					'large' => __( 'Large', 'pods' )
322
				)
323
			),
324
			*/
325
		);
326
327
		$post_type_pick_objects = array();
328
329
		foreach ( get_post_types( '', 'names' ) as $post_type ) {
330
			$post_type_pick_objects[] = 'post-type_' . $post_type;
331
		}
332
333
		$options[ self::$type . '_post_status' ] = array(
334
			'name'             => 'post_status',
335
			'label'            => __( 'Post Status', 'pods' ),
336
			'help'             => __( 'help', 'pods' ),
337
			'type'             => 'pick',
338
			'pick_object'      => 'post-status',
339
			'pick_format_type' => 'multi',
340
			'default'          => 'publish',
341
			'depends-on'       => array(
342
				self::$type . '_object' => $post_type_pick_objects,
343
			),
344
		);
345
346
		/*
0 ignored issues
show
Unused Code Comprehensibility introduced by
55% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
347
		if ( ! is_multisite() ) {
348
			unset( $options[ self::$type . '_user_site' ] );
349
		}
350
		*/
351
352
		return $options;
353
354
	}
355
356
	/**
357
	 * Register a related object
358
	 *
359
	 * @param string $name    Object name
360
	 * @param string $label   Object label
361
	 * @param array  $options Object options
362
	 *
363
	 * @return array|boolean Object array or false if unsuccessful
364
	 * @since 2.3
365
	 */
366
	public function register_related_object( $name, $label, $options = null ) {
367
368
		if ( empty( $name ) || empty( $label ) ) {
369
			return false;
370
		}
371
372
		$related_object = array(
373
			'label'         => $label,
374
			'group'         => 'Custom Relationships',
375
			'simple'        => true,
376
			'bidirectional' => false,
377
			'data'          => array(),
378
			'data_callback' => null,
379
		);
380
381
		$related_object = array_merge( $related_object, $options );
382
383
		self::$custom_related_objects[ $name ] = $related_object;
384
385
		return true;
386
387
	}
388
389
	/**
390
	 * Setup related objects
391
	 *
392
	 * @param boolean $force Whether to force refresh of related objects
393
	 *
394
	 * @return bool True when data has been loaded
395
	 * @since 2.3
396
	 */
397
	public function setup_related_objects( $force = false ) {
398
399
		$new_data_loaded = false;
400
401
		if ( ! $force && empty( self::$related_objects ) ) {
402
			// Only load transient if we aren't forcing a refresh.
403
			self::$related_objects = pods_transient_get( 'pods_related_objects' );
404
405
			if ( false !== self::$related_objects ) {
406
				$new_data_loaded = true;
407
			}
408
		} elseif ( $force ) {
409
			// If we are rebuilding, make sure we start with a clean slate.
410
			self::$related_objects = array();
411
		}
412
413
		if ( empty( self::$related_objects ) ) {
414
			// Do a complete build of related_objects.
415
			$new_data_loaded = true;
416
417
			// Custom simple relationship lists.
418
			self::$related_objects['custom-simple'] = array(
419
				'label'  => __( 'Simple (custom defined list)', 'pods' ),
420
				'group'  => __( 'Custom', 'pods' ),
421
				'simple' => true,
422
			);
423
424
			// Pods options.
425
			$pod_options = array();
426
427
			// Include PodsMeta if not already included.
428
			pods_meta();
429
430
			// Advanced Content Types for relationships.
431
			$_pods = PodsMeta::$advanced_content_types;
432
433 View Code Duplication
			foreach ( $_pods as $pod ) {
434
				$pod_options[ $pod['name'] ] = $pod['label'] . ' (' . $pod['name'] . ')';
435
			}
436
437
			// Settings pods for relationships.
438
			$_pods = PodsMeta::$settings;
439
440 View Code Duplication
			foreach ( $_pods as $pod ) {
441
				$pod_options[ $pod['name'] ] = $pod['label'] . ' (' . $pod['name'] . ')';
442
			}
443
444
			asort( $pod_options );
445
446
			foreach ( $pod_options as $pod => $label ) {
447
				self::$related_objects[ 'pod-' . $pod ] = array(
448
					'label'         => $label,
449
					'group'         => __( 'Pods', 'pods' ),
450
					'bidirectional' => true,
451
				);
452
			}
453
454
			// Post Types for relationships.
455
			$post_types = get_post_types();
456
			asort( $post_types );
457
458
			$ignore = array( 'attachment', 'revision', 'nav_menu_item' );
459
460 View Code Duplication
			foreach ( $post_types as $post_type => $label ) {
461
				if ( in_array( $post_type, $ignore, true ) || empty( $post_type ) ) {
462
					unset( $post_types[ $post_type ] );
463
464
					continue;
465
				} elseif ( 0 === strpos( $post_type, '_pods_' ) && apply_filters( 'pods_pick_ignore_internal', true ) ) {
466
					unset( $post_types[ $post_type ] );
467
468
					continue;
469
				}
470
471
				$post_type = get_post_type_object( $post_type );
472
473
				self::$related_objects[ 'post_type-' . $post_type->name ] = array(
474
					'label'         => $post_type->label . ' (' . $post_type->name . ')',
475
					'group'         => __( 'Post Types', 'pods' ),
476
					'bidirectional' => true,
477
				);
478
			}
479
480
			// Taxonomies for relationships.
481
			$taxonomies = get_taxonomies();
482
			asort( $taxonomies );
483
484
			$ignore = array( 'nav_menu', 'post_format' );
485
486 View Code Duplication
			foreach ( $taxonomies as $taxonomy => $label ) {
487
				/**
488
				 * Prevent ability to extend core Pods content types.
489
				 *
490
				 * @param bool $ignore_internal Default is true, when set to false Pods internal content types can not be extended.
491
				 *
492
				 * @since 2.3.19
493
				 */
494
				$ignore_internal = apply_filters( 'pods_pick_ignore_internal', true );
495
496
				if ( in_array( $taxonomy, $ignore, true ) || empty( $taxonomy ) ) {
497
					unset( $taxonomies[ $taxonomy ] );
498
499
					continue;
500
				} elseif ( 0 === strpos( $taxonomy, '_pods_' ) && $ignore_internal ) {
501
					unset( $taxonomies[ $taxonomy ] );
502
503
					continue;
504
				}
505
506
				$taxonomy = get_taxonomy( $taxonomy );
507
508
				self::$related_objects[ 'taxonomy-' . $taxonomy->name ] = array(
509
					'label'         => $taxonomy->label . ' (' . $taxonomy->name . ')',
510
					'group'         => __( 'Taxonomies', 'pods' ),
511
					'bidirectional' => true,
512
				);
513
			}
514
515
			// Other WP Objects for relationships.
516
			self::$related_objects['user'] = array(
517
				'label'         => __( 'Users', 'pods' ),
518
				'group'         => __( 'Other WP Objects', 'pods' ),
519
				'bidirectional' => true,
520
			);
521
522
			self::$related_objects['role'] = array(
523
				'label'         => __( 'User Roles', 'pods' ),
524
				'group'         => __( 'Other WP Objects', 'pods' ),
525
				'simple'        => true,
526
				'data_callback' => array( $this, 'data_roles' ),
527
			);
528
529
			self::$related_objects['capability'] = array(
530
				'label'         => __( 'User Capabilities', 'pods' ),
531
				'group'         => __( 'Other WP Objects', 'pods' ),
532
				'simple'        => true,
533
				'data_callback' => array( $this, 'data_capabilities' ),
534
			);
535
536
			self::$related_objects['media'] = array(
537
				'label'         => __( 'Media', 'pods' ),
538
				'group'         => __( 'Other WP Objects', 'pods' ),
539
				'bidirectional' => true,
540
			);
541
542
			self::$related_objects['comment'] = array(
543
				'label'         => __( 'Comments', 'pods' ),
544
				'group'         => __( 'Other WP Objects', 'pods' ),
545
				'bidirectional' => true,
546
			);
547
548
			self::$related_objects['image-size'] = array(
549
				'label'         => __( 'Image Sizes', 'pods' ),
550
				'group'         => __( 'Other WP Objects', 'pods' ),
551
				'simple'        => true,
552
				'data_callback' => array( $this, 'data_image_sizes' ),
553
			);
554
555
			self::$related_objects['nav_menu'] = array(
556
				'label' => __( 'Navigation Menus', 'pods' ),
557
				'group' => __( 'Other WP Objects', 'pods' ),
558
			);
559
560
			self::$related_objects['post_format'] = array(
561
				'label' => __( 'Post Formats', 'pods' ),
562
				'group' => __( 'Other WP Objects', 'pods' ),
563
			);
564
565
			self::$related_objects['post-status'] = array(
566
				'label'         => __( 'Post Status', 'pods' ),
567
				'group'         => __( 'Other WP Objects', 'pods' ),
568
				'simple'        => true,
569
				'data_callback' => array( $this, 'data_post_stati' ),
570
			);
571
572
			do_action( 'pods_form_ui_field_pick_related_objects_other' );
573
574
			self::$related_objects['country'] = array(
575
				'label'         => __( 'Countries', 'pods' ),
576
				'group'         => __( 'Predefined Lists', 'pods' ),
577
				'simple'        => true,
578
				'data_callback' => array( $this, 'data_countries' ),
579
			);
580
581
			self::$related_objects['us_state'] = array(
582
				'label'         => __( 'US States', 'pods' ),
583
				'group'         => __( 'Predefined Lists', 'pods' ),
584
				'simple'        => true,
585
				'data_callback' => array( $this, 'data_us_states' ),
586
			);
587
588
			self::$related_objects['days_of_week'] = array(
589
				'label'         => __( 'Calendar - Days of Week', 'pods' ),
590
				'group'         => __( 'Predefined Lists', 'pods' ),
591
				'simple'        => true,
592
				'data_callback' => array( $this, 'data_days_of_week' ),
593
			);
594
595
			self::$related_objects['months_of_year'] = array(
596
				'label'         => __( 'Calendar - Months of Year', 'pods' ),
597
				'group'         => __( 'Predefined Lists', 'pods' ),
598
				'simple'        => true,
599
				'data_callback' => array( $this, 'data_months_of_year' ),
600
			);
601
602
			do_action( 'pods_form_ui_field_pick_related_objects_predefined' );
603
604
			if ( did_action( 'init' ) ) {
605
				pods_transient_set( 'pods_related_objects', self::$related_objects );
606
			}
607
		}
608
609
		/**
610
		 * Allow custom related objects to be defined
611
		 */
612
		do_action( 'pods_form_ui_field_pick_related_objects_custom' );
613
614
		foreach ( self::$custom_related_objects as $object => $related_object ) {
615
			if ( ! isset( self::$related_objects[ $object ] ) ) {
616
				$new_data_loaded = true;
617
618
				self::$related_objects[ $object ] = $related_object;
619
			}
620
		}
621
622
		return $new_data_loaded;
623
624
	}
625
626
	/**
627
	 * Return available related objects
628
	 *
629
	 * @param boolean $force Whether to force refresh of related objects
630
	 *
631
	 * @return array Field selection array
632
	 * @since 2.3
633
	 */
634
	public function related_objects( $force = false ) {
635
636
		if ( $this->setup_related_objects( $force ) || null === self::$names_related ) {
637
			$related_objects = array();
638
639
			foreach ( self::$related_objects as $related_object_name => $related_object ) {
640
				if ( ! isset( $related_objects[ $related_object['group'] ] ) ) {
641
					$related_objects[ $related_object['group'] ] = array();
642
				}
643
644
				$related_objects[ $related_object['group'] ][ $related_object_name ] = $related_object['label'];
645
			}
646
647
			self::$names_related = (array) apply_filters( 'pods_form_ui_field_pick_related_objects', $related_objects );
648
		}
649
650
		return self::$names_related;
651
652
	}
653
654
	/**
655
	 * Return available simple object names
656
	 *
657
	 * @return array Simple object names
658
	 * @since 2.3
659
	 */
660 View Code Duplication
	public function simple_objects() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
661
662
		if ( $this->setup_related_objects() || null === self::$names_simple ) {
663
			$simple_objects = array();
664
665
			foreach ( self::$related_objects as $object => $related_object ) {
666
				if ( ! isset( $related_object['simple'] ) || ! $related_object['simple'] ) {
667
					continue;
668
				}
669
670
				$simple_objects[] = $object;
671
			}
672
673
			self::$names_simple = (array) apply_filters( 'pods_form_ui_field_pick_simple_objects', $simple_objects );
674
		}
675
676
		return self::$names_simple;
677
678
	}
679
680
	/**
681
	 * Return available bidirectional object names
682
	 *
683
	 * @return array Bidirectional object names
684
	 * @since 2.3.4
685
	 */
686 View Code Duplication
	public function bidirectional_objects() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
687
688
		if ( $this->setup_related_objects() || null === self::$names_bidirectional ) {
689
			$bidirectional_objects = array();
690
691
			foreach ( self::$related_objects as $object => $related_object ) {
692
				if ( ! isset( $related_object['bidirectional'] ) || ! $related_object['bidirectional'] ) {
693
					continue;
694
				}
695
696
				$bidirectional_objects[] = $object;
697
			}
698
699
			self::$names_bidirectional = (array) apply_filters( 'pods_form_ui_field_pick_bidirectional_objects', $bidirectional_objects );
700
		}
701
702
		return self::$names_bidirectional;
703
704
	}
705
706
	/**
707
	 * {@inheritdoc}
708
	 */
709
	public function schema( $options = null ) {
710
711
		$schema = false;
712
713
		$simple_tableless_objects = $this->simple_objects();
714
715
		if ( in_array( pods_v( self::$type . '_object', $options ), $simple_tableless_objects, true ) ) {
716
			$schema = 'LONGTEXT';
717
		}
718
719
		return $schema;
720
721
	}
722
723
	/**
724
	 * {@inheritdoc}
725
	 */
726
	public function display( $value = null, $name = null, $options = null, $pod = null, $id = null ) {
727
728
		$fields = null;
729
730
		if ( is_object( $pod ) && isset( $pod->fields ) ) {
731
			/**
732
			 * @var $pod Pods
733
			 */
734
			$fields = $pod->fields;
735
736 View Code Duplication
			if ( ! empty( $pod->pod_data['object_fields'] ) ) {
737
				$fields = array_merge( $fields, $pod->pod_data['object_fields'] );
738
			}
739 View Code Duplication
		} elseif ( is_array( $pod ) && isset( $pod['fields'] ) ) {
740
			$fields = $pod['fields'];
741
742
			if ( ! empty( $pod['object_fields'] ) ) {
743
				$fields = array_merge( $fields, $pod['object_fields'] );
744
			}
745
		}
746
747
		return pods_serial_comma( $value, array( 'field' => $name, 'fields' => $fields ) );
748
749
	}
750
751
	/**
752
	 * {@inheritdoc}
753
	 */
754
	public function input( $name, $value = null, $options = null, $pod = null, $id = null ) {
755
756
		$options = (array) $options;
757
758
		$type = pods_v( 'type', $options, static::$type );
759
760
		$args = compact( array_keys( get_defined_vars() ) );
761
		$args = (object) $args;
762
763
		wp_enqueue_style( 'pods-dfv-list' );
764
		wp_enqueue_script( 'pods-dfv' );
765
766
		wp_enqueue_style( 'pods-select2' );
767
		wp_enqueue_script( 'pods-select2' );
768
769
		$this->render_input_script( $args );
770
771
		return;
772
773
		// @todo Support custom integrations.
774
		do_action( 'pods_form_ui_field_pick_input_' . pods_v( self::$type . '_format_type', $options, 'single' ) . '_' . pods_v( self::$type . '_format_multi', $options, 'checkbox' ), $name, $value, $options, $pod, $id );
0 ignored issues
show
Unused Code introduced by
// @todo Support custom ..., $options, $pod, $id); does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
775
		do_action( 'pods_form_ui_field_pick_input', pods_v( self::$type . '_format_type', $options, 'single' ), $name, $value, $options, $pod, $id );
776
777
		// @todo Support custom integrations.
778
		do_action( 'pods_form_ui_field_pick_input', pods_v( self::$type . '_format_type', $options, 'single' ), $name, $value, $options, $pod, $id );
779
780
	}
781
782
	/**
783
	 * {@inheritdoc}
784
	 */
785
	public function build_dfv_field_options( $options, $args ) {
786
787
		$options['grouped'] = 1;
788
789
		if ( empty( $options[ $args->type . '_object' ] ) ) {
790
			$options[ $args->type . '_object' ] = '';
791
		}
792
793
		if ( empty( $options[ $args->type . '_val' ] ) ) {
794
			$options[ $args->type . '_val' ] = '';
795
		}
796
797
		$options['table_info'] = array();
798
799
		$custom = pods_v( $args->type . '_custom', $options, false );
800
801
		$custom = apply_filters( 'pods_form_ui_field_pick_custom_values', $custom, $args->name, $args->value, $options, $args->pod, $args->id );
802
803
		$ajax = false;
804
805
		if ( ( 'custom-simple' !== pods_v( $args->type . '_object', $options ) || empty( $custom ) ) && '' !== pods_v( $args->type . '_object', $options, '', true ) ) {
806
			$ajax = true;
807
		}
808
809
		if ( ! empty( self::$field_data ) && self::$field_data['id'] === $options['id'] ) {
810
			$ajax = (boolean) self::$field_data['autocomplete'];
811
		}
812
813
		$ajax = apply_filters( 'pods_form_ui_field_pick_ajax', $ajax, $args->name, $args->value, $options, $args->pod, $args->id );
814
815
		if ( 0 === (int) pods_v( $args->type . '_ajax', $options, 1 ) ) {
816
			$ajax = false;
817
		}
818
819
		$options[ $args->type . '_ajax' ] = (int) $ajax;
820
821
		$format_type = pods_v( $args->type . '_format_type', $options, 'single', true );
822
823
		$limit = 1;
824
825
		if ( 'single' === $format_type ) {
826
			$format_single = pods_v( $args->type . '_format_single', $options, 'dropdown', true );
827
828 View Code Duplication
			if ( 'dropdown' === $format_single ) {
829
				$options['view_name'] = 'select';
830
			} elseif ( 'radio' === $format_single ) {
831
				$options['view_name'] = 'radio';
832
			} elseif ( 'autocomplete' === $format_single ) {
833
				$options['view_name'] = 'select2';
834
			} elseif ( 'list' === $format_single ) {
835
				$options['view_name'] = 'list';
836
			} else {
837
				$options['view_name'] = $format_single;
838
			}
839
		} elseif ( 'multi' === $format_type ) {
840
			$format_multi = pods_v( $args->type . '_format_multi', $options, 'checkbox', true );
841
842
			if ( ! empty( $args->value ) && ! is_array( $args->value ) ) {
843
				$args->value = explode( ',', $args->value );
844
			}
845
846 View Code Duplication
			if ( 'checkbox' === $format_multi ) {
847
				$options['view_name'] = 'checkbox';
848
			} elseif ( 'multiselect' === $format_multi ) {
849
				$options['view_name'] = 'select';
850
			} elseif ( 'autocomplete' === $format_multi ) {
851
				$options['view_name'] = 'select2';
852
			} elseif ( 'list' === $format_multi ) {
853
				$options['view_name'] = 'list';
854
			} else {
855
				$options['view_name'] = $format_multi;
856
			}
857
858
			$limit = 0;
859
860
			if ( ! empty( $options[ $args->type . '_limit' ] ) ) {
861
				$limit = absint( $options[ $args->type . '_limit' ] );
862
			}
863
		} else {
864
			$options['view_name'] = $format_type;
865
		}
866
867
		$options[ $args->type . '_limit' ] = $limit;
868
869
		$options[ 'ajax_data' ] = $this->build_dfv_autocomplate_ajax_data( $options, $args, $ajax );
870
871
		return $options;
872
873
	}
874
875
	/**
876
	 * @param array     $options
877
	 * @param object    $args    {
878
	 *     Field information arguments.
879
	 *
880
	 *     @type string     $name    Field name
881
	 *     @type string     $type    Field type
882
	 *     @type array      $options Field options
883
	 *     @type mixed      $value   Current value
884
	 *     @type array      $pod     Pod information
885
	 *     @type int|string $id      Current item ID
886
	 * }
887
	 *
888
	 * @param Boolean   $ajax    True if ajax mode should be used
889
	 *
890
	 * @return array
891
	 */
892
	public function build_dfv_autocomplate_ajax_data( $options, $args, $ajax ) {
893
894
		if ( is_object( $args->pod ) ) {
895
			$pod_id = (int) $args->pod->pod_id;
896
		} else {
897
			$pod_id = 0;
898
		}
899
900
		$field_id = (int) $options[ 'id' ];
901
902
		$id = (int) $args->id;
903
904
		if ( is_user_logged_in() ) {
905
			$uid = 'user_' . get_current_user_id();
906
		} else {
907
			$uid = @session_id();
908
		}
909
910
		$uri_hash = wp_create_nonce( 'pods_uri_' . $_SERVER[ 'REQUEST_URI' ] );
911
912
		$field_nonce = wp_create_nonce( 'pods_relationship_' . $pod_id . '_' . $uid . '_' . $uri_hash . '_' . $field_id );
913
914
		return array(
915
			'ajax'     => $ajax,
916
			'pod'      => $pod_id,
917
			'field'    => $field_id,
918
			'id'       => $id,
919
			'uri'      => $uri_hash,
920
			'_wpnonce' => $field_nonce
921
		);
922
923
	}
924
925
	/**
926
	 * {@inheritdoc}
927
	 */
928
	public function build_dfv_field_config( $args ) {
929
930
		$config = parent::build_dfv_field_config( $args );
931
932
		if ( ! isset( $config['optgroup'] ) ) {
933
			$config['optgroup'] = false;
934
		}
935
936
		/**
937
		 * Filter on whether to allow modals to be used on the front of the site (in an non-admin area).
938
		 *
939
		 * @param boolean $show_on_front
940
		 *
941
		 * @since 2.7
942
		 */
943
		$show_on_front = apply_filters( 'pods_ui_dfv_pick_modals_show_on_front', false );
944
945
		/**
946
		 * Filter on whether to allow nested modals to be used (modals within modals).
947
		 *
948
		 * @param boolean $allow_nested_modals
949
		 *
950
		 * @since 2.7
951
		 */
952
		$allow_nested_modals = apply_filters( 'pods_ui_dfv_pick_modals_allow_nested', false );
953
954
		// Disallow add/edit outside the admin and when we're already in a modal
955
		if ( ( ! $show_on_front && ! is_admin() ) || ( ! $allow_nested_modals && pods_is_modal_window() ) ) {
956
			$config[ $args->type . '_allow_add_new' ]  = false;
957
			$config[ $args->type . '_show_edit_link' ] = false;
958
		}
959
960
		$file_name  = '';
961
		$query_args = array();
962
963
		// Set the file name and args based on the content type of the relationship
964
		switch ( $args->options['pick_object'] ) {
965
			case 'post_type':
966
				if ( ! empty( $args->options['pick_val'] ) ) {
967
					$post_type_obj = get_post_type_object( $args->options['pick_val'] );
968
969
					if ( $post_type_obj && current_user_can( $post_type_obj->cap->create_posts ) ) {
970
						$file_name  = 'post-new.php';
971
						$query_args = array(
972
							'post_type' => $args->options['pick_val'],
973
						);
974
					}
975
				}
976
977
				break;
978
979
			case 'taxonomy':
980
				// @todo Fix add new modal issues
981
				/*if ( ! empty( $args->options['pick_val'] ) ) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
54% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
982
					$taxonomy_obj = get_taxonomy( $args->options['pick_val'] );
983
984
					if ( $taxonomy_obj && current_user_can( $taxonomy_obj->cap->edit_terms ) ) {
985
						$file_name  = 'edit-tags.php';
986
						$query_args = array(
987
							'taxonomy' => $args->options['pick_val'],
988
						);
989
					}
990
				}*/
991
992
				break;
993
994
			case 'user':
995
				if ( current_user_can( 'create_users' ) ) {
996
					$file_name  = 'user-new.php';
997
				}
998
999
				break;
1000
1001
			case 'pod':
1002
				if ( ! empty( $args->options['pick_val'] ) ) {
1003
					if ( pods_is_admin( array( 'pods', 'pods_content', 'pods_edit_' . $args->options['pick_val'] ) ) ) {
1004
						$file_name  = 'admin.php';
1005
						$query_args = array(
1006
							'page'   => 'pods-manage-' . $args->options['pick_val'],
1007
							'action' => 'add',
1008
						);
1009
1010
					}
1011
				}
1012
1013
				break;
1014
		}
1015
1016
		$iframe_src = '';
1017
1018
		// Potential valid modal target if we've set the file name
1019
		if ( ! empty( $file_name ) ) {
1020
			// We extend wp.media.view.Modal for modal add/edit, we must ensure we load the template for it
1021
			wp_enqueue_media();
1022
1023
			// @todo: Replace string literal with defined constant
1024
			$query_args['pods_modal'] = 1;
1025
1026
			// Add args we always need
1027
			$iframe_src = add_query_arg( $query_args, admin_url( $file_name ) );
1028
		}
1029
1030
		$config['iframe_src']   = $iframe_src;
1031
		$config['iframe_title_add'] = sprintf( __( '%s: Add New', 'pods' ), $args->options['label'] );
1032
		$config['iframe_title_edit'] = sprintf( __( '%s: Edit', 'pods' ), $args->options['label'] );
1033
1034
		return $config;
1035
1036
	}
1037
1038
	/**
1039
	 * {@inheritdoc}
1040
	 */
1041
	public function build_dfv_field_item_data( $args ) {
1042
1043
		$args->options['supports_thumbnails'] = null;
1044
1045
		$item_data = array();
1046
1047
		if ( ! empty( $args->options['data'] ) ) {
1048
			$item_data = $this->build_dfv_field_item_data_recurse( $args->options['data'], $args );
1049
		}
1050
1051
		return $item_data;
1052
1053
	}
1054
1055
	/**
1056
	 * Loop through relationship data and expand item data with additional information for DFV.
1057
	 *
1058
	 * @param array     $data    Item data to expand.
1059
	 * @param object    $args    {
1060
	 *                           Field information arguments.
1061
	 *
1062
	 * @type string     $name    Field name
1063
	 * @type string     $type    Field type
1064
	 * @type array      $options Field options
1065
	 * @type mixed      $value   Current value
1066
	 * @type array      $pod     Pod information
1067
	 * @type int|string $id      Current item ID
1068
	 * }
1069
	 *
1070
	 * @return array
1071
	 */
1072
	public function build_dfv_field_item_data_recurse( $data, $args ) {
1073
1074
		$item_data = array();
1075
1076
		foreach ( $data as $item_id => $item_title ) {
1077
			if ( is_array( $item_title ) ) {
1078
				$args->options['optgroup'] = true;
1079
1080
				$item_data[] = array(
1081
					'label'      => $item_id,
1082
					'collection' => $this->build_dfv_field_item_data_recurse( $item_title, $args ),
1083
				);
1084
			} else {
1085
				// Key by item_id temporarily to be able to sort based on $args->value
1086
				$item_data[ $item_id ] = $this->build_dfv_field_item_data_recurse_item( $item_id, $item_title, $args );
1087
			}
1088
		}
1089
1090
		// Maintain any saved sort order from $args->value
1091
		if ( is_array( $args->value ) && 1 < count( $args->value ) && $this->is_autocomplete( $args->options ) ) {
1092
			$item_data = array_replace( $args->value, $item_data );
1093
		}
1094
1095
		// Convert from associative to numeric array
1096
		$item_data = array_values( $item_data );
1097
1098
		return $item_data;
1099
1100
	}
1101
1102
	/**
1103
	 * Loop through relationship data and expand item data with additional information for DFV.
1104
	 *
1105
	 * @param int|string $item_id
1106
	 * @param string     $item_title
1107
	 * @param object     $args    {
1108
	 *                            Field information arguments.
1109
	 *
1110
	 * @type string      $name    Field name
1111
	 * @type string      $type    Field type
1112
	 * @type array       $options Field options
1113
	 * @type mixed       $value   Current value
1114
	 * @type array       $pod     Pod information
1115
	 * @type int|string  $id      Current item ID
1116
	 * }
1117
	 *
1118
	 * @return array
1119
	 */
1120
	public function build_dfv_field_item_data_recurse_item( $item_id, $item_title, $args ) {
1121
1122
		$use_dashicon = false;
1123
		$icon         = '';
1124
		$img_icon     = '';
1125
		$edit_link    = '';
1126
		$link         = '';
1127
1128
		if ( ! isset( $args->options['supports_thumbnails'] ) ) {
1129
			$args->options['supports_thumbnails'] = null;
1130
		}
1131
1132
		switch ( $args->options['pick_object'] ) {
1133
			case 'post_type':
1134
				$item_id = (int) $item_id;
1135
1136
				if ( null === $args->options['supports_thumbnails'] && ! empty( $args->options['pick_val'] ) ) {
1137
					$args->options['supports_thumbnails'] = post_type_supports( $args->options['pick_val'], 'thumbnail' );
1138
				}
1139
1140
				if ( true === $args->options['supports_thumbnails'] ) {
1141
					$post_thumbnail_id = get_post_thumbnail_id( $item_id );
1142
1143
					if ( $post_thumbnail_id ) {
1144
						$thumb = wp_get_attachment_image_src( $post_thumbnail_id, 'thumbnail', false );
1145
					}
1146
1147
					if ( ! empty( $thumb[0] ) ) {
1148
						$img_icon = $thumb[0];
1149
					}
1150
				}
1151
1152
				if ( empty( $img_icon ) ) {
1153
1154
					// Default icon for posts.
1155
					$icon = 'dashicons-admin-post';
1156
1157
					// Post type icons.
1158
					$post_type = (array) get_post_type_object( get_post_type( $item_id ) );
1159
1160
					if ( ! empty( $post_type['menu_icon'] ) ) {
1161
						// Post specific icon.
1162
						$icon = $post_type['menu_icon'];
1163
					} elseif ( isset( $post_type['name'] ) && 'page' ) {
1164
						switch ( $post_type['name'] ) {
1165
							case 'page':
1166
								// Default for pages.
1167
								$icon = 'dashicons-admin-page';
1168
							break;
1169
							case 'attachment':
1170
								// Default for attachments.
1171
								$icon = 'dashicons-admin-media';
1172
							break;
1173
						}
1174
					}
1175
				}
1176
1177
				$edit_link = get_edit_post_link( $item_id, 'raw' );
1178
1179
				$link = get_permalink( $item_id );
1180
1181
				break;
1182
1183
			case 'taxonomy':
1184
				$item_id = (int) $item_id;
1185
1186
				if ( ! empty( $args->options['pick_val'] ) ) {
1187
1188
					// Default icon for taxonomy.
1189
					$icon = 'dashicons-category';
1190
1191
					// Change icon for non-hierarchical taxonomies.
1192
					$taxonomy = get_term( $item_id );
1193
					if ( isset( $taxonomy->taxonomy ) ) {
1194
						$taxonomy = (array) get_taxonomy( $taxonomy->taxonomy );
1195
						if ( isset( $taxonomy['hierarchical'] ) && ! $taxonomy['hierarchical'] ) {
1196
							$icon = 'dashicons-tag';
1197
						}
1198
					}
1199
1200
					$edit_link = get_edit_term_link( $item_id, $args->options['pick_val'] );
1201
1202
					$link = get_term_link( $item_id, $args->options['pick_val'] );
1203
				}
1204
1205
				break;
1206
1207
			case 'user':
1208
				$item_id = (int) $item_id;
1209
1210
				$args->options['supports_thumbnails'] = true;
1211
1212
				$icon = 'dashicons-admin-users';
1213
				$img_icon = get_avatar_url( $item_id, array( 'size' => 150 ) );
1214
1215
				$edit_link = get_edit_user_link( $item_id );
1216
1217
				$link = get_author_posts_url( $item_id );
1218
1219
				break;
1220
1221
			case 'comment':
1222
				$item_id = (int) $item_id;
1223
1224
				$args->options['supports_thumbnails'] = true;
1225
1226
				$icon = 'dashicons-admin-comments';
1227
				$img_icon = get_avatar_url( get_comment( $item_id ), array( 'size' => 150 ) );
1228
1229
				$edit_link = get_edit_comment_link( $item_id );
1230
1231
				$link = get_comment_link( $item_id );
1232
1233
				break;
1234
1235
			case 'pod':
1236
				$item_id = (int) $item_id;
1237
1238
				if ( ! empty( $args->options['pick_val'] ) ) {
1239
1240
					$icon = 'dashicons-pods';
1241
1242
					if ( pods_is_admin( array( 'pods', 'pods_content', 'pods_edit_' . $args->options['pick_val'] ) ) ) {
1243
						$file_name  = 'admin.php';
1244
						$query_args = array(
1245
							'page'   => 'pods-manage-' . $args->options['pick_val'],
1246
							'action' => 'edit',
1247
							'id'     => $item_id,
1248
						);
1249
1250
						$edit_link = add_query_arg( $query_args, admin_url( $file_name ) );
1251
					}
1252
1253
					// @todo Add $link support
1254
					$link = '';
1255
				}
1256
1257
				break;
1258
		}
1259
1260
		// Image icons always overwrite default icons
1261
		if ( ! empty( $img_icon ) ) {
1262
			$icon = $img_icon;
1263
		}
1264
1265
		// Parse icon type
1266
		if ( 'none' === $icon || 'div' === $icon ) {
1267
			$icon = '';
1268
			$use_dashicon = true;
1269
		} elseif ( 0 === strpos( $icon, 'data:image/svg+xml;base64,' ) ) {
1270
			$icon = esc_attr( $icon );
1271
			$use_dashicon = false;
1272
		} elseif ( 0 === strpos( $icon, 'dashicons-' ) ) {
1273
			$icon = sanitize_html_class( $icon );
1274
			$use_dashicon = true;
1275
		}
1276
1277
		// Support modal editing
1278
		if ( ! empty( $edit_link ) ) {
1279
			// @todo: Replace string literal with defined constant
1280
			$edit_link = add_query_arg( array( 'pods_modal' => '1' ), $edit_link );
1281
		}
1282
1283
		// Determine if this is a selected item
1284
		$selected = false;
1285
1286
		if ( is_array( $args->value ) ) {
1287
			if ( isset( $args->value[ $item_id ] ) ) {
1288
				$selected = true;
1289
			} elseif ( in_array( $item_id, $args->value, true ) ) {
1290
				$selected = true;
1291
			}
1292
		} elseif ( $item_id === $args->value ) {
1293
			$selected = true;
1294
		}
1295
1296
		$item = array(
1297
			'id'           => $item_id,
1298
			'use_dashicon' => $use_dashicon,
1299
			'icon'         => $icon,
1300
			'name'         => $item_title,
1301
			'edit_link'    => $edit_link,
1302
			'link'         => $link,
1303
			'selected'     => $selected,
1304
		);
1305
1306
		return $item;
1307
1308
	}
1309
1310
	/**
1311
	 * {@inheritdoc}
1312
	 */
1313
	public function validate( $value, $name = null, $options = null, $fields = null, $pod = null, $id = null, $params = null ) {
1314
1315
		if ( empty( self::$api ) ) {
1316
			self::$api = pods_api();
1317
		}
1318
1319
		$simple_tableless_objects = $this->simple_objects();
1320
1321
		$related_pick_limit = 0;
1322
		$related_field      = $related_pod = $current_related_ids = false;
1323
1324
		// Bidirectional relationship requirement checks
1325
		$related_object = pods_v( self::$type . '_object', $options, '' ); // pod, post_type, taxonomy, etc..
1326
		$related_val    = pods_v( self::$type . '_val', $options, $related_object, null, true ); // pod name, post type name, taxonomy name, etc..
1327
		if ( empty( $related_val ) ) {
1328
			$related_val = $related_object;
1329
		}
1330
1331
		$related_sister_id = (int) pods_v( 'sister_id', $options, 0 );
1332
1333
		$options['id'] = (int) $options['id'];
1334
1335
		if ( ! isset( self::$related_data[ $options['id'] ] ) || empty( self::$related_data[ $options['id'] ] ) ) {
1336
			self::$related_data[ $options['id'] ] = array();
1337
		}
1338
1339
		if ( ! empty( $related_sister_id ) && ! in_array( $related_object, $simple_tableless_objects, true ) ) {
1340
			$related_pod = self::$api->load_pod( array( 'name' => $related_val, 'table_info' => false ), false );
1341
1342
			if ( false !== $related_pod && ( 'pod' === $related_object || $related_object === $related_pod['type'] ) ) {
1343
				$related_field = false;
1344
1345
				// Ensure sister_id exists on related Pod.
1346 View Code Duplication
				foreach ( $related_pod['fields'] as $related_pod_field ) {
1347
					if ( 'pick' === $related_pod_field['type'] && $related_sister_id === $related_pod_field['id'] ) {
1348
						$related_field = $related_pod_field;
1349
1350
						break;
1351
					}
1352
				}
1353
1354
				if ( ! empty( $related_field ) ) {
1355
					$current_ids = self::$api->lookup_related_items( $fields[ $name ]['id'], $pod['id'], $id, $fields[ $name ], $pod );
1356
1357
					self::$related_data[ $options['id'] ]['current_ids'] = $current_ids;
1358
1359
					$value_ids = $value;
1360
1361
					// Convert values from a comma-separated string into an array.
1362
					if ( ! is_array( $value_ids ) ) {
1363
						$value_ids = explode( ',', $value_ids );
1364
					}
1365
1366
					$value_ids = array_unique( array_filter( $value_ids ) );
1367
1368
					// Get ids to remove.
1369
					$remove_ids = array_diff( $current_ids, $value_ids );
1370
1371
					$related_required   = (boolean) pods_v( 'required', $related_field['options'], 0 );
1372
					$related_pick_limit = (int) pods_v( self::$type . '_limit', $related_field['options'], 0 );
1373
1374
					if ( 'single' === pods_v( self::$type . '_format_type', $related_field['options'] ) ) {
1375
						$related_pick_limit = 1;
1376
					}
1377
1378
					// Validate Required fields.
1379
					if ( $related_required && ! empty( $remove_ids ) ) {
1380
						foreach ( $remove_ids as $related_id ) {
1381
							$bidirectional_ids = self::$api->lookup_related_items( $related_field['id'], $related_pod['id'], $related_id, $related_field, $related_pod );
1382
1383
							self::$related_data[ $options['id'] ][ 'related_ids_' . $related_id ] = $bidirectional_ids;
1384
1385
							if ( empty( $bidirectional_ids ) || ( in_array( (int) $id, $bidirectional_ids, true ) && 1 === count( $bidirectional_ids ) ) ) {
1386
								return sprintf( __( 'The %1$s field is required and cannot be removed by the %2$s field', 'pods' ), $related_field['label'], $options['label'] );
1387
							}
1388
						}
1389
					}
1390
				} else {
1391
					$related_pod = false;
1392
				}
1393
			} else {
1394
				$related_pod = false;
1395
			}
1396
		}
1397
1398
		if ( empty( self::$related_data[ $options['id'] ] ) ) {
1399
			unset( self::$related_data[ $options['id'] ] );
1400
		} else {
1401
			self::$related_data[ $options['id'] ]['related_pod']        = $related_pod;
1402
			self::$related_data[ $options['id'] ]['related_field']      = $related_field;
1403
			self::$related_data[ $options['id'] ]['related_pick_limit'] = $related_pick_limit;
1404
1405
			$pick_limit = (int) pods_v( self::$type . '_limit', $options['options'], 0 );
1406
1407
			if ( 'single' === pods_v( self::$type . '_format_type', $options['options'] ) ) {
1408
				$pick_limit = 1;
1409
			}
1410
1411
			$related_field['id'] = (int) $related_field['id'];
1412
1413
			if ( ! isset( self::$related_data[ $related_field['id'] ] ) || empty( self::$related_data[ $related_field['id'] ] ) ) {
1414
				self::$related_data[ $related_field['id'] ] = array(
1415
					'related_pod'        => $pod,
1416
					'related_field'      => $options,
1417
					'related_pick_limit' => $pick_limit,
1418
				);
1419
			}
1420
		}
1421
1422
		return true;
1423
1424
	}
1425
1426
	/**
1427
	 * {@inheritdoc}
1428
	 */
1429
	public function save( $value, $id = null, $name = null, $options = null, $fields = null, $pod = null, $params = null ) {
1430
1431
		if ( empty( self::$api ) ) {
1432
			self::$api = pods_api();
1433
		}
1434
1435
		$options['id'] = (int) $options['id'];
1436
1437
		if ( ! isset( self::$related_data[ $options['id'] ] ) ) {
1438
			return;
1439
		}
1440
1441
		$related_pod        = self::$related_data[ $options['id'] ]['related_pod'];
1442
		$related_field      = self::$related_data[ $options['id'] ]['related_field'];
1443
		$related_pick_limit = self::$related_data[ $options['id'] ]['related_pick_limit'];
1444
1445
		// Bidirectional relationship updates.
1446
		if ( ! empty( $related_field ) ) {
1447
			// Don't use no conflict mode unless this isn't the current pod type.
1448
			$no_conflict = true;
1449
1450
			if ( $related_pod['type'] !== $pod['type'] ) {
1451
				$no_conflict = pods_no_conflict_check( $related_pod['type'] );
1452
			}
1453
1454
			if ( ! $no_conflict ) {
1455
				pods_no_conflict_on( $related_pod['type'] );
1456
			}
1457
1458
			$value = array_filter( $value );
1459
1460
			foreach ( $value as $related_id ) {
1461
				if ( isset( self::$related_data[ $options['id'] ][ 'related_ids_' . $related_id ] ) && ! empty( self::$related_data[ $options['id'] ][ 'related_ids_' . $related_id ] ) ) {
1462
					$bidirectional_ids = self::$related_data[ $options['id'] ][ 'related_ids_' . $related_id ];
1463
				} else {
1464
					$bidirectional_ids = self::$api->lookup_related_items( $related_field['id'], $related_pod['id'], $related_id, $related_field, $related_pod );
1465
				}
1466
1467
				$bidirectional_ids = array_filter( $bidirectional_ids );
1468
1469
				if ( empty( $bidirectional_ids ) ) {
1470
					$bidirectional_ids = array();
1471
				}
1472
1473
				$remove_ids = array();
1474
1475
				if ( 0 < $related_pick_limit && ! empty( $bidirectional_ids ) && ! in_array( $id, $bidirectional_ids, true ) ) {
1476
					while ( $related_pick_limit <= count( $bidirectional_ids ) ) {
1477
						$remove_ids[] = (int) array_pop( $bidirectional_ids );
1478
					}
1479
				}
1480
1481
				// Remove this item from related items no longer related to.
1482
				$remove_ids = array_unique( array_filter( $remove_ids ) );
1483
1484
				if ( ! in_array( $id, $bidirectional_ids, true ) ) {
1485
					// Add to related items.
1486
					$bidirectional_ids[] = $id;
1487
				} elseif ( empty( $remove_ids ) ) {
1488
					// Nothing to change.
1489
					continue;
1490
				}
1491
1492
				self::$api->save_relationships( $related_id, $bidirectional_ids, $related_pod, $related_field );
1493
1494
				if ( ! empty( $remove_ids ) ) {
1495
					self::$api->delete_relationships( $remove_ids, $related_id, $pod, $options );
1496
				}
1497
			}
1498
1499
			if ( ! $no_conflict ) {
1500
				pods_no_conflict_off( $related_pod['type'] );
1501
			}
1502
		}
1503
1504
	}
1505
1506
	/**
1507
	 * Delete the value from the DB
1508
	 *
1509
	 * @param int    $id
1510
	 * @param string $name
1511
	 * @param array  $options
1512
	 * @param array  $pod
1513
	 *
1514
	 * @since 2.3
1515
	 */
1516
	public function delete( $id = null, $name = null, $options = null, $pod = null ) {
1517
1518
		if ( empty( self::$api ) ) {
1519
			self::$api = pods_api();
1520
		}
1521
1522
		$simple_tableless_objects = $this->simple_objects();
1523
1524
		// Bidirectional relationship requirement checks.
1525
		$related_object    = pods_v( self::$type . '_object', $options, '' ); // pod, post_type, taxonomy, etc..
1526
		$related_val       = pods_v( self::$type . '_val', $options, $related_object, true ); // pod name, post type name, taxonomy name, etc..
1527
		$related_sister_id = (int) pods_v( 'sister_id', $options, 0 );
1528
1529
		if ( ! empty( $related_sister_id ) && ! in_array( $related_object, $simple_tableless_objects, true ) ) {
1530
			$related_pod = self::$api->load_pod( array( 'name' => $related_val, 'table_info' => false ), false );
1531
1532
			if ( false !== $related_pod && ( 'pod' === $related_object || $related_object === $related_pod['type'] ) ) {
1533
				$related_field = false;
1534
1535
				// Ensure sister_id exists on related Pod.
1536 View Code Duplication
				foreach ( $related_pod['fields'] as $related_pod_field ) {
1537
					if ( 'pick' === $related_pod_field['type'] && (int) $related_sister_id === (int) $related_pod_field['id'] ) {
1538
						$related_field = $related_pod_field;
1539
1540
						break;
1541
					}
1542
				}
1543
1544
				if ( ! empty( $related_field ) ) {
1545
					$values = self::$api->lookup_related_items( $options['id'], $pod['id'], $id, $options, $pod );
1546
1547
					if ( ! empty( $values ) ) {
1548
						$no_conflict = pods_no_conflict_check( $related_pod['type'] );
1549
1550
						if ( ! $no_conflict ) {
1551
							pods_no_conflict_on( $related_pod['type'] );
1552
						}
1553
1554
						self::$api->delete_relationships( $values, $id, $related_pod, $related_field );
1555
1556
						if ( ! $no_conflict ) {
1557
							pods_no_conflict_off( $related_pod['type'] );
1558
						}
1559
					}
1560
				}
1561
			}
1562
		}
1563
1564
	}
1565
1566
	/**
1567
	 * {@inheritdoc}
1568
	 */
1569
	public function ui( $id, $value, $name = null, $options = null, $fields = null, $pod = null ) {
1570
1571
		$value = $this->simple_value( $name, $value, $options, $pod, $id );
1572
1573
		return $this->display( $value, $name, $options, $pod, $id );
1574
1575
	}
1576
1577
	/**
1578
	 * Get the data from the field
1579
	 *
1580
	 * @param string       $name    The name of the field
1581
	 * @param string|array $value   The value of the field
1582
	 * @param array        $options Field options
1583
	 * @param array        $pod     Pod data
1584
	 * @param int          $id      Item ID
1585
	 * @param boolean      $in_form
1586
	 *
1587
	 * @return array Array of possible field data
1588
	 *
1589
	 * @since 2.0
1590
	 */
1591
	public function data( $name, $value = null, $options = null, $pod = null, $id = null, $in_form = true ) {
1592
1593 View Code Duplication
		if ( isset( $options['options'] ) ) {
1594
			$options = array_merge( $options, $options['options'] );
1595
1596
			unset( $options['options'] );
1597
		}
1598
1599
		$data = pods_v( 'data', $options, null, true );
1600
1601
		$object_params = array(
1602
			'name'    => $name, // The name of the field.
1603
			'value'   => $value, // The value of the field.
1604
			'options' => $options, // Field options.
1605
			'pod'     => $pod, // Pod data.
1606
			'id'      => $id, // Item ID.
1607
			'context' => 'data', // Data context.
1608
		);
1609
1610
		if ( null !== $data ) {
1611
			$data = (array) $data;
1612
		} else {
1613
			$data = $this->get_object_data( $object_params );
1614
		}
1615
1616
		if ( 'single' === pods_v( self::$type . '_format_type', $options, 'single' ) && 'dropdown' === pods_v( self::$type . '_format_single', $options, 'dropdown' ) ) {
1617
			$data = array( '' => pods_v( self::$type . '_select_text', $options, __( '-- Select One --', 'pods' ), true ) ) + $data;
1618
		}
1619
1620
		$data = apply_filters( 'pods_field_pick_data', $data, $name, $value, $options, $pod, $id );
1621
1622
		return $data;
1623
1624
	}
1625
1626
	/**
1627
	 * Convert a simple value to the correct value
1628
	 *
1629
	 * @param string       $name    The name of the field
1630
	 * @param string|array $value   The value of the field
1631
	 * @param array        $options Field options
1632
	 * @param array        $pod     Pod data
1633
	 * @param int          $id      Item ID
1634
	 * @param boolean      $raw     Whether to return the raw list of keys (true) or convert to key=>value (false)
1635
	 *
1636
	 * @return mixed Corrected value
1637
	 */
1638
	public function simple_value( $name, $value = null, $options = null, $pod = null, $id = null, $raw = false ) {
1639
1640
		if ( in_array( pods_v( self::$type . '_object', $options ), self::simple_objects(), true ) ) {
1641 View Code Duplication
			if ( isset( $options['options'] ) ) {
1642
				$options = array_merge( $options, $options['options'] );
1643
1644
				unset( $options['options'] );
1645
			}
1646
1647
			if ( ! is_array( $value ) && 0 < strlen( $value ) ) {
1648
				$simple = @json_decode( $value, true );
1649
1650
				if ( is_array( $simple ) ) {
1651
					$value = $simple;
1652
				}
1653
			}
1654
1655
			$data = pods_v( 'data', $options, null, true );
1656
1657
			$object_params = array(
1658
				'name'    => $name, // The name of the field.
1659
				'value'   => $value, // The value of the field.
1660
				'options' => $options, // Field options.
1661
				'pod'     => $pod, // Pod data.
1662
				'id'      => $id, // Item ID.
1663
				'context' => 'simple_value', // Data context.
1664
			);
1665
1666
			if ( null === $data ) {
1667
				$data = $this->get_object_data( $object_params );
1668
			}
1669
1670
			$data = (array) $data;
1671
1672
			$key = 0;
1673
1674
			if ( is_array( $value ) ) {
1675
				if ( ! empty( $data ) ) {
1676
					$val = array();
1677
1678
					foreach ( $value as $k => $v ) {
1679
						if ( isset( $data[ $v ] ) ) {
1680
							if ( false === $raw ) {
1681
								$k = $v;
1682
								$v = $data[ $v ];
1683
							}
1684
1685
							$val[ $k ] = $v;
1686
						}
1687
					}
1688
1689
					$value = $val;
1690
				}
1691
			} elseif ( isset( $data[ $value ] ) && false === $raw ) {
1692
				$key   = $value;
1693
				$value = $data[ $value ];
1694
			}
1695
1696
			$single_multi = pods_v( self::$type . '_format_type', $options, 'single' );
1697
1698
			if ( 'multi' === $single_multi ) {
1699
				$limit = (int) pods_v( self::$type . '_limit', $options, 0 );
1700
			} else {
1701
				$limit = 1;
1702
			}
1703
1704
			if ( is_array( $value ) && 0 < $limit ) {
1705
				if ( 1 === $limit ) {
1706
					$value = current( $value );
1707
				} else {
1708
					$value = array_slice( $value, 0, $limit, true );
1709
				}
1710
			} elseif ( ! is_array( $value ) && null !== $value && 0 < strlen( $value ) ) {
1711
				if ( 1 !== $limit || ( true === $raw && 'multi' === $single_multi ) ) {
1712
					$value = array(
1713
						$key => $value,
1714
					);
1715
				}
1716
			}
1717
		}
1718
1719
		return $value;
1720
1721
	}
1722
1723
	/**
1724
	 * Get the label from a pick value
1725
	 *
1726
	 * @param string       $name    The name of the field
1727
	 * @param string|array $value   The value of the field
1728
	 * @param array        $options Field options
1729
	 * @param array        $pod     Pod data
1730
	 * @param int          $id      Item ID
1731
	 *
1732
	 * @return string
1733
	 *
1734
	 * @since 2.2
1735
	 */
1736
	public function value_to_label( $name, $value = null, $options = null, $pod = null, $id = null ) {
1737
1738 View Code Duplication
		if ( isset( $options['options'] ) ) {
1739
			$options = array_merge( $options, $options['options'] );
1740
1741
			unset( $options['options'] );
1742
		}
1743
1744
		$data = pods_v( 'data', $options, null, true );
1745
1746
		$object_params = array(
1747
			'name'    => $name, // The name of the field.
1748
			'value'   => $value, // The value of the field.
1749
			'options' => $options, // Field options.
1750
			'pod'     => $pod, // Pod data.
1751
			'id'      => $id, // Item ID.
1752
			'context' => 'value_to_label', // Data context.
1753
		);
1754
1755
		if ( null !== $data ) {
1756
			$data = (array) $data;
1757
		} else {
1758
			$data = $this->get_object_data( $object_params );
1759
		}
1760
1761
		$labels = array();
1762
1763
		$check_value = $value;
1764
1765
		foreach ( $check_value as &$check_v ) {
0 ignored issues
show
Bug introduced by
The expression $check_value of type string|array|null is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
1766
			$check_v = (string) $check_v;
1767
		}
1768
1769
		foreach ( $data as $v => $l ) {
0 ignored issues
show
Bug introduced by
The expression $data of type array|boolean is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
1770
			if ( ! in_array( (string) $l, $labels, true ) && ( (string) $value === (string) $v || ( is_array( $value ) && in_array( (string) $v, $value, true ) ) ) ) {
1771
				$labels[] = (string) $l;
1772
			}
1773
		}
1774
1775
		$labels = apply_filters( 'pods_field_pick_value_to_label', $labels, $name, $value, $options, $pod, $id );
1776
1777
		$labels = pods_serial_comma( $labels );
1778
1779
		return $labels;
1780
1781
	}
1782
1783
	/**
1784
	 * Get available items from a relationship field
1785
	 *
1786
	 * @param array|string $field         Field array or field name
1787
	 * @param array        $options       [optional] Field options array overrides
1788
	 * @param array        $object_params [optional] Additional get_object_data options
1789
	 *
1790
	 * @return array An array of available items from a relationship field
1791
	 */
1792
	public function get_field_data( $field, $options = array(), $object_params = array() ) {
1793
1794
		// Handle field array overrides.
1795
		if ( is_array( $field ) ) {
1796
			$options = array_merge( $field, $options );
1797
		}
1798
1799
		// Get field name from array.
1800
		$field = pods_v( 'name', $options, $field, true );
1801
1802
		// Field name or options not set.
1803
		if ( empty( $field ) || empty( $options ) ) {
1804
			return array();
1805
		}
1806
1807
		// Options normalization.
1808
		$options = array_merge( $options, pods_v( 'options', $options, array(), true ) );
1809
1810
		// Setup object params.
1811
		$object_params = array_merge( array(
1812
			'name'    => $field, // The name of the field.
1813
			'options' => $options, // Field options.
1814
		), $object_params );
1815
1816
		// Get data override.
1817
		$data = pods_v( 'data', $options, null, true );
1818
1819
		if ( null !== $data ) {
1820
			// Return data override.
1821
			$data = (array) $data;
1822
		} else {
1823
			// Get object data.
1824
			$data = $this->get_object_data( $object_params );
1825
		}
1826
1827
		return $data;
1828
1829
	}
1830
1831
	/**
1832
	 * Get data from relationship objects
1833
	 *
1834
	 * @param array $object_params Object data parameters
1835
	 *
1836
	 * @return array|bool Object data
1837
	 */
1838
	public function get_object_data( $object_params = null ) {
1839
1840
		/**
1841
		 * @var $wpdb wpdb
1842
		 */
1843
		global $wpdb;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
1844
1845
		$object_params = array_merge( array(
1846
			// The name of the field.
1847
			'name'        => '',
1848
			// The value of the field.
1849
			'value'       => '',
1850
			// Field options.
1851
			'options'     => array(),
1852
			// Pod data.
1853
			'pod'         => '',
1854
			// Item ID.
1855
			'id'          => '',
1856
			// Data context.
1857
			'context'     => '',
1858
			// Data parameters.
1859
			'data_params' => array(
1860
				'query' => '', // Query being searched.
1861
			),
1862
			// Page number of results to get.
1863
			'page'        => 1,
1864
			// How many data items to limit to (autocomplete defaults to 30, set to -1 or 1+ to override).
1865
			'limit'       => 0,
1866
		), $object_params );
1867
1868
		$name         = $object_params[ 'name' ];
1869
		$value        = $object_params[ 'value' ];
1870
		$options      = $object_params[ 'options' ] = (array) $object_params[ 'options' ];
1871
		$pod          = $object_params[ 'pod' ];
1872
		$id           = $object_params[ 'id' ];
1873
		$context      = $object_params[ 'context' ];
1874
		$data_params  = $object_params[ 'data_params' ] = (array) $object_params[ 'data_params' ];
1875
		$page         = min( 1, (int) $object_params[ 'page' ] );
1876
		$limit        = (int) $object_params[ 'limit' ];
1877
		$autocomplete = false;
1878
1879 View Code Duplication
		if ( isset( $options['options'] ) ) {
1880
			$options = array_merge( $options, $options['options'] );
1881
1882
			unset( $options['options'] );
1883
		}
1884
1885
		$data  = apply_filters( 'pods_field_pick_object_data', null, $name, $value, $options, $pod, $id, $object_params );
1886
		$items = array();
1887
1888
		if ( ! isset( $options[ self::$type . '_object' ] ) ) {
1889
			$data = pods_v( 'data', $options, array(), true );
1890
		}
1891
1892
		$simple = false;
1893
1894
		if ( null === $data ) {
1895
			$data = array();
1896
1897
			if ( 'custom-simple' === $options[ self::$type . '_object' ] ) {
1898
				$custom = pods_v( self::$type . '_custom', $options, '' );
1899
1900
				$custom = apply_filters( 'pods_form_ui_field_pick_custom_values', $custom, $name, $value, $options, $pod, $id, $object_params );
1901
1902
				if ( ! empty( $custom ) ) {
1903
					if ( ! is_array( $custom ) ) {
1904
						$data = array();
1905
1906
						$custom = explode( "\n", trim( $custom ) );
1907
1908
						foreach ( $custom as $custom_value ) {
1909
							$custom_label = explode( '|', $custom_value );
1910
1911
							if ( empty( $custom_label ) ) {
1912
								continue;
1913
							}
1914
1915
							if ( 1 === count( $custom_label ) ) {
1916
								$custom_label = $custom_value;
1917
							} else {
1918
								$custom_value = $custom_label[0];
1919
								$custom_label = $custom_label[1];
1920
							}
1921
1922
							$custom_value = trim( (string) $custom_value );
1923
							$custom_label = trim( (string) $custom_label );
1924
1925
							$data[ $custom_value ] = $custom_label;
1926
						}
1927
					} else {
1928
						$data = $custom;
1929
					}
1930
1931
					$simple = true;
1932
				}
1933
			} elseif ( isset( self::$related_objects[ $options[ self::$type . '_object' ] ] ) && isset( self::$related_objects[ $options[ self::$type . '_object' ] ]['data'] ) && ! empty( self::$related_objects[ $options[ self::$type . '_object' ] ]['data'] ) ) {
1934
				$data = self::$related_objects[ $options[ self::$type . '_object' ] ]['data'];
1935
1936
				$simple = true;
1937
			} elseif ( isset( self::$related_objects[ $options[ self::$type . '_object' ] ] ) && isset( self::$related_objects[ $options[ self::$type . '_object' ] ]['data_callback'] ) && is_callable( self::$related_objects[ $options[ self::$type . '_object' ] ]['data_callback'] ) ) {
1938
				$data = call_user_func_array( self::$related_objects[ $options[ self::$type . '_object' ] ]['data_callback'], array(
1939
						$name,
1940
						$value,
1941
						$options,
1942
						$pod,
1943
						$id,
1944
					)
1945
				);
1946
1947 View Code Duplication
				if ( 'data' === $context ) {
1948
					self::$field_data = array(
1949
						'field'        => $name,
1950
						'id'           => $options['id'],
1951
						'autocomplete' => false,
1952
					);
1953
				}
1954
1955
				$simple = true;
1956
1957
				// Cache data from callback.
1958
				if ( ! empty( $data ) ) {
1959
					self::$related_objects[ $options[ self::$type . '_object' ] ]['data'] = $data;
1960
				}
1961
			} elseif ( 'simple_value' !== $context ) {
1962
				$pick_val = pods_v( self::$type . '_val', $options );
1963
1964
				if ( 'table' === pods_v( self::$type . '_object', $options ) ) {
1965
					$pick_val = pods_v( self::$type . '_table', $options, $pick_val, true );
1966
				}
1967
1968 View Code Duplication
				if ( '__current__' === $pick_val ) {
1969
					if ( is_object( $pod ) ) {
1970
						$pick_val = $pod->pod;
1971
					} elseif ( is_array( $pod ) ) {
1972
						$pick_val = $pod['name'];
1973
					} elseif ( 0 < strlen( $pod ) ) {
1974
						$pick_val = $pod;
1975
					}
1976
				}
1977
1978
				$options['table_info'] = pods_api()->get_table_info( pods_v( self::$type . '_object', $options ), $pick_val, null, null, $options );
1979
1980
				$search_data = pods_data();
1981
				$search_data->table( $options['table_info'] );
1982
1983
				if ( isset( $options['table_info']['pod'] ) && ! empty( $options['table_info']['pod'] ) && isset( $options['table_info']['pod']['name'] ) ) {
1984
					$search_data->pod    = $options['table_info']['pod']['name'];
1985
					$search_data->fields = $options['table_info']['pod']['fields'];
1986
				}
1987
1988
				$params = array(
1989
					'select'     => "`t`.`{$search_data->field_id}`, `t`.`{$search_data->field_index}`",
1990
					'table'      => $search_data->table,
1991
					'where'      => pods_v( self::$type . '_where', $options, (array) $options['table_info']['where_default'], true ),
1992
					'orderby'    => pods_v( self::$type . '_orderby', $options, null, true ),
1993
					'groupby'    => pods_v( self::$type . '_groupby', $options, null, true ),
1994
					// 'having' => pods_v( self::$type . '_having', $options, null, true ),
0 ignored issues
show
Unused Code Comprehensibility introduced by
56% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1995
					'pagination' => false,
1996
					'search'     => false
1997
				);
1998
1999
				if ( in_array( $options[ self::$type . '_object' ], array( 'site', 'network' ), true ) ) {
2000
					$params['select'] .= ', `t`.`path`';
2001
				}
2002
2003
				if ( ! empty( $params['where'] ) && (array) $options['table_info']['where_default'] !== $params['where'] ) {
2004
					$params['where'] = pods_evaluate_tags( $params['where'], true );
2005
				}
2006
2007
				if ( empty( $params['where'] ) || ( ! is_array( $params['where'] ) && strlen( trim( $params['where'] ) ) < 1 ) ) {
2008
					$params['where'] = array();
2009
				} elseif ( ! is_array( $params['where'] ) ) {
2010
					$params['where'] = (array) $params['where'];
2011
				}
2012
2013
				if ( 'value_to_label' === $context ) {
2014
					$params['where'][] = "`t`.`{$search_data->field_id}` = " . number_format( $value, 0, '', '' );
2015
				}
2016
2017
				/*
0 ignored issues
show
Unused Code Comprehensibility introduced by
60% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
2018
				if ( ! empty( $params['orderby'] ) ) {
2019
					$params['orderby'] = pods_evaluate_tags( $params['orderby'], true );
2020
				}
2021
2022
				if ( ! empty( $params['groupby'] ) ) {
2023
					$params['groupby'] = pods_evaluate_tags( $params['groupby'], true );
2024
				}
2025
				*/
2026
2027
				$display = trim( pods_v( self::$type . '_display', $options ), ' {@}' );
2028
2029
				if ( 0 < strlen( $display ) ) {
2030
					if ( isset( $options['table_info']['pod'] ) && ! empty( $options['table_info']['pod'] ) ) {
2031
						if ( isset( $options['table_info']['pod']['object_fields'] ) && isset( $options['table_info']['pod']['object_fields'][ $display ] ) ) {
2032
							$search_data->field_index = $display;
2033
2034
							$params['select'] = "`t`.`{$search_data->field_id}`, `t`.`{$search_data->field_index}`";
2035
						} elseif ( isset( $options['table_info']['pod']['fields'][ $display ] ) ) {
2036
							$search_data->field_index = $display;
2037
2038
							if ( 'table' === $options['table_info']['pod']['storage'] && ! in_array( $options['table_info']['pod']['type'], array(
2039
									'pod',
2040
									'table',
2041
								), true )
2042
							) {
2043
								$params['select'] = "`t`.`{$search_data->field_id}`, `d`.`{$search_data->field_index}`";
2044
							} elseif ( 'meta' === $options['table_info']['pod']['storage'] ) {
2045
								$params['select'] = "`t`.`{$search_data->field_id}`, `{$search_data->field_index}`.`meta_value` AS {$search_data->field_index}";
2046
							} else {
2047
								$params['select'] = "`t`.`{$search_data->field_id}`, `t`.`{$search_data->field_index}`";
2048
							}
2049
						}
2050
					} elseif ( isset( $options['table_info']['object_fields'] ) && isset( $options['table_info']['object_fields'][ $display ] ) ) {
2051
						$search_data->field_index = $display;
2052
2053
						$params['select'] = "`t`.`{$search_data->field_id}`, `t`.`{$search_data->field_index}`";
2054
					}
2055
				}
2056
2057
				$autocomplete = $this->is_autocomplete( $options );
2058
2059
				$hierarchy = false;
2060
2061
				if ( 'data' === $context && ! $autocomplete ) {
2062
					if ( 'single' === pods_v( self::$type . '_format_type', $options, 'single' ) && in_array( pods_v( self::$type . '_format_single', $options, 'dropdown' ), array(
2063
							'dropdown',
2064
							'radio',
2065
						), true )
2066
					) {
2067
						$hierarchy = true;
2068 View Code Duplication
					} elseif ( 'multi' === pods_v( self::$type . '_format_type', $options, 'single' ) && in_array( pods_v( self::$type . '_format_multi', $options, 'checkbox' ), array(
2069
							'multiselect',
2070
							'checkbox',
2071
						), true )
2072
					) {
2073
						$hierarchy = true;
2074
					}
2075
				}
2076
2077
				if ( $hierarchy && $options['table_info']['object_hierarchical'] && ! empty( $options['table_info']['field_parent'] ) ) {
2078
					$params['select'] .= ', ' . $options['table_info']['field_parent_select'];
2079
				}
2080
2081
				if ( $autocomplete ) {
2082
					if ( 0 === $limit ) {
2083
						$limit = 30;
2084
					}
2085
2086
					$params['limit'] = apply_filters( 'pods_form_ui_field_pick_autocomplete_limit', $limit, $name, $value, $options, $pod, $id, $object_params );
2087
2088
					if ( is_array( $value ) && $params['limit'] < count( $value ) ) {
2089
						$params['limit'] = count( $value );
2090
					}
2091
2092
					$params['page'] = $page;
2093
2094
					if ( 'admin_ajax_relationship' === $context ) {
2095
						$lookup_where = array(
2096
							$search_data->field_index => "`t`.`{$search_data->field_index}` LIKE '%" . pods_sanitize_like( $data_params['query'] ) . "%'",
2097
						);
2098
2099
						// @todo Hook into WPML for each table
2100
						if ( $wpdb->users === $search_data->table ) {
2101
							$lookup_where['display_name'] = "`t`.`display_name` LIKE '%" . pods_sanitize_like( $data_params['query'] ) . "%'";
2102
							$lookup_where['user_login']   = "`t`.`user_login` LIKE '%" . pods_sanitize_like( $data_params['query'] ) . "%'";
2103
							$lookup_where['user_email']   = "`t`.`user_email` LIKE '%" . pods_sanitize_like( $data_params['query'] ) . "%'";
2104
						} elseif ( $wpdb->posts === $search_data->table ) {
2105
							$lookup_where['post_title']   = "`t`.`post_title` LIKE '%" . pods_sanitize_like( $data_params['query'] ) . "%'";
2106
							$lookup_where['post_name']    = "`t`.`post_name` LIKE '%" . pods_sanitize_like( $data_params['query'] ) . "%'";
2107
							$lookup_where['post_content'] = "`t`.`post_content` LIKE '%" . pods_sanitize_like( $data_params['query'] ) . "%'";
2108
							$lookup_where['post_excerpt'] = "`t`.`post_excerpt` LIKE '%" . pods_sanitize_like( $data_params['query'] ) . "%'";
2109
						} elseif ( $wpdb->terms === $search_data->table ) {
2110
							$lookup_where['name'] = "`t`.`name` LIKE '%" . pods_sanitize_like( $data_params['query'] ) . "%'";
2111
							$lookup_where['slug'] = "`t`.`slug` LIKE '%" . pods_sanitize_like( $data_params['query'] ) . "%'";
2112
						} elseif ( $wpdb->comments === $search_data->table ) {
2113
							$lookup_where['comment_content']      = "`t`.`comment_content` LIKE '%" . pods_sanitize_like( $data_params['query'] ) . "%'";
2114
							$lookup_where['comment_author']       = "`t`.`comment_author` LIKE '%" . pods_sanitize_like( $data_params['query'] ) . "%'";
2115
							$lookup_where['comment_author_email'] = "`t`.`comment_author_email` LIKE '%" . pods_sanitize_like( $data_params['query'] ) . "%'";
2116
						}
2117
2118
						$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 );
2119
2120
						if ( ! empty( $lookup_where ) ) {
2121
							$params['where'][] = implode( ' OR ', $lookup_where );
2122
						}
2123
2124
						$orderby   = array();
2125
						$orderby[] = "(`t`.`{$search_data->field_index}` LIKE '%" . pods_sanitize_like( $data_params['query'] ) . "%' ) DESC";
2126
2127
						$pick_orderby = pods_v( self::$type . '_orderby', $options, null, true );
2128
2129
						if ( 0 < strlen( $pick_orderby ) ) {
2130
							$orderby[] = $pick_orderby;
2131
						}
2132
2133
						$orderby[] = "`t`.`{$search_data->field_index}`";
2134
						$orderby[] = "`t`.`{$search_data->field_id}`";
2135
2136
						$params['orderby'] = $orderby;
2137
					}
2138
				} elseif ( 0 < $limit ) {
2139
					$params['limit'] = $limit;
2140
					$params['page']  = $page;
2141
				}
2142
2143
				$extra = '';
2144
2145
				if ( $wpdb->posts === $search_data->table ) {
2146
					$extra = ', `t`.`post_type`';
2147
				} elseif ( $wpdb->terms === $search_data->table ) {
2148
					$extra = ', `tt`.`taxonomy`';
2149
				} elseif ( $wpdb->comments === $search_data->table ) {
2150
					$extra = ', `t`.`comment_type`';
2151
				}
2152
2153
				$params['select'] .= $extra;
2154
2155
				if ( 'user' === pods_v( self::$type . '_object', $options ) ) {
2156
					$roles = pods_v( self::$type . '_user_role', $options );
2157
2158
					if ( ! empty( $roles ) ) {
2159
						$where = array();
2160
2161
						foreach ( (array) $roles as $role ) {
2162
							if ( empty( $role ) || ( pods_clean_name( $role ) !== $role && sanitize_title( $role ) !== $role ) ) {
2163
								continue;
2164
							}
2165
2166
							$where[] = $wpdb->base_prefix . ( ( is_multisite() && ! is_main_site() ) ? get_current_blog_id() . '_' : '' ) . 'capabilities.meta_value LIKE "%\"' . pods_sanitize_like( $role ) . '\"%"';
2167
						}
2168
2169
						if ( ! empty( $where ) ) {
2170
							$params['where'][] = implode( ' OR ', $where );
2171
						}
2172
					}
2173
				}
2174
2175
				$results = $search_data->select( $params );
2176
2177
				if ( $autocomplete && $params['limit'] < $search_data->total_found() ) {
2178
					if ( ! empty( $value ) ) {
2179
						$ids = $value;
2180
2181
						if ( is_array( $ids ) && isset( $ids[0] ) && is_array( $ids[0] ) ) {
2182
							$ids = wp_list_pluck( $ids, $search_data->field_id );
2183
						}
2184
2185
						if ( is_array( $ids ) ) {
2186
							$ids = implode( ', ', $ids );
2187
						}
2188
2189
						if ( is_array( $params['where'] ) ) {
2190
							$params['where'] = implode( ' AND ', $params['where'] );
2191
						}
2192
						if ( ! empty( $params['where'] ) ) {
2193
							$params['where'] .= ' AND ';
2194
						}
2195
2196
						$params['where'] .= "`t`.`{$search_data->field_id}` IN ( {$ids} )";
2197
2198
						$results = $search_data->select( $params );
2199
					}
2200
				} else {
2201
					$autocomplete = false;
2202
				}
2203
2204 View Code Duplication
				if ( 'data' === $context ) {
2205
					self::$field_data = array(
2206
						'field'        => $name,
2207
						'id'           => $options['id'],
2208
						'autocomplete' => $autocomplete,
2209
					);
2210
				}
2211
2212
				if ( $hierarchy && ! $autocomplete && ! empty( $results ) && $options['table_info']['object_hierarchical'] && ! empty( $options['table_info']['field_parent'] ) ) {
2213
					$select_args = array(
2214
						'id'     => $options['table_info']['field_id'],
2215
						'index'  => $options['table_info']['field_index'],
2216
						'parent' => $options['table_info']['field_parent'],
2217
					);
2218
2219
					$results = pods_hierarchical_select( $results, $select_args );
2220
				}
2221
2222
				$ids = array();
2223
2224
				if ( ! empty( $results ) ) {
2225
					$display_filter = pods_v( 'display_filter', pods_v( 'options', pods_v( $search_data->field_index, $search_data->pod_data['object_fields'] ) ) );
2226
2227
					foreach ( $results as $result ) {
2228
						$result = get_object_vars( $result );
2229
2230
						if ( ! isset( $result[ $search_data->field_id ] ) || ! isset( $result[ $search_data->field_index ] ) ) {
2231
							continue;
2232
						}
2233
2234
						$result[ $search_data->field_index ] = trim( $result[ $search_data->field_index ] );
2235
2236
						$object = $object_type = '';
2237
2238
						if ( $wpdb->posts === $search_data->table && isset( $result['post_type'] ) ) {
2239
							$object      = $result['post_type'];
2240
							$object_type = 'post_type';
2241
						} elseif ( $wpdb->terms === $search_data->table && isset( $result['taxonomy'] ) ) {
2242
							$object      = $result['taxonomy'];
2243
							$object_type = 'taxonomy';
2244
						}
2245
2246
						if ( 0 < strlen( $display_filter ) ) {
2247
							$display_filter_args = pods_v( 'display_filter_args', pods_v( 'options', pods_v( $search_data->field_index, $search_data->pod_data['object_fields'] ) ) );
2248
2249
							$filter_args = array(
2250
								$display_filter,
2251
								$result[ $search_data->field_index ],
2252
							);
2253
2254
							if ( ! empty( $display_filter_args ) ) {
2255
								foreach ( (array) $display_filter_args as $display_filter_arg ) {
2256
									if ( isset( $result[ $display_filter_arg ] ) ) {
2257
										$filter_args[] = $result[ $display_filter_arg ];
2258
									}
2259
								}
2260
							}
2261
2262
							$result[ $search_data->field_index ] = call_user_func_array( 'apply_filters', $filter_args );
2263
						}
2264
2265
						if ( in_array( $options[ self::$type . '_object' ], array( 'site', 'network' ), true ) ) {
2266
							$result[ $search_data->field_index ] = $result[ $search_data->field_index ] . $result['path'];
2267
						} elseif ( strlen( $result[ $search_data->field_index ] ) < 1 ) {
2268
							$result[ $search_data->field_index ] = '(No Title)';
2269
						}
2270
2271
						if ( 'admin_ajax_relationship' === $context ) {
2272
							$items[] = array(
2273
								'id'    => $result[ $search_data->field_id ],
2274
								'text'  => $result[ $search_data->field_index ],
2275
								'image' => '',
2276
							);
2277
						} else {
2278
							$data[ $result[ $search_data->field_id ] ] = $result[ $search_data->field_index ];
2279
						}
2280
2281
						$ids[] = $result[ $search_data->field_id ];
2282
					}
2283
				}
2284
			}
2285
2286
			if ( $simple && 'admin_ajax_relationship' === $context ) {
2287
				$found_data = array();
2288
2289
				foreach ( $data as $k => $v ) {
2290
					if ( false !== stripos( $v, $data_params['query'] ) || false !== stripos( $k, $data_params['query'] ) ) {
2291
						$found_data[ $k ] = $v;
2292
					}
2293
				}
2294
2295
				$data = $found_data;
2296
			}
2297
		}
2298
2299
		if ( 'admin_ajax_relationship' === $context ) {
2300
			if ( empty( $items ) && ! empty( $data ) ) {
2301
				foreach ( $data as $k => $v ) {
2302
					$items[] = array(
2303
						'id'    => $k,
2304
						'text'  => $v,
2305
						'image' => '',
2306
					);
2307
				}
2308
			}
2309
2310
			$data = $items;
2311
		}
2312
2313
		return $data;
2314
2315
	}
2316
2317
	/**
2318
	 * @param array $options Field options
2319
	 *
2320
	 * @return bool
2321
	 */
2322
	public function is_autocomplete( $options ) {
2323
2324
		$autocomplete = false;
2325
2326
		if ( 'single' === pods_v( self::$type . '_format_type', $options, 'single' ) ) {
2327
			if ( in_array( pods_v( self::$type . '_format_single', $options, 'dropdown' ), array( 'autocomplete', 'list' ) ) ) {
2328
				$autocomplete = true;
2329
			}
2330 View Code Duplication
		} elseif ( 'multi' === pods_v( self::$type . '_format_type', $options, 'single' ) ) {
2331
			if ( in_array( pods_v( self::$type . '_format_multi', $options, 'checkbox' ), array( 'autocomplete', 'list' ) ) ) {
2332
				$autocomplete = true;
2333
			}
2334
		}
2335
2336
		return $autocomplete;
2337
	}
2338
2339
	/**
2340
	 * Handle autocomplete AJAX.
2341
	 *
2342
	 * @since 2.3
2343
	 */
2344
	public function admin_ajax_relationship() {
2345
2346
		pods_session_start();
2347
2348
		// Sanitize input.
2349
		$params = pods_unslash( (array) $_POST );
2350
2351 View Code Duplication
		foreach ( $params as $key => $value ) {
2352
			if ( 'action' === $key ) {
2353
				continue;
2354
			}
2355
2356
			unset( $params[ $key ] );
2357
2358
			$params[ str_replace( '_podsfix_', '', $key ) ] = $value;
2359
		}
2360
2361
		$params = (object) $params;
2362
2363
		$uid = @session_id();
2364
2365
		if ( is_user_logged_in() ) {
2366
			$uid = 'user_' . get_current_user_id();
2367
		}
2368
2369
		$nonce_check = 'pods_relationship_' . (int) $params->pod . '_' . $uid . '_' . $params->uri . '_' . (int) $params->field;
2370
2371 View Code Duplication
		if ( ! isset( $params->_wpnonce ) || false === wp_verify_nonce( $params->_wpnonce, $nonce_check ) ) {
2372
			pods_error( __( 'Unauthorized request', 'pods' ), PodsInit::$admin );
0 ignored issues
show
Bug introduced by
The property admin cannot be accessed from this context as it is declared private in class PodsInit.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
2373
		}
2374
2375
		if ( empty( self::$api ) ) {
2376
			self::$api = pods_api();
2377
		}
2378
2379
		$pod   = self::$api->load_pod( array( 'id' => (int) $params->pod ) );
2380
		$field = self::$api->load_field( array( 'id' => (int) $params->field, 'table_info' => true ) );
2381
		$id    = (int) $params->id;
2382
2383
		$limit = 15;
2384
2385
		if ( isset( $params->limit ) ) {
2386
			$limit = (int) $params->limit;
2387
		}
2388
2389
		$page = 1;
2390
2391
		if ( isset( $params->page ) ) {
2392
			$page = (int) $params->page;
2393
		}
2394
2395
		if ( ! isset( $params->query ) || strlen( trim( $params->query ) ) < 1 ) {
2396
			pods_error( __( 'Invalid field request', 'pods' ), PodsInit::$admin );
0 ignored issues
show
Bug introduced by
The property admin cannot be accessed from this context as it is declared private in class PodsInit.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
2397
		} elseif ( empty( $pod ) || empty( $field ) || (int) $pod['id'] !== (int) $field['pod_id'] || ! isset( $pod['fields'][ $field['name'] ] ) ) {
2398
			pods_error( __( 'Invalid field request', 'pods' ), PodsInit::$admin );
0 ignored issues
show
Bug introduced by
The property admin cannot be accessed from this context as it is declared private in class PodsInit.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
2399
		} elseif ( 'pick' !== $field['type'] || empty( $field['table_info'] ) ) {
2400
			pods_error( __( 'Invalid field', 'pods' ), PodsInit::$admin );
0 ignored issues
show
Bug introduced by
The property admin cannot be accessed from this context as it is declared private in class PodsInit.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
2401
		} elseif ( 'single' === pods_v( self::$type . '_format_type', $field ) && 'autocomplete' === pods_v( self::$type . '_format_single', $field ) ) {
2402
			pods_error( __( 'Invalid field', 'pods' ), PodsInit::$admin );
0 ignored issues
show
Bug introduced by
The property admin cannot be accessed from this context as it is declared private in class PodsInit.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
2403
		} elseif ( 'multi' === pods_v( self::$type . '_format_type', $field ) && 'autocomplete' === pods_v( self::$type . '_format_multi', $field ) ) {
2404
			pods_error( __( 'Invalid field', 'pods' ), PodsInit::$admin );
0 ignored issues
show
Bug introduced by
The property admin cannot be accessed from this context as it is declared private in class PodsInit.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
2405
		}
2406
2407
		$object_params = array(
2408
			'name'        => $field['name'], // The name of the field.
2409
			'value'       => null, // The value of the field.
2410
			'options'     => array_merge( $field, $field['options'] ), // Field options.
2411
			'pod'         => $pod, // Pod data.
2412
			'id'          => $id, // Item ID.
2413
			'context'     => 'admin_ajax_relationship', // Data context.
2414
			'data_params' => $params,
2415
			'page'        => $page,
2416
			'limit'       => $limit
2417
		);
2418
2419
		$pick_data = apply_filters( 'pods_field_pick_data_ajax', null, $field['name'], null, $field, $pod, $id );
2420
2421
		if ( null !== $pick_data ) {
2422
			$items = $pick_data;
2423
		} else {
2424
			$items = $this->get_object_data( $object_params );
2425
		}
2426
2427
		if ( ! empty( $items ) && isset( $items[0] ) && ! is_array( $items[0] ) ) {
2428
			$new_items = array();
2429
2430
			foreach ( $items as $id => $text ) {
2431
				$new_items[] = array(
2432
					'id'    => $id,
2433
					'text'  => $text,
2434
					'image' => '',
2435
				);
2436
			}
2437
2438
			$items = $new_items;
2439
		}
2440
2441
		$items = apply_filters( 'pods_field_pick_data_ajax_items', $items, $field['name'], null, $field, $pod, $id );
2442
2443
		$items = array(
2444
			'results' => $items,
2445
		);
2446
2447
		wp_send_json( $items );
2448
2449
		die(); // KBAI!
2450
2451
	}
2452
2453
	/**
2454
	 * Data callback for Post Stati
2455
	 *
2456
	 * @param string       $name    The name of the field
2457
	 * @param string|array $value   The value of the field
2458
	 * @param array        $options Field options
2459
	 * @param array        $pod     Pod data
2460
	 * @param int          $id      Item ID
2461
	 *
2462
	 * @return array
2463
	 *
2464
	 * @since 2.3
2465
	 */
2466
	public function data_post_stati( $name = null, $value = null, $options = null, $pod = null, $id = null ) {
2467
2468
		$data = array();
2469
2470
		$post_stati = get_post_stati( array(), 'objects' );
2471
2472
		foreach ( $post_stati as $post_status ) {
2473
			$data[ $post_status->name ] = $post_status->label;
2474
		}
2475
2476
		return apply_filters( 'pods_form_ui_field_pick_' . __FUNCTION__, $data, $name, $value, $options, $pod, $id );
2477
2478
	}
2479
2480
	/**
2481
	 * Data callback for User Roles
2482
	 *
2483
	 * @param string       $name    The name of the field
2484
	 * @param string|array $value   The value of the field
2485
	 * @param array        $options Field options
2486
	 * @param array        $pod     Pod data
2487
	 * @param int          $id      Item ID
2488
	 *
2489
	 * @return array
2490
	 *
2491
	 * @since 2.3
2492
	 */
2493
	public function data_roles( $name = null, $value = null, $options = null, $pod = null, $id = null ) {
2494
2495
		$data = array();
2496
2497
		global $wp_roles;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
2498
2499
		foreach ( $wp_roles->role_objects as $key => $role ) {
2500
			$data[ $key ] = $wp_roles->role_names[ $key ];
2501
		}
2502
2503
		return apply_filters( 'pods_form_ui_field_pick_' . __FUNCTION__, $data, $name, $value, $options, $pod, $id );
2504
2505
	}
2506
2507
	/**
2508
	 * Data callback for User Capabilities
2509
	 *
2510
	 * @param string       $name    The name of the field
2511
	 * @param string|array $value   The value of the field
2512
	 * @param array        $options Field options
2513
	 * @param array        $pod     Pod data
2514
	 * @param int          $id      Item ID
2515
	 *
2516
	 * @return array
2517
	 *
2518
	 * @since 2.3
2519
	 */
2520
	public function data_capabilities( $name = null, $value = null, $options = null, $pod = null, $id = null ) {
2521
2522
		$data = array();
2523
2524
		global $wp_roles;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
2525
2526
		$default_caps = array(
2527
			'activate_plugins',
2528
			'add_users',
2529
			'create_users',
2530
			'delete_others_pages',
2531
			'delete_others_posts',
2532
			'delete_pages',
2533
			'delete_plugins',
2534
			'delete_posts',
2535
			'delete_private_pages',
2536
			'delete_private_posts',
2537
			'delete_published_pages',
2538
			'delete_published_posts',
2539
			'delete_users',
2540
			'edit_dashboard',
2541
			'edit_files',
2542
			'edit_others_pages',
2543
			'edit_others_posts',
2544
			'edit_pages',
2545
			'edit_plugins',
2546
			'edit_posts',
2547
			'edit_private_pages',
2548
			'edit_private_posts',
2549
			'edit_published_pages',
2550
			'edit_published_posts',
2551
			'edit_theme_options',
2552
			'edit_themes',
2553
			'edit_users',
2554
			'import',
2555
			'install_plugins',
2556
			'install_themes',
2557
			'list_users',
2558
			'manage_categories',
2559
			'manage_links',
2560
			'manage_options',
2561
			'moderate_comments',
2562
			'promote_users',
2563
			'publish_pages',
2564
			'publish_posts',
2565
			'read',
2566
			'read_private_pages',
2567
			'read_private_posts',
2568
			'remove_users',
2569
			'switch_themes',
2570
			'unfiltered_html',
2571
			'unfiltered_upload',
2572
			'update_core',
2573
			'update_plugins',
2574
			'update_themes',
2575
			'upload_files',
2576
		);
2577
2578
		$role_caps = array();
2579
2580 View Code Duplication
		foreach ( $wp_roles->role_objects as $key => $role ) {
2581
			if ( is_array( $role->capabilities ) ) {
2582
				foreach ( $role->capabilities as $cap => $grant ) {
2583
					$role_caps[ $cap ] = $cap;
2584
				}
2585
			}
2586
		}
2587
2588
		$role_caps = array_unique( $role_caps );
2589
2590
		$capabilities = array_merge( $default_caps, $role_caps );
2591
2592
		// To support Members filters
2593
		$capabilities = apply_filters( 'members_get_capabilities', $capabilities );
2594
2595
		$capabilities = apply_filters( 'pods_roles_get_capabilities', $capabilities );
2596
2597
		sort( $capabilities );
2598
2599
		$capabilities = array_unique( $capabilities );
2600
2601
		global $wp_roles;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
2602
2603
		foreach ( $capabilities as $capability ) {
2604
			$data[ $capability ] = $capability;
2605
		}
2606
2607
		return apply_filters( 'pods_form_ui_field_pick_' . __FUNCTION__, $data, $name, $value, $options, $pod, $id );
2608
2609
	}
2610
2611
	/**
2612
	 * Data callback for Image Sizes
2613
	 *
2614
	 * @param string       $name    The name of the field
2615
	 * @param string|array $value   The value of the field
2616
	 * @param array        $options Field options
2617
	 * @param array        $pod     Pod data
2618
	 * @param int          $id      Item ID
2619
	 *
2620
	 * @return array
2621
	 *
2622
	 * @since 2.3
2623
	 */
2624 View Code Duplication
	public function data_image_sizes( $name = null, $value = null, $options = null, $pod = null, $id = null ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2625
2626
		$data = array();
2627
2628
		$image_sizes = get_intermediate_image_sizes();
2629
2630
		foreach ( $image_sizes as $image_size ) {
2631
			$data[ $image_size ] = ucwords( str_replace( '-', ' ', $image_size ) );
2632
		}
2633
2634
		return apply_filters( 'pods_form_ui_field_pick_' . __FUNCTION__, $data, $name, $value, $options, $pod, $id );
2635
2636
	}
2637
2638
	/**
2639
	 * Data callback for Countries
2640
	 *
2641
	 * @param string       $name    The name of the field
2642
	 * @param string|array $value   The value of the field
2643
	 * @param array        $options Field options
2644
	 * @param array        $pod     Pod data
2645
	 * @param int          $id      Item ID
2646
	 *
2647
	 * @return array
2648
	 *
2649
	 * @since 2.3
2650
	 */
2651
	public function data_countries( $name = null, $value = null, $options = null, $pod = null, $id = null ) {
2652
2653
		$data = array(
2654
			'AF' => __( 'Afghanistan' ),
2655
			'AL' => __( 'Albania' ),
2656
			'DZ' => __( 'Algeria' ),
2657
			'AS' => __( 'American Samoa' ),
2658
			'AD' => __( 'Andorra' ),
2659
			'AO' => __( 'Angola' ),
2660
			'AI' => __( 'Anguilla' ),
2661
			'AQ' => __( 'Antarctica' ),
2662
			'AG' => __( 'Antigua and Barbuda' ),
2663
			'AR' => __( 'Argentina' ),
2664
			'AM' => __( 'Armenia' ),
2665
			'AW' => __( 'Aruba' ),
2666
			'AU' => __( 'Australia' ),
2667
			'AT' => __( 'Austria' ),
2668
			'AZ' => __( 'Azerbaijan' ),
2669
			'BS' => __( 'Bahamas' ),
2670
			'BH' => __( 'Bahrain' ),
2671
			'BD' => __( 'Bangladesh' ),
2672
			'BB' => __( 'Barbados' ),
2673
			'BY' => __( 'Belarus' ),
2674
			'BE' => __( 'Belgium' ),
2675
			'BZ' => __( 'Belize' ),
2676
			'BJ' => __( 'Benin' ),
2677
			'BM' => __( 'Bermuda' ),
2678
			'BT' => __( 'Bhutan' ),
2679
			'BO' => __( 'Bolivia' ),
2680
			'BA' => __( 'Bosnia and Herzegovina' ),
2681
			'BW' => __( 'Botswana' ),
2682
			'BV' => __( 'Bouvet Island' ),
2683
			'BR' => __( 'Brazil' ),
2684
			'BQ' => __( 'British Antarctic Territory' ),
2685
			'IO' => __( 'British Indian Ocean Territory' ),
2686
			'VG' => __( 'British Virgin Islands' ),
2687
			'BN' => __( 'Brunei' ),
2688
			'BG' => __( 'Bulgaria' ),
2689
			'BF' => __( 'Burkina Faso' ),
2690
			'BI' => __( 'Burundi' ),
2691
			'KH' => __( 'Cambodia' ),
2692
			'CM' => __( 'Cameroon' ),
2693
			'CA' => __( 'Canada' ),
2694
			'CT' => __( 'Canton and Enderbury Islands' ),
2695
			'CV' => __( 'Cape Verde' ),
2696
			'KY' => __( 'Cayman Islands' ),
2697
			'CF' => __( 'Central African Republic' ),
2698
			'TD' => __( 'Chad' ),
2699
			'CL' => __( 'Chile' ),
2700
			'CN' => __( 'China' ),
2701
			'CX' => __( 'Christmas Island' ),
2702
			'CC' => __( 'Cocos [Keeling] Islands' ),
2703
			'CO' => __( 'Colombia' ),
2704
			'KM' => __( 'Comoros' ),
2705
			'CG' => __( 'Congo - Brazzaville' ),
2706
			'CD' => __( 'Congo - Kinshasa' ),
2707
			'CK' => __( 'Cook Islands' ),
2708
			'CR' => __( 'Costa Rica' ),
2709
			'HR' => __( 'Croatia' ),
2710
			'CU' => __( 'Cuba' ),
2711
			'CY' => __( 'Cyprus' ),
2712
			'CZ' => __( 'Czech Republic' ),
2713
			'CI' => __( 'Côte d’Ivoire' ),
2714
			'DK' => __( 'Denmark' ),
2715
			'DJ' => __( 'Djibouti' ),
2716
			'DM' => __( 'Dominica' ),
2717
			'DO' => __( 'Dominican Republic' ),
2718
			'NQ' => __( 'Dronning Maud Land' ),
2719
			'DD' => __( 'East Germany' ),
2720
			'EC' => __( 'Ecuador' ),
2721
			'EG' => __( 'Egypt' ),
2722
			'SV' => __( 'El Salvador' ),
2723
			'GQ' => __( 'Equatorial Guinea' ),
2724
			'ER' => __( 'Eritrea' ),
2725
			'EE' => __( 'Estonia' ),
2726
			'ET' => __( 'Ethiopia' ),
2727
			'FK' => __( 'Falkland Islands' ),
2728
			'FO' => __( 'Faroe Islands' ),
2729
			'FJ' => __( 'Fiji' ),
2730
			'FI' => __( 'Finland' ),
2731
			'FR' => __( 'France' ),
2732
			'GF' => __( 'French Guiana' ),
2733
			'PF' => __( 'French Polynesia' ),
2734
			'TF' => __( 'French Southern Territories' ),
2735
			'FQ' => __( 'French Southern and Antarctic Territories' ),
2736
			'GA' => __( 'Gabon' ),
2737
			'GM' => __( 'Gambia' ),
2738
			'GE' => __( 'Georgia' ),
2739
			'DE' => __( 'Germany' ),
2740
			'GH' => __( 'Ghana' ),
2741
			'GI' => __( 'Gibraltar' ),
2742
			'GR' => __( 'Greece' ),
2743
			'GL' => __( 'Greenland' ),
2744
			'GD' => __( 'Grenada' ),
2745
			'GP' => __( 'Guadeloupe' ),
2746
			'GU' => __( 'Guam' ),
2747
			'GT' => __( 'Guatemala' ),
2748
			'GG' => __( 'Guernsey' ),
2749
			'GN' => __( 'Guinea' ),
2750
			'GW' => __( 'Guinea-Bissau' ),
2751
			'GY' => __( 'Guyana' ),
2752
			'HT' => __( 'Haiti' ),
2753
			'HM' => __( 'Heard Island and McDonald Islands' ),
2754
			'HN' => __( 'Honduras' ),
2755
			'HK' => __( 'Hong Kong SAR China' ),
2756
			'HU' => __( 'Hungary' ),
2757
			'IS' => __( 'Iceland' ),
2758
			'IN' => __( 'India' ),
2759
			'ID' => __( 'Indonesia' ),
2760
			'IR' => __( 'Iran' ),
2761
			'IQ' => __( 'Iraq' ),
2762
			'IE' => __( 'Ireland' ),
2763
			'IM' => __( 'Isle of Man' ),
2764
			'IL' => __( 'Israel' ),
2765
			'IT' => __( 'Italy' ),
2766
			'JM' => __( 'Jamaica' ),
2767
			'JP' => __( 'Japan' ),
2768
			'JE' => __( 'Jersey' ),
2769
			'JT' => __( 'Johnston Island' ),
2770
			'JO' => __( 'Jordan' ),
2771
			'KZ' => __( 'Kazakhstan' ),
2772
			'KE' => __( 'Kenya' ),
2773
			'KI' => __( 'Kiribati' ),
2774
			'KW' => __( 'Kuwait' ),
2775
			'KG' => __( 'Kyrgyzstan' ),
2776
			'LA' => __( 'Laos' ),
2777
			'LV' => __( 'Latvia' ),
2778
			'LB' => __( 'Lebanon' ),
2779
			'LS' => __( 'Lesotho' ),
2780
			'LR' => __( 'Liberia' ),
2781
			'LY' => __( 'Libya' ),
2782
			'LI' => __( 'Liechtenstein' ),
2783
			'LT' => __( 'Lithuania' ),
2784
			'LU' => __( 'Luxembourg' ),
2785
			'MO' => __( 'Macau SAR China' ),
2786
			'MK' => __( 'Macedonia' ),
2787
			'MG' => __( 'Madagascar' ),
2788
			'MW' => __( 'Malawi' ),
2789
			'MY' => __( 'Malaysia' ),
2790
			'MV' => __( 'Maldives' ),
2791
			'ML' => __( 'Mali' ),
2792
			'MT' => __( 'Malta' ),
2793
			'MH' => __( 'Marshall Islands' ),
2794
			'MQ' => __( 'Martinique' ),
2795
			'MR' => __( 'Mauritania' ),
2796
			'MU' => __( 'Mauritius' ),
2797
			'YT' => __( 'Mayotte' ),
2798
			'FX' => __( 'Metropolitan France' ),
2799
			'MX' => __( 'Mexico' ),
2800
			'FM' => __( 'Micronesia' ),
2801
			'MI' => __( 'Midway Islands' ),
2802
			'MD' => __( 'Moldova' ),
2803
			'MC' => __( 'Monaco' ),
2804
			'MN' => __( 'Mongolia' ),
2805
			'ME' => __( 'Montenegro' ),
2806
			'MS' => __( 'Montserrat' ),
2807
			'MA' => __( 'Morocco' ),
2808
			'MZ' => __( 'Mozambique' ),
2809
			'MM' => __( 'Myanmar [Burma]' ),
2810
			'NA' => __( 'Namibia' ),
2811
			'NR' => __( 'Nauru' ),
2812
			'NP' => __( 'Nepal' ),
2813
			'NL' => __( 'Netherlands' ),
2814
			'AN' => __( 'Netherlands Antilles' ),
2815
			'NT' => __( 'Neutral Zone' ),
2816
			'NC' => __( 'New Caledonia' ),
2817
			'NZ' => __( 'New Zealand' ),
2818
			'NI' => __( 'Nicaragua' ),
2819
			'NE' => __( 'Niger' ),
2820
			'NG' => __( 'Nigeria' ),
2821
			'NU' => __( 'Niue' ),
2822
			'NF' => __( 'Norfolk Island' ),
2823
			'KP' => __( 'North Korea' ),
2824
			'VD' => __( 'North Vietnam' ),
2825
			'MP' => __( 'Northern Mariana Islands' ),
2826
			'NO' => __( 'Norway' ),
2827
			'OM' => __( 'Oman' ),
2828
			'PC' => __( 'Pacific Islands Trust Territory' ),
2829
			'PK' => __( 'Pakistan' ),
2830
			'PW' => __( 'Palau' ),
2831
			'PS' => __( 'Palestinian Territories' ),
2832
			'PA' => __( 'Panama' ),
2833
			'PZ' => __( 'Panama Canal Zone' ),
2834
			'PG' => __( 'Papua New Guinea' ),
2835
			'PY' => __( 'Paraguay' ),
2836
			'YD' => __( "People's Democratic Republic of Yemen" ),
2837
			'PE' => __( 'Peru' ),
2838
			'PH' => __( 'Philippines' ),
2839
			'PN' => __( 'Pitcairn Islands' ),
2840
			'PL' => __( 'Poland' ),
2841
			'PT' => __( 'Portugal' ),
2842
			'PR' => __( 'Puerto Rico' ),
2843
			'QA' => __( 'Qatar' ),
2844
			'RO' => __( 'Romania' ),
2845
			'RU' => __( 'Russia' ),
2846
			'RW' => __( 'Rwanda' ),
2847
			'RE' => __( 'Réunion' ),
2848
			'BL' => __( 'Saint Barthélemy' ),
2849
			'SH' => __( 'Saint Helena' ),
2850
			'KN' => __( 'Saint Kitts and Nevis' ),
2851
			'LC' => __( 'Saint Lucia' ),
2852
			'MF' => __( 'Saint Martin' ),
2853
			'PM' => __( 'Saint Pierre and Miquelon' ),
2854
			'VC' => __( 'Saint Vincent and the Grenadines' ),
2855
			'WS' => __( 'Samoa' ),
2856
			'SM' => __( 'San Marino' ),
2857
			'SA' => __( 'Saudi Arabia' ),
2858
			'SN' => __( 'Senegal' ),
2859
			'RS' => __( 'Serbia' ),
2860
			'CS' => __( 'Serbia and Montenegro' ),
2861
			'SC' => __( 'Seychelles' ),
2862
			'SL' => __( 'Sierra Leone' ),
2863
			'SG' => __( 'Singapore' ),
2864
			'SK' => __( 'Slovakia' ),
2865
			'SI' => __( 'Slovenia' ),
2866
			'SB' => __( 'Solomon Islands' ),
2867
			'SO' => __( 'Somalia' ),
2868
			'ZA' => __( 'South Africa' ),
2869
			'GS' => __( 'South Georgia and the South Sandwich Islands' ),
2870
			'KR' => __( 'South Korea' ),
2871
			'ES' => __( 'Spain' ),
2872
			'LK' => __( 'Sri Lanka' ),
2873
			'SD' => __( 'Sudan' ),
2874
			'SR' => __( 'Suriname' ),
2875
			'SJ' => __( 'Svalbard and Jan Mayen' ),
2876
			'SZ' => __( 'Swaziland' ),
2877
			'SE' => __( 'Sweden' ),
2878
			'CH' => __( 'Switzerland' ),
2879
			'SY' => __( 'Syria' ),
2880
			'ST' => __( 'São Tomé and Príncipe' ),
2881
			'TW' => __( 'Taiwan' ),
2882
			'TJ' => __( 'Tajikistan' ),
2883
			'TZ' => __( 'Tanzania' ),
2884
			'TH' => __( 'Thailand' ),
2885
			'TL' => __( 'Timor-Leste' ),
2886
			'TG' => __( 'Togo' ),
2887
			'TK' => __( 'Tokelau' ),
2888
			'TO' => __( 'Tonga' ),
2889
			'TT' => __( 'Trinidad and Tobago' ),
2890
			'TN' => __( 'Tunisia' ),
2891
			'TR' => __( 'Turkey' ),
2892
			'TM' => __( 'Turkmenistan' ),
2893
			'TC' => __( 'Turks and Caicos Islands' ),
2894
			'TV' => __( 'Tuvalu' ),
2895
			'UM' => __( 'U.S. Minor Outlying Islands' ),
2896
			'PU' => __( 'U.S. Miscellaneous Pacific Islands' ),
2897
			'VI' => __( 'U.S. Virgin Islands' ),
2898
			'UG' => __( 'Uganda' ),
2899
			'UA' => __( 'Ukraine' ),
2900
			'SU' => __( 'Union of Soviet Socialist Republics' ),
2901
			'AE' => __( 'United Arab Emirates' ),
2902
			'GB' => __( 'United Kingdom' ),
2903
			'US' => __( 'United States' ),
2904
			'ZZ' => __( 'Unknown or Invalid Region' ),
2905
			'UY' => __( 'Uruguay' ),
2906
			'UZ' => __( 'Uzbekistan' ),
2907
			'VU' => __( 'Vanuatu' ),
2908
			'VA' => __( 'Vatican City' ),
2909
			'VE' => __( 'Venezuela' ),
2910
			'VN' => __( 'Vietnam' ),
2911
			'WK' => __( 'Wake Island' ),
2912
			'WF' => __( 'Wallis and Futuna' ),
2913
			'EH' => __( 'Western Sahara' ),
2914
			'YE' => __( 'Yemen' ),
2915
			'ZM' => __( 'Zambia' ),
2916
			'ZW' => __( 'Zimbabwe' ),
2917
			'AX' => __( 'Åland Islands' ),
2918
		);
2919
2920
		return apply_filters( 'pods_form_ui_field_pick_' . __FUNCTION__, $data, $name, $value, $options, $pod, $id );
2921
2922
	}
2923
2924
	/**
2925
	 * Data callback for US States
2926
	 *
2927
	 * @param string       $name    The name of the field
2928
	 * @param string|array $value   The value of the field
2929
	 * @param array        $options Field options
2930
	 * @param array        $pod     Pod data
2931
	 * @param int          $id      Item ID
2932
	 *
2933
	 * @return array
2934
	 *
2935
	 * @since 2.3
2936
	 */
2937
	public function data_us_states( $name = null, $value = null, $options = null, $pod = null, $id = null ) {
2938
2939
		$data = array(
2940
			'AL' => __( 'Alabama' ),
2941
			'AK' => __( 'Alaska' ),
2942
			'AZ' => __( 'Arizona' ),
2943
			'AR' => __( 'Arkansas' ),
2944
			'CA' => __( 'California' ),
2945
			'CO' => __( 'Colorado' ),
2946
			'CT' => __( 'Connecticut' ),
2947
			'DE' => __( 'Delaware' ),
2948
			'DC' => __( 'District Of Columbia' ),
2949
			'FL' => __( 'Florida' ),
2950
			'GA' => __( 'Georgia' ),
2951
			'HI' => __( 'Hawaii' ),
2952
			'ID' => __( 'Idaho' ),
2953
			'IL' => __( 'Illinois' ),
2954
			'IN' => __( 'Indiana' ),
2955
			'IA' => __( 'Iowa' ),
2956
			'KS' => __( 'Kansas' ),
2957
			'KY' => __( 'Kentucky' ),
2958
			'LA' => __( 'Louisiana' ),
2959
			'ME' => __( 'Maine' ),
2960
			'MD' => __( 'Maryland' ),
2961
			'MA' => __( 'Massachusetts' ),
2962
			'MI' => __( 'Michigan' ),
2963
			'MN' => __( 'Minnesota' ),
2964
			'MS' => __( 'Mississippi' ),
2965
			'MO' => __( 'Missouri' ),
2966
			'MT' => __( 'Montana' ),
2967
			'NE' => __( 'Nebraska' ),
2968
			'NV' => __( 'Nevada' ),
2969
			'NH' => __( 'New Hampshire' ),
2970
			'NJ' => __( 'New Jersey' ),
2971
			'NM' => __( 'New Mexico' ),
2972
			'NY' => __( 'New York' ),
2973
			'NC' => __( 'North Carolina' ),
2974
			'ND' => __( 'North Dakota' ),
2975
			'OH' => __( 'Ohio' ),
2976
			'OK' => __( 'Oklahoma' ),
2977
			'OR' => __( 'Oregon' ),
2978
			'PA' => __( 'Pennsylvania' ),
2979
			'RI' => __( 'Rhode Island' ),
2980
			'SC' => __( 'South Carolina' ),
2981
			'SD' => __( 'South Dakota' ),
2982
			'TN' => __( 'Tennessee' ),
2983
			'TX' => __( 'Texas' ),
2984
			'UT' => __( 'Utah' ),
2985
			'VT' => __( 'Vermont' ),
2986
			'VA' => __( 'Virginia' ),
2987
			'WA' => __( 'Washington' ),
2988
			'WV' => __( 'West Virginia' ),
2989
			'WI' => __( 'Wisconsin' ),
2990
			'WY' => __( 'Wyoming' ),
2991
		);
2992
2993
		return apply_filters( 'pods_form_ui_field_pick_' . __FUNCTION__, $data, $name, $value, $options, $pod, $id );
2994
2995
	}
2996
2997
	/**
2998
	 * Data callback for US States
2999
	 *
3000
	 * @param string       $name    The name of the field
3001
	 * @param string|array $value   The value of the field
3002
	 * @param array        $options Field options
3003
	 * @param array        $pod     Pod data
3004
	 * @param int          $id      Item ID
3005
	 *
3006
	 * @return array
3007
	 *
3008
	 * @since 2.3
3009
	 */
3010
	public function data_days_of_week( $name = null, $value = null, $options = null, $pod = null, $id = null ) {
3011
3012
		/**
3013
		 * @var WP_Locale
3014
		 */
3015
		global $wp_locale;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
3016
3017
		return $wp_locale->weekday;
3018
3019
	}
3020
3021
	/**
3022
	 * Data callback for US States
3023
	 *
3024
	 * @param string       $name    The name of the field
3025
	 * @param string|array $value   The value of the field
3026
	 * @param array        $options Field options
3027
	 * @param array        $pod     Pod data
3028
	 * @param int          $id      Item ID
3029
	 *
3030
	 * @return array
3031
	 *
3032
	 * @since 2.3
3033
	 */
3034
	public function data_months_of_year( $name = null, $value = null, $options = null, $pod = null, $id = null ) {
3035
3036
		/**
3037
		 * @var WP_Locale
3038
		 */
3039
		global $wp_locale;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
3040
3041
		return $wp_locale->month;
3042
3043
	}
3044
3045
	/**
3046
	 * Add our modal input to the form so we can track whether we're in our modal during saving or not.
3047
	 */
3048
	public function admin_modal_input() {
3049
3050
		if ( ! pods_is_modal_window() ) {
3051
			return;
3052
		}
3053
3054
		echo '<input name="pods_modal" type="hidden" value="1" />';
3055
3056
	}
3057
3058
	/**
3059
	 * Bail to send new saved data back to our modal handler.
3060
	 *
3061
	 * @param int    $item_id
3062
	 * @param string $item_title
3063
	 * @param object $field_args
3064
	 */
3065
	public function admin_modal_bail( $item_id, $item_title, $field_args ) {
3066
3067
		$model_data = $this->build_dfv_field_item_data_recurse_item( $item_id, $item_title, $field_args );
3068
		?>
3069
			<script type="text/javascript">
3070
				window.parent.jQuery( window.parent ).trigger(
3071
					'dfv:modal:update',
3072
					<?php echo json_encode( $model_data, JSON_HEX_TAG ); ?>
0 ignored issues
show
Unused Code introduced by
The call to json_encode() has too many arguments starting with JSON_HEX_TAG.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
3073
				);
3074
			</script>
3075
		<?php
3076
3077
		die();
3078
3079
	}
3080
3081
	/**
3082
	 * Bail to send new saved data back to our modal handler.
3083
	 *
3084
	 * @param int    $item_id
3085
	 * @param string $item_title
3086
	 * @param object $field_args
3087
	 */
3088
	public function admin_modal_bail_JSON( $item_id, $item_title, $field_args ) {
3089
3090
		$model_data = $this->build_dfv_field_item_data_recurse_item( $item_id, $item_title, $field_args );
3091
		echo json_encode( $model_data, JSON_HEX_TAG );
0 ignored issues
show
Unused Code introduced by
The call to json_encode() has too many arguments starting with JSON_HEX_TAG.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
3092
3093
		die();
3094
	}
3095
3096
	/**
3097
	 * Bail on Post save redirect for Admin modal.
3098
	 *
3099
	 * @param string $location The destination URL.
3100
	 * @param int    $post_id  The post ID.
3101
	 *
3102
	 * @return string
3103
	 */
3104
	public function admin_modal_bail_post_redirect( $location, $post_id ) {
3105
3106
		if ( ! pods_is_modal_window() ) {
3107
			return $location;
3108
		}
3109
3110
		$post_title = get_the_title( $post_id );
3111
3112
		$field_args = (object) array(
3113
			'options' => array(
3114
				'pick_object' => 'post_type',
3115
				'pick_val'    => get_post_type( $post_id ),
3116
			),
3117
			'value'   => array(
3118
				$post_id => $post_title,
3119
			),
3120
		);
3121
3122
		$this->admin_modal_bail( $post_id, $post_title, $field_args );
3123
3124
		return $location;
3125
3126
	}
3127
3128
	/**
3129
	 * Hook into term updating process to bail on redirect.
3130
	 */
3131
	public function admin_modal_bail_term_action() {
3132
3133
		if ( ! pods_is_modal_window() ) {
3134
			return;
3135
		}
3136
3137
		add_action( 'created_term', array( $this, 'admin_modal_bail_term' ), 10, 3 );
3138
		add_action( 'edited_term', array( $this, 'admin_modal_bail_term' ), 10, 3 );
3139
3140
	}
3141
3142
	/**
3143
	 * Bail on Term save redirect for Admin modal.
3144
	 *
3145
	 * @param int    $term_id  Term ID.
3146
	 * @param int    $tt_id    Term taxonomy ID.
3147
	 * @param string $taxonomy Taxonomy slug.
3148
	 */
3149
	public function admin_modal_bail_term( $term_id, $tt_id, $taxonomy ) {
3150
3151
		if ( ! pods_is_modal_window() ) {
3152
			return;
3153
		}
3154
3155
		$term = get_term( $term_id );
3156
3157
		if ( ! $term || is_wp_error( $term ) ) {
3158
			return;
3159
		}
3160
3161
		$field_args = (object) array(
3162
			'options' => array(
3163
				'pick_object' => 'taxonomy',
3164
				'pick_val'    => $term->taxonomy,
3165
			),
3166
			'value'   => array(
3167
				$term->term_id => $term->name,
3168
			),
3169
		);
3170
3171
		$this->admin_modal_bail( $term->term_id, $term->name, $field_args );
3172
3173
	}
3174
3175
	/**
3176
	 * Hook into user updating process to bail on redirect.
3177
	 */
3178
	public function admin_modal_bail_user_action() {
3179
3180
		if ( ! pods_is_modal_window() ) {
3181
			return;
3182
		}
3183
3184
		add_filter( 'wp_redirect', array( $this, 'admin_modal_bail_user_redirect' ) );
3185
3186
	}
3187
3188
	/**
3189
	 * Bail on User save redirect for Admin modal.
3190
	 *
3191
	 * @param string $location The destination URL.
3192
	 *
3193
	 * @return string
3194
	 */
3195
	public function admin_modal_bail_user_redirect( $location ) {
3196
3197
		if ( ! pods_is_modal_window() ) {
3198
			return $location;
3199
		}
3200
3201
		global $user_id;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
3202
3203
		$user = get_userdata( $user_id );
3204
3205
		if ( ! $user || is_wp_error( $user ) ) {
3206
			return $location;
3207
		}
3208
3209
		$field_args = (object) array(
3210
			'options' => array(
3211
				'pick_object' => 'user',
3212
				'pick_val'    => '',
3213
			),
3214
			'value'   => array(
3215
				$user->ID => $user->display_name,
3216
			),
3217
		);
3218
3219
		$this->admin_modal_bail( $user->ID, $user->display_name, $field_args );
3220
3221
		return $location;
3222
3223
	}
3224
3225
	/**
3226
	 * Bail on Pod item save for Admin modal.
3227
	 *
3228
	 * @param int       $id     Item ID.
3229
	 * @param array     $params save_pod_item parameters.
3230
	 * @param null|Pods $obj    Pod object (if set).
3231
	 */
3232
	public function admin_modal_bail_pod( $id, $params, $obj ) {
3233
3234
		if ( ! pods_is_modal_window() ) {
3235
			return;
3236
		}
3237
3238
		if ( ! $obj ) {
3239
			$obj = pods( $params['pod'] );
3240
		}
3241
3242
		if ( ! $obj || ! $obj->fetch( $id ) ) {
3243
			return;
3244
		}
3245
3246
		$item_id    = $obj->id();
3247
		$item_title = $obj->index();
3248
3249
		$field_args = (object) array(
3250
			'options' => array(
3251
				'pick_object' => $obj->pod_data['type'],
3252
				'pick_val'    => $obj->pod,
3253
			),
3254
			'value'   => array(
3255
				$obj->id() => $item_title,
3256
			),
3257
		);
3258
3259
		$this->admin_modal_bail_JSON( $item_id, $item_title, $field_args );
3260
3261
	}
3262
3263
}
3264