Issues (2873)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

classes/fields/pick.php (30 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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
	 * {@inheritdoc}
25
	 */
26
	protected static $api = false;
27
28
	/**
29
	 * Available Related Objects.
30
	 *
31
	 * @var array
32
	 * @since 2.3
33
	 */
34
	public static $related_objects = array();
35
36
	/**
37
	 * Custom Related Objects
38
	 *
39
	 * @var array
40
	 * @since 2.3
41
	 */
42
	public static $custom_related_objects = array();
0 ignored issues
show
Comprehensibility Naming introduced by
The variable name $custom_related_objects exceeds the maximum configured length of 20.

Very long variable names usually make code harder to read. It is therefore recommended not to make variable names too verbose.

Loading history...
43
44
	/**
45
	 * Data used during validate / save to avoid extra queries.
46
	 *
47
	 * @var array
48
	 * @since 2.3
49
	 */
50
	public static $related_data = array();
51
52
	/**
53
	 * Data used during input method (mainly for autocomplete).
54
	 *
55
	 * @var array
56
	 * @since 2.3
57
	 */
58
	public static $field_data = array();
59
60
	/**
61
	 * Saved array of simple relationship names.
62
	 *
63
	 * @var array
64
	 * @since 2.5
65
	 */
66
	private static $names_simple = null;
67
68
	/**
69
	 * Saved array of relationship names
70
	 *
71
	 * @var array
72
	 * @since 2.5
73
	 */
74
	private static $names_related = null;
75
76
	/**
77
	 * Saved array of bidirectional relationship names
78
	 *
79
	 * @var array
80
	 * @since 2.5
81
	 */
82
	private static $names_bidirectional = null;
83
84
	/**
85
	 * {@inheritdoc}
86
	 */
87
	public function setup() {
88
89
		self::$label = __( 'Relationship', 'pods' );
90
	}
91
92
	/**
93
	 * {@inheritdoc}
94
	 */
95
	public function admin_init() {
96
97
		// AJAX for Relationship lookups.
98
		add_action( 'wp_ajax_pods_relationship', array( $this, 'admin_ajax_relationship' ) );
99
		add_action( 'wp_ajax_nopriv_pods_relationship', array( $this, 'admin_ajax_relationship' ) );
100
101
		// Handle modal input.
102
		add_action( 'edit_form_top', array( $this, 'admin_modal_input' ) );
103
		add_action( 'show_user_profile', array( $this, 'admin_modal_input' ) );
104
		add_action( 'edit_user_profile', array( $this, 'admin_modal_input' ) );
105
		add_action( 'edit_category_form', array( $this, 'admin_modal_input' ) );
106
		add_action( 'edit_link_category_form', array( $this, 'admin_modal_input' ) );
107
		add_action( 'edit_tag_form', array( $this, 'admin_modal_input' ) );
108
		add_action( 'add_tag_form', array( $this, 'admin_modal_input' ) );
109
		add_action( 'pods_meta_box_pre', array( $this, 'admin_modal_input' ) );
110
111
		// Handle modal saving.
112
		add_filter( 'redirect_post_location', array( $this, 'admin_modal_bail_post_redirect' ), 10, 2 );
113
		add_action( 'load-edit-tags.php', array( $this, 'admin_modal_bail_term_action' ) );
114
		add_action( 'load-categories.php', array( $this, 'admin_modal_bail_term_action' ) );
115
		add_action( 'load-edit-link-categories.php', array( $this, 'admin_modal_bail_term_action' ) );
116
		add_action( 'personal_options_update', array( $this, 'admin_modal_bail_user_action' ) );
117
		add_action( 'user_register', array( $this, 'admin_modal_bail_user_action' ) );
118
		add_action( 'pods_api_processed_form', array( $this, 'admin_modal_bail_pod' ), 10, 3 );
119
120
	}
121
122
	/**
123
	 * {@inheritdoc}
124
	 */
125
	public function options() {
126
127
		$options = array(
128
			static::$type . '_format_type'    => array(
129
				'label'      => __( 'Selection Type', 'pods' ),
130
				'help'       => __( 'help', 'pods' ),
131
				'default'    => 'single',
132
				'type'       => 'pick',
133
				'data'       => array(
134
					'single' => __( 'Single Select', 'pods' ),
135
					'multi'  => __( 'Multiple Select', 'pods' ),
136
				),
137
				'dependency' => true,
138
			),
139
			static::$type . '_format_single'  => array(
140
				'label'      => __( 'Format', 'pods' ),
141
				'help'       => __( 'help', 'pods' ),
142
				'depends-on' => array( static::$type . '_format_type' => 'single' ),
143
				'default'    => 'dropdown',
144
				'type'       => 'pick',
145
				'data'       => apply_filters(
146
					'pods_form_ui_field_pick_format_single_options', array(
147
						'dropdown'     => __( 'Drop Down', 'pods' ),
148
						'radio'        => __( 'Radio Buttons', 'pods' ),
149
						'autocomplete' => __( 'Autocomplete', 'pods' ),
150
						'list'         => __( 'List view', 'pods' ),
151
					)
152
				),
153
				'dependency' => true,
154
			),
155
			static::$type . '_format_multi'   => array(
156
				'label'      => __( 'Format', 'pods' ),
157
				'help'       => __( 'help', 'pods' ),
158
				'depends-on' => array( static::$type . '_format_type' => 'multi' ),
159
				'default'    => 'checkbox',
160
				'type'       => 'pick',
161
				'data'       => apply_filters(
162
					'pods_form_ui_field_pick_format_multi_options', array(
163
						'checkbox'     => __( 'Checkboxes', 'pods' ),
164
						'multiselect'  => __( 'Multi Select', 'pods' ),
165
						'autocomplete' => __( 'Autocomplete', 'pods' ),
166
						'list'         => __( 'List view', 'pods' ),
167
					)
168
				),
169
				'dependency' => true,
170
			),
171
			static::$type . '_allow_add_new'  => array(
172
				'label'       => __( 'Allow Add New', 'pods' ),
173
				'help'        => __( 'Allow new related records to be created in a modal window', 'pods' ),
174
				'wildcard-on' => array(
175
					static::$type . '_object' => array( '^post-type-(?!(custom-css|customize-changeset)).*$', '^taxonomy-.*$', '^user$', '^pod-.*$' ),
176
				),
177
				'type'        => 'boolean',
178
				'default'     => 1,
179
			),
180
			static::$type . '_taggable'       => array(
181
				'label'       => __( 'Taggable', 'pods' ),
182
				'help'        => __( 'Allow new values to be inserted when using an Autocomplete field', 'pods' ),
183
				'excludes-on' => array(
184
					static::$type . '_format_single' => array( 'dropdown', 'radio', 'list' ),
185
					static::$type . '_format_multi'  => array( 'checkbox', 'multiselect', 'list' ),
186
					static::$type . '_object'        => array_merge( array( 'site', 'network' ), self::simple_objects() ),
187
				),
188
				'type'        => 'boolean',
189
				'default'     => 0,
190
			),
191
			static::$type . '_show_icon'      => array(
192
				'label'       => __( 'Show Icons', 'pods' ),
193
				'excludes-on' => array(
194
					static::$type . '_format_single' => array( 'dropdown', 'radio', 'autocomplete' ),
195
					static::$type . '_format_multi'  => array( 'checkbox', 'multiselect', 'autocomplete' ),
196
					static::$type . '_object'        => array_merge( array( 'site', 'network' ), self::simple_objects() ),
197
				),
198
				'type'        => 'boolean',
199
				'default'     => 1,
200
			),
201
			static::$type . '_show_edit_link' => array(
202
				'label'       => __( 'Show Edit Links', 'pods' ),
203
				'excludes-on' => array(
204
					static::$type . '_format_single' => array( 'dropdown', 'radio', 'autocomplete' ),
205
					static::$type . '_format_multi'  => array( 'checkbox', 'multiselect', 'autocomplete' ),
206
					static::$type . '_object'        => array_merge( array( 'site', 'network' ), self::simple_objects() ),
207
				),
208
				'type'        => 'boolean',
209
				'default'     => 1,
210
			),
211
			static::$type . '_show_view_link' => array(
212
				'label'       => __( 'Show View Links', 'pods' ),
213
				'excludes-on' => array(
214
					static::$type . '_format_single' => array( 'dropdown', 'radio', 'autocomplete' ),
215
					static::$type . '_format_multi'  => array( 'checkbox', 'multiselect', 'autocomplete' ),
216
					static::$type . '_object'        => array_merge( array( 'site', 'network' ), self::simple_objects() ),
217
				),
218
				'type'        => 'boolean',
219
				'default'     => 1,
220
			),
221
			static::$type . '_select_text'    => array(
222
				'label'      => __( 'Default Select Text', 'pods' ),
223
				'help'       => __( 'This is the text use for the default "no selection" dropdown item, if empty, it will default to "-- Select One --"', 'pods' ),
224
				'depends-on' => array(
225
					static::$type . '_format_type'   => 'single',
226
					static::$type . '_format_single' => 'dropdown',
227
				),
228
				'default'    => '',
229
				'type'       => 'text',
230
			),
231
			static::$type . '_limit'          => array(
232
				'label'      => __( 'Selection Limit', 'pods' ),
233
				'help'       => __( 'help', 'pods' ),
234
				'depends-on' => array( static::$type . '_format_type' => 'multi' ),
235
				'default'    => 0,
236
				'type'       => 'number',
237
			),
238
			static::$type . '_table_id'       => array(
239
				'label'      => __( 'Table ID Column', 'pods' ),
240
				'help'       => __( 'You must provide the ID column name for the table, this will be used to keep track of the relationship', 'pods' ),
241
				'depends-on' => array( static::$type . '_object' => 'table' ),
242
				'required'   => 1,
243
				'default'    => '',
244
				'type'       => 'text',
245
			),
246
			static::$type . '_table_index'    => array(
247
				'label'      => __( 'Table Index Column', 'pods' ),
248
				'help'       => __( 'You must provide the index column name for the table, this may optionally also be the ID column name', 'pods' ),
249
				'depends-on' => array( static::$type . '_object' => 'table' ),
250
				'required'   => 1,
251
				'default'    => '',
252
				'type'       => 'text',
253
			),
254
			static::$type . '_display'        => array(
255
				'label'       => __( 'Display Field in Selection List', 'pods' ),
256
				'help'        => __( 'Provide the name of a field on the related object to reference, example: {@post_title}', 'pods' ),
257
				'excludes-on' => array(
258
					static::$type . '_object' => array_merge( array( 'site', 'network' ), self::simple_objects() ),
259
				),
260
				'default'     => '',
261
				'type'        => 'text',
262
			),
263
			static::$type . '_user_role'      => array(
264
				'label'            => __( 'Limit list to Role(s)', 'pods' ),
265
				'help'             => __( 'help', 'pods' ),
266
				'depends-on'       => array( static::$type . '_object' => 'user' ),
267
				'default'          => '',
268
				'type'             => 'pick',
269
				'pick_object'      => 'role',
270
				'pick_format_type' => 'multi',
271
			),
272
			static::$type . '_where'          => array(
273
				'label'       => __( 'Customized <em>WHERE</em>', 'pods' ),
274
				'help'        => __( 'help', 'pods' ),
275
				'excludes-on' => array(
276
					static::$type . '_object' => array_merge( array( 'site', 'network' ), self::simple_objects() ),
277
				),
278
				'default'     => '',
279
				'type'        => 'text',
280
			),
281
			static::$type . '_orderby'        => array(
282
				'label'       => __( 'Customized <em>ORDER BY</em>', 'pods' ),
283
				'help'        => __( 'help', 'pods' ),
284
				'excludes-on' => array(
285
					static::$type . '_object' => array_merge( array( 'site', 'network' ), self::simple_objects() ),
286
				),
287
				'default'     => '',
288
				'type'        => 'text',
289
			),
290
			static::$type . '_groupby'        => array(
291
				'label'       => __( 'Customized <em>GROUP BY</em>', 'pods' ),
292
				'help'        => __( 'help', 'pods' ),
293
				'excludes-on' => array(
294
					static::$type . '_object' => array_merge( array( 'site', 'network' ), self::simple_objects() ),
295
				),
296
				'default'     => '',
297
				'type'        => 'text',
298
			),
299
		);
300
301
		$post_type_pick_objects = array();
0 ignored issues
show
Comprehensibility Naming introduced by
The variable name $post_type_pick_objects exceeds the maximum configured length of 20.

Very long variable names usually make code harder to read. It is therefore recommended not to make variable names too verbose.

Loading history...
302
303
		foreach ( get_post_types( '', 'names' ) as $post_type ) {
304
			$post_type_pick_objects[] = 'post-type_' . $post_type;
305
		}
306
307
		$options[ static::$type . '_post_status' ] = array(
308
			'name'             => 'post_status',
309
			'label'            => __( 'Post Status', 'pods' ),
310
			'help'             => __( 'help', 'pods' ),
311
			'type'             => 'pick',
312
			'pick_object'      => 'post-status',
313
			'pick_format_type' => 'multi',
314
			'default'          => 'publish',
315
			'depends-on'       => array(
316
				static::$type . '_object' => $post_type_pick_objects,
317
			),
318
		);
319
320
		return $options;
321
322
	}
323
324
	/**
325
	 * Register a related object.
326
	 *
327
	 * @param string $name    Object name.
328
	 * @param string $label   Object label.
329
	 * @param array  $options Object options.
0 ignored issues
show
Should the type for parameter $options not be array|null? Also, consider making the array more specific, something like array<String>, or String[].

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive. In addition it looks for parameters that have the generic type array and suggests a stricter type like array<String>.

Most often this is a case of a parameter that can be null in addition to its declared types.

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

Very long variable names usually make code harder to read. It is therefore recommended not to make variable names too verbose.

Loading history...
665
666
			foreach ( self::$related_objects as $object => $related_object ) {
667
				if ( ! isset( $related_object['bidirectional'] ) || ! $related_object['bidirectional'] ) {
668
					continue;
669
				}
670
671
				$bidirectional_objects[] = $object;
672
			}
673
674
			self::$names_bidirectional = (array) apply_filters( 'pods_form_ui_field_pick_bidirectional_objects', $bidirectional_objects );
675
		}
676
677
		return self::$names_bidirectional;
678
679
	}
680
681
	/**
682
	 * {@inheritdoc}
683
	 */
684
	public function schema( $options = null ) {
685
686
		$schema = false;
687
688
		$simple_tableless_objects = $this->simple_objects();
0 ignored issues
show
Comprehensibility Naming introduced by
The variable name $simple_tableless_objects exceeds the maximum configured length of 20.

Very long variable names usually make code harder to read. It is therefore recommended not to make variable names too verbose.

Loading history...
689
690
		if ( in_array( pods_v( static::$type . '_object', $options ), $simple_tableless_objects, true ) ) {
691
			$schema = 'LONGTEXT';
692
		}
693
694
		return $schema;
695
696
	}
697
698
	/**
699
	 * {@inheritdoc}
700
	 */
701
	public function display( $value = null, $name = null, $options = null, $pod = null, $id = null ) {
702
703
		$fields = null;
704
705
		if ( is_object( $pod ) && isset( $pod->fields ) ) {
706
			/**
707
			 * @var $pod Pods Pods object.
708
			 */
709
			$fields = $pod->fields;
710
711
			if ( ! empty( $pod->pod_data['object_fields'] ) ) {
712
				$fields = array_merge( $fields, $pod->pod_data['object_fields'] );
713
			}
714
		} elseif ( is_array( $pod ) && isset( $pod['fields'] ) ) {
715
			$fields = $pod['fields'];
716
717
			if ( ! empty( $pod['object_fields'] ) ) {
718
				$fields = array_merge( $fields, $pod['object_fields'] );
719
			}
720
		}
721
722
		return pods_serial_comma(
723
			$value, array(
724
				'field'  => $name,
725
				'fields' => $fields,
726
			)
727
		);
728
729
	}
730
731
	/**
732
	 * {@inheritdoc}
733
	 */
734
	public function input( $name, $value = null, $options = null, $pod = null, $id = null ) {
735
736
		$options = (array) $options;
737
738
		$type = pods_v( 'type', $options, static::$type );
739
740
		$args = compact( array_keys( get_defined_vars() ) );
741
		$args = (object) $args;
742
743
		wp_enqueue_script( 'pods-dfv' );
744
745
		wp_enqueue_style( 'pods-select2' );
746
		wp_enqueue_script( 'pods-select2' );
747
748
		$this->render_input_script( $args );
749
750
		/**
751
		 * @todo Support custom integrations.
752
		 *
753
		 * Run the action 'pods_form_ui_field_pick_input_' . pods_v( static::$type . '_format_type', $options, 'single' ) . '_' . pods_v( static::$type . '_format_multi', $options, 'checkbox' )
754
		 * Run the action 'pods_form_ui_field_pick_input'
755
		 * Pass the arguments: $name, $value, $options, $pod, $id
756
		 */
757
758
	}
759
760
	/**
761
	 * {@inheritdoc}
762
	 */
763
	public function build_dfv_field_options( $options, $args ) {
764
765
		$options['grouped'] = 1;
766
767
		if ( empty( $options[ $args->type . '_object' ] ) ) {
768
			$options[ $args->type . '_object' ] = '';
769
		}
770
771
		if ( empty( $options[ $args->type . '_val' ] ) ) {
772
			$options[ $args->type . '_val' ] = '';
773
		}
774
775
		$options['table_info'] = array();
776
777
		$custom = pods_v( $args->type . '_custom', $options, false );
778
779
		$custom = apply_filters( 'pods_form_ui_field_pick_custom_values', $custom, $args->name, $args->value, $options, $args->pod, $args->id );
780
781
		$ajax = false;
782
783
		if ( ( 'custom-simple' !== pods_v( $args->type . '_object', $options ) || empty( $custom ) ) && '' !== pods_v( $args->type . '_object', $options, '', true ) ) {
784
			$ajax = true;
785
		}
786
787
		if ( ! empty( self::$field_data ) && self::$field_data['id'] === $options['id'] ) {
788
			$ajax = (boolean) self::$field_data['autocomplete'];
789
		}
790
791
		$ajax = apply_filters( 'pods_form_ui_field_pick_ajax', $ajax, $args->name, $args->value, $options, $args->pod, $args->id );
792
793
		if ( 0 === (int) pods_v( $args->type . '_ajax', $options, 1 ) ) {
794
			$ajax = false;
795
		}
796
797
		$options[ $args->type . '_ajax' ] = (int) $ajax;
798
799
		$format_type = pods_v( $args->type . '_format_type', $options, 'single', true );
800
801
		$limit = 1;
802
803
		if ( 'single' === $format_type ) {
804
			$format_single = pods_v( $args->type . '_format_single', $options, 'dropdown', true );
805
806
			if ( 'dropdown' === $format_single ) {
807
				$options['view_name'] = 'select';
808
			} elseif ( 'radio' === $format_single ) {
809
				$options['view_name'] = 'radio';
810
			} elseif ( 'autocomplete' === $format_single ) {
811
				$options['view_name'] = 'select2';
812
			} elseif ( 'list' === $format_single ) {
813
				$options['view_name'] = 'list';
814
			} else {
815
				$options['view_name'] = $format_single;
816
			}
817
		} elseif ( 'multi' === $format_type ) {
818
			$format_multi = pods_v( $args->type . '_format_multi', $options, 'checkbox', true );
819
820
			if ( ! empty( $args->value ) && ! is_array( $args->value ) ) {
821
				$args->value = explode( ',', $args->value );
822
			}
823
824
			if ( 'checkbox' === $format_multi ) {
825
				$options['view_name'] = 'checkbox';
826
			} elseif ( 'multiselect' === $format_multi ) {
827
				$options['view_name'] = 'select';
828
			} elseif ( 'autocomplete' === $format_multi ) {
829
				$options['view_name'] = 'select2';
830
			} elseif ( 'list' === $format_multi ) {
831
				$options['view_name'] = 'list';
832
			} else {
833
				$options['view_name'] = $format_multi;
834
			}
835
836
			$limit = 0;
837
838
			if ( ! empty( $options[ $args->type . '_limit' ] ) ) {
839
				$limit = absint( $options[ $args->type . '_limit' ] );
840
			}
841
		} else {
842
			$options['view_name'] = $format_type;
843
		}//end if
844
845
		$options[ $args->type . '_limit' ] = $limit;
846
847
		$options['ajax_data'] = $this->build_dfv_autocomplete_ajax_data( $options, $args, $ajax );
848
849
		/**
850
		 * Allow overriding some of the Select2 options used in the JS init.
851
		 *
852
		 * @param array|null $select2_overrides Override options for Select2/SelectWoo.
853
		 *
854
		 * @since 2.7
855
		 */
856
		$options['select2_overrides'] = apply_filters( 'pods_pick_select2_overrides', null );
857
858
		return $options;
859
860
	}
861
862
	/**
863
	 * Build DFV autocomplete AJAX data.
864
	 *
865
	 * @param array  $options DFV options.
866
	 * @param object $args    {
867
	 *  Field information arguments.
868
	 *
869
	 *     @type string     $name    Field name.
870
	 *     @type string     $type    Field type.
871
	 *     @type array      $options Field options.
872
	 *     @type mixed      $value   Current value.
873
	 *     @type array      $pod     Pod information.
874
	 *     @type int|string $id      Current item ID.
875
	 * }
876
	 * @param bool   $ajax    True if ajax mode should be used.
877
	 *
878
	 * @return array
879
	 */
880
	public function build_dfv_autocomplete_ajax_data( $options, $args, $ajax = false ) {
881
882
		if ( is_object( $args->pod ) ) {
883
			$pod_id = (int) $args->pod->pod_id;
884
		} else {
885
			$pod_id = 0;
886
		}
887
888
		$field_id = (int) $options['id'];
889
890
		$id = (int) $args->id;
891
892
		if ( is_user_logged_in() ) {
893
			$uid = 'user_' . get_current_user_id();
894
		} else {
895
			$uid = @session_id();
0 ignored issues
show
Silencing errors is discouraged
Loading history...
The use of PHP session function session_id() is prohibited.
Loading history...
896
		}
897
898
		$uri_hash = wp_create_nonce( 'pods_uri_' . $_SERVER['REQUEST_URI'] );
899
900
		$field_nonce = wp_create_nonce( 'pods_relationship_' . $pod_id . '_' . $uid . '_' . $uri_hash . '_' . $field_id );
901
902
		// Values can be overridden via the `pods_field_dfv_data` filter in $data['fieldConfig']['ajax_data'].
903
		return array(
904
			'ajax'                 => $ajax,
905
			'delay'                => 300,
906
			'minimum_input_length' => 1,
907
			'pod'                  => $pod_id,
908
			'field'                => $field_id,
909
			'id'                   => $id,
910
			'uri'                  => $uri_hash,
911
			'_wpnonce'             => $field_nonce,
912
		);
913
914
	}
915
916
	/**
917
	 * {@inheritdoc}
918
	 */
919
	public function build_dfv_field_config( $args ) {
920
921
		$config = parent::build_dfv_field_config( $args );
922
923
		if ( ! isset( $config['optgroup'] ) ) {
924
			$config['optgroup'] = false;
925
		}
926
927
		/**
928
		 * Filter on whether to allow modals to be used on the front of the site (in an non-admin area).
929
		 *
930
		 * @param boolean $show_on_front
931
		 * @param array $config
932
		 * @param array $args
933
		 *
934
		 * @since 2.7
935
		 */
936
		$show_on_front = apply_filters( 'pods_ui_dfv_pick_modals_show_on_front', false, $config, $args );
937
938
		/**
939
		 * Filter on whether to allow nested modals to be used (modals within modals).
940
		 *
941
		 * @param boolean $allow_nested_modals
942
		 * @param array $config
943
		 * @param array $args
944
		 *
945
		 * @since 2.7
946
		 */
947
		$allow_nested_modals = apply_filters( 'pods_ui_dfv_pick_modals_allow_nested', false, $config, $args );
948
949
		// Disallow add/edit outside the admin and when we're already in a modal
950
		if ( ( ! $show_on_front && ! is_admin() ) || ( ! $allow_nested_modals && pods_is_modal_window() ) ) {
951
			$config[ $args->type . '_allow_add_new' ]  = false;
952
			$config[ $args->type . '_show_edit_link' ] = false;
953
		}
954
955
		$iframe = array(
956
			'src'        => '',
957
			'url'        => '',
958
			'query_args' => array(),
959
		);
960
961
		// Set the file name and args based on the content type of the relationship
962
		switch ( $args->options['pick_object'] ) {
963
			case 'post_type':
964
				if ( ! empty( $args->options['pick_val'] ) ) {
965
					$post_type_obj = get_post_type_object( $args->options['pick_val'] );
966
967
					if ( $post_type_obj && current_user_can( $post_type_obj->cap->create_posts ) ) {
968
						$iframe['url']        = admin_url( 'post-new.php' );
969
						$iframe['query_args'] = array(
970
							'post_type' => $args->options['pick_val'],
971
						);
972
					}
973
				}
974
975
				break;
976
977
			case 'taxonomy':
978
				/*
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% 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...
979
				 * @todo Fix add new modal issues
980
				if ( ! empty( $args->options['pick_val'] ) ) {
981
					$taxonomy_obj = get_taxonomy( $args->options['pick_val'] );
982
983
					if ( $taxonomy_obj && current_user_can( $taxonomy_obj->cap->edit_terms ) ) {
984
						$iframe['url']  = admin_url( 'edit-tags.php' );
985
						$iframe['query_args'] = array(
986
							'taxonomy' => $args->options['pick_val'],
987
						);
988
					}
989
				}
990
				*/
991
992
				break;
993
994
			case 'user':
995
				if ( current_user_can( 'create_users' ) ) {
996
					$iframe['url'] = admin_url( '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
						$iframe['url']        = admin_url( 'admin.php' );
1005
						$iframe['query_args'] = array(
1006
							'page'   => 'pods-manage-' . $args->options['pick_val'],
1007
							'action' => 'add',
1008
						);
1009
1010
					}
1011
				}
1012
1013
				break;
1014
		}//end switch
1015
1016
		// Potential valid modal target if we've set the file name
1017
		if ( ! empty( $iframe['url'] ) ) {
1018
			// @todo: Replace string literal with defined constant
1019
			$iframe['query_args']['pods_modal'] = 1;
1020
1021
			// Add args we always need
1022
			$iframe['src'] = add_query_arg( $iframe['query_args'], $iframe['url'] );
1023
		}
1024
1025
		$iframe['title_add']  = sprintf( __( '%s: Add New', 'pods' ), $args->options['label'] );
1026
		$iframe['title_edit'] = sprintf( __( '%s: Edit', 'pods' ), $args->options['label'] );
1027
1028
		/**
1029
		 * Allow filtering iframe configuration
1030
		 *
1031
		 * @param array $iframe
1032
		 * @param array $config
1033
		 * @param array $args
1034
		 *
1035
		 * @since 2.7
1036
		 */
1037
		$iframe = apply_filters( 'pods_ui_dfv_pick_modals_iframe', $iframe, $config, $args );
1038
1039
		if ( ! empty( $iframe['src'] ) ) {
1040
			// We extend wp.media.view.Modal for modal add/edit, we must ensure we load the template for it
1041
			wp_enqueue_media();
1042
1043
		}
1044
1045
		$config['iframe_src']        = $iframe['src'];
1046
		$config['iframe_title_add']  = $iframe['title_add'];
1047
		$config['iframe_title_edit'] = $iframe['title_edit'];
1048
1049
		return $config;
1050
1051
	}
1052
1053
	/**
1054
	 * {@inheritdoc}
1055
	 */
1056
	public function build_dfv_field_item_data( $args ) {
1057
1058
		$args->options['supports_thumbnails'] = null;
1059
1060
		$item_data = array();
1061
1062
		if ( ! empty( $args->options['data'] ) ) {
1063
			$item_data = $this->build_dfv_field_item_data_recurse( $args->options['data'], $args );
1064
		}
1065
1066
		return $item_data;
1067
1068
	}
1069
1070
	/**
1071
	 * Loop through relationship data and expand item data with additional information for DFV.
1072
	 *
1073
	 * @param array  $data    Item data to expand.
1074
	 * @param object $args    {
1075
	 *      Field information arguments.
1076
	 *
1077
	 *     @type string     $name    Field name.
1078
	 *     @type string     $type    Field type.
1079
	 *     @type array      $options Field options.
1080
	 *     @type mixed      $value   Current value.
1081
	 *     @type array      $pod     Pod information.
1082
	 *     @type int|string $id      Current item ID.
1083
	 * }
1084
	 *
1085
	 * @return array
1086
	 */
1087
	public function build_dfv_field_item_data_recurse( $data, $args ) {
1088
1089
		$item_data = array();
1090
1091
		foreach ( $data as $item_id => $item_title ) {
1092
			if ( is_array( $item_title ) ) {
1093
				$args->options['optgroup'] = true;
1094
1095
				$item_data[] = array(
1096
					'label'      => $item_id,
1097
					'collection' => $this->build_dfv_field_item_data_recurse( $item_title, $args ),
1098
				);
1099
			} else {
1100
				// Key by item_id temporarily to be able to sort based on $args->value
1101
				$item_data[ $item_id ] = $this->build_dfv_field_item_data_recurse_item( $item_id, $item_title, $args );
1102
			}
1103
		}
1104
1105
		// Maintain any saved sort order from $args->value
1106
		if ( is_array( $args->value ) && 1 < count( $args->value ) && $this->is_autocomplete( $args->options ) ) {
1107
			$item_data = array_replace( $args->value, $item_data );
1108
		}
1109
1110
		// Convert from associative to numeric array
1111
		$item_data = array_values( $item_data );
1112
1113
		return $item_data;
1114
1115
	}
1116
1117
	/**
1118
	 * Loop through relationship data and expand item data with additional information for DFV.
1119
	 *
1120
	 * @param int|string $item_id    Item ID.
1121
	 * @param string     $item_title Item title.
1122
	 * @param object     $args       {
1123
	 *      Field information arguments.
1124
	 *
1125
	 *     @type string      $name    Field name.
1126
	 *     @type string      $type    Field type.
1127
	 *     @type array       $options Field options.
1128
	 *     @type mixed       $value   Current value.
1129
	 *     @type array       $pod     Pod information.
1130
	 *     @type int|string  $id      Current item ID.
1131
	 * }
1132
	 *
1133
	 * @return array
1134
	 */
1135
	public function build_dfv_field_item_data_recurse_item( $item_id, $item_title, $args ) {
1136
1137
		$use_dashicon = false;
1138
		$icon         = '';
1139
		$img_icon     = '';
1140
		$edit_link    = '';
1141
		$link         = '';
1142
1143
		if ( ! isset( $args->options['supports_thumbnails'] ) ) {
1144
			$args->options['supports_thumbnails'] = null;
1145
		}
1146
1147
		switch ( $args->options['pick_object'] ) {
1148
			case 'post_type':
1149
				$item_id = (int) $item_id;
1150
1151
				if ( null === $args->options['supports_thumbnails'] && ! empty( $args->options['pick_val'] ) ) {
1152
					$args->options['supports_thumbnails'] = post_type_supports( $args->options['pick_val'], 'thumbnail' );
1153
				}
1154
1155
				if ( true === $args->options['supports_thumbnails'] ) {
1156
					$post_thumbnail_id = get_post_thumbnail_id( $item_id );
1157
1158
					if ( $post_thumbnail_id ) {
1159
						$thumb = wp_get_attachment_image_src( $post_thumbnail_id, 'thumbnail', false );
1160
					}
1161
1162
					if ( ! empty( $thumb[0] ) ) {
1163
						$img_icon = $thumb[0];
1164
					}
1165
				}
1166
1167
				if ( empty( $img_icon ) ) {
1168
1169
					// Default icon for posts.
1170
					$icon = 'dashicons-admin-post';
1171
1172
					// Post type icons.
1173
					$post_type = (array) get_post_type_object( get_post_type( $item_id ) );
1174
1175
					if ( ! empty( $post_type['menu_icon'] ) ) {
1176
						// Post specific icon.
1177
						$icon = $post_type['menu_icon'];
1178
					} elseif ( isset( $post_type['name'] ) && 'page' ) {
1179
						switch ( $post_type['name'] ) {
1180
							case 'page':
1181
								// Default for pages.
1182
								$icon = 'dashicons-admin-page';
1183
								break;
1184
							case 'attachment':
1185
								// Default for attachments.
1186
								$icon = 'dashicons-admin-media';
1187
								break;
1188
						}
1189
					}
1190
				}//end if
1191
1192
				$edit_link = get_edit_post_link( $item_id, 'raw' );
1193
1194
				$link = get_permalink( $item_id );
1195
1196
				break;
1197
1198
			case 'taxonomy':
1199
				$item_id = (int) $item_id;
1200
1201
				if ( ! empty( $args->options['pick_val'] ) ) {
1202
1203
					// Default icon for taxonomy.
1204
					$icon = 'dashicons-category';
1205
1206
					// Change icon for non-hierarchical taxonomies.
1207
					$taxonomy = get_term( $item_id );
1208
					if ( isset( $taxonomy->taxonomy ) ) {
1209
						$taxonomy = (array) get_taxonomy( $taxonomy->taxonomy );
1210
						if ( isset( $taxonomy['hierarchical'] ) && ! $taxonomy['hierarchical'] ) {
1211
							$icon = 'dashicons-tag';
1212
						}
1213
					}
1214
1215
					$edit_link = get_edit_term_link( $item_id, $args->options['pick_val'] );
1216
1217
					$link = get_term_link( $item_id, $args->options['pick_val'] );
1218
				}
1219
1220
				break;
1221
1222
			case 'user':
1223
				$item_id = (int) $item_id;
1224
1225
				$args->options['supports_thumbnails'] = true;
1226
1227
				$icon     = 'dashicons-admin-users';
1228
				$img_icon = get_avatar_url( $item_id, array( 'size' => 150 ) );
1229
1230
				$edit_link = get_edit_user_link( $item_id );
1231
1232
				$link = get_author_posts_url( $item_id );
1233
1234
				break;
1235
1236
			case 'comment':
1237
				$item_id = (int) $item_id;
1238
1239
				$args->options['supports_thumbnails'] = true;
1240
1241
				$icon     = 'dashicons-admin-comments';
1242
				$img_icon = get_avatar_url( get_comment( $item_id ), array( 'size' => 150 ) );
1243
1244
				$edit_link = get_edit_comment_link( $item_id );
1245
1246
				$link = get_comment_link( $item_id );
1247
1248
				break;
1249
1250
			case 'pod':
1251
				$item_id = (int) $item_id;
1252
1253
				if ( ! empty( $args->options['pick_val'] ) ) {
1254
1255
					$icon = 'dashicons-pods';
1256
1257
					if ( pods_is_admin( array( 'pods', 'pods_content', 'pods_edit_' . $args->options['pick_val'] ) ) ) {
1258
						$file_name  = 'admin.php';
1259
						$query_args = array(
1260
							'page'   => 'pods-manage-' . $args->options['pick_val'],
1261
							'action' => 'edit',
1262
							'id'     => $item_id,
1263
						);
1264
1265
						$edit_link = add_query_arg( $query_args, admin_url( $file_name ) );
1266
					}
1267
1268
					// @todo Add $link support
1269
					$link = '';
1270
				}
1271
1272
				break;
1273
		}//end switch
1274
1275
		// Image icons always overwrite default icons
1276
		if ( ! empty( $img_icon ) ) {
1277
			$icon = $img_icon;
1278
		}
1279
1280
		// Parse icon type
1281
		if ( 'none' === $icon || 'div' === $icon ) {
1282
			$icon         = '';
1283
			$use_dashicon = true;
1284
		} elseif ( 0 === strpos( $icon, 'data:image/svg+xml;base64,' ) ) {
1285
			$icon         = esc_attr( $icon );
1286
			$use_dashicon = false;
1287
		} elseif ( 0 === strpos( $icon, 'dashicons-' ) ) {
1288
			$icon         = sanitize_html_class( $icon );
1289
			$use_dashicon = true;
1290
		}
1291
1292
		// Support modal editing
1293
		if ( ! empty( $edit_link ) ) {
1294
			// @todo: Replace string literal with defined constant
1295
			$edit_link = add_query_arg( array( 'pods_modal' => '1' ), $edit_link );
1296
		}
1297
1298
		// Determine if this is a selected item
1299
		$selected = false;
1300
1301
		if ( is_array( $args->value ) ) {
1302
			if ( isset( $args->value[ $item_id ] ) ) {
1303
				$selected = true;
1304
			} elseif ( in_array( $item_id, $args->value, true ) ) {
1305
				$selected = true;
1306
			}
1307
		} elseif ( (string) $item_id === (string) $args->value ) {
1308
			$selected = true;
1309
		}
1310
1311
		$item = array(
1312
			'id'           => $item_id,
1313
			'use_dashicon' => $use_dashicon,
1314
			'icon'         => $icon,
1315
			'name'         => $item_title,
1316
			'edit_link'    => $edit_link,
1317
			'link'         => $link,
1318
			'selected'     => $selected,
1319
		);
1320
1321
		return $item;
1322
1323
	}
1324
1325
	/**
1326
	 * {@inheritdoc}
1327
	 */
1328
	public function validate( $value, $name = null, $options = null, $fields = null, $pod = null, $id = null, $params = null ) {
1329
1330
		if ( empty( self::$api ) ) {
1331
			self::$api = pods_api();
1332
		}
1333
1334
		$simple_tableless_objects = $this->simple_objects();
0 ignored issues
show
Comprehensibility Naming introduced by
The variable name $simple_tableless_objects exceeds the maximum configured length of 20.

Very long variable names usually make code harder to read. It is therefore recommended not to make variable names too verbose.

Loading history...
1335
1336
		$related_pick_limit  = 0;
1337
		$related_field       = false;
1338
		$related_pod         = false;
1339
		$current_related_ids = false;
1340
1341
		// Bidirectional relationship requirement checks
1342
		$related_object = pods_v( static::$type . '_object', $options, '' );
1343
		// pod, post_type, taxonomy, etc..
1344
		$related_val = pods_v( static::$type . '_val', $options, $related_object, null, true );
1345
		// pod name, post type name, taxonomy name, etc..
1346
		if ( empty( $related_val ) ) {
1347
			$related_val = $related_object;
1348
		}
1349
1350
		$related_sister_id = (int) pods_v( 'sister_id', $options, 0 );
1351
1352
		$options['id'] = (int) $options['id'];
1353
1354
		if ( ! isset( self::$related_data[ $options['id'] ] ) || empty( self::$related_data[ $options['id'] ] ) ) {
1355
			self::$related_data[ $options['id'] ] = array();
1356
		}
1357
1358
		if ( ! empty( $related_sister_id ) && ! in_array( $related_object, $simple_tableless_objects, true ) ) {
1359
			$related_pod = self::$api->load_pod(
1360
				array(
1361
					'name'       => $related_val,
1362
					'table_info' => false,
1363
				), false
1364
			);
1365
1366
			if ( false !== $related_pod && ( 'pod' === $related_object || $related_object === $related_pod['type'] ) ) {
1367
				$related_field = false;
1368
1369
				// Ensure sister_id exists on related Pod.
1370
				foreach ( $related_pod['fields'] as $related_pod_field ) {
1371
					if ( 'pick' === $related_pod_field['type'] && $related_sister_id === $related_pod_field['id'] ) {
1372
						$related_field = $related_pod_field;
1373
1374
						break;
1375
					}
1376
				}
1377
1378
				if ( ! empty( $related_field ) ) {
1379
					$current_ids = self::$api->lookup_related_items( $fields[ $name ]['id'], $pod['id'], $id, $fields[ $name ], $pod );
1380
1381
					self::$related_data[ $options['id'] ]['current_ids'] = $current_ids;
1382
1383
					$value_ids = $value;
1384
1385
					// Convert values from a comma-separated string into an array.
1386
					if ( ! is_array( $value_ids ) ) {
1387
						$value_ids = explode( ',', $value_ids );
1388
					}
1389
1390
					$value_ids = array_unique( array_filter( $value_ids ) );
1391
1392
					// Get ids to remove.
1393
					$remove_ids = array_diff( $current_ids, $value_ids );
1394
1395
					$related_required   = (boolean) pods_v( 'required', $related_field['options'], 0 );
1396
					$related_pick_limit = (int) pods_v( static::$type . '_limit', $related_field['options'], 0 );
1397
1398
					if ( 'single' === pods_v( static::$type . '_format_type', $related_field['options'] ) ) {
1399
						$related_pick_limit = 1;
1400
					}
1401
1402
					// Validate Required fields.
1403
					if ( $related_required && ! empty( $remove_ids ) ) {
1404
						foreach ( $remove_ids as $related_id ) {
1405
							$bidirectional_ids = self::$api->lookup_related_items( $related_field['id'], $related_pod['id'], $related_id, $related_field, $related_pod );
1406
1407
							self::$related_data[ $options['id'] ][ 'related_ids_' . $related_id ] = $bidirectional_ids;
1408
1409
							if ( empty( $bidirectional_ids ) || ( in_array( (int) $id, $bidirectional_ids, true ) && 1 === count( $bidirectional_ids ) ) ) {
1410
								return sprintf( __( 'The %1$s field is required and cannot be removed by the %2$s field', 'pods' ), $related_field['label'], $options['label'] );
0 ignored issues
show
Bug Best Practice introduced by
The return type of return sprintf(__('The %...'], $options['label']); (string) is incompatible with the return type of the parent method PodsField::validate of type boolean.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
1411
							}
1412
						}
1413
					}
1414
				} else {
1415
					$related_pod = false;
1416
				}//end if
1417
			} else {
1418
				$related_pod = false;
1419
			}//end if
1420
		}//end if
1421
1422
		if ( empty( self::$related_data[ $options['id'] ] ) ) {
1423
			unset( self::$related_data[ $options['id'] ] );
1424
		} else {
1425
			self::$related_data[ $options['id'] ]['related_pod']        = $related_pod;
1426
			self::$related_data[ $options['id'] ]['related_field']      = $related_field;
1427
			self::$related_data[ $options['id'] ]['related_pick_limit'] = $related_pick_limit;
1428
1429
			$pick_limit = (int) pods_v( static::$type . '_limit', $options['options'], 0 );
1430
1431
			if ( 'single' === pods_v( static::$type . '_format_type', $options['options'] ) ) {
1432
				$pick_limit = 1;
1433
			}
1434
1435
			$related_field['id'] = (int) $related_field['id'];
1436
1437
			if ( ! isset( self::$related_data[ $related_field['id'] ] ) || empty( self::$related_data[ $related_field['id'] ] ) ) {
1438
				self::$related_data[ $related_field['id'] ] = array(
1439
					'related_pod'        => $pod,
1440
					'related_field'      => $options,
1441
					'related_pick_limit' => $pick_limit,
1442
				);
1443
			}
1444
		}//end if
1445
1446
		return true;
1447
1448
	}
1449
1450
	/**
1451
	 * {@inheritdoc}
1452
	 */
1453
	public function save( $value, $id = null, $name = null, $options = null, $fields = null, $pod = null, $params = null ) {
1454
1455
		if ( empty( self::$api ) ) {
1456
			self::$api = pods_api();
1457
		}
1458
1459
		$options['id'] = (int) $options['id'];
1460
1461
		if ( ! isset( self::$related_data[ $options['id'] ] ) ) {
1462
			return;
1463
		}
1464
1465
		$related_pod        = self::$related_data[ $options['id'] ]['related_pod'];
1466
		$related_field      = self::$related_data[ $options['id'] ]['related_field'];
1467
		$related_pick_limit = self::$related_data[ $options['id'] ]['related_pick_limit'];
1468
1469
		// Bidirectional relationship updates.
1470
		if ( ! empty( $related_field ) ) {
1471
			// Don't use no conflict mode unless this isn't the current pod type.
1472
			$no_conflict = true;
1473
1474
			if ( $related_pod['type'] !== $pod['type'] ) {
1475
				$no_conflict = pods_no_conflict_check( $related_pod['type'] );
1476
			}
1477
1478
			if ( ! $no_conflict ) {
1479
				pods_no_conflict_on( $related_pod['type'] );
1480
			}
1481
1482
			$value = array_filter( $value );
1483
1484
			foreach ( $value as $related_id ) {
1485
				if ( isset( self::$related_data[ $options['id'] ][ 'related_ids_' . $related_id ] ) && ! empty( self::$related_data[ $options['id'] ][ 'related_ids_' . $related_id ] ) ) {
1486
					$bidirectional_ids = self::$related_data[ $options['id'] ][ 'related_ids_' . $related_id ];
1487
				} else {
1488
					$bidirectional_ids = self::$api->lookup_related_items( $related_field['id'], $related_pod['id'], $related_id, $related_field, $related_pod );
1489
				}
1490
1491
				$bidirectional_ids = array_filter( $bidirectional_ids );
1492
1493
				if ( empty( $bidirectional_ids ) ) {
1494
					$bidirectional_ids = array();
1495
				}
1496
1497
				$remove_ids = array();
1498
1499
				if ( 0 < $related_pick_limit && ! empty( $bidirectional_ids ) && ! in_array( $id, $bidirectional_ids, true ) ) {
1500
					$total_bidirectional_ids = count( $bidirectional_ids );
0 ignored issues
show
Comprehensibility Naming introduced by
The variable name $total_bidirectional_ids exceeds the maximum configured length of 20.

Very long variable names usually make code harder to read. It is therefore recommended not to make variable names too verbose.

Loading history...
1501
1502
					while ( $related_pick_limit <= $total_bidirectional_ids ) {
1503
						$remove_ids[] = (int) array_pop( $bidirectional_ids );
1504
1505
						$total_bidirectional_ids = count( $bidirectional_ids );
1506
					}
1507
				}
1508
1509
				// Remove this item from related items no longer related to.
1510
				$remove_ids = array_unique( array_filter( $remove_ids ) );
1511
1512
				if ( ! in_array( $id, $bidirectional_ids, true ) ) {
1513
					// Add to related items.
1514
					$bidirectional_ids[] = $id;
1515
				} elseif ( empty( $remove_ids ) ) {
1516
					// Nothing to change.
1517
					continue;
1518
				}
1519
1520
				self::$api->save_relationships( $related_id, $bidirectional_ids, $related_pod, $related_field );
1521
1522
				if ( ! empty( $remove_ids ) ) {
1523
					self::$api->delete_relationships( $remove_ids, $related_id, $pod, $options );
1524
				}
1525
			}//end foreach
1526
1527
			if ( ! $no_conflict ) {
1528
				pods_no_conflict_off( $related_pod['type'] );
1529
			}
1530
		}//end if
1531
1532
	}
1533
1534
	/**
1535
	 * Delete the value from the DB
1536
	 *
1537
	 * @param int|null    $id      Item ID.
1538
	 * @param string|null $name    Field name.
1539
	 * @param array|null  $options Field options.
1540
	 * @param array|null  $pod     Pod options.
1541
	 *
1542
	 * @since 2.3
1543
	 */
1544
	public function delete( $id = null, $name = null, $options = null, $pod = null ) {
1545
1546
		if ( empty( self::$api ) ) {
1547
			self::$api = pods_api();
1548
		}
1549
1550
		$simple_tableless_objects = $this->simple_objects();
0 ignored issues
show
Comprehensibility Naming introduced by
The variable name $simple_tableless_objects exceeds the maximum configured length of 20.

Very long variable names usually make code harder to read. It is therefore recommended not to make variable names too verbose.

Loading history...
1551
1552
		// Bidirectional relationship requirement checks.
1553
		$related_object = pods_v( static::$type . '_object', $options, '' );
1554
		// pod, post_type, taxonomy, etc..
1555
		$related_val = pods_v( static::$type . '_val', $options, $related_object, true );
1556
		// pod name, post type name, taxonomy name, etc..
1557
		$related_sister_id = (int) pods_v( 'sister_id', $options, 0 );
1558
1559
		if ( ! empty( $related_sister_id ) && ! in_array( $related_object, $simple_tableless_objects, true ) ) {
1560
			$related_pod = self::$api->load_pod(
1561
				array(
1562
					'name'       => $related_val,
1563
					'table_info' => false,
1564
				), false
1565
			);
1566
1567
			if ( false !== $related_pod && ( 'pod' === $related_object || $related_object === $related_pod['type'] ) ) {
1568
				$related_field = false;
1569
1570
				// Ensure sister_id exists on related Pod.
1571
				foreach ( $related_pod['fields'] as $related_pod_field ) {
1572
					if ( 'pick' === $related_pod_field['type'] && (int) $related_sister_id === (int) $related_pod_field['id'] ) {
1573
						$related_field = $related_pod_field;
1574
1575
						break;
1576
					}
1577
				}
1578
1579
				if ( ! empty( $related_field ) ) {
1580
					$values = self::$api->lookup_related_items( $options['id'], $pod['id'], $id, $options, $pod );
1581
1582
					if ( ! empty( $values ) ) {
1583
						$no_conflict = pods_no_conflict_check( $related_pod['type'] );
1584
1585
						if ( ! $no_conflict ) {
1586
							pods_no_conflict_on( $related_pod['type'] );
1587
						}
1588
1589
						self::$api->delete_relationships( $values, $id, $related_pod, $related_field );
1590
1591
						if ( ! $no_conflict ) {
1592
							pods_no_conflict_off( $related_pod['type'] );
1593
						}
1594
					}
1595
				}
1596
			}//end if
1597
		}//end if
1598
1599
	}
1600
1601
	/**
1602
	 * {@inheritdoc}
1603
	 */
1604
	public function ui( $id, $value, $name = null, $options = null, $fields = null, $pod = null ) {
0 ignored issues
show
This method's name is shorter than the configured minimum length of 3 characters.

Even though PHP does not care about the name of your methods, it is generally a good practice to choose method names which can be easily understood by other human readers.

Loading history...
1605
1606
		$value = $this->simple_value( $name, $value, $options, $pod, $id );
1607
1608
		return $this->display( $value, $name, $options, $pod, $id );
1609
1610
	}
1611
1612
	/**
1613
	 * {@inheritdoc}
1614
	 */
1615
	public function data( $name, $value = null, $options = null, $pod = null, $id = null, $in_form = true ) {
0 ignored issues
show
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
1616
1617
		if ( isset( $options['options'] ) ) {
1618
			$options = array_merge( $options, $options['options'] );
1619
1620
			unset( $options['options'] );
1621
		}
1622
1623
		$data = pods_v( 'data', $options, null, true );
1624
1625
		$object_params = array(
1626
			// The name of the field.
1627
			'name'    => $name,
1628
			// The value of the field.
1629
			'value'   => $value,
1630
			// Field options.
1631
			'options' => $options,
1632
			// Pod data.
1633
			'pod'     => $pod,
1634
			// Item ID.
1635
			'id'      => $id,
1636
			// Data context.
1637
			'context' => 'data',
1638
		);
1639
1640
		if ( null !== $data ) {
1641
			$data = (array) $data;
1642
		} else {
1643
			$data = $this->get_object_data( $object_params );
1644
		}
1645
1646
		if ( 'single' === pods_v( static::$type . '_format_type', $options, 'single' ) && 'dropdown' === pods_v( static::$type . '_format_single', $options, 'dropdown' ) ) {
1647
			$data = array( '' => pods_v( static::$type . '_select_text', $options, __( '-- Select One --', 'pods' ), true ) ) + $data;
1648
		}
1649
1650
		$data = apply_filters( 'pods_field_pick_data', $data, $name, $value, $options, $pod, $id );
1651
1652
		return $data;
1653
1654
	}
1655
1656
	/**
1657
	 * Convert a simple value to the correct value
1658
	 *
1659
	 * @param string            $name    The name of the field.
1660
	 * @param string|array|null $value   The value of the field.
1661
	 * @param array|null        $options Field options.
1662
	 * @param array|null        $pod     Pod data.
1663
	 * @param int|null          $id      Item ID.
1664
	 * @param boolean           $raw     Whether to return the raw list of keys (true) or convert to key=>value (false).
1665
	 *
1666
	 * @return mixed Corrected value
1667
	 */
1668
	public function simple_value( $name, $value = null, $options = null, $pod = null, $id = null, $raw = false ) {
1669
1670
		if ( in_array( pods_v( static::$type . '_object', $options ), self::simple_objects(), true ) ) {
1671
			if ( isset( $options['options'] ) ) {
1672
				$options = array_merge( $options, $options['options'] );
1673
1674
				unset( $options['options'] );
1675
			}
1676
1677
			if ( ! is_array( $value ) && 0 < strlen( $value ) ) {
1678
				$simple = @json_decode( $value, true );
0 ignored issues
show
Silencing errors is discouraged
Loading history...
1679
1680
				if ( is_array( $simple ) ) {
1681
					$value = $simple;
1682
				}
1683
			}
1684
1685
			$data = pods_v( 'data', $options, null, true );
1686
1687
			$object_params = array(
1688
				// The name of the field.
1689
				'name'    => $name,
1690
				// The value of the field.
1691
				'value'   => $value,
1692
				// Field options.
1693
				'options' => $options,
1694
				// Pod data.
1695
				'pod'     => $pod,
1696
				// Item ID.
1697
				'id'      => $id,
1698
				// Data context.
1699
				'context' => 'simple_value',
1700
			);
1701
1702
			if ( null === $data ) {
1703
				$data = $this->get_object_data( $object_params );
1704
			}
1705
1706
			$data = (array) $data;
1707
1708
			$key = 0;
1709
1710
			if ( is_array( $value ) ) {
1711
				if ( ! empty( $data ) ) {
1712
					$val = array();
1713
1714
					foreach ( $value as $k => $v ) {
1715
						if ( isset( $data[ $v ] ) ) {
1716
							if ( false === $raw ) {
1717
								$k = $v;
1718
								$v = $data[ $v ];
1719
							}
1720
1721
							$val[ $k ] = $v;
1722
						}
1723
					}
1724
1725
					$value = $val;
1726
				}
1727
			} elseif ( isset( $data[ $value ] ) && false === $raw ) {
1728
				$key   = $value;
1729
				$value = $data[ $value ];
1730
			}//end if
1731
1732
			$single_multi = pods_v( static::$type . '_format_type', $options, 'single' );
1733
1734
			if ( 'multi' === $single_multi ) {
1735
				$limit = (int) pods_v( static::$type . '_limit', $options, 0 );
1736
			} else {
1737
				$limit = 1;
1738
			}
1739
1740
			if ( is_array( $value ) && 0 < $limit ) {
1741
				if ( 1 === $limit ) {
1742
					$value = current( $value );
1743
				} else {
1744
					$value = array_slice( $value, 0, $limit, true );
1745
				}
1746
			} elseif ( ! is_array( $value ) && null !== $value && 0 < strlen( $value ) ) {
1747
				if ( 1 !== $limit || ( true === $raw && 'multi' === $single_multi ) ) {
1748
					$value = array(
1749
						$key => $value,
1750
					);
1751
				}
1752
			}
1753
		}//end if
1754
1755
		return $value;
1756
1757
	}
1758
1759
	/**
1760
	 * Get the label from a pick value.
1761
	 *
1762
	 * @param string            $name    The name of the field.
1763
	 * @param string|array|null $value   The value of the field.
1764
	 * @param array|null        $options Field options.
1765
	 * @param array|null        $pod     Pod data.
1766
	 * @param int|null          $id      Item ID.
1767
	 *
1768
	 * @return string
1769
	 *
1770
	 * @since 2.2
1771
	 */
1772
	public function value_to_label( $name, $value = null, $options = null, $pod = null, $id = null ) {
1773
1774
		if ( isset( $options['options'] ) ) {
1775
			$options = array_merge( $options, $options['options'] );
1776
1777
			unset( $options['options'] );
1778
		}
1779
1780
		$data = pods_v( 'data', $options, null, true );
1781
1782
		$object_params = array(
1783
			// The name of the field.
1784
			'name'    => $name,
1785
			// The value of the field.
1786
			'value'   => $value,
1787
			// Field options.
1788
			'options' => $options,
1789
			// Pod data.
1790
			'pod'     => $pod,
1791
			// Item ID.
1792
			'id'      => $id,
1793
			// Data context.
1794
			'context' => 'value_to_label',
1795
		);
1796
1797
		if ( null !== $data ) {
1798
			$data = (array) $data;
1799
		} else {
1800
			$data = $this->get_object_data( $object_params );
1801
		}
1802
1803
		$labels = array();
1804
1805
		$check_value = $value;
1806
1807
		foreach ( $check_value as $check_k => $check_v ) {
0 ignored issues
show
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...
1808
			$check_value[ $check_k ] = (string) $check_v;
1809
		}
1810
1811
		foreach ( $data as $v => $l ) {
0 ignored issues
show
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...
1812
			if ( ! in_array( (string) $l, $labels, true ) && ( (string) $value === (string) $v || ( is_array( $value ) && in_array( (string) $v, $value, true ) ) ) ) {
1813
				$labels[] = (string) $l;
1814
			}
1815
		}
1816
1817
		$labels = apply_filters( 'pods_field_pick_value_to_label', $labels, $name, $value, $options, $pod, $id );
1818
1819
		$labels = pods_serial_comma( $labels );
1820
1821
		return $labels;
1822
1823
	}
1824
1825
	/**
1826
	 * Get available items from a relationship field.
1827
	 *
1828
	 * @param array|string $field         Field array or field name.
1829
	 * @param array        $options       Field options array overrides.
1830
	 * @param array        $object_params Additional get_object_data options.
1831
	 *
1832
	 * @return array An array of available items from a relationship field
0 ignored issues
show
Should the return type not be array|boolean? Also, consider making the array more specific, something like array<String>, or String[].

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

If the return type contains the type array, this check recommends the use of a more specific type like String[] or array<String>.

Loading history...
1833
	 */
1834
	public function get_field_data( $field, $options = array(), $object_params = array() ) {
1835
1836
		// Handle field array overrides.
1837
		if ( is_array( $field ) ) {
1838
			$options = array_merge( $field, $options );
1839
		}
1840
1841
		// Get field name from array.
1842
		$field = pods_v( 'name', $options, $field, true );
1843
1844
		// Field name or options not set.
1845
		if ( empty( $field ) || empty( $options ) ) {
1846
			return array();
1847
		}
1848
1849
		// Options normalization.
1850
		$options = array_merge( $options, pods_v( 'options', $options, array(), true ) );
1851
1852
		// Setup object params.
1853
		$object_params = array_merge(
1854
			array(
1855
				// The name of the field.
1856
				'name'    => $field,
1857
				// Field options.
1858
				'options' => $options,
1859
			), $object_params
1860
		);
1861
1862
		// Get data override.
1863
		$data = pods_v( 'data', $options, null, true );
1864
1865
		if ( null !== $data ) {
1866
			// Return data override.
1867
			$data = (array) $data;
1868
		} else {
1869
			// Get object data.
1870
			$data = $this->get_object_data( $object_params );
1871
		}
1872
1873
		return $data;
1874
1875
	}
1876
1877
	/**
1878
	 * Get data from relationship objects.
1879
	 *
1880
	 * @param array $object_params Object data parameters.
0 ignored issues
show
Should the type for parameter $object_params not be array|null? Also, consider making the array more specific, something like array<String>, or String[].

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive. In addition it looks for parameters that have the generic type array and suggests a stricter type like array<String>.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
1881
	 *
1882
	 * @return array|bool Object data
1883
	 */
1884
	public function get_object_data( $object_params = null ) {
1885
1886
		/**
1887
		 * @var $wpdb wpdb
1888
		 */
1889
		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...
1890
1891
		$object_params = array_merge(
1892
			array(
1893
				// The name of the field.
1894
				'name'        => '',
1895
				// The value of the field.
1896
				'value'       => '',
1897
				// Field options.
1898
				'options'     => array(),
1899
				// Pod data.
1900
				'pod'         => '',
1901
				// Item ID.
1902
				'id'          => '',
1903
				// Data context.
1904
				'context'     => '',
1905
				// Data parameters.
1906
				'data_params' => array(
1907
					// Query being searched.
1908
					'query' => '',
1909
				),
1910
				// Page number of results to get.
1911
				'page'        => 1,
1912
				// How many data items to limit to (autocomplete defaults to 30, set to -1 or 1+ to override).
1913
				'limit'       => 0,
1914
			), $object_params
1915
		);
1916
1917
		$object_params['options']     = (array) $object_params['options'];
1918
		$object_params['data_params'] = (array) $object_params['data_params'];
1919
1920
		$name         = $object_params['name'];
1921
		$value        = $object_params['value'];
1922
		$options      = $object_params['options'];
1923
		$pod          = $object_params['pod'];
1924
		$id           = $object_params['id'];
1925
		$context      = $object_params['context'];
1926
		$data_params  = $object_params['data_params'];
1927
		$page         = min( 1, (int) $object_params['page'] );
1928
		$limit        = (int) $object_params['limit'];
1929
		$autocomplete = false;
1930
1931
		if ( isset( $options['options'] ) ) {
1932
			$options = array_merge( $options, $options['options'] );
1933
1934
			unset( $options['options'] );
1935
		}
1936
1937
		$data  = apply_filters( 'pods_field_pick_object_data', null, $name, $value, $options, $pod, $id, $object_params );
1938
		$items = array();
1939
1940
		if ( ! isset( $options[ static::$type . '_object' ] ) ) {
1941
			$data = pods_v( 'data', $options, array(), true );
1942
		}
1943
1944
		$simple = false;
1945
1946
		if ( null === $data ) {
1947
			$data = array();
1948
1949
			if ( 'custom-simple' === $options[ static::$type . '_object' ] ) {
1950
				$custom = pods_v( static::$type . '_custom', $options, '' );
1951
1952
				$custom = apply_filters( 'pods_form_ui_field_pick_custom_values', $custom, $name, $value, $options, $pod, $id, $object_params );
1953
1954
				if ( ! empty( $custom ) ) {
1955
					if ( ! is_array( $custom ) ) {
1956
						$data = array();
1957
1958
						$custom = explode( "\n", trim( $custom ) );
1959
1960
						foreach ( $custom as $custom_value ) {
1961
							$custom_label = explode( '|', $custom_value );
1962
1963
							if ( empty( $custom_label ) ) {
1964
								continue;
1965
							}
1966
1967
							if ( 1 === count( $custom_label ) ) {
1968
								$custom_label = $custom_value;
1969
							} else {
1970
								$custom_value = $custom_label[0];
1971
								$custom_label = $custom_label[1];
1972
							}
1973
1974
							$custom_value = trim( (string) $custom_value );
1975
							$custom_label = trim( (string) $custom_label );
1976
1977
							$data[ $custom_value ] = $custom_label;
1978
						}
1979
					} else {
1980
						$data = $custom;
1981
					}//end if
1982
1983
					$simple = true;
1984
				}//end if
1985
			} elseif ( isset( self::$related_objects[ $options[ static::$type . '_object' ] ] ) && isset( self::$related_objects[ $options[ static::$type . '_object' ] ]['data'] ) && ! empty( self::$related_objects[ $options[ static::$type . '_object' ] ]['data'] ) ) {
1986
				$data = self::$related_objects[ $options[ static::$type . '_object' ] ]['data'];
1987
1988
				$simple = true;
1989
			} elseif ( isset( self::$related_objects[ $options[ static::$type . '_object' ] ] ) && isset( self::$related_objects[ $options[ static::$type . '_object' ] ]['data_callback'] ) && is_callable( self::$related_objects[ $options[ static::$type . '_object' ] ]['data_callback'] ) ) {
1990
				$data = call_user_func_array(
1991
					self::$related_objects[ $options[ static::$type . '_object' ] ]['data_callback'], array(
1992
						$name,
1993
						$value,
1994
						$options,
1995
						$pod,
1996
						$id,
1997
					)
1998
				);
1999
2000
				if ( 'data' === $context ) {
2001
					self::$field_data = array(
2002
						'field'        => $name,
2003
						'id'           => $options['id'],
2004
						'autocomplete' => false,
2005
					);
2006
				}
2007
2008
				$simple = true;
2009
2010
				// Cache data from callback.
2011
				if ( ! empty( $data ) ) {
2012
					self::$related_objects[ $options[ static::$type . '_object' ] ]['data'] = $data;
2013
				}
2014
			} elseif ( 'simple_value' !== $context ) {
2015
				$pick_val = pods_v( static::$type . '_val', $options );
2016
2017
				if ( 'table' === pods_v( static::$type . '_object', $options ) ) {
2018
					$pick_val = pods_v( static::$type . '_table', $options, $pick_val, true );
2019
				}
2020
2021
				if ( '__current__' === $pick_val ) {
2022
					if ( is_object( $pod ) ) {
2023
						$pick_val = $pod->pod;
2024
					} elseif ( is_array( $pod ) ) {
2025
						$pick_val = $pod['name'];
2026
					} elseif ( 0 < strlen( $pod ) ) {
2027
						$pick_val = $pod;
2028
					}
2029
				}
2030
2031
				$options['table_info'] = pods_api()->get_table_info( pods_v( static::$type . '_object', $options ), $pick_val, null, null, $object_params );
2032
2033
				$search_data = pods_data();
2034
				$search_data->table( $options['table_info'] );
2035
2036
				if ( isset( $options['table_info']['pod'] ) && ! empty( $options['table_info']['pod'] ) && isset( $options['table_info']['pod']['name'] ) ) {
2037
					$search_data->pod    = $options['table_info']['pod']['name'];
2038
					$search_data->fields = $options['table_info']['pod']['fields'];
2039
				}
2040
2041
				$params = array(
2042
					'select'     => "`t`.`{$search_data->field_id}`, `t`.`{$search_data->field_index}`",
2043
					'table'      => $search_data->table,
2044
					'where'      => pods_v( static::$type . '_where', $options, (array) $options['table_info']['where_default'], true ),
2045
					'orderby'    => pods_v( static::$type . '_orderby', $options, null, true ),
2046
					'groupby'    => pods_v( static::$type . '_groupby', $options, null, true ),
2047
					'pagination' => false,
2048
					'search'     => false,
2049
				);
2050
2051
				if ( in_array( $options[ static::$type . '_object' ], array( 'site', 'network' ), true ) ) {
2052
					$params['select'] .= ', `t`.`path`';
2053
				}
2054
2055
				if ( ! empty( $params['where'] ) && (array) $options['table_info']['where_default'] !== $params['where'] ) {
2056
					$params['where'] = pods_evaluate_tags( $params['where'], true );
2057
				}
2058
2059
				if ( empty( $params['where'] ) || ( ! is_array( $params['where'] ) && '' === trim( $params['where'] ) ) ) {
2060
					$params['where'] = array();
2061
				} elseif ( ! is_array( $params['where'] ) ) {
2062
					$params['where'] = (array) $params['where'];
2063
				}
2064
2065
				if ( 'value_to_label' === $context ) {
2066
					$params['where'][] = "`t`.`{$search_data->field_id}` = " . number_format( $value, 0, '', '' );
2067
				}
2068
2069
				$display = trim( pods_v( static::$type . '_display', $options ), ' {@}' );
2070
2071
				if ( 0 < strlen( $display ) ) {
2072
					if ( isset( $options['table_info']['pod'] ) && ! empty( $options['table_info']['pod'] ) ) {
2073
						if ( isset( $options['table_info']['pod']['object_fields'] ) && isset( $options['table_info']['pod']['object_fields'][ $display ] ) ) {
2074
							$search_data->field_index = $display;
2075
2076
							$params['select'] = "`t`.`{$search_data->field_id}`, `t`.`{$search_data->field_index}`";
2077
						} elseif ( isset( $options['table_info']['pod']['fields'][ $display ] ) ) {
2078
							$search_data->field_index = $display;
2079
2080
							if ( 'table' === $options['table_info']['pod']['storage'] && ! in_array(
2081
								$options['table_info']['pod']['type'], array(
2082
									'pod',
2083
									'table',
2084
								), true
2085
							)
2086
							) {
2087
								$params['select'] = "`t`.`{$search_data->field_id}`, `d`.`{$search_data->field_index}`";
2088
							} elseif ( 'meta' === $options['table_info']['pod']['storage'] ) {
2089
								$params['select'] = "`t`.`{$search_data->field_id}`, `{$search_data->field_index}`.`meta_value` AS {$search_data->field_index}";
2090
							} else {
2091
								$params['select'] = "`t`.`{$search_data->field_id}`, `t`.`{$search_data->field_index}`";
2092
							}
2093
						}//end if
2094
					} elseif ( isset( $options['table_info']['object_fields'] ) && isset( $options['table_info']['object_fields'][ $display ] ) ) {
2095
						$search_data->field_index = $display;
2096
2097
						$params['select'] = "`t`.`{$search_data->field_id}`, `t`.`{$search_data->field_index}`";
2098
					}//end if
2099
				}//end if
2100
2101
				$autocomplete = $this->is_autocomplete( $options );
2102
2103
				$hierarchy = false;
2104
2105
				if ( 'data' === $context && ! $autocomplete ) {
2106
					if ( 'single' === pods_v( static::$type . '_format_type', $options, 'single' ) && in_array(
2107
						pods_v( static::$type . '_format_single', $options, 'dropdown' ), array(
2108
							'dropdown',
2109
							'radio',
2110
						), true
2111
					)
2112
					) {
2113
						$hierarchy = true;
2114
					} elseif ( 'multi' === pods_v( static::$type . '_format_type', $options, 'single' ) && in_array(
2115
						pods_v( static::$type . '_format_multi', $options, 'checkbox' ), array(
2116
							'multiselect',
2117
							'checkbox',
2118
						), true
2119
					)
2120
					) {
2121
						$hierarchy = true;
2122
					}
2123
				}
2124
2125
				if ( $hierarchy && $options['table_info']['object_hierarchical'] && ! empty( $options['table_info']['field_parent'] ) ) {
2126
					$params['select'] .= ', ' . $options['table_info']['field_parent_select'];
2127
				}
2128
2129
				if ( $autocomplete ) {
2130
					if ( 0 === $limit ) {
2131
						$limit = 30;
2132
					}
2133
2134
					$params['limit'] = apply_filters( 'pods_form_ui_field_pick_autocomplete_limit', $limit, $name, $value, $options, $pod, $id, $object_params );
2135
2136
					if ( is_array( $value ) && $params['limit'] < count( $value ) ) {
2137
						$params['limit'] = count( $value );
2138
					}
2139
2140
					$params['page'] = $page;
2141
2142
					if ( 'admin_ajax_relationship' === $context ) {
2143
						$lookup_where = array(
2144
							$search_data->field_index => "`t`.`{$search_data->field_index}` LIKE '%" . pods_sanitize_like( $data_params['query'] ) . "%'",
2145
						);
2146
2147
						// @todo Hook into WPML for each table
2148
						if ( $wpdb->users === $search_data->table ) {
0 ignored issues
show
Usage of users/usermeta tables is highly discouraged in VIP context, For storing user additional user metadata, you should look at User Attributes.
Loading history...
2149
							$lookup_where['display_name'] = "`t`.`display_name` LIKE '%" . pods_sanitize_like( $data_params['query'] ) . "%'";
2150
							$lookup_where['user_login']   = "`t`.`user_login` LIKE '%" . pods_sanitize_like( $data_params['query'] ) . "%'";
2151
							$lookup_where['user_email']   = "`t`.`user_email` LIKE '%" . pods_sanitize_like( $data_params['query'] ) . "%'";
2152
						} elseif ( $wpdb->posts === $search_data->table ) {
2153
							$lookup_where['post_title']   = "`t`.`post_title` LIKE '%" . pods_sanitize_like( $data_params['query'] ) . "%'";
2154
							$lookup_where['post_name']    = "`t`.`post_name` LIKE '%" . pods_sanitize_like( $data_params['query'] ) . "%'";
2155
							$lookup_where['post_content'] = "`t`.`post_content` LIKE '%" . pods_sanitize_like( $data_params['query'] ) . "%'";
2156
							$lookup_where['post_excerpt'] = "`t`.`post_excerpt` LIKE '%" . pods_sanitize_like( $data_params['query'] ) . "%'";
2157
						} elseif ( $wpdb->terms === $search_data->table ) {
2158
							$lookup_where['name'] = "`t`.`name` LIKE '%" . pods_sanitize_like( $data_params['query'] ) . "%'";
2159
							$lookup_where['slug'] = "`t`.`slug` LIKE '%" . pods_sanitize_like( $data_params['query'] ) . "%'";
2160
						} elseif ( $wpdb->comments === $search_data->table ) {
2161
							$lookup_where['comment_content']      = "`t`.`comment_content` LIKE '%" . pods_sanitize_like( $data_params['query'] ) . "%'";
2162
							$lookup_where['comment_author']       = "`t`.`comment_author` LIKE '%" . pods_sanitize_like( $data_params['query'] ) . "%'";
2163
							$lookup_where['comment_author_email'] = "`t`.`comment_author_email` LIKE '%" . pods_sanitize_like( $data_params['query'] ) . "%'";
2164
						}
2165
2166
						$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 );
2167
2168
						if ( ! empty( $lookup_where ) ) {
2169
							$params['where'][] = implode( ' OR ', $lookup_where );
2170
						}
2171
2172
						$orderby   = array();
2173
						$orderby[] = "(`t`.`{$search_data->field_index}` LIKE '%" . pods_sanitize_like( $data_params['query'] ) . "%' ) DESC";
2174
2175
						$pick_orderby = pods_v( static::$type . '_orderby', $options, null, true );
2176
2177
						if ( 0 < strlen( $pick_orderby ) ) {
2178
							$orderby[] = $pick_orderby;
2179
						}
2180
2181
						$orderby[] = "`t`.`{$search_data->field_index}`";
2182
						$orderby[] = "`t`.`{$search_data->field_id}`";
2183
2184
						$params['orderby'] = $orderby;
2185
					}//end if
2186
				} elseif ( 0 < $limit ) {
2187
					$params['limit'] = $limit;
2188
					$params['page']  = $page;
2189
				}//end if
2190
2191
				$extra = '';
2192
2193
				if ( $wpdb->posts === $search_data->table ) {
2194
					$extra = ', `t`.`post_type`';
2195
				} elseif ( $wpdb->terms === $search_data->table ) {
2196
					$extra = ', `tt`.`taxonomy`';
2197
				} elseif ( $wpdb->comments === $search_data->table ) {
2198
					$extra = ', `t`.`comment_type`';
2199
				}
2200
2201
				$params['select'] .= $extra;
2202
2203
				if ( 'user' === pods_v( static::$type . '_object', $options ) ) {
2204
					$roles = pods_v( static::$type . '_user_role', $options );
2205
2206
					if ( ! empty( $roles ) ) {
2207
						$where = array();
2208
2209
						foreach ( (array) $roles as $role ) {
2210
							if ( empty( $role ) || ( pods_clean_name( $role ) !== $role && sanitize_title( $role ) !== $role ) ) {
2211
								continue;
2212
							}
2213
2214
							$prefix = $wpdb->base_prefix;
2215
2216
							if ( is_multisite() && ! is_main_site() ) {
2217
								$prefix .= get_current_blog_id() . '_';
2218
							}
2219
2220
							$where[] = $prefix . 'capabilities.meta_value LIKE "%\"' . pods_sanitize_like( $role ) . '\"%"';
2221
						}
2222
2223
						if ( ! empty( $where ) ) {
2224
							$params['where'][] = implode( ' OR ', $where );
2225
						}
2226
					}//end if
2227
				}//end if
2228
2229
				$results = $search_data->select( $params );
2230
2231
				if ( $autocomplete && $params['limit'] < $search_data->total_found() ) {
2232
					if ( ! empty( $value ) ) {
2233
						$ids = $value;
2234
2235
						if ( is_array( $ids ) && isset( $ids[0] ) && is_array( $ids[0] ) ) {
2236
							$ids = wp_list_pluck( $ids, $search_data->field_id );
2237
						}
2238
2239
						if ( is_array( $ids ) ) {
2240
							$ids = implode( ', ', $ids );
2241
						}
2242
2243
						if ( is_array( $params['where'] ) ) {
2244
							$params['where'] = implode( ' AND ', $params['where'] );
2245
						}
2246
						if ( ! empty( $params['where'] ) ) {
2247
							$params['where'] .= ' AND ';
2248
						}
2249
2250
						$params['where'] .= "`t`.`{$search_data->field_id}` IN ( {$ids} )";
2251
2252
						$results = $search_data->select( $params );
2253
					}//end if
2254
				} else {
2255
					$autocomplete = false;
2256
				}//end if
2257
2258
				if ( 'data' === $context ) {
2259
					self::$field_data = array(
2260
						'field'        => $name,
2261
						'id'           => $options['id'],
2262
						'autocomplete' => $autocomplete,
2263
					);
2264
				}
2265
2266
				if ( $hierarchy && ! $autocomplete && ! empty( $results ) && $options['table_info']['object_hierarchical'] && ! empty( $options['table_info']['field_parent'] ) ) {
2267
					$select_args = array(
2268
						'id'     => $options['table_info']['field_id'],
2269
						'index'  => $options['table_info']['field_index'],
2270
						'parent' => $options['table_info']['field_parent'],
2271
					);
2272
2273
					$results = pods_hierarchical_select( $results, $select_args );
2274
				}
2275
2276
				$ids = array();
2277
2278
				if ( ! empty( $results ) ) {
2279
					$display_filter = pods_v( 'display_filter', pods_v( 'options', pods_v( $search_data->field_index, $search_data->pod_data['object_fields'] ) ) );
2280
2281
					foreach ( $results as $result ) {
2282
						$result = get_object_vars( $result );
2283
2284
						if ( ! isset( $result[ $search_data->field_id ], $result[ $search_data->field_index ] ) ) {
2285
							continue;
2286
						}
2287
2288
						$result[ $search_data->field_index ] = trim( $result[ $search_data->field_index ] );
2289
2290
						$object      = '';
2291
						$object_type = '';
2292
2293
						if ( $wpdb->posts === $search_data->table && isset( $result['post_type'] ) ) {
2294
							$object      = $result['post_type'];
2295
							$object_type = 'post_type';
2296
						} elseif ( $wpdb->terms === $search_data->table && isset( $result['taxonomy'] ) ) {
2297
							$object      = $result['taxonomy'];
2298
							$object_type = 'taxonomy';
2299
						}
2300
2301
						if ( 0 < strlen( $display_filter ) ) {
2302
							$display_filter_args = pods_v( 'display_filter_args', pods_v( 'options', pods_v( $search_data->field_index, $search_data->pod_data['object_fields'] ) ) );
2303
2304
							$filter_args = array(
2305
								$display_filter,
2306
								$result[ $search_data->field_index ],
2307
							);
2308
2309
							if ( ! empty( $display_filter_args ) ) {
2310
								foreach ( (array) $display_filter_args as $display_filter_arg ) {
2311
									if ( isset( $result[ $display_filter_arg ] ) ) {
2312
										$filter_args[] = $result[ $display_filter_arg ];
2313
									}
2314
								}
2315
							}
2316
2317
							$result[ $search_data->field_index ] = call_user_func_array( 'apply_filters', $filter_args );
2318
						}
2319
2320
						if ( in_array( $options[ static::$type . '_object' ], array( 'site', 'network' ), true ) ) {
2321
							$result[ $search_data->field_index ] = $result[ $search_data->field_index ] . $result['path'];
2322
						} elseif ( '' === $result[ $search_data->field_index ] ) {
2323
							$result[ $search_data->field_index ] = '(No Title)';
2324
						}
2325
2326
						if ( 'admin_ajax_relationship' === $context ) {
2327
							$items[] = $this->build_dfv_field_item_data_recurse_item( $result[ $search_data->field_id ], $result[ $search_data->field_index ], (object) $object_params );
2328
						} else {
2329
							$data[ $result[ $search_data->field_id ] ] = $result[ $search_data->field_index ];
2330
						}
2331
2332
						$ids[] = $result[ $search_data->field_id ];
2333
					}//end foreach
2334
				}//end if
2335
			}//end if
2336
2337
			if ( $simple && 'admin_ajax_relationship' === $context ) {
2338
				$found_data = array();
2339
2340
				foreach ( $data as $k => $v ) {
2341
					if ( false !== stripos( $v, $data_params['query'] ) || false !== stripos( $k, $data_params['query'] ) ) {
2342
						$found_data[ $k ] = $v;
2343
					}
2344
				}
2345
2346
				$data = $found_data;
2347
			}
2348
		}//end if
2349
2350
		if ( 'admin_ajax_relationship' === $context ) {
2351
			if ( empty( $items ) && ! empty( $data ) ) {
2352
				foreach ( $data as $k => $v ) {
2353
					$items[] = array(
2354
						'id'   => $k,
2355
						'text' => $v,
2356
					);
2357
				}
2358
			}
2359
2360
			$data = $items;
2361
		}
2362
2363
		return $data;
2364
2365
	}
2366
2367
	/**
2368
	 * Check if field is autocomplete enabled.
2369
	 *
2370
	 * @param array $options Field options.
2371
	 *
2372
	 * @return bool
2373
	 */
2374
	public function is_autocomplete( $options ) {
2375
2376
		$autocomplete = false;
2377
2378
		if ( 'single' === pods_v( static::$type . '_format_type', $options, 'single' ) ) {
2379
			if ( in_array( pods_v( static::$type . '_format_single', $options, 'dropdown' ), array( 'autocomplete', 'list' ), true ) ) {
2380
				$autocomplete = true;
2381
			}
2382
		} elseif ( 'multi' === pods_v( static::$type . '_format_type', $options, 'single' ) ) {
2383
			if ( in_array( pods_v( static::$type . '_format_multi', $options, 'checkbox' ), array( 'autocomplete', 'list' ), true ) ) {
2384
				$autocomplete = true;
2385
			}
2386
		}
2387
2388
		return $autocomplete;
2389
	}
2390
2391
	/**
2392
	 * Handle autocomplete AJAX.
2393
	 *
2394
	 * @since 2.3
2395
	 */
2396
	public function admin_ajax_relationship() {
2397
2398
		pods_session_start();
2399
2400
		// Sanitize input.
2401
		// @codingStandardsIgnoreLine
2402
		$params = pods_unslash( (array) $_POST );
2403
2404
		foreach ( $params as $key => $value ) {
2405
			if ( 'action' === $key ) {
2406
				continue;
2407
			}
2408
2409
			unset( $params[ $key ] );
2410
2411
			$params[ str_replace( '_podsfix_', '', $key ) ] = $value;
2412
		}
2413
2414
		$params = (object) $params;
2415
2416
		$uid = @session_id();
0 ignored issues
show
Silencing errors is discouraged
Loading history...
The use of PHP session function session_id() is prohibited.
Loading history...
2417
2418
		if ( is_user_logged_in() ) {
2419
			$uid = 'user_' . get_current_user_id();
2420
		}
2421
2422
		$nonce_check = 'pods_relationship_' . (int) $params->pod . '_' . $uid . '_' . $params->uri . '_' . (int) $params->field;
2423
2424
		if ( ! isset( $params->_wpnonce ) || false === wp_verify_nonce( $params->_wpnonce, $nonce_check ) ) {
2425
			pods_error( __( 'Unauthorized request', 'pods' ), PodsInit::$admin );
2426
		}
2427
2428
		if ( empty( self::$api ) ) {
2429
			self::$api = pods_api();
2430
		}
2431
2432
		$pod   = self::$api->load_pod( array( 'id' => (int) $params->pod ) );
2433
		$field = self::$api->load_field(
2434
			array(
2435
				'id'         => (int) $params->field,
2436
				'table_info' => true,
2437
			)
2438
		);
2439
		$id    = (int) $params->id;
2440
2441
		$limit = 15;
2442
2443
		if ( isset( $params->limit ) ) {
2444
			$limit = (int) $params->limit;
2445
		}
2446
2447
		$page = 1;
2448
2449
		if ( isset( $params->page ) ) {
2450
			$page = (int) $params->page;
2451
		}
2452
2453
		if ( ! isset( $params->query ) || '' === trim( $params->query ) ) {
2454
			pods_error( __( 'Invalid field request', 'pods' ), PodsInit::$admin );
2455
		} elseif ( empty( $pod ) || empty( $field ) || (int) $pod['id'] !== (int) $field['pod_id'] || ! isset( $pod['fields'][ $field['name'] ] ) ) {
2456
			pods_error( __( 'Invalid field request', 'pods' ), PodsInit::$admin );
2457
		} elseif ( 'pick' !== $field['type'] || empty( $field['table_info'] ) ) {
2458
			pods_error( __( 'Invalid field', 'pods' ), PodsInit::$admin );
2459
		} elseif ( 'single' === pods_v( static::$type . '_format_type', $field ) && 'autocomplete' === pods_v( static::$type . '_format_single', $field ) ) {
2460
			pods_error( __( 'Invalid field', 'pods' ), PodsInit::$admin );
2461
		} elseif ( 'multi' === pods_v( static::$type . '_format_type', $field ) && 'autocomplete' === pods_v( static::$type . '_format_multi', $field ) ) {
2462
			pods_error( __( 'Invalid field', 'pods' ), PodsInit::$admin );
2463
		}
2464
2465
		$object_params = array(
2466
			// The name of the field.
2467
			'name'        => $field['name'],
2468
			// The value of the field.
2469
			'value'       => null,
2470
			// Field options.
2471
			'options'     => array_merge( $field, $field['options'] ),
2472
			// Pod data.
2473
			'pod'         => $pod,
2474
			// Item ID.
2475
			'id'          => $id,
2476
			// Data context.
2477
			'context'     => 'admin_ajax_relationship',
2478
			'data_params' => $params,
2479
			'page'        => $page,
2480
			'limit'       => $limit,
2481
		);
2482
2483
		$pick_data = apply_filters( 'pods_field_pick_data_ajax', null, $field['name'], null, $field, $pod, $id );
2484
2485
		if ( null !== $pick_data ) {
2486
			$items = $pick_data;
2487
		} else {
2488
			$items = $this->get_object_data( $object_params );
2489
		}
2490
2491
		if ( ! empty( $items ) && isset( $items[0] ) && ! is_array( $items[0] ) ) {
2492
			$new_items = array();
2493
2494
			foreach ( $items as $id => $text ) {
2495
				$new_items[] = array(
2496
					'id'    => $id,
2497
					'text'  => $text,
2498
					'image' => '',
2499
				);
2500
			}
2501
2502
			$items = $new_items;
2503
		}
2504
2505
		$items = apply_filters( 'pods_field_pick_data_ajax_items', $items, $field['name'], null, $field, $pod, $id );
2506
2507
		$items = array(
2508
			'results' => $items,
2509
		);
2510
2511
		wp_send_json( $items );
2512
2513
		die();
2514
		// KBAI!
2515
	}
2516
2517
	/**
2518
	 * Data callback for Post Stati.
2519
	 *
2520
	 * @param string|null       $name    The name of the field.
2521
	 * @param string|array|null $value   The value of the field.
2522
	 * @param array|null        $options Field options.
2523
	 * @param array|null        $pod     Pod data.
2524
	 * @param int|null          $id      Item ID.
2525
	 *
2526
	 * @return array
2527
	 *
2528
	 * @since 2.3
2529
	 */
2530
	public function data_post_stati( $name = null, $value = null, $options = null, $pod = null, $id = null ) {
2531
2532
		$data = array();
2533
2534
		$post_stati = get_post_stati( array(), 'objects' );
2535
2536
		foreach ( $post_stati as $post_status ) {
2537
			$data[ $post_status->name ] = $post_status->label;
2538
		}
2539
2540
		return apply_filters( 'pods_form_ui_field_pick_' . __FUNCTION__, $data, $name, $value, $options, $pod, $id );
2541
2542
	}
2543
2544
	/**
2545
	 * Data callback for User Roles.
2546
	 *
2547
	 * @param string|null       $name    The name of the field.
2548
	 * @param string|array|null $value   The value of the field.
2549
	 * @param array|null        $options Field options.
2550
	 * @param array|null        $pod     Pod data.
2551
	 * @param int|null          $id      Item ID.
2552
	 *
2553
	 * @return array
2554
	 *
2555
	 * @since 2.3
2556
	 */
2557
	public function data_roles( $name = null, $value = null, $options = null, $pod = null, $id = null ) {
2558
2559
		$data = array();
2560
2561
		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...
2562
2563
		foreach ( $wp_roles->role_objects as $key => $role ) {
2564
			$data[ $key ] = $wp_roles->role_names[ $key ];
2565
		}
2566
2567
		return apply_filters( 'pods_form_ui_field_pick_' . __FUNCTION__, $data, $name, $value, $options, $pod, $id );
2568
2569
	}
2570
2571
	/**
2572
	 * Data callback for User Capabilities.
2573
	 *
2574
	 * @param string|null       $name    The name of the field.
2575
	 * @param string|array|null $value   The value of the field.
2576
	 * @param array|null        $options Field options.
2577
	 * @param array|null        $pod     Pod data.
2578
	 * @param int|null          $id      Item ID.
2579
	 *
2580
	 * @return array
2581
	 *
2582
	 * @since 2.3
2583
	 */
2584
	public function data_capabilities( $name = null, $value = null, $options = null, $pod = null, $id = null ) {
2585
2586
		$data = array();
2587
2588
		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...
2589
2590
		$default_caps = array(
2591
			'activate_plugins',
2592
			'add_users',
2593
			'create_users',
2594
			'delete_others_pages',
2595
			'delete_others_posts',
2596
			'delete_pages',
2597
			'delete_plugins',
2598
			'delete_posts',
2599
			'delete_private_pages',
2600
			'delete_private_posts',
2601
			'delete_published_pages',
2602
			'delete_published_posts',
2603
			'delete_users',
2604
			'edit_dashboard',
2605
			'edit_files',
2606
			'edit_others_pages',
2607
			'edit_others_posts',
2608
			'edit_pages',
2609
			'edit_plugins',
2610
			'edit_posts',
2611
			'edit_private_pages',
2612
			'edit_private_posts',
2613
			'edit_published_pages',
2614
			'edit_published_posts',
2615
			'edit_theme_options',
2616
			'edit_themes',
2617
			'edit_users',
2618
			'import',
2619
			'install_plugins',
2620
			'install_themes',
2621
			'list_users',
2622
			'manage_categories',
2623
			'manage_links',
2624
			'manage_options',
2625
			'moderate_comments',
2626
			'promote_users',
2627
			'publish_pages',
2628
			'publish_posts',
2629
			'read',
2630
			'read_private_pages',
2631
			'read_private_posts',
2632
			'remove_users',
2633
			'switch_themes',
2634
			'unfiltered_html',
2635
			'unfiltered_upload',
2636
			'update_core',
2637
			'update_plugins',
2638
			'update_themes',
2639
			'upload_files',
2640
		);
2641
2642
		$role_caps = array();
2643
2644
		foreach ( $wp_roles->role_objects as $key => $role ) {
2645
			if ( is_array( $role->capabilities ) ) {
2646
				foreach ( $role->capabilities as $cap => $grant ) {
2647
					$role_caps[ $cap ] = $cap;
2648
				}
2649
			}
2650
		}
2651
2652
		$role_caps = array_unique( $role_caps );
2653
2654
		$capabilities = array_merge( $default_caps, $role_caps );
2655
2656
		// To support Members filters.
2657
		$capabilities = apply_filters( 'members_get_capabilities', $capabilities );
2658
2659
		$capabilities = apply_filters( 'pods_roles_get_capabilities', $capabilities );
2660
2661
		sort( $capabilities );
2662
2663
		$capabilities = array_unique( $capabilities );
2664
2665
		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...
2666
2667
		foreach ( $capabilities as $capability ) {
2668
			$data[ $capability ] = $capability;
2669
		}
2670
2671
		return apply_filters( 'pods_form_ui_field_pick_' . __FUNCTION__, $data, $name, $value, $options, $pod, $id );
2672
2673
	}
2674
2675
	/**
2676
	 * Data callback for Image Sizes.
2677
	 *
2678
	 * @param string|null       $name    The name of the field.
2679
	 * @param string|array|null $value   The value of the field.
2680
	 * @param array|null        $options Field options.
2681
	 * @param array|null        $pod     Pod data.
2682
	 * @param int|null          $id      Item ID.
2683
	 *
2684
	 * @return array
2685
	 *
2686
	 * @since 2.3
2687
	 */
2688
	public function data_image_sizes( $name = null, $value = null, $options = null, $pod = null, $id = null ) {
2689
2690
		$data = array();
2691
2692
		$image_sizes = get_intermediate_image_sizes();
2693
2694
		foreach ( $image_sizes as $image_size ) {
2695
			$data[ $image_size ] = ucwords( str_replace( '-', ' ', $image_size ) );
2696
		}
2697
2698
		return apply_filters( 'pods_form_ui_field_pick_' . __FUNCTION__, $data, $name, $value, $options, $pod, $id );
2699
2700
	}
2701
2702
	/**
2703
	 * Data callback for Countries.
2704
	 *
2705
	 * @param string|null       $name    The name of the field.
2706
	 * @param string|array|null $value   The value of the field.
2707
	 * @param array|null        $options Field options.
2708
	 * @param array|null        $pod     Pod data.
2709
	 * @param int|null          $id      Item ID.
2710
	 *
2711
	 * @return array
2712
	 *
2713
	 * @since 2.3
2714
	 */
2715
	public function data_countries( $name = null, $value = null, $options = null, $pod = null, $id = null ) {
2716
2717
		$data = array(
2718
			'AF' => __( 'Afghanistan' ),
2719
			'AL' => __( 'Albania' ),
2720
			'DZ' => __( 'Algeria' ),
2721
			'AS' => __( 'American Samoa' ),
2722
			'AD' => __( 'Andorra' ),
2723
			'AO' => __( 'Angola' ),
2724
			'AI' => __( 'Anguilla' ),
2725
			'AQ' => __( 'Antarctica' ),
2726
			'AG' => __( 'Antigua and Barbuda' ),
2727
			'AR' => __( 'Argentina' ),
2728
			'AM' => __( 'Armenia' ),
2729
			'AW' => __( 'Aruba' ),
2730
			'AU' => __( 'Australia' ),
2731
			'AT' => __( 'Austria' ),
2732
			'AZ' => __( 'Azerbaijan' ),
2733
			'BS' => __( 'Bahamas' ),
2734
			'BH' => __( 'Bahrain' ),
2735
			'BD' => __( 'Bangladesh' ),
2736
			'BB' => __( 'Barbados' ),
2737
			'BY' => __( 'Belarus' ),
2738
			'BE' => __( 'Belgium' ),
2739
			'BZ' => __( 'Belize' ),
2740
			'BJ' => __( 'Benin' ),
2741
			'BM' => __( 'Bermuda' ),
2742
			'BT' => __( 'Bhutan' ),
2743
			'BO' => __( 'Bolivia' ),
2744
			'BA' => __( 'Bosnia and Herzegovina' ),
2745
			'BW' => __( 'Botswana' ),
2746
			'BV' => __( 'Bouvet Island' ),
2747
			'BR' => __( 'Brazil' ),
2748
			'BQ' => __( 'British Antarctic Territory' ),
2749
			'IO' => __( 'British Indian Ocean Territory' ),
2750
			'VG' => __( 'British Virgin Islands' ),
2751
			'BN' => __( 'Brunei' ),
2752
			'BG' => __( 'Bulgaria' ),
2753
			'BF' => __( 'Burkina Faso' ),
2754
			'BI' => __( 'Burundi' ),
2755
			'KH' => __( 'Cambodia' ),
2756
			'CM' => __( 'Cameroon' ),
2757
			'CA' => __( 'Canada' ),
2758
			'CT' => __( 'Canton and Enderbury Islands' ),
2759
			'CV' => __( 'Cape Verde' ),
2760
			'KY' => __( 'Cayman Islands' ),
2761
			'CF' => __( 'Central African Republic' ),
2762
			'TD' => __( 'Chad' ),
2763
			'CL' => __( 'Chile' ),
2764
			'CN' => __( 'China' ),
2765
			'CX' => __( 'Christmas Island' ),
2766
			'CC' => __( 'Cocos [Keeling] Islands' ),
2767
			'CO' => __( 'Colombia' ),
2768
			'KM' => __( 'Comoros' ),
2769
			'CG' => __( 'Congo - Brazzaville' ),
2770
			'CD' => __( 'Congo - Kinshasa' ),
2771
			'CK' => __( 'Cook Islands' ),
2772
			'CR' => __( 'Costa Rica' ),
2773
			'HR' => __( 'Croatia' ),
2774
			'CU' => __( 'Cuba' ),
2775
			'CY' => __( 'Cyprus' ),
2776
			'CZ' => __( 'Czech Republic' ),
2777
			'CI' => __( 'Côte d’Ivoire' ),
2778
			'DK' => __( 'Denmark' ),
2779
			'DJ' => __( 'Djibouti' ),
2780
			'DM' => __( 'Dominica' ),
2781
			'DO' => __( 'Dominican Republic' ),
2782
			'NQ' => __( 'Dronning Maud Land' ),
2783
			'DD' => __( 'East Germany' ),
2784
			'EC' => __( 'Ecuador' ),
2785
			'EG' => __( 'Egypt' ),
2786
			'SV' => __( 'El Salvador' ),
2787
			'GQ' => __( 'Equatorial Guinea' ),
2788
			'ER' => __( 'Eritrea' ),
2789
			'EE' => __( 'Estonia' ),
2790
			'ET' => __( 'Ethiopia' ),
2791
			'FK' => __( 'Falkland Islands' ),
2792
			'FO' => __( 'Faroe Islands' ),
2793
			'FJ' => __( 'Fiji' ),
2794
			'FI' => __( 'Finland' ),
2795
			'FR' => __( 'France' ),
2796
			'GF' => __( 'French Guiana' ),
2797
			'PF' => __( 'French Polynesia' ),
2798
			'TF' => __( 'French Southern Territories' ),
2799
			'FQ' => __( 'French Southern and Antarctic Territories' ),
2800
			'GA' => __( 'Gabon' ),
2801
			'GM' => __( 'Gambia' ),
2802
			'GE' => __( 'Georgia' ),
2803
			'DE' => __( 'Germany' ),
2804
			'GH' => __( 'Ghana' ),
2805
			'GI' => __( 'Gibraltar' ),
2806
			'GR' => __( 'Greece' ),
2807
			'GL' => __( 'Greenland' ),
2808
			'GD' => __( 'Grenada' ),
2809
			'GP' => __( 'Guadeloupe' ),
2810
			'GU' => __( 'Guam' ),
2811
			'GT' => __( 'Guatemala' ),
2812
			'GG' => __( 'Guernsey' ),
2813
			'GN' => __( 'Guinea' ),
2814
			'GW' => __( 'Guinea-Bissau' ),
2815
			'GY' => __( 'Guyana' ),
2816
			'HT' => __( 'Haiti' ),
2817
			'HM' => __( 'Heard Island and McDonald Islands' ),
2818
			'HN' => __( 'Honduras' ),
2819
			'HK' => __( 'Hong Kong SAR China' ),
2820
			'HU' => __( 'Hungary' ),
2821
			'IS' => __( 'Iceland' ),
2822
			'IN' => __( 'India' ),
2823
			'ID' => __( 'Indonesia' ),
2824
			'IR' => __( 'Iran' ),
2825
			'IQ' => __( 'Iraq' ),
2826
			'IE' => __( 'Ireland' ),
2827
			'IM' => __( 'Isle of Man' ),
2828
			'IL' => __( 'Israel' ),
2829
			'IT' => __( 'Italy' ),
2830
			'JM' => __( 'Jamaica' ),
2831
			'JP' => __( 'Japan' ),
2832
			'JE' => __( 'Jersey' ),
2833
			'JT' => __( 'Johnston Island' ),
2834
			'JO' => __( 'Jordan' ),
2835
			'KZ' => __( 'Kazakhstan' ),
2836
			'KE' => __( 'Kenya' ),
2837
			'KI' => __( 'Kiribati' ),
2838
			'KW' => __( 'Kuwait' ),
2839
			'KG' => __( 'Kyrgyzstan' ),
2840
			'LA' => __( 'Laos' ),
2841
			'LV' => __( 'Latvia' ),
2842
			'LB' => __( 'Lebanon' ),
2843
			'LS' => __( 'Lesotho' ),
2844
			'LR' => __( 'Liberia' ),
2845
			'LY' => __( 'Libya' ),
2846
			'LI' => __( 'Liechtenstein' ),
2847
			'LT' => __( 'Lithuania' ),
2848
			'LU' => __( 'Luxembourg' ),
2849
			'MO' => __( 'Macau SAR China' ),
2850
			'MK' => __( 'Macedonia' ),
2851
			'MG' => __( 'Madagascar' ),
2852
			'MW' => __( 'Malawi' ),
2853
			'MY' => __( 'Malaysia' ),
2854
			'MV' => __( 'Maldives' ),
2855
			'ML' => __( 'Mali' ),
2856
			'MT' => __( 'Malta' ),
2857
			'MH' => __( 'Marshall Islands' ),
2858
			'MQ' => __( 'Martinique' ),
2859
			'MR' => __( 'Mauritania' ),
2860
			'MU' => __( 'Mauritius' ),
2861
			'YT' => __( 'Mayotte' ),
2862
			'FX' => __( 'Metropolitan France' ),
2863
			'MX' => __( 'Mexico' ),
2864
			'FM' => __( 'Micronesia' ),
2865
			'MI' => __( 'Midway Islands' ),
2866
			'MD' => __( 'Moldova' ),
2867
			'MC' => __( 'Monaco' ),
2868
			'MN' => __( 'Mongolia' ),
2869
			'ME' => __( 'Montenegro' ),
2870
			'MS' => __( 'Montserrat' ),
2871
			'MA' => __( 'Morocco' ),
2872
			'MZ' => __( 'Mozambique' ),
2873
			'MM' => __( 'Myanmar [Burma]' ),
2874
			'NA' => __( 'Namibia' ),
2875
			'NR' => __( 'Nauru' ),
2876
			'NP' => __( 'Nepal' ),
2877
			'NL' => __( 'Netherlands' ),
2878
			'AN' => __( 'Netherlands Antilles' ),
2879
			'NT' => __( 'Neutral Zone' ),
2880
			'NC' => __( 'New Caledonia' ),
2881
			'NZ' => __( 'New Zealand' ),
2882
			'NI' => __( 'Nicaragua' ),
2883
			'NE' => __( 'Niger' ),
2884
			'NG' => __( 'Nigeria' ),
2885
			'NU' => __( 'Niue' ),
2886
			'NF' => __( 'Norfolk Island' ),
2887
			'KP' => __( 'North Korea' ),
2888
			'VD' => __( 'North Vietnam' ),
2889
			'MP' => __( 'Northern Mariana Islands' ),
2890
			'NO' => __( 'Norway' ),
2891
			'OM' => __( 'Oman' ),
2892
			'PC' => __( 'Pacific Islands Trust Territory' ),
2893
			'PK' => __( 'Pakistan' ),
2894
			'PW' => __( 'Palau' ),
2895
			'PS' => __( 'Palestinian Territories' ),
2896
			'PA' => __( 'Panama' ),
2897
			'PZ' => __( 'Panama Canal Zone' ),
2898
			'PG' => __( 'Papua New Guinea' ),
2899
			'PY' => __( 'Paraguay' ),
2900
			'YD' => __( "People's Democratic Republic of Yemen" ),
2901
			'PE' => __( 'Peru' ),
2902
			'PH' => __( 'Philippines' ),
2903
			'PN' => __( 'Pitcairn Islands' ),
2904
			'PL' => __( 'Poland' ),
2905
			'PT' => __( 'Portugal' ),
2906
			'PR' => __( 'Puerto Rico' ),
2907
			'QA' => __( 'Qatar' ),
2908
			'RO' => __( 'Romania' ),
2909
			'RU' => __( 'Russia' ),
2910
			'RW' => __( 'Rwanda' ),
2911
			'RE' => __( 'Réunion' ),
2912
			'BL' => __( 'Saint Barthélemy' ),
2913
			'SH' => __( 'Saint Helena' ),
2914
			'KN' => __( 'Saint Kitts and Nevis' ),
2915
			'LC' => __( 'Saint Lucia' ),
2916
			'MF' => __( 'Saint Martin' ),
2917
			'PM' => __( 'Saint Pierre and Miquelon' ),
2918
			'VC' => __( 'Saint Vincent and the Grenadines' ),
2919
			'WS' => __( 'Samoa' ),
2920
			'SM' => __( 'San Marino' ),
2921
			'SA' => __( 'Saudi Arabia' ),
2922
			'SN' => __( 'Senegal' ),
2923
			'RS' => __( 'Serbia' ),
2924
			'CS' => __( 'Serbia and Montenegro' ),
2925
			'SC' => __( 'Seychelles' ),
2926
			'SL' => __( 'Sierra Leone' ),
2927
			'SG' => __( 'Singapore' ),
2928
			'SK' => __( 'Slovakia' ),
2929
			'SI' => __( 'Slovenia' ),
2930
			'SB' => __( 'Solomon Islands' ),
2931
			'SO' => __( 'Somalia' ),
2932
			'ZA' => __( 'South Africa' ),
2933
			'GS' => __( 'South Georgia and the South Sandwich Islands' ),
2934
			'KR' => __( 'South Korea' ),
2935
			'ES' => __( 'Spain' ),
2936
			'LK' => __( 'Sri Lanka' ),
2937
			'SD' => __( 'Sudan' ),
2938
			'SR' => __( 'Suriname' ),
2939
			'SJ' => __( 'Svalbard and Jan Mayen' ),
2940
			'SZ' => __( 'Swaziland' ),
2941
			'SE' => __( 'Sweden' ),
2942
			'CH' => __( 'Switzerland' ),
2943
			'SY' => __( 'Syria' ),
2944
			'ST' => __( 'São Tomé and Príncipe' ),
2945
			'TW' => __( 'Taiwan' ),
2946
			'TJ' => __( 'Tajikistan' ),
2947
			'TZ' => __( 'Tanzania' ),
2948
			'TH' => __( 'Thailand' ),
2949
			'TL' => __( 'Timor-Leste' ),
2950
			'TG' => __( 'Togo' ),
2951
			'TK' => __( 'Tokelau' ),
2952
			'TO' => __( 'Tonga' ),
2953
			'TT' => __( 'Trinidad and Tobago' ),
2954
			'TN' => __( 'Tunisia' ),
2955
			'TR' => __( 'Turkey' ),
2956
			'TM' => __( 'Turkmenistan' ),
2957
			'TC' => __( 'Turks and Caicos Islands' ),
2958
			'TV' => __( 'Tuvalu' ),
2959
			'UM' => __( 'U.S. Minor Outlying Islands' ),
2960
			'PU' => __( 'U.S. Miscellaneous Pacific Islands' ),
2961
			'VI' => __( 'U.S. Virgin Islands' ),
2962
			'UG' => __( 'Uganda' ),
2963
			'UA' => __( 'Ukraine' ),
2964
			'SU' => __( 'Union of Soviet Socialist Republics' ),
2965
			'AE' => __( 'United Arab Emirates' ),
2966
			'GB' => __( 'United Kingdom' ),
2967
			'US' => __( 'United States' ),
2968
			'ZZ' => __( 'Unknown or Invalid Region' ),
2969
			'UY' => __( 'Uruguay' ),
2970
			'UZ' => __( 'Uzbekistan' ),
2971
			'VU' => __( 'Vanuatu' ),
2972
			'VA' => __( 'Vatican City' ),
2973
			'VE' => __( 'Venezuela' ),
2974
			'VN' => __( 'Vietnam' ),
2975
			'WK' => __( 'Wake Island' ),
2976
			'WF' => __( 'Wallis and Futuna' ),
2977
			'EH' => __( 'Western Sahara' ),
2978
			'YE' => __( 'Yemen' ),
2979
			'ZM' => __( 'Zambia' ),
2980
			'ZW' => __( 'Zimbabwe' ),
2981
			'AX' => __( 'Ã…land Islands' ),
2982
		);
2983
2984
		return apply_filters( 'pods_form_ui_field_pick_' . __FUNCTION__, $data, $name, $value, $options, $pod, $id );
2985
2986
	}
2987
2988
	/**
2989
	 * Data callback for US States.
2990
	 *
2991
	 * @param string|null       $name    The name of the field.
2992
	 * @param string|array|null $value   The value of the field.
2993
	 * @param array|null        $options Field options.
2994
	 * @param array|null        $pod     Pod data.
2995
	 * @param int|null          $id      Item ID.
2996
	 *
2997
	 * @return array
2998
	 *
2999
	 * @since 2.3
3000
	 */
3001
	public function data_us_states( $name = null, $value = null, $options = null, $pod = null, $id = null ) {
3002
3003
		$data = array(
3004
			'AL' => __( 'Alabama' ),
3005
			'AK' => __( 'Alaska' ),
3006
			'AZ' => __( 'Arizona' ),
3007
			'AR' => __( 'Arkansas' ),
3008
			'CA' => __( 'California' ),
3009
			'CO' => __( 'Colorado' ),
3010
			'CT' => __( 'Connecticut' ),
3011
			'DE' => __( 'Delaware' ),
3012
			'DC' => __( 'District Of Columbia' ),
3013
			'FL' => __( 'Florida' ),
3014
			'GA' => __( 'Georgia' ),
3015
			'HI' => __( 'Hawaii' ),
3016
			'ID' => __( 'Idaho' ),
3017
			'IL' => __( 'Illinois' ),
3018
			'IN' => __( 'Indiana' ),
3019
			'IA' => __( 'Iowa' ),
3020
			'KS' => __( 'Kansas' ),
3021
			'KY' => __( 'Kentucky' ),
3022
			'LA' => __( 'Louisiana' ),
3023
			'ME' => __( 'Maine' ),
3024
			'MD' => __( 'Maryland' ),
3025
			'MA' => __( 'Massachusetts' ),
3026
			'MI' => __( 'Michigan' ),
3027
			'MN' => __( 'Minnesota' ),
3028
			'MS' => __( 'Mississippi' ),
3029
			'MO' => __( 'Missouri' ),
3030
			'MT' => __( 'Montana' ),
3031
			'NE' => __( 'Nebraska' ),
3032
			'NV' => __( 'Nevada' ),
3033
			'NH' => __( 'New Hampshire' ),
3034
			'NJ' => __( 'New Jersey' ),
3035
			'NM' => __( 'New Mexico' ),
3036
			'NY' => __( 'New York' ),
3037
			'NC' => __( 'North Carolina' ),
3038
			'ND' => __( 'North Dakota' ),
3039
			'OH' => __( 'Ohio' ),
3040
			'OK' => __( 'Oklahoma' ),
3041
			'OR' => __( 'Oregon' ),
3042
			'PA' => __( 'Pennsylvania' ),
3043
			'RI' => __( 'Rhode Island' ),
3044
			'SC' => __( 'South Carolina' ),
3045
			'SD' => __( 'South Dakota' ),
3046
			'TN' => __( 'Tennessee' ),
3047
			'TX' => __( 'Texas' ),
3048
			'UT' => __( 'Utah' ),
3049
			'VT' => __( 'Vermont' ),
3050
			'VA' => __( 'Virginia' ),
3051
			'WA' => __( 'Washington' ),
3052
			'WV' => __( 'West Virginia' ),
3053
			'WI' => __( 'Wisconsin' ),
3054
			'WY' => __( 'Wyoming' ),
3055
		);
3056
3057
		return apply_filters( 'pods_form_ui_field_pick_' . __FUNCTION__, $data, $name, $value, $options, $pod, $id );
3058
3059
	}
3060
3061
	/**
3062
	 * Data callback for CA Provinces.
3063
	 *
3064
	 * @param string|null       $name    The name of the field.
3065
	 * @param string|array|null $value   The value of the field.
3066
	 * @param array|null        $options Field options.
3067
	 * @param array|null        $pod     Pod data.
3068
	 * @param int|null          $id      Item ID.
3069
	 *
3070
	 * @return array
3071
	 *
3072
	 * @since 2.3
3073
	 */
3074
	public function data_ca_provinces( $name = null, $value = null, $options = null, $pod = null, $id = null ) {
3075
3076
		$data = array(
3077
			'AB' => __( 'Alberta' ),
3078
			'BC' => __( 'British Columbia' ),
3079
			'MB' => __( 'Manitoba' ),
3080
			'NB' => __( 'New Brunswick' ),
3081
			'NL' => __( 'Newfoundland and Labrador' ),
3082
			'NT' => __( 'Northwest Territories' ),
3083
			'NS' => __( 'Nova Scotia' ),
3084
			'NU' => __( 'Nunavut' ),
3085
			'ON' => __( 'Ontario' ),
3086
			'PE' => __( 'Prince Edward Island' ),
3087
			'QC' => __( 'Quebec' ),
3088
			'SK' => __( 'Saskatchewan' ),
3089
			'YT' => __( 'Yukon' ),
3090
		);
3091
3092
		return apply_filters( 'pods_form_ui_field_pick_' . __FUNCTION__, $data, $name, $value, $options, $pod, $id );
3093
3094
	}
3095
3096
	/**
3097
	 * Data callback for US States.
3098
	 *
3099
	 * @param string|null       $name    The name of the field.
3100
	 * @param string|array|null $value   The value of the field.
3101
	 * @param array|null        $options Field options.
3102
	 * @param array|null        $pod     Pod data.
3103
	 * @param int|null          $id      Item ID.
3104
	 *
3105
	 * @return array
3106
	 *
3107
	 * @since 2.3
3108
	 */
3109
	public function data_days_of_week( $name = null, $value = null, $options = null, $pod = null, $id = null ) {
3110
3111
		/**
3112
		 * @var WP_Locale
3113
		 */
3114
		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...
3115
3116
		return $wp_locale->weekday;
3117
3118
	}
3119
3120
	/**
3121
	 * Data callback for US States.
3122
	 *
3123
	 * @param string|null       $name    The name of the field.
3124
	 * @param string|array|null $value   The value of the field.
3125
	 * @param array|null        $options Field options.
3126
	 * @param array|null        $pod     Pod data.
3127
	 * @param int|null          $id      Item ID.
3128
	 *
3129
	 * @return array
3130
	 *
3131
	 * @since 2.3
3132
	 */
3133
	public function data_months_of_year( $name = null, $value = null, $options = null, $pod = null, $id = null ) {
3134
3135
		/**
3136
		 * @var WP_Locale
3137
		 */
3138
		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...
3139
3140
		return $wp_locale->month;
3141
3142
	}
3143
3144
	/**
3145
	 * Add our modal input to the form so we can track whether we're in our modal during saving or not.
3146
	 */
3147
	public function admin_modal_input() {
3148
3149
		if ( ! pods_is_modal_window() ) {
3150
			return;
3151
		}
3152
3153
		echo '<input name="pods_modal" type="hidden" value="1" />';
3154
3155
	}
3156
3157
	/**
3158
	 * Bail to send new saved data back to our modal handler.
3159
	 *
3160
	 * @param int    $item_id    Item ID.
3161
	 * @param string $item_title Item title.
3162
	 * @param object $field_args Field arguments.
3163
	 */
3164
	public function admin_modal_bail( $item_id, $item_title, $field_args ) {
3165
3166
		$model_data = $this->build_dfv_field_item_data_recurse_item( $item_id, $item_title, $field_args );
3167
		?>
3168
			<script type="text/javascript">
3169
				window.parent.jQuery( window.parent ).trigger(
3170
					'dfv:modal:update',
3171
					<?php echo wp_json_encode( $model_data, JSON_HEX_TAG ); ?>
3172
				);
3173
			</script>
3174
		<?php
3175
3176
		die();
3177
3178
	}
3179
3180
	/**
3181
	 * Bail to send new saved data back to our modal handler.
3182
	 *
3183
	 * @param int    $item_id    Item ID.
3184
	 * @param string $item_title Item title.
3185
	 * @param object $field_args Field arguments.
3186
	 */
3187
	public function admin_modal_bail_JSON( $item_id, $item_title, $field_args ) {
0 ignored issues
show
The function name admin_modal_bail_JSON is in camel caps, but expected admin_modal_bail_j_s_o_n instead as per the coding standard.
Loading history...
3188
3189
		$model_data = $this->build_dfv_field_item_data_recurse_item( $item_id, $item_title, $field_args );
3190
		echo wp_json_encode( $model_data, JSON_HEX_TAG );
3191
3192
		die();
3193
	}
3194
3195
	/**
3196
	 * Bail on Post save redirect for Admin modal.
3197
	 *
3198
	 * @param string $location The destination URL.
3199
	 * @param int    $post_id  The post ID.
3200
	 *
3201
	 * @return string
3202
	 */
3203
	public function admin_modal_bail_post_redirect( $location, $post_id ) {
3204
3205
		if ( ! pods_is_modal_window() ) {
3206
			return $location;
3207
		}
3208
3209
		$post_title = get_the_title( $post_id );
3210
3211
		$field_args = (object) array(
3212
			'options' => array(
3213
				'pick_object' => 'post_type',
3214
				'pick_val'    => get_post_type( $post_id ),
3215
			),
3216
			'value'   => array(
3217
				$post_id => $post_title,
3218
			),
3219
		);
3220
3221
		$this->admin_modal_bail( $post_id, $post_title, $field_args );
3222
3223
		return $location;
3224
3225
	}
3226
3227
	/**
3228
	 * Hook into term updating process to bail on redirect.
3229
	 */
3230
	public function admin_modal_bail_term_action() {
3231
3232
		if ( ! pods_is_modal_window() ) {
3233
			return;
3234
		}
3235
3236
		add_action( 'created_term', array( $this, 'admin_modal_bail_term' ), 10, 3 );
3237
		add_action( 'edited_term', array( $this, 'admin_modal_bail_term' ), 10, 3 );
3238
3239
	}
3240
3241
	/**
3242
	 * Bail on Term save redirect for Admin modal.
3243
	 *
3244
	 * @param int    $term_id  Term ID.
3245
	 * @param int    $tt_id    Term taxonomy ID.
3246
	 * @param string $taxonomy Taxonomy slug.
3247
	 */
3248
	public function admin_modal_bail_term( $term_id, $tt_id, $taxonomy ) {
3249
3250
		if ( ! pods_is_modal_window() ) {
3251
			return;
3252
		}
3253
3254
		$term = get_term( $term_id );
3255
3256
		if ( ! $term || is_wp_error( $term ) ) {
3257
			return;
3258
		}
3259
3260
		$field_args = (object) array(
3261
			'options' => array(
3262
				'pick_object' => 'taxonomy',
3263
				'pick_val'    => $term->taxonomy,
3264
			),
3265
			'value'   => array(
3266
				$term->term_id => $term->name,
3267
			),
3268
		);
3269
3270
		$this->admin_modal_bail( $term->term_id, $term->name, $field_args );
3271
3272
	}
3273
3274
	/**
3275
	 * Hook into user updating process to bail on redirect.
3276
	 */
3277
	public function admin_modal_bail_user_action() {
3278
3279
		if ( ! pods_is_modal_window() ) {
3280
			return;
3281
		}
3282
3283
		add_filter( 'wp_redirect', array( $this, 'admin_modal_bail_user_redirect' ) );
3284
3285
	}
3286
3287
	/**
3288
	 * Bail on User save redirect for Admin modal.
3289
	 *
3290
	 * @param string $location The destination URL.
3291
	 *
3292
	 * @return string
3293
	 */
3294
	public function admin_modal_bail_user_redirect( $location ) {
3295
3296
		if ( ! pods_is_modal_window() ) {
3297
			return $location;
3298
		}
3299
3300
		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...
3301
3302
		$user = get_userdata( $user_id );
3303
3304
		if ( ! $user || is_wp_error( $user ) ) {
3305
			return $location;
3306
		}
3307
3308
		$field_args = (object) array(
3309
			'options' => array(
3310
				'pick_object' => 'user',
3311
				'pick_val'    => '',
3312
			),
3313
			'value'   => array(
3314
				$user->ID => $user->display_name,
3315
			),
3316
		);
3317
3318
		$this->admin_modal_bail( $user->ID, $user->display_name, $field_args );
3319
3320
		return $location;
3321
3322
	}
3323
3324
	/**
3325
	 * Bail on Pod item save for Admin modal.
3326
	 *
3327
	 * @param int       $id     Item ID.
3328
	 * @param array     $params save_pod_item parameters.
3329
	 * @param null|Pods $obj    Pod object (if set).
3330
	 */
3331
	public function admin_modal_bail_pod( $id, $params, $obj ) {
3332
3333
		if ( ! pods_is_modal_window() ) {
3334
			return;
3335
		}
3336
3337
		if ( ! $obj ) {
3338
			$obj = pods( $params['pod'] );
3339
		}
3340
3341
		if ( ! $obj || ! $obj->fetch( $id ) ) {
3342
			return;
3343
		}
3344
3345
		$item_id    = $obj->id();
3346
		$item_title = $obj->index();
3347
3348
		$field_args = (object) array(
3349
			'options' => array(
3350
				'pick_object' => $obj->pod_data['type'],
3351
				'pick_val'    => $obj->pod,
3352
			),
3353
			'value'   => array(
3354
				$obj->id() => $item_title,
3355
			),
3356
		);
3357
3358
		$this->admin_modal_bail_JSON( $item_id, $item_title, $field_args );
3359
3360
	}
3361
3362
}
3363