Completed
Pull Request — 2.x (#4569)
by Scott Kingsley
07:47
created

Pods   D

Complexity

Total Complexity 809

Size/Duplication

Total Lines 4521
Duplicated Lines 11.1 %

Coupling/Cohesion

Components 1
Dependencies 7

Importance

Changes 0
Metric Value
dl 502
loc 4521
rs 4.4102
c 0
b 0
f 0
wmc 809
lcom 1
cbo 7

56 Methods

Rating   Name   Duplication   Size   Complexity  
F __construct() 0 102 19
A valid() 0 12 3
A is_iterator() 0 4 1
A stop_iterator() 0 5 1
A rewind() 0 10 2
A current() 0 8 3
A key() 0 8 2
A next() 0 10 2
A exists() 0 8 2
A data() 0 10 2
B input() 0 28 5
C fields() 0 52 13
A row() 0 10 2
D display() 10 44 9
B raw() 10 20 5
F field() 115 1147 313
C has() 40 65 17
D is() 33 108 27
A id() 0 9 2
F prev_id() 32 79 23
C next_id() 11 59 14
C first_id() 4 36 7
C last_id() 25 63 15
A index() 0 4 1
D find() 50 222 52
A fetch() 0 20 2
A reset() 0 16 1
A total() 0 10 1
A total_found() 0 18 1
A total_pages() 0 19 4
A zebra() 0 6 1
A nth() 0 6 1
A position() 0 6 1
A add() 0 20 3
D add_to() 30 101 22
D remove_from() 30 121 25
D save() 6 63 17
A delete() 16 19 3
A reset_pod() 0 13 1
A duplicate() 16 19 3
A import() 0 4 1
C export() 4 40 11
A export_data() 0 16 2
C pagination() 0 68 10
D filters() 2 107 13
C helper() 0 79 10
D template() 7 113 9
F form() 14 135 21
C view() 12 64 13
A do_magic_tags() 0 19 2
C process_magic_tags() 4 63 17
F ui() 16 241 53
A do_hook() 10 12 2
D __get() 0 31 9
B __call() 5 25 6
A __toString() 0 11 2

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Pods often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Pods, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * Pods class.
5
 *
6
 * @package Pods
7
 */
8
class Pods implements Iterator {
9
10
	/**
11
	 * Whether the Pods object is in a PHP Iterator call.
12
	 *
13
	 * @var bool
14
	 */
15
	private $iterator = false;
16
17
	/**
18
	 * PodsAPI object.
19
	 *
20
	 * @var PodsAPI
21
	 */
22
	public $api;
23
24
	/**
25
	 * PodsData object.
26
	 *
27
	 * @var PodsData
28
	 */
29
	public $data;
30
31
	/**
32
	 * PodsData object for additional calls.
33
	 *
34
	 * @var PodsData
35
	 */
36
	public $alt_data;
37
38
	/**
39
	 * Array of pod item arrays.
40
	 *
41
	 * @var array
42
	 */
43
	public $rows;
44
45
	/**
46
	 * Current pod item array.
47
	 *
48
	 * @var array
49
	 */
50
	public $row;
51
52
	/**
53
	 * Row number.
54
	 *
55
	 * @var int
56
	 */
57
	private $row_number;
58
59
	/**
60
	 * Override pod item array.
61
	 *
62
	 * @var array
63
	 */
64
	public $row_override = array();
65
66
	/**
67
	 * Whether to display errors on the screen.
68
	 *
69
	 * @var bool
70
	 */
71
	public $display_errors = true;
72
73
	/**
74
	 * Current pod information.
75
	 *
76
	 * @var array|bool|mixed|null|void
77
	 */
78
	public $pod_data;
79
80
	/**
81
	 * Last used Pods::find() parameters.
82
	 *
83
	 * @var array
84
	 */
85
	public $params = array();
86
87
	/**
88
	 * Current Pod name.
89
	 *
90
	 * @var string
91
	 */
92
	public $pod;
93
94
	/**
95
	 * Current Pod ID.
96
	 *
97
	 * @var int
98
	 */
99
	public $pod_id;
100
101
	/**
102
	 * Pod fields information.
103
	 *
104
	 * @var array
105
	 */
106
	public $fields;
107
108
	/**
109
	 * Last used filters() parameters.
110
	 *
111
	 * @var array
112
	 */
113
	public $filters = array();
114
115
	/**
116
	 * Detail page URL used for Advanced Content Types.
117
	 *
118
	 * @var string
119
	 */
120
	public $detail_page;
121
122
	/**
123
	 * Current Item ID.
124
	 *
125
	 * @var int
126
	 */
127
	public $id;
128
129
	/**
130
	 * Last used limit from find() lookup.
131
	 *
132
	 * @var int
133
	 */
134
	public $limit = 15;
135
136
	/**
137
	 * Last used offset from find() lookup.
138
	 *
139
	 * @var int
140
	 */
141
	public $offset = 0;
142
143
	/**
144
	 * Query variable used for pagination number.
145
	 *
146
	 * @var string
147
	 */
148
	public $page_var = 'pg';
149
150
	/**
151
	 * Last used page from find() lookup.
152
	 *
153
	 * @var int|mixed
154
	 */
155
	public $page = 1;
156
157
	/**
158
	 * Last used state of whether pagination was enabled from find() lookup.
159
	 *
160
	 * @var bool
161
	 */
162
	public $pagination = true;
163
164
	/**
165
	 * Last used state of whether search was enabled from find() lookup.
166
	 *
167
	 * @var bool
168
	 */
169
	public $search = true;
170
171
	/**
172
	 * Query variable used for search string.
173
	 *
174
	 * @var string
175
	 */
176
	public $search_var = 'search';
177
178
	/**
179
	 * Search mode (int | text | text_like).
180
	 *
181
	 * @var string
182
	 */
183
	public $search_mode = 'int';
184
185
	/**
186
	 * Total number of records returned from find() lookup.
187
	 *
188
	 * @var int
189
	 */
190
	public $total = 0;
191
192
	/**
193
	 * Total number of records found from find() lookup.
194
	 *
195
	 * @var int
196
	 */
197
	public $total_found = 0;
198
199
	/**
200
	 * Last used ui options for ui() call.
201
	 *
202
	 * @var array
203
	 */
204
	public $ui = array();
205
206
	/**
207
	 * Page template to use for SEO feature in Pods Pages.
208
	 *
209
	 * @var string
210
	 */
211
	public $page_template;
212
213
	/**
214
	 * Body classes to use for SEO feature in Pods Pages.
215
	 *
216
	 * @var array
217
	 */
218
	public $body_classes;
219
220
	/**
221
	 * Meta tags to use for SEO feature in Pods Pages.
222
	 *
223
	 * @var array
224
	 */
225
	public $meta = array();
226
227
	/**
228
	 * Meta properties to use for SEO feature in Pods Pages.
229
	 *
230
	 * @var array
231
	 */
232
	public $meta_properties = array();
233
234
	/**
235
	 * Meta custom HTML to use for SEO feature in Pods Pages.
236
	 *
237
	 * @var string
238
	 */
239
	public $meta_extra = '';
240
241
	/**
242
	 * Last SQL query used by a find() lookup.
243
	 *
244
	 * @var string
245
	 */
246
	public $sql;
247
248
	/**
249
	 * Pods_Deprecated object.
250
	 *
251
	 * @var Pods_Deprecated
252
	 */
253
	public $deprecated;
254
255
	/**
256
	 * Old Pod name variable.
257
	 *
258
	 * @var string
259
	 *
260
	 * @deprecated 2.0
261
	 */
262
	public $datatype;
263
264
	/**
265
	 * Old Pod ID variable.
266
	 *
267
	 * @var int
268
	 *
269
	 * @deprecated 2.0
270
	 */
271
	public $datatype_id;
272
273
	/**
274
	 * Constructor - Pods Framework core.
275
	 *
276
	 * @param string $pod The pod name.
277
	 * @param mixed  $id  (optional) The ID or slug, to load a single record; Provide array of $params to run 'find'.
278
	 *
279
	 * @license http://www.gnu.org/licenses/gpl-2.0.html
280
	 * @since   1.0.0
281
	 * @link    https://pods.io/docs/pods/
282
	 */
283
	public function __construct( $pod = null, $id = null ) {
284
285
		if ( null === $pod ) {
286
			$queried_object = get_queried_object();
287
288
			if ( $queried_object ) {
289
				$id_lookup = true;
290
291
				// Post Type Singular
292
				if ( isset( $queried_object->post_type ) ) {
293
					$pod = $queried_object->post_type;
294
				} // Term Archive
295
				elseif ( isset( $queried_object->taxonomy ) ) {
296
					$pod = $queried_object->taxonomy;
297
				} // Author Archive
298
				elseif ( isset( $queried_object->user_login ) ) {
299
					$pod = 'user';
300
				} // Post Type Archive
301
				elseif ( isset( $queried_object->public, $queried_object->name ) ) {
302
					$pod = $queried_object->name;
303
304
					$id_lookup = false;
305
				}
306
307
				if ( null === $id && $id_lookup ) {
308
					$id = get_queried_object_id();
309
				}
310
			}
311
		}
312
313
		$this->api                 = pods_api( $pod );
314
		$this->api->display_errors =& $this->display_errors;
315
316
		$this->data               = pods_data( $this->api, $id, false );
317
		PodsData::$display_errors =& $this->display_errors;
318
319
		// Set up page variable
320
		if ( pods_strict( false ) ) {
321
			$this->page       = 1;
322
			$this->pagination = false;
323
			$this->search     = false;
324
		} else {
325
			// Get the page variable
326
			$this->page = pods_v( $this->page_var, 'get' );
327
			$this->page = ( empty( $this->page ) ? 1 : max( pods_absint( $this->page ), 1 ) );
328
		}
329
330
		// Set default pagination handling to on/off
331
		if ( defined( 'PODS_GLOBAL_POD_PAGINATION' ) ) {
332
			if ( ! PODS_GLOBAL_POD_PAGINATION ) {
333
				$this->page       = 1;
334
				$this->pagination = false;
335
			} else {
336
				$this->pagination = true;
337
			}
338
		}
339
340
		// Set default search to on/off
341
		if ( defined( 'PODS_GLOBAL_POD_SEARCH' ) ) {
342
			if ( PODS_GLOBAL_POD_SEARCH ) {
343
				$this->search = true;
344
			} else {
345
				$this->search = false;
346
			}
347
		}
348
349
		// Set default search mode
350
		$allowed_search_modes = array( 'int', 'text', 'text_like' );
351
352
		if ( defined( 'PODS_GLOBAL_POD_SEARCH_MODE' ) && in_array( PODS_GLOBAL_POD_SEARCH_MODE, $allowed_search_modes, true ) ) {
353
			$this->search_mode = PODS_GLOBAL_POD_SEARCH_MODE;
354
		}
355
356
		// Sync Settings
357
		$this->data->page        =& $this->page;
358
		$this->data->limit       =& $this->limit;
359
		$this->data->pagination  =& $this->pagination;
360
		$this->data->search      =& $this->search;
361
		$this->data->search_mode =& $this->search_mode;
362
363
		// Sync Pod Data
364
		$this->api->pod_data =& $this->data->pod_data;
365
		$this->pod_data      =& $this->api->pod_data;
366
		$this->api->pod_id   =& $this->data->pod_id;
0 ignored issues
show
Bug introduced by
The property pod_id does not seem to exist in PodsData.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
367
		$this->pod_id        =& $this->api->pod_id;
368
		$this->datatype_id   =& $this->pod_id;
0 ignored issues
show
Deprecated Code introduced by
The property Pods::$datatype_id has been deprecated with message: 2.0

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
369
		$this->api->pod      =& $this->data->pod;
370
		$this->pod           =& $this->api->pod;
371
		$this->datatype      =& $this->pod;
0 ignored issues
show
Deprecated Code introduced by
The property Pods::$datatype has been deprecated with message: 2.0

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
372
		$this->api->fields   =& $this->data->fields;
373
		$this->fields        =& $this->api->fields;
374
		$this->detail_page   =& $this->data->detail_page;
375
		$this->id            =& $this->data->id;
376
		$this->row           =& $this->data->row;
377
		$this->rows          =& $this->data->data;
378
		$this->row_number    =& $this->data->row_number;
379
		$this->sql           =& $this->data->sql;
380
381
		if ( is_array( $id ) || is_object( $id ) ) {
382
			$this->find( $id );
383
		}
384
	}
385
386
	/**
387
	 * Whether this Pod object is valid or not
388
	 *
389
	 * @return bool
390
	 *
391
	 * @since 2.0
392
	 */
393
	public function valid() {
394
395
		if ( empty( $this->pod_id ) ) {
396
			return false;
397
		}
398
399
		if ( $this->iterator ) {
400
			return isset( $this->rows[ $this->row_number ] );
401
		}
402
403
		return true;
404
	}
405
406
	/**
407
	 * Check if in Iterator mode
408
	 *
409
	 * @return bool
410
	 *
411
	 * @since 2.3.4
412
	 *
413
	 * @link  http://www.php.net/manual/en/class.iterator.php
414
	 */
415
	public function is_iterator() {
416
417
		return $this->iterator;
418
	}
419
420
	/**
421
	 * Turn off Iterator mode to off
422
	 *
423
	 * @return void
424
	 *
425
	 * @since 2.3.4
426
	 *
427
	 * @link  http://www.php.net/manual/en/class.iterator.php
428
	 */
429
	public function stop_iterator() {
430
431
		$this->iterator = false;
432
433
	}
434
435
	/**
436
	 * Rewind Iterator
437
	 *
438
	 * @return void|boolean
439
	 *
440
	 * @since 2.3.4
441
	 *
442
	 * @link  http://www.php.net/manual/en/class.iterator.php
443
	 */
444
	public function rewind() {
445
446
		if ( ! $this->iterator ) {
447
			$this->row_number = 0;
448
449
			return;
450
		}
451
452
		return false;
453
	}
454
455
	/**
456
	 * Get current Iterator row
457
	 *
458
	 * @return mixed|boolean
459
	 *
460
	 * @since 2.3.4
461
	 *
462
	 * @link  http://www.php.net/manual/en/class.iterator.php
463
	 */
464
	public function current() {
465
466
		if ( $this->iterator && $this->fetch() ) {
467
			return $this;
468
		}
469
470
		return false;
471
	}
472
473
	/**
474
	 * Get current Iterator key
475
	 *
476
	 * @return int|boolean
477
	 *
478
	 * @since 2.3.4
479
	 *
480
	 * @link  http://www.php.net/manual/en/class.iterator.php
481
	 */
482
	public function key() {
483
484
		if ( $this->iterator ) {
485
			return $this->row_number;
486
		}
487
488
		return false;
489
	}
490
491
	/**
492
	 * Move onto the next Iterator row
493
	 *
494
	 * @return void|boolean
495
	 *
496
	 * @since 2.3.4
497
	 *
498
	 * @link  http://www.php.net/manual/en/class.iterator.php
499
	 */
500
	public function next() {
501
502
		if ( $this->iterator ) {
503
			$this->row_number ++;
504
505
			return;
506
		}
507
508
		return false;
509
	}
510
511
	/**
512
	 * Whether a Pod item exists or not when using fetch() or construct with an ID or slug
513
	 *
514
	 * @return bool
515
	 *
516
	 * @since 2.0
517
	 */
518
	public function exists() {
519
520
		if ( empty( $this->row ) ) {
521
			return false;
522
		}
523
524
		return true;
525
	}
526
527
	/**
528
	 * Return an array of all rows returned from a find() call.
529
	 *
530
	 * Most of the time, you will want to loop through data using fetch()
531
	 * instead of using this function.
532
	 *
533
	 * @return array|bool An array of all rows returned from a find() call, or false if no items returned
534
	 *
535
	 * @since 2.0
536
	 * @link  https://pods.io/docs/data/
537
	 */
538
	public function data() {
539
540
		do_action( 'pods_pods_data', $this );
541
542
		if ( empty( $this->rows ) ) {
543
			return false;
544
		}
545
546
		return (array) $this->rows;
547
	}
548
549
	/**
550
	 * Return a field input for a specific field
551
	 *
552
	 * @param string|array      $field      Field name or Field data array
553
	 * @param string|array|null $input_name Input field name to use (overrides default name)
554
	 * @param mixed             $value      Current value to use
555
	 *
556
	 * @return string Field Input HTML
557
	 *
558
	 * @since 2.3.10
559
	 */
560
	public function input( $field, $input_name = null, $value = '__null' ) {
561
562
		// Field data override
563
		if ( is_array( $field ) ) {
564
			$field_data = $field;
565
			$field      = pods_v( 'name', $field );
566
		} // Get field data from field name
567
		else {
568
			$field_data = $this->fields( $field );
569
		}
570
571
		if ( ! empty( $field_data ) ) {
572
			$field_type = pods_v( 'type', $field_data );
573
574
			if ( empty( $input_name ) ) {
575
				$input_name = $field;
576
			}
577
578
			if ( '__null' === $value ) {
579
				$value = $this->field( array( 'name' => $field, 'in_form' => true ) );
580
			}
581
582
			return PodsForm::field( $input_name, $value, $field_type, $field_data, $this, $this->id() );
583
		}
584
585
		return '';
586
587
	}
588
589
	/**
590
	 * Return field array from a Pod, a field's data, or a field option
591
	 *
592
	 * @param null $field
593
	 * @param null $option
594
	 *
595
	 * @return bool|mixed
596
	 *
597
	 * @since 2.0
598
	 */
599
	public function fields( $field = null, $option = null ) {
600
601
		$field_data = null;
602
603
		if ( empty( $this->fields ) ) {
604
			// No fields found
605
			$field_data = array();
606
		} elseif ( empty( $field ) ) {
607
			// Return all fields
608
			$field_data = (array) $this->fields;
609
		} elseif ( ! isset( $this->fields[ $field ] ) && ! isset( $this->pod_data['object_fields'][ $field ] ) ) {
610
			// Field not found
611
			$field_data = array();
612
		} elseif ( empty( $option ) ) {
613
			// Return all field data
614
			if ( isset( $this->fields[ $field ] ) ) {
615
				$field_data = $this->fields[ $field ];
616
			} elseif ( isset( $this->pod_data['object_fields'] ) ) {
617
				$field_data = $this->pod_data['object_fields'][ $field ];
618
			}
619
		} else {
620
			$options = array();
621
622
			// Merge options
623
			if ( isset( $this->fields[ $field ] ) ) {
624
				$options = array_merge( $this->fields[ $field ], $this->fields[ $field ]['options'] );
625
			} elseif ( isset( $this->pod_data['object_fields'] ) ) {
626
				$options = array_merge( $this->pod_data['object_fields'][ $field ], $this->pod_data['object_fields'][ $field ]['options'] );
627
			}
628
629
			// Get a list of available items from a relationship field
630
			if ( 'data' === $option && in_array( pods_v( 'type', $options ), PodsForm::tableless_field_types(), true ) ) {
631
				$field_data = PodsForm::field_method( 'pick', 'get_field_data', $options );
632
			} // Return option
633
			elseif ( isset( $options[ $option ] ) ) {
634
				$field_data = $options[ $option ];
635
			}
636
		}
637
638
		/**
639
		 * Modify the field data before returning
640
		 *
641
		 * @since unknown
642
		 *
643
		 * @param array       $field_data The data for the field.
644
		 * @param string|null $field      The specific field that data is being return for, if set when method is called or null.
645
		 * @param string|null $option     Value of option param when method was called. Can be used to get a list of available items from a relationship field.
646
		 * @param Pods|object $this       The current Pods class instance.
647
		 */
648
		return apply_filters( 'pods_pods_fields', $field_data, $field, $option, $this );
649
650
	}
651
652
	/**
653
	 * Return row array for an item
654
	 *
655
	 * @return array|false
656
	 *
657
	 * @since 2.0
658
	 */
659
	public function row() {
660
661
		do_action( 'pods_pods_row', $this );
662
663
		if ( ! is_array( $this->row ) ) {
664
			return false;
665
		}
666
667
		return (array) $this->row;
668
	}
669
670
	/**
671
	 * Return the output for a field. If you want the raw value for use in PHP for custom manipulation,
672
	 * you will want to use field() instead. This function will automatically convert arrays into a
673
	 * list of text such as "Rick, John, and Gary"
674
	 *
675
	 * @param string|array|object  $name   The field name, or an associative array of parameters
676
	 * @param boolean|array|object $single (optional) For tableless fields, to return an array or the first
677
	 *
678
	 * @return string|null|false The output from the field, null if the field doesn't exist, false if no value returned
679
	 *                           for tableless fields
680
	 * @since 2.0
681
	 * @link  https://pods.io/docs/display/
682
	 */
683
	public function display( $name, $single = null ) {
684
685
		$defaults = array(
686
			'name'          => $name,
687
			'single'        => $single,
688
			'display'       => true,
689
			'serial_params' => null,
690
		);
691
692 View Code Duplication
		if ( is_array( $name ) || is_object( $name ) ) {
693
			$defaults['name'] = null;
694
			$params           = (object) array_merge( $defaults, (array) $name );
695
		} elseif ( is_array( $single ) || is_object( $single ) ) {
696
			$defaults['single'] = null;
697
			$params             = (object) array_merge( $defaults, (array) $single );
698
		} else {
699
			$params = $defaults;
700
		}
701
702
		$params = (object) $params;
703
704
		$value = $this->field( $params );
705
706
		if ( is_array( $value ) ) {
707
			$fields = $this->fields;
708
709
			if ( isset( $this->pod_data['object_fields'] ) ) {
710
				$fields = array_merge( $fields, $this->pod_data['object_fields'] );
711
			}
712
713
			$serial_params = array(
714
				'field'  => $params->name,
715
				'fields' => $fields,
716
			);
717
718
			if ( ! empty( $params->serial_params ) && is_array( $params->serial_params ) ) {
719
				$serial_params = array_merge( $serial_params, $params->serial_params );
720
			}
721
722
			$value = pods_serial_comma( $value, $serial_params );
723
		}
724
725
		return $value;
726
	}
727
728
	/**
729
	 * Return the raw output for a field If you want the raw value for use in PHP for custom manipulation,
730
	 * you will want to use field() instead. This function will automatically convert arrays into a
731
	 * list of text such as "Rick, John, and Gary"
732
	 *
733
	 * @param string|array|object  $name   The field name, or an associative array of parameters
734
	 * @param boolean|array|object $single (optional) For tableless fields, to return an array or the first
735
	 *
736
	 * @return string|null|false The output from the field, null if the field doesn't exist, false if no value returned
737
	 *                           for tableless fields
738
	 * @since 2.0
739
	 * @link  https://pods.io/docs/display/
740
	 */
741
	public function raw( $name, $single = null ) {
742
743
		$defaults = array(
744
			'name'   => $name,
745
			'single' => $single,
746
			'raw'    => true,
747
		);
748
749 View Code Duplication
		if ( is_array( $name ) || is_object( $name ) ) {
750
			$defaults['name'] = null;
751
			$params           = (object) array_merge( $defaults, (array) $name );
752
		} elseif ( is_array( $single ) || is_object( $single ) ) {
753
			$defaults['single'] = null;
754
			$params             = (object) array_merge( $defaults, (array) $single );
755
		} else {
756
			$params = (object) $defaults;
757
		}
758
759
		return $this->field( $params );
760
	}
761
762
	/**
763
	 * Return the value for a field.
764
	 *
765
	 * If you are getting a field for output in a theme, most of the time you will want to use display() instead.
766
	 *
767
	 * This function will return arrays for relationship and file fields.
768
	 *
769
	 * @param string|array|object  $name   The field name, or an associative array of parameters
770
	 * @param boolean|array|object $single (optional) For tableless fields, to return the whole array or the just the first
771
	 *                                     item, or an associative array of parameters
772
	 * @param boolean|array|object $raw    (optional) Whether to return the raw value, or to run through the field type's
773
	 *                                     display method, or an associative array of parameters
774
	 *
775
	 * @return mixed|null Value returned depends on the field type, null if the field doesn't exist, false if no value
776
	 *                    returned for tableless fields
777
	 * @since 2.0
778
	 * @link  https://pods.io/docs/field/
779
	 */
780
	public function field( $name, $single = null, $raw = false ) {
781
782
		$defaults = array(
783
			'name'        => $name,
784
			'orderby'     => null,
785
			'single'      => $single,
786
			'params'      => null,
787
			'in_form'     => false,
788
			'raw'         => $raw,
789
			'raw_display' => false,
790
			'display'     => false,
791
			'get_meta'    => false,
792
			'output'      => null,
793
			'deprecated'  => false,
794
			// extra data to send to field handlers
795
			'args'        => array(),
796
		);
797
798
		if ( is_array( $name ) || is_object( $name ) ) {
799
			if ( is_object( $name ) ) {
800
				$name = get_object_vars( $name );
801
			}
802
803
			$defaults['name'] = null;
804
805
			$params = (object) array_merge( $defaults, (array) $name );
806
		} elseif ( is_array( $single ) || is_object( $single ) ) {
807
			if ( is_object( $single ) ) {
808
				$single = get_object_vars( $single );
809
			}
810
811
			$defaults['single'] = null;
812
813
			$params = (object) array_merge( $defaults, (array) $single );
814
		} elseif ( is_array( $raw ) || is_object( $raw ) ) {
815
			if ( is_object( $raw ) ) {
816
				$raw = get_object_vars( $raw );
817
			}
818
819
			$defaults['raw'] = false;
820
821
			$params = (object) array_merge( $defaults, (array) $raw );
822
		} else {
823
			$params = (object) $defaults;
824
		}
825
826
		if ( $params->in_form ) {
827
			$params->output = 'ids';
828
		} elseif ( null === $params->output ) {
829
			/**
830
			 * Override the way related fields are output
831
			 *
832
			 * @param string       $output How to output related fields. Default is 'arrays'. Options: ids|names|objects|arrays|pods|find
833
			 * @param array|object $row    Current row being outputted.
834
			 * @param array        $params Params array passed to field().
835
			 * @param Pods         $this   Current Pods object.
836
			 */
837
			$params->output = apply_filters( 'pods_pods_field_related_output_type', 'arrays', $this->row, $params, $this );
838
		}
839
840
		if ( in_array( $params->output, array( 'id', 'name', 'object', 'array', 'pod' ), true ) ) {
841
			$params->output .= 's';
842
		}
843
844
		// Support old $orderby variable
845
		if ( null !== $params->single && is_string( $params->single ) && empty( $params->orderby ) ) {
846
			if ( ! class_exists( 'Pod' ) || Pod::$deprecated_notice ) {
847
				pods_deprecated( 'Pods::field', '2.0', 'Use $params[ \'orderby\' ] instead' );
848
			}
849
850
			$params->orderby = $params->single;
851
			$params->single  = false;
852
		}
853
854
		if ( null !== $params->single ) {
855
			$params->single = (boolean) $params->single;
856
		}
857
858
		$params->name = trim( $params->name );
859
		if ( is_array( $params->name ) || '' === $params->name ) {
860
			return null;
861
		}
862
863
		$params->full_name = $params->name;
864
865
		$value = null;
866
867
		if ( isset( $this->row_override[ $params->name ] ) ) {
868
			$value = $this->row_override[ $params->name ];
869
		}
870
871
		if ( false === $this->row() ) {
872
			if ( false !== $this->data() ) {
873
				$this->fetch();
874
			} else {
875
				return $value;
876
			}
877
		}
878
879
		if ( $this->data->field_id === $params->name ) {
880 View Code Duplication
			if ( isset( $this->row[ $params->name ] ) ) {
881
				return $this->row[ $params->name ];
882
			} elseif ( null !== $value ) {
883
				return $value;
884
			}
885
886
			return 0;
887
		}
888
889
		$tableless_field_types    = PodsForm::tableless_field_types();
890
		$simple_tableless_objects = PodsForm::simple_tableless_objects();
891
892
		$params->traverse = array();
893
894
		if ( in_array( $params->name, array(
895
				'_link',
896
				'detail_url',
897
			), true ) || ( in_array( $params->name, array(
898
					'permalink',
899
					'the_permalink',
900
				), true ) && in_array( $this->pod_data['type'], array(
901
					'post_type',
902
					'taxonomy',
903
					'media',
904
					'user',
905
					'comment',
906
				), true ) ) ) {
907
			if ( 0 < strlen( $this->detail_page ) ) {
908
				$value = get_home_url() . '/' . $this->do_magic_tags( $this->detail_page );
909
			} elseif ( in_array( $this->pod_data['type'], array( 'post_type', 'media' ), true ) ) {
910
				$value = get_permalink( $this->id() );
911
			} elseif ( 'taxonomy' === $this->pod_data['type'] ) {
912
				$value = get_term_link( $this->id(), $this->pod_data['name'] );
913
			} elseif ( 'user' === $this->pod_data['type'] ) {
914
				$value = get_author_posts_url( $this->id() );
915
			} elseif ( 'comment' === $this->pod_data['type'] ) {
916
				$value = get_comment_link( $this->id() );
917
			}
918
		}
919
920
		$field_data      = false;
921
		$last_field_data = false;
922
		$field_type      = false;
923
924
		$first_field = explode( '.', $params->name );
925
		$first_field = $first_field[0];
926
927
		if ( isset( $this->fields[ $first_field ] ) ) {
928
			$field_data = $this->fields[ $first_field ];
929
			$field_type = 'field';
930
		} elseif ( ! empty( $this->pod_data['object_fields'] ) ) {
931
			if ( isset( $this->pod_data['object_fields'][ $first_field ] ) ) {
932
				$field_data = $this->pod_data['object_fields'][ $first_field ];
933
				$field_type = 'object_field';
934
			} else {
935
				$object_fields = (array) $this->pod_data['object_fields'];
936
937
				foreach ( $object_fields as $object_field => $object_field_opt ) {
938
					if ( in_array( $first_field, $object_field_opt['alias'], true ) ) {
939
						if ( $first_field === $params->name ) {
940
							$params->name = $object_field;
941
						}
942
943
						$first_field = $object_field;
944
						$field_data  = $object_field_opt;
945
						$field_type  = 'object_field';
946
947
						break;
948
					}
949
				}
950
			}
951
		}
952
953
		// Simple fields have no other output options
954
		if ( 'pick' === $field_data['type'] && in_array( $field_data['pick_object'], $simple_tableless_objects, true ) ) {
955
			$params->output = 'arrays';
956
		}
957
958
		if ( empty( $value ) && in_array( $field_data['type'], $tableless_field_types, true ) ) {
959
			$params->raw = true;
960
961
			$value = false;
962
963
			$row_key = sprintf( '_%s_%s', $params->output, $params->name );
964
965
			if ( 'arrays' !== $params->output && isset( $this->row[ $row_key ] ) ) {
966
				$value = $this->row[ '_' . $params->output . '_' . $params->name ];
967
			} elseif ( 'arrays' === $params->output && isset( $this->row[ $params->name ] ) ) {
968
				$value = $this->row[ $params->name ];
969
			}
970
971
			if ( false !== $value && ! is_array( $value ) && 'pick' === $field_data['type'] && in_array( $field_data['pick_object'], $simple_tableless_objects, true ) ) {
972
				$value = PodsForm::field_method( 'pick', 'simple_value', $params->name, $value, $field_data, $this->pod_data, $this->id(), true );
973
			}
974
		}
975
976
		if ( empty( $value ) && isset( $this->row[ $params->name ] ) && ( ! in_array( $field_data['type'], $tableless_field_types, true ) || 'arrays' === $params->output ) ) {
977
			if ( empty( $field_data ) || in_array( $field_data['type'], array(
978
					'boolean',
979
					'number',
980
					'currency',
981
				), true ) ) {
982
				$params->raw = true;
983
			}
984
985
			if ( null === $params->single ) {
986
				if ( isset( $this->fields[ $params->name ] ) && ! in_array( $this->fields[ $params->name ]['type'], $tableless_field_types, true ) ) {
987
					$params->single = true;
988
				} else {
989
					$params->single = false;
990
				}
991
			}
992
993
			$value = $this->row[ $params->name ];
994
		} elseif ( empty( $value ) ) {
995
			$object_field_found = false;
996
997
			if ( 'object_field' === $field_type ) {
998
				$object_field_found = true;
999
1000
				if ( isset( $this->row[ $first_field ] ) ) {
1001
					$value = $this->row[ $first_field ];
1002
				} elseif ( in_array( $field_data['type'], $tableless_field_types, true ) ) {
1003
					$this->fields[ $first_field ] = $field_data;
1004
1005
					$object_field_found = false;
1006
				} else {
1007
					return null;
1008
				}
1009
			}
1010
1011
			if ( 'post_type' === $this->pod_data['type'] && ! isset( $this->fields[ $params->name ] ) ) {
1012
				if ( ! isset( $this->fields['post_thumbnail'] ) && ( 'post_thumbnail' === $params->name || 0 === strpos( $params->name, 'post_thumbnail.' ) ) ) {
1013
					$size = 'thumbnail';
1014
1015 View Code Duplication
					if ( 0 === strpos( $params->name, 'post_thumbnail.' ) ) {
1016
						$field_names = explode( '.', $params->name );
1017
1018
						if ( isset( $field_names[1] ) ) {
1019
							$size = $field_names[1];
1020
						}
1021
					}
1022
1023
					// Pods will auto-get the thumbnail ID if this isn't an attachment
1024
					$value = pods_image( $this->id(), $size, 0, null, true );
1025
1026
					$object_field_found = true;
1027
				} elseif ( ! isset( $this->fields['post_thumbnail_url'] ) && ( 'post_thumbnail_url' === $params->name || 0 === strpos( $params->name, 'post_thumbnail_url.' ) ) ) {
1028
					$size = 'thumbnail';
1029
1030 View Code Duplication
					if ( 0 === strpos( $params->name, 'post_thumbnail_url.' ) ) {
1031
						$field_names = explode( '.', $params->name );
1032
1033
						if ( isset( $field_names[1] ) ) {
1034
							$size = $field_names[1];
1035
						}
1036
					}
1037
1038
					// Pods will auto-get the thumbnail ID if this isn't an attachment
1039
					$value = pods_image_url( $this->id(), $size, 0, true );
1040
1041
					$object_field_found = true;
1042 View Code Duplication
				} elseif ( 0 === strpos( $params->name, 'image_attachment.' ) ) {
1043
					$size = 'thumbnail';
1044
1045
					$image_id = 0;
1046
1047
					$field_names = explode( '.', $params->name );
1048
1049
					if ( isset( $field_names[1] ) ) {
1050
						$image_id = $field_names[1];
1051
					}
1052
1053
					if ( isset( $field_names[2] ) ) {
1054
						$size = $field_names[2];
1055
					}
1056
1057
					if ( ! empty( $image_id ) ) {
1058
						$value = pods_image( $image_id, $size, 0, null, true );
1059
1060
						if ( ! empty( $value ) ) {
1061
							$object_field_found = true;
1062
						}
1063
					}
1064
				} elseif ( 0 === strpos( $params->name, 'image_attachment_url.' ) ) {
1065
					$size = 'thumbnail';
1066
1067
					$image_id = 0;
1068
1069
					$field_names = explode( '.', $params->name );
1070
1071
					if ( isset( $field_names[1] ) ) {
1072
						$image_id = $field_names[1];
1073
					}
1074
1075
					if ( isset( $field_names[2] ) ) {
1076
						$size = $field_names[2];
1077
					}
1078
1079
					if ( ! empty( $image_id ) ) {
1080
						$value = pods_image_url( $image_id, $size, 0, true );
1081
1082
						if ( ! empty( $value ) ) {
1083
							$object_field_found = true;
1084
						}
1085
					}
1086
				}
1087
			} elseif ( 'user' === $this->pod_data['type'] && ! isset( $this->fields[ $params->name ] ) ) {
1088
				if ( ! isset( $this->fields['avatar'] ) && ( 'avatar' === $params->name || 0 === strpos( $params->name, 'avatar.' ) ) ) {
1089
					$size = null;
1090
1091 View Code Duplication
					if ( 0 === strpos( $params->name, 'avatar.' ) ) {
1092
						$field_names = explode( '.', $params->name );
1093
1094
						if ( isset( $field_names[1] ) ) {
1095
							$size = (int) $field_names[1];
1096
						}
1097
					}
1098
1099
					if ( 0 < $size ) {
1100
						$value = get_avatar( $this->id(), $size );
1101
					} else {
1102
						$value = get_avatar( $this->id() );
1103
					}
1104
1105
					$object_field_found = true;
1106
				}
1107 View Code Duplication
			} elseif ( 0 === strpos( $params->name, 'image_attachment.' ) ) {
1108
				$size = 'thumbnail';
1109
1110
				$image_id = 0;
1111
1112
				$field_names = explode( '.', $params->name );
1113
1114
				if ( isset( $field_names[1] ) ) {
1115
					$image_id = $field_names[1];
1116
				}
1117
1118
				if ( isset( $field_names[2] ) ) {
1119
					$size = $field_names[2];
1120
				}
1121
1122
				if ( ! empty( $image_id ) ) {
1123
					$value = pods_image( $image_id, $size, 0, null, true );
1124
1125
					if ( ! empty( $value ) ) {
1126
						$object_field_found = true;
1127
					}
1128
				}
1129
			} elseif ( 0 === strpos( $params->name, 'image_attachment_url.' ) ) {
1130
				$size = 'thumbnail';
1131
1132
				$image_id = 0;
1133
1134
				$field_names = explode( '.', $params->name );
1135
1136
				if ( isset( $field_names[1] ) ) {
1137
					$image_id = $field_names[1];
1138
				}
1139
1140
				if ( isset( $field_names[2] ) ) {
1141
					$size = $field_names[2];
1142
				}
1143
1144
				if ( ! empty( $image_id ) ) {
1145
					$value = pods_image_url( $image_id, $size, 0, true );
1146
1147
					if ( ! empty( $value ) ) {
1148
						$object_field_found = true;
1149
					}
1150
				}
1151
			}
1152
1153
			if ( false === $object_field_found ) {
1154
				$params->traverse = array( $params->name );
1155
1156
				if ( false !== strpos( $params->name, '.' ) ) {
1157
					$params->traverse = explode( '.', $params->name );
1158
1159
					$params->name = $params->traverse[0];
1160
				}
1161
1162
				if ( isset( $this->fields[ $params->name ], $this->fields[ $params->name ]['type'] ) ) {
1163
					/**
1164
					 * Modify value returned by field() after its retrieved, but before its validated or formatted
1165
					 *
1166
					 * Filter name is set dynamically with name of field: "pods_pods_field_{field_name}"
1167
					 *
1168
					 * @since unknown
1169
					 *
1170
					 * @param array|string|null $value  Value retrieved.
1171
					 * @param array|object      $row    Current row being outputted.
1172
					 * @param array             $params Params array passed to field().
1173
					 * @param object|Pods       $this   Current Pods object.
1174
					 */
1175
					$v = apply_filters( 'pods_pods_field_' . $this->fields[ $params->name ]['type'], null, $this->fields[ $params->name ], $this->row, $params, $this );
1176
1177
					if ( null !== $v ) {
1178
						return $v;
1179
					}
1180
				}
1181
1182
				$simple = false;
1183
1184
				if ( isset( $this->fields[ $params->name ] ) ) {
1185
					if ( 'meta' === $this->pod_data['storage'] && ! in_array( $this->fields[ $params->name ]['type'], $tableless_field_types, true ) ) {
1186
						$simple = true;
1187
					}
1188
1189
					if ( in_array( $this->fields[ $params->name ]['type'], $tableless_field_types, true ) ) {
1190
						$params->raw = true;
1191
1192
						if ( 'pick' === $this->fields[ $params->name ]['type'] && in_array( $this->fields[ $params->name ]['pick_object'], $simple_tableless_objects, true ) ) {
1193
							$simple         = true;
1194
							$params->single = true;
1195
						}
1196
					} elseif ( in_array( $this->fields[ $params->name ]['type'], array(
1197
						'boolean',
1198
						'number',
1199
						'currency',
1200
					), true ) ) {
1201
						$params->raw = true;
1202
					}
1203
				}
1204
1205
				$is_field_set       = isset( $this->fields[ $params->name ] );
1206
				$is_tableless_field = in_array( $this->fields[ $params->name ]['type'], $tableless_field_types, true );
1207
1208
				if ( $simple || ! $is_field_set || ! $is_tableless_field ) {
1209
					if ( null === $params->single ) {
1210
						if ( $is_field_set && $is_tableless_field ) {
1211
							$params->single = true;
1212
						} else {
1213
							$params->single = false;
1214
						}
1215
					}
1216
1217
					$no_conflict = pods_no_conflict_check( $this->pod_data['type'] );
1218
1219
					if ( ! $no_conflict ) {
1220
						pods_no_conflict_on( $this->pod_data['type'] );
1221
					}
1222
1223
					if ( in_array( $this->pod_data['type'], array(
1224
						'post_type',
1225
						'media',
1226
						'taxonomy',
1227
						'user',
1228
						'comment',
1229
					), true ) ) {
1230
						$id = $this->id();
1231
1232
						$metadata_type = $this->pod_data['type'];
1233
1234
						if ( in_array( $this->pod_data['type'], array( 'post_type', 'media' ), true ) ) {
1235
							$metadata_type = 'post';
1236
1237
							// Support for WPML 'duplicated' translation handling
1238 View Code Duplication
							if ( did_action( 'wpml_loaded' ) && apply_filters( 'wpml_is_translated_post_type', false, $this->pod_data['name'] ) ) {
1239
								$master_post_id = (int) apply_filters( 'wpml_master_post_from_duplicate', $id );
1240
1241
								if ( 0 < $master_post_id ) {
1242
									$id = $master_post_id;
1243
								}
1244
							}
1245
						} elseif ( 'taxonomy' === $this->pod_data['type'] ) {
1246
							$metadata_type = 'term';
1247
						}
1248
1249
						$value = get_metadata( $metadata_type, $id, $params->name, $params->single );
1250
1251
						$single_multi = 'single';
1252
1253
						if ( isset( $this->fields[ $params->name ] ) ) {
1254
							$single_multi = pods_v( $this->fields[ $params->name ]['type'] . '_format_type', $this->fields[ $params->name ]['options'], 'single' );
1255
						}
1256
1257
						if ( $simple && ! is_array( $value ) && 'single' !== $single_multi ) {
1258
							$value = get_metadata( $metadata_type, $id, $params->name );
1259
						}
1260
					} elseif ( 'settings' === $this->pod_data['type'] ) {
1261
						$value = get_option( $this->pod_data['name'] . '_' . $params->name, null );
1262
					}
1263
1264
					// Handle Simple Relationships
1265
					if ( $simple ) {
1266
						if ( null === $params->single ) {
1267
							$params->single = false;
1268
						}
1269
1270
						$value = PodsForm::field_method( 'pick', 'simple_value', $params->name, $value, $this->fields[ $params->name ], $this->pod_data, $this->id(), true );
1271
					}
1272
1273
					if ( ! $no_conflict ) {
1274
						pods_no_conflict_off( $this->pod_data['type'] );
1275
					}
1276
				} else {
1277
					// Dot-traversal
1278
					$pod        = $this->pod;
1279
					$ids        = array( $this->id() );
1280
					$all_fields = array();
1281
1282
					$lookup = $params->traverse;
1283
1284
					// Get fields matching traversal names
1285
					if ( ! empty( $lookup ) ) {
1286
						$fields = $this->api->load_fields( array(
1287
							'name'          => $lookup,
1288
							'type'          => $tableless_field_types,
1289
							'object_fields' => true,
1290
							// @todo support object fields too
1291
						) );
1292
1293
						if ( ! empty( $fields ) ) {
1294
							foreach ( $fields as $field ) {
1295
								if ( ! empty( $field ) ) {
1296
									if ( ! isset( $all_fields[ $field['pod'] ] ) ) {
1297
										$all_fields[ $field['pod'] ] = array();
1298
									}
1299
1300
									$all_fields[ $field['pod'] ][ $field['name'] ] = $field;
1301
								}
1302
							}
1303
						}
1304
1305
						if ( ! empty( $this->pod_data['object_fields'] ) ) {
1306
							$object_fields = (array) $this->pod_data['object_fields'];
1307
1308
							foreach ( $object_fields as $object_field => $object_field_opt ) {
1309
								if ( in_array( $object_field_opt['type'], $tableless_field_types, true ) ) {
1310
									$all_fields[ $this->pod ][ $object_field ] = $object_field_opt;
1311
								}
1312
							}
1313
						}
1314
					}
1315
1316
					$last_type     = '';
1317
					$last_object   = '';
1318
					$last_pick_val = '';
1319
1320
					$single_multi = pods_v( $this->fields[ $params->name ]['type'] . '_format_type', $this->fields[ $params->name ]['options'], 'single' );
1321
1322
					if ( 'multi' === $single_multi ) {
1323
						$limit = (int) pods_v( $this->fields[ $params->name ]['type'] . '_limit', $this->fields[ $params->name ]['options'], 0 );
1324
					} else {
1325
						$limit = 1;
1326
					}
1327
1328
					// Loop through each traversal level
1329
					foreach ( $params->traverse as $key => $field ) {
1330
						$last_loop = false;
1331
1332
						if ( count( $params->traverse ) <= ( $key + 1 ) ) {
1333
							$last_loop = true;
1334
						}
1335
1336
						$field_exists = isset( $all_fields[ $pod ][ $field ] );
1337
1338
						$simple       = false;
1339
						$last_options = array();
1340
1341
						if ( $field_exists && 'pick' === $all_fields[ $pod ][ $field ]['type'] && in_array( $all_fields[ $pod ][ $field ]['pick_object'], $simple_tableless_objects, true ) ) {
1342
							$simple       = true;
1343
							$last_options = $all_fields[ $pod ][ $field ];
1344
						}
1345
1346
						// Tableless handler
1347
						if ( $field_exists && ( ! in_array( $all_fields[ $pod ][ $field ]['type'], array(
1348
									'pick',
1349
									'taxonomy',
1350
									'comment',
1351
								), true ) || ! $simple ) ) {
1352
							$type        = $all_fields[ $pod ][ $field ]['type'];
1353
							$pick_object = $all_fields[ $pod ][ $field ]['pick_object'];
1354
							$pick_val    = $all_fields[ $pod ][ $field ]['pick_val'];
1355
1356
							if ( 'table' === $pick_object ) {
1357
								$pick_val = pods_v( 'pick_table', $all_fields[ $pod ][ $field ]['options'], $pick_val, true );
1358
							} elseif ( '__current__' === $pick_val ) {
1359
								$pick_val = $pod;
1360
							}
1361
1362
							$last_limit = 0;
1363
1364
							if ( in_array( $type, $tableless_field_types, true ) ) {
1365
								$single_multi = pods_v( "{$type}_format_type", $all_fields[ $pod ][ $field ]['options'], 'single' );
1366
1367
								if ( 'multi' === $single_multi ) {
1368
									$last_limit = (int) pods_v( "{$type}_limit", $all_fields[ $pod ][ $field ]['options'], 0 );
1369
								} else {
1370
									$last_limit = 1;
1371
								}
1372
							}
1373
1374
							$last_type     = $type;
1375
							$last_object   = $pick_object;
1376
							$last_pick_val = $pick_val;
1377
							$last_options  = $all_fields[ $pod ][ $field ];
1378
1379
							// Temporary hack until there's some better handling here
1380
							$last_limit *= count( $ids );
1381
1382
							// Get related IDs
1383
							if ( ! isset( $all_fields[ $pod ][ $field ]['pod_id'] ) ) {
1384
								$all_fields[ $pod ][ $field ]['pod_id'] = 0;
1385
							}
1386
1387
							if ( isset( $all_fields[ $pod ][ $field ]['id'] ) ) {
1388
								$ids = $this->api->lookup_related_items( $all_fields[ $pod ][ $field ]['id'], $all_fields[ $pod ][ $field ]['pod_id'], $ids, $all_fields[ $pod ][ $field ] );
1389
							}
1390
1391
							// No items found
1392
							if ( empty( $ids ) ) {
1393
								return false;
1394
							} // @todo This should return array() if not $params->single
1395
							elseif ( 0 < $last_limit ) {
1396
								$ids = array_slice( $ids, 0, $last_limit );
1397
							}
1398
1399
							// Get $pod if related to a Pod
1400
							if ( ! empty( $pick_object ) && ( ! empty( $pick_val ) || in_array( $pick_object, array(
1401
										'user',
1402
										'media',
1403
										'comment',
1404
									), true ) ) ) {
1405
								if ( 'pod' === $pick_object ) {
1406
									$pod = $pick_val;
1407
								} else {
1408
									$check = $this->api->get_table_info( $pick_object, $pick_val );
1409
1410
									if ( ! empty( $check ) && ! empty( $check['pod'] ) ) {
1411
										$pod = $check['pod']['name'];
1412
									}
1413
								}
1414
							}
1415
						} // Assume last iteration
1416
						else {
1417
							// Invalid field
1418
							if ( 0 === $key ) {
1419
								return false;
1420
							}
1421
1422
							$last_loop = true;
1423
						}
1424
1425
						if ( $last_loop ) {
1426
							$object_type = $last_object;
1427
							$object      = $last_pick_val;
1428
1429
							if ( in_array( $last_type, PodsForm::file_field_types(), true ) ) {
1430
								$object_type = 'media';
1431
								$object      = 'attachment';
1432
							}
1433
1434
							$data = array();
1435
1436
							$table = $this->api->get_table_info( $object_type, $object, null, null, $last_options );
1437
1438
							$join  = array();
1439
							$where = array();
1440
1441
							if ( ! empty( $table['join'] ) ) {
1442
								$join = (array) $table['join'];
1443
							}
1444
1445
							if ( ! empty( $ids ) || ! empty( $table['where'] ) ) {
1446
								foreach ( $ids as $id ) {
1447
									$where[ $id ] = '`t`.`' . $table['field_id'] . '` = ' . (int) $id;
1448
								}
1449
1450
								if ( ! empty( $where ) ) {
1451
									$where = array( implode( ' OR ', $where ) );
1452
								}
1453
1454
								if ( ! empty( $table['where'] ) ) {
1455
									$where = array_merge( $where, array_values( (array) $table['where'] ) );
1456
								}
1457
							}
1458
1459
							/**
1460
							 * Related object.
1461
							 *
1462
							 * @var $related_obj Pods|false
1463
							 */
1464
							$related_obj = false;
1465
1466
							// Check if we can return the full object/array or if we need to traverse into it.
1467
							$is_field_output_full = false;
1468
1469
							if ( false !== $field_exists && ( in_array( $last_type, $tableless_field_types, true ) && ! $simple ) ) {
1470
								$is_field_output_full = true;
1471
							}
1472
1473
							if ( 'pod' === $object_type ) {
1474
								$related_obj = pods( $object, null, false );
1475
							} elseif ( ! empty( $table['pod'] ) ) {
1476
								$related_obj = pods( $table['pod']['name'], null, false );
1477
							}
1478
1479
							if ( $related_obj || ! empty( $table['table'] ) ) {
1480
								$sql = array(
1481
									'select'     => '*, `t`.`' . $table['field_id'] . '` AS `pod_item_id`',
1482
									'table'      => $table['table'],
1483
									'join'       => $join,
1484
									'where'      => $where,
1485
									'orderby'    => $params->orderby,
1486
									'pagination' => false,
1487
									'search'     => false,
1488
									'limit'      => - 1,
1489
									'expires'    => 180,
1490
									// @todo This could potentially cause issues if someone changes the data within this time and persistent storage is used.
1491
								);
1492
1493
								if ( ! empty( $table['where_default'] ) ) {
1494
									$sql['where_default'] = $table['where_default'];
1495
								}
1496
1497
								// Output types
1498
								if ( in_array( $params->output, array( 'ids', 'objects', 'pods' ), true ) ) {
1499
									$sql['select'] = '`t`.`' . $table['field_id'] . '` AS `pod_item_id`';
1500 View Code Duplication
								} elseif ( 'names' === $params->output && ! empty( $table['field_index'] ) ) {
1501
									$sql['select'] = '`t`.`' . $table['field_index'] . '` AS `pod_item_index`, `t`.`' . $table['field_id'] . '` AS `pod_item_id`';
1502
								}
1503
1504
								if ( ! empty( $params->params ) && is_array( $params->params ) ) {
1505
									$where = $sql['where'];
1506
1507
									$sql = array_merge( $sql, $params->params );
1508
1509
									if ( isset( $params->params['where'] ) ) {
1510
										$sql['where'] = array_merge( (array) $where, (array) $params->params['where'] );
1511
									}
1512
								}
1513
1514
								$item_data = array();
1515
1516
								if ( ! $related_obj ) {
1517
									if ( ! is_object( $this->alt_data ) ) {
1518
										$this->alt_data = pods_data( null, 0, true, true );
1519
									}
1520
1521
									$item_data = $this->alt_data->select( $sql );
1522
								} else {
1523
									// Support 'find' output ordering
1524
									if ( $ids && 'find' === $params->output && $is_field_output_full && empty( $sql['orderby'] ) ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $ids of type integer[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
1525
										// Handle default orderby for ordering by the IDs
1526
										$order_ids = implode( ', ', array_map( 'absint', $ids ) );
1527
1528
										$sql['orderby'] = 'FIELD( `t`.`' . $table['field_id'] . '`, ' . $order_ids . ' )';
1529
									}
1530
1531
									$related_obj->find( $sql );
1532
1533
									// Support 'find' output
1534
									if ( 'find' === $params->output && $is_field_output_full ) {
1535
										$data = $related_obj;
1536
1537
										$is_field_output_full = true;
1538
									} else {
1539
										$item_data = $related_obj->data();
1540
									}
1541
								}
1542
1543
								$items = array();
1544
1545
								if ( ! empty( $item_data ) ) {
1546
									foreach ( $item_data as $item ) {
1547
										if ( is_array( $item ) ) {
1548
											$item = (object) $item;
1549
										}
1550
1551
										if ( empty( $item->pod_item_id ) ) {
1552
											continue;
1553
										}
1554
1555
										// Bypass pass field
1556
										if ( isset( $item->user_pass ) ) {
1557
											unset( $item->user_pass );
1558
										}
1559
1560
										// Get Item ID
1561
										$item_id = $item->pod_item_id;
1562
1563
										// Output types
1564
										if ( 'ids' === $params->output ) {
1565
											$item = (int) $item_id;
1566
										} elseif ( 'names' === $params->output && ! empty( $table['field_index'] ) ) {
1567
											$item = $item->pod_item_index;
1568
										} elseif ( 'objects' === $params->output ) {
1569
											if ( in_array( $object_type, array( 'post_type', 'media' ), true ) ) {
1570
												$item = get_post( $item_id );
1571
											} elseif ( 'taxonomy' === $object_type ) {
1572
												$item = get_term( $item_id, $object );
1573
											} elseif ( 'user' === $object_type ) {
1574
												$item = get_userdata( $item_id );
1575
1576
												if ( ! empty( $item ) ) {
1577
													// Get other vars
1578
													$roles   = $item->roles;
1579
													$caps    = $item->caps;
1580
													$allcaps = $item->allcaps;
1581
1582
													$item = $item->data;
1583
1584
													// Set other vars
1585
													$item->roles   = $roles;
1586
													$item->caps    = $caps;
1587
													$item->allcaps = $allcaps;
1588
1589
													unset( $item->user_pass );
1590
												}
1591
											} elseif ( 'comment' === $object_type ) {
1592
												$item = get_comment( $item_id );
1593
											} else {
1594
												$item = (object) $item;
1595
											}
1596
										} elseif ( 'pods' === $params->output ) {
1597
											if ( in_array( $object_type, array( 'user', 'media' ), true ) ) {
1598
												$item = pods( $object_type, (int) $item_id );
1599
											} else {
1600
												$item = pods( $object, (int) $item_id );
1601
											}
1602
										} else // arrays
1603
										{
1604
											$item = get_object_vars( (object) $item );
1605
										}
1606
1607
										// Pass item data into $data
1608
										$items[ $item_id ] = $item;
1609
									}
1610
1611
									// Cleanup
1612
									unset( $item_data );
1613
1614
									// Return all of the data in the order expected
1615
									if ( empty( $params->orderby ) ) {
1616
										foreach ( $ids as $id ) {
1617
											if ( isset( $items[ $id ] ) ) {
1618
												$data[ $id ] = $items[ $id ];
1619
											}
1620
										}
1621
									} else {
1622
										// Use order set by orderby
1623
										foreach ( $items as $id => $v ) {
1624
											if ( in_array( $id, $ids ) ) {
1625
												$data[ $id ] = $v;
1626
											}
1627
										}
1628
									}
1629
								}
1630
							}
1631
1632
							if ( in_array( $last_type, $tableless_field_types, true ) || in_array( $last_type, array(
1633
									'boolean',
1634
									'number',
1635
									'currency',
1636
								), true ) ) {
1637
								$params->raw = true;
1638
							}
1639
1640
							if ( empty( $data ) ) {
1641
								$value = false;
1642
							} else {
1643
								$object_type = $table['type'];
1644
1645
								if ( in_array( $table['type'], array( 'post_type', 'attachment', 'media' ), true ) ) {
1646
									$object_type = 'post';
1647
								}
1648
1649
								$no_conflict = true;
1650
1651 View Code Duplication
								if ( in_array( $object_type, array(
1652
									'post',
1653
									'taxonomy',
1654
									'user',
1655
									'comment',
1656
									'settings',
1657
								), true ) ) {
1658
									$no_conflict = pods_no_conflict_check( $object_type );
1659
1660
									if ( ! $no_conflict ) {
1661
										pods_no_conflict_on( $object_type );
1662
									}
1663
								}
1664
1665
								// Return entire array
1666
								if ( $is_field_output_full ) {
1667
									$value = $data;
1668
								} // Return an array of single column values
1669
								else {
1670
									$value = array();
1671
1672
									foreach ( $data as $item_id => $item ) {
1673
										// $field is 123x123, needs to be _src.123x123
1674
										$full_field = implode( '.', array_splice( $params->traverse, $key ) );
1675
1676
										if ( is_array( $item ) && isset( $item[ $field ] ) ) {
1677 View Code Duplication
											if ( $table['field_id'] === $field ) {
1678
												$value[] = (int) $item[ $field ];
1679
											} else {
1680
												$value[] = $item[ $field ];
1681
											}
1682
										} elseif ( is_object( $item ) && isset( $item->{$field} ) ) {
1683 View Code Duplication
											if ( $table['field_id'] === $field ) {
1684
												$value[] = (int) $item->{$field};
1685
											} else {
1686
												$value[] = $item->{$field};
1687
											}
1688
										} elseif ( ( ( false !== strpos( $full_field, '_src' ) || 'guid' === $field ) && ( in_array( $table['type'], array(
1689
														'attachment',
1690
														'media',
1691
													), true ) || in_array( $last_type, PodsForm::file_field_types(), true ) ) ) || ( in_array( $field, array(
1692
													'_link',
1693
													'detail_url',
1694
												), true ) || in_array( $field, array(
1695
													'permalink',
1696
													'the_permalink',
1697
												), true ) && in_array( $last_type, PodsForm::file_field_types(), true ) ) ) {
1698
											// @todo Refactor the above condition statement
1699
											$size = 'full';
1700
1701
											if ( false === strpos( 'image', get_post_mime_type( $item_id ) ) ) {
1702
												// No default sizes for non-images. When a size is defined this will be overwritten.
1703
												$size = null;
1704
											}
1705
1706
											if ( false !== strpos( $full_field, '_src.' ) && 5 < strlen( $full_field ) ) {
1707
												$size = substr( $full_field, 5 );
1708 View Code Duplication
											} elseif ( false !== strpos( $full_field, '_src_relative.' ) && 14 < strlen( $full_field ) ) {
1709
												$size = substr( $full_field, 14 );
1710
											} elseif ( false !== strpos( $full_field, '_src_schemeless.' ) && 16 < strlen( $full_field ) ) {
1711
												$size = substr( $full_field, 16 );
1712
											}
1713
1714
											if ( $size ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $size of type null|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
1715
												$value_url = pods_image_url( $item_id, $size );
1716
											} else {
1717
												$value_url = wp_get_attachment_url( $item_id );
1718
											}
1719
1720
											if ( ! empty( $value_url ) ) {
1721
												if ( false !== strpos( $full_field, '_src_relative' ) ) {
1722
													$value_url_parsed = parse_url( $value_url );
1723
													$value_url        = $value_url_parsed['path'];
1724
												} elseif ( false !== strpos( $full_field, '_src_schemeless' ) ) {
1725
													$value_url = str_replace( array(
1726
														'http://',
1727
														'https://',
1728
													), '//', $value_url );
1729
												}
1730
											}
1731
1732
											if ( ! empty( $value_url ) ) {
1733
												$value[] = $value_url;
1734
											}
1735
1736
											$params->raw_display = true;
1737
										} elseif ( false !== strpos( $full_field, '_img' ) && ( in_array( $table['type'], array(
1738
													'attachment',
1739
													'media',
1740
												), true ) || in_array( $last_type, PodsForm::file_field_types(), true ) ) ) {
1741
											$size = 'full';
1742
1743 View Code Duplication
											if ( false !== strpos( $full_field, '_img.' ) && 5 < strlen( $full_field ) ) {
1744
												$size = substr( $full_field, 5 );
1745
											}
1746
1747
											$value[] = pods_image( $item_id, $size );
1748
1749
											$params->raw_display = true;
1750
										} elseif ( in_array( $field, array(
1751
												'_link',
1752
												'detail_url',
1753
											), true ) || in_array( $field, array( 'permalink', 'the_permalink' ), true ) ) {
1754
											if ( 'pod' === $object_type ) {
1755
												if ( is_object( $related_obj ) ) {
1756
													$related_obj->fetch( $item_id );
1757
1758
													$value[] = $related_obj->field( 'detail_url' );
1759
												} else {
1760
													$value[] = '';
1761
												}
1762
											} elseif ( 'post' === $object_type ) {
1763
												$value[] = get_permalink( $item_id );
1764
											} elseif ( 'taxonomy' === $object_type ) {
1765
												$value[] = get_term_link( $item_id, $object );
1766
											} elseif ( 'user' === $object_type ) {
1767
												$value[] = get_author_posts_url( $item_id );
1768
											} elseif ( 'comment' === $object_type ) {
1769
												$value[] = get_comment_link( $item_id );
1770
											} else {
1771
												$value[] = '';
1772
											}
1773
1774
											$params->raw_display = true;
1775
										} elseif ( in_array( $object_type, array(
1776
											'post',
1777
											'taxonomy',
1778
											'user',
1779
											'comment',
1780
										), true ) ) {
1781
											$metadata_object_id = $item_id;
1782
1783
											$metadata_type = $object_type;
1784
1785
											if ( 'post' === $object_type ) {
1786
												// Support for WPML 'duplicated' translation handling
1787 View Code Duplication
												if ( did_action( 'wpml_loaded' ) && apply_filters( 'wpml_is_translated_post_type', false, $object ) ) {
1788
													$master_post_id = (int) apply_filters( 'wpml_master_post_from_duplicate', $metadata_object_id );
1789
1790
													if ( 0 < $master_post_id ) {
1791
														$metadata_object_id = $master_post_id;
1792
													}
1793
												}
1794
											} elseif ( 'taxonomy' === $object_type ) {
1795
												$metadata_type = 'term';
1796
											}
1797
1798
											$value[] = get_metadata( $metadata_type, $metadata_object_id, $field, true );
1799
										} elseif ( 'settings' === $object_type ) {
1800
											$value[] = get_option( $object . '_' . $field );
1801
										}
1802
									}
1803
								}
1804
1805 View Code Duplication
								if ( ! $no_conflict && in_array( $object_type, array(
1806
										'post',
1807
										'taxonomy',
1808
										'user',
1809
										'comment',
1810
										'settings',
1811
									), true ) ) {
1812
									pods_no_conflict_off( $object_type );
1813
								}
1814
1815
								// Handle Simple Relationships
1816
								if ( $simple ) {
1817
									if ( null === $params->single ) {
1818
										$params->single = false;
1819
									}
1820
1821
									$value = PodsForm::field_method( 'pick', 'simple_value', $field, $value, $last_options, $all_fields[ $pod ], 0, true );
1822
								} elseif ( false === $params->in_form && ! empty( $value ) && is_array( $value ) ) {
1823
									$value = array_values( $value );
1824
								}
1825
1826
								// Return a single column value
1827
								if ( false === $params->in_form && 1 === $limit && ! empty( $value ) && is_array( $value ) && 1 === count( $value ) ) {
1828
									$value = current( $value );
1829
								}
1830
							}
1831
1832
							if ( $last_options ) {
1833
								$last_field_data = $last_options;
1834
							}
1835
1836
							break;
1837
						}
1838
					}
1839
				}
1840
			}
1841
		}
1842
1843
		if ( ! empty( $params->traverse ) && 1 < count( $params->traverse ) ) {
1844
			$field_names = implode( '.', $params->traverse );
1845
1846
			$this->row[ $field_names ] = $value;
1847
		} elseif ( 'arrays' !== $params->output && in_array( $field_data['type'], $tableless_field_types, true ) ) {
1848
			$this->row[ '_' . $params->output . '_' . $params->full_name ] = $value;
1849
		} elseif ( 'arrays' === $params->output || ! in_array( $field_data['type'], $tableless_field_types, true ) ) {
1850
			$this->row[ $params->full_name ] = $value;
1851
		}
1852
1853
		if ( $params->single && is_array( $value ) && 1 === count( $value ) ) {
1854
			$value = current( $value );
1855
		}
1856
1857
		if ( ! empty( $last_field_data ) ) {
1858
			$field_data = $last_field_data;
1859
		}
1860
1861
		// @todo Expand this into traversed fields too
1862
		if ( ! empty( $field_data ) && ( $params->display || ! $params->raw ) && ! $params->in_form && ! $params->raw_display ) {
1863
			if ( $params->display || ( ( $params->get_meta || $params->deprecated ) && ! in_array( $field_data['type'], $tableless_field_types, true ) ) ) {
1864
				$field_data['options'] = pods_v( 'options', $field_data, array(), true );
1865
1866
				$post_temp = false;
1867
				$old_post  = null;
1868
				$old_ID    = null;
1869
1870
				if ( empty( $GLOBALS['post'] ) && 'post_type' === pods_v( 'type', $this->pod_data ) && 0 < $this->id() ) {
1871
					global $post_ID, $post;
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...
1872
1873
					$post_temp = true;
1874
1875
					$old_post = $GLOBALS['post'];
1876
					$old_ID   = $GLOBALS['post_ID'];
1877
1878
					$post    = get_post( $this->id() );
1879
					$post_ID = $this->id();
1880
				}
1881
1882
				$filter = pods_v( 'display_filter', $field_data['options'] );
1883
1884
				if ( 0 < strlen( $filter ) ) {
1885
					$args = array(
1886
						$filter,
1887
						$value
1888
					);
1889
1890
					$filter_args = pods_v( 'display_filter_args', $field_data['options'] );
1891
1892
					if ( ! empty( $filter_args ) ) {
1893
						$args = array_merge( $args, compact( $filter_args ) );
1894
					}
1895
1896
					$value = call_user_func_array( 'apply_filters', $args );
1897
				} elseif ( 1 === (int) pods_v( 'display_process', $field_data['options'], 1 ) ) {
1898
					$value = PodsForm::display( $field_data['type'], $value, $params->name, array_merge( $field_data, $field_data['options'] ), $this->pod_data, $this->id() );
1899
				}
1900
1901
				if ( $post_temp ) {
1902
					$post    = $old_post;
1903
					$post_ID = $old_ID;
1904
				}
1905
			} else {
1906
				$value = PodsForm::value( $field_data['type'], $value, $params->name, array_merge( $field_data, $field_data['options'] ), $this->pod_data, $this->id() );
1907
			}
1908
		}
1909
1910
		/**
1911
		 * Modify value returned by field() directly before output.
1912
		 *
1913
		 * Will not run if value was null
1914
		 *
1915
		 * @since unknown
1916
		 *
1917
		 * @param array|string|null $value  Value to be returned.
1918
		 * @param array|object      $row    Current row being outputted.
1919
		 * @param array             $params Params array passed to field().
1920
		 * @param object|Pods       $this   Current Pods object.
1921
		 *
1922
		 */
1923
		$value = apply_filters( 'pods_pods_field', $value, $this->row, $params, $this );
1924
1925
		return $value;
1926
	}
1927
1928
	/**
1929
	 * Check if an item field has a specific value in it
1930
	 *
1931
	 * @param string $field Field name
1932
	 * @param mixed  $value Value to check
1933
	 * @param int    $id    (optional) ID of the pod item to check
1934
	 *
1935
	 * @return bool Whether the value was found
1936
	 *
1937
	 * @since 2.3.3
1938
	 */
1939
	public function has( $field, $value, $id = null ) {
1940
1941
		$pod =& $this;
1942
1943 View Code Duplication
		if ( null === $id ) {
1944
			$id = $this->id();
1945
		} elseif ( $id != $this->id() ) {
1946
			$pod = pods( $this->pod, $id );
1947
		}
1948
1949
		$this->do_hook( 'has', $field, $value, $id );
1950
1951
		if ( ! isset( $this->fields[ $field ] ) ) {
1952
			return false;
1953
		}
1954
1955
		// Tableless fields
1956
		if ( in_array( $this->fields[ $field ]['type'], PodsForm::tableless_field_types(), true ) ) {
1957
			if ( ! is_array( $value ) ) {
1958
				$value = explode( ',', $value );
1959
			}
1960
1961 View Code Duplication
			if ( 'pick' === $this->fields[ $field ]['type'] && in_array( $this->fields[ $field ]['pick_object'], PodsForm::simple_tableless_objects(), true ) ) {
1962
				$current_value = $pod->raw( $field );
1963
1964
				if ( ! empty( $current_value ) ) {
1965
					$current_value = (array) $current_value;
1966
				}
1967
1968
				foreach ( $current_value as $v ) {
1969
					if ( in_array( $v, $value ) ) {
1970
						return true;
1971
					}
1972
				}
1973
			} else {
1974
				$related_ids = $this->api->lookup_related_items( $this->fields[ $field ]['id'], $this->pod_data['id'], $id, $this->fields[ $field ], $this->pod_data );
1975
1976
				foreach ( $value as $k => $v ) {
1977
					if ( ! preg_match( '/[^\D]/', $v ) ) {
1978
						$value[ $k ] = (int) $v;
1979
					}
1980
1981
					// @todo Convert slugs into IDs
1982
				}
1983
1984
				foreach ( $related_ids as $v ) {
1985
					if ( in_array( $v, $value ) ) {
1986
						return true;
1987
					}
1988
				}
1989
			}
1990
		} // Text fields
1991 View Code Duplication
		elseif ( in_array( $this->fields[ $field ]['type'], PodsForm::text_field_types(), true ) ) {
1992
			$current_value = $pod->raw( $field );
1993
1994
			if ( 0 < strlen( $current_value ) ) {
1995
				return stripos( $current_value, $value );
1996
			}
1997
		} // All other fields
1998
		else {
1999
			return $this->is( $field, $value, $id );
2000
		}
2001
2002
		return false;
2003
	}
2004
2005
	/**
2006
	 * Check if an item field is a specific value
2007
	 *
2008
	 * @param string $field Field name
2009
	 * @param mixed  $value Value to check
2010
	 * @param int    $id    (optional) ID of the pod item to check
2011
	 *
2012
	 * @return bool Whether the value was found
2013
	 *
2014
	 * @since 2.3.3
2015
	 */
2016
	public function is( $field, $value, $id = null ) {
2017
2018
		$pod =& $this;
2019
2020 View Code Duplication
		if ( null === $id ) {
2021
			$id = $this->id();
2022
		} elseif ( $id != $this->id() ) {
2023
			$pod = pods( $this->pod, $id );
2024
		}
2025
2026
		$this->do_hook( 'is', $field, $value, $id );
2027
2028
		if ( ! isset( $this->fields[ $field ] ) ) {
2029
			return false;
2030
		}
2031
2032
		// Tableless fields
2033
		if ( in_array( $this->fields[ $field ]['type'], PodsForm::tableless_field_types(), true ) ) {
2034
			if ( ! is_array( $value ) ) {
2035
				$value = explode( ',', $value );
2036
			}
2037
2038
			$current_value = array();
2039
2040 View Code Duplication
			if ( 'pick' === $this->fields[ $field ]['type'] && in_array( $this->fields[ $field ]['pick_object'], PodsForm::simple_tableless_objects(), true ) ) {
2041
				$current_value = $pod->raw( $field );
2042
2043
				if ( ! empty( $current_value ) ) {
2044
					$current_value = (array) $current_value;
2045
				}
2046
2047
				foreach ( $current_value as $v ) {
2048
					if ( in_array( $v, $value ) ) {
2049
						return true;
2050
					}
2051
				}
2052
			} else {
2053
				$related_ids = $this->api->lookup_related_items( $this->fields[ $field ]['id'], $this->pod_data['id'], $id, $this->fields[ $field ], $this->pod_data );
2054
2055
				foreach ( $value as $k => $v ) {
2056
					if ( ! preg_match( '/[^\D]/', $v ) ) {
2057
						$value[ $k ] = (int) $v;
2058
					}
2059
2060
					// @todo Convert slugs into IDs
2061
				}
2062
2063
				foreach ( $related_ids as $v ) {
2064
					if ( in_array( $v, $value ) ) {
2065
						return true;
2066
					}
2067
				}
2068
			}
2069
2070
			if ( ! empty( $current_value ) ) {
2071
				$current_value = array_filter( array_unique( $current_value ) );
2072
			} else {
2073
				$current_value = array();
2074
			}
2075
2076
			if ( ! empty( $value ) ) {
2077
				$value = array_filter( array_unique( $value ) );
2078
			} else {
2079
				$value = array();
2080
			}
2081
2082
			sort( $current_value );
2083
			sort( $value );
2084
2085
			if ( $value === $current_value ) {
2086
				return true;
2087
			}
2088
		} // Number fields
2089
		elseif ( in_array( $this->fields[ $field ]['type'], PodsForm::number_field_types(), true ) ) {
2090
			$current_value = $pod->raw( $field );
2091
2092
			if ( (float) $current_value === (float) $value ) {
2093
				return true;
2094
			}
2095
		} // Date fields
2096
		elseif ( in_array( $this->fields[ $field ]['type'], PodsForm::date_field_types(), true ) ) {
2097
			$current_value = $pod->raw( $field );
2098
2099
			if ( 0 < strlen( $current_value ) ) {
2100
				if ( strtotime( $current_value ) === strtotime( $value ) ) {
2101
					return true;
2102
				}
2103
			} elseif ( empty( $value ) ) {
2104
				return true;
2105
			}
2106
		} // Text fields
2107
		elseif ( in_array( $this->fields[ $field ]['type'], PodsForm::text_field_types(), true ) ) {
2108
			$current_value = $pod->raw( $field );
2109
2110
			if ( (string) $current_value === (string) $value ) {
2111
				return true;
2112
			}
2113
		} // All other fields
2114
		else {
2115
			$current_value = $pod->raw( $field );
2116
2117
			if ( $current_value === $value ) {
2118
				return true;
2119
			}
2120
		}
2121
2122
		return false;
2123
	}
2124
2125
	/**
2126
	 * Return the item ID
2127
	 *
2128
	 * @return int
2129
	 * @since 2.0
2130
	 */
2131
	public function id() {
2132
2133
		if ( isset( $this->data->row, $this->data->row['id'] ) ) {
2134
			// If we already have data loaded return that ID
2135
			return $this->data->row['id'];
2136
		}
2137
2138
		return $this->field( $this->data->field_id );
2139
	}
2140
2141
	/**
2142
	 * Return the previous item ID, loops at the last id to return the first
2143
	 *
2144
	 * @param int|null          $id
2145
	 * @param array|object|null $params_override
2146
	 *
2147
	 * @return int
2148
	 * @since 2.0
2149
	 */
2150
	public function prev_id( $id = null, $params_override = null ) {
2151
2152
		if ( null === $id ) {
2153
			$id = $this->id();
2154
		}
2155
2156
		$id = (int) $id;
2157
2158
		$params = array(
2159
			'select'  => "`t`.`{$this->data->field_id}`",
2160
			'where'   => "`t`.`{$this->data->field_id}` < {$id}",
2161
			'orderby' => "`t`.`{$this->data->field_id}` DESC",
2162
			'limit'   => 1
2163
		);
2164
2165
		if ( ! empty( $params_override ) || ! empty( $this->params ) ) {
2166 View Code Duplication
			if ( ! empty( $params_override ) ) {
2167
				$params = $params_override;
2168
			} elseif ( ! empty( $this->params ) ) {
2169
				$params = $this->params;
2170
			}
2171
2172
			if ( is_object( $params ) ) {
2173
				$params = get_object_vars( $params );
2174
			}
2175
2176
			if ( 0 < $id ) {
2177 View Code Duplication
				if ( isset( $params['where'] ) && ! empty( $params['where'] ) ) {
2178
					$params['where']   = (array) $params['where'];
2179
					$params['where'][] = "`t`.`{$this->data->field_id}` < {$id}";
2180
				} else {
2181
					$params['where'] = "`t`.`{$this->data->field_id}` < {$id}";
2182
				}
2183
			} elseif ( isset( $params['offset'] ) && 0 < $params['offset'] ) {
2184
				$params['offset'] --;
2185
			} elseif ( 0 < $this->row_number && ! isset( $params['offset'] ) && ! empty( $this->params ) ) {
2186
				$params['offset'] = $this->row_number - 1;
2187
			} else {
2188
				return 0;
2189
			}
2190
2191 View Code Duplication
			if ( isset( $params['orderby'] ) && ! empty( $params['orderby'] ) ) {
2192
				if ( is_array( $params['orderby'] ) ) {
2193
					foreach ( $params['orderby'] as $orderby => $dir ) {
2194
						$dir = strtoupper( $dir );
2195
2196
						if ( ! in_array( $dir, array( 'ASC', 'DESC' ), true ) ) {
2197
							continue;
2198
						}
2199
2200
						if ( 'ASC' === $dir ) {
2201
							$params['orderby'][ $orderby ] = 'DESC';
2202
						} else {
2203
							$params['orderby'][ $orderby ] = 'ASC';
2204
						}
2205
					}
2206
2207
					$params['orderby'][ $this->data->field_id ] = 'DESC';
2208
				} elseif ( "`t`.`{$this->data->field_id}` DESC" !== $params['orderby'] ) {
2209
					$params['orderby'] .= ", `t`.`{$this->data->field_id}` DESC";
2210
				}
2211
			}
2212
2213
			$params['select'] = "`t`.`{$this->data->field_id}`";
2214
			$params['limit']  = 1;
2215
		}
2216
2217
		$pod = pods( $this->pod, $params );
2218
2219
		$new_id = 0;
2220
2221
		if ( $pod->fetch() ) {
2222
			$new_id = $pod->id();
2223
		}
2224
2225
		$new_id = $this->do_hook( 'prev_id', $new_id, $id, $pod, $params_override );
2226
2227
		return $new_id;
2228
	}
2229
2230
	/**
2231
	 * Return the next item ID, loops at the first id to return the last
2232
	 *
2233
	 * @param int|null          $id
2234
	 * @param array|object|null $params_override
2235
	 *
2236
	 * @return int
2237
	 * @since 2.0
2238
	 */
2239
	public function next_id( $id = null, $params_override = null ) {
2240
2241
		if ( null === $id ) {
2242
			$id = $this->id();
2243
		}
2244
2245
		$id = (int) $id;
2246
2247
		$params = array(
2248
			'select'  => "`t`.`{$this->data->field_id}`",
2249
			'where'   => "{$id} < `t`.`{$this->data->field_id}`",
2250
			'orderby' => "`t`.`{$this->data->field_id}` ASC",
2251
			'limit'   => 1
2252
		);
2253
2254
		if ( ! empty( $params_override ) || ! empty( $this->params ) ) {
2255 View Code Duplication
			if ( ! empty( $params_override ) ) {
2256
				$params = $params_override;
2257
			} elseif ( ! empty( $this->params ) ) {
2258
				$params = $this->params;
2259
			}
2260
2261
			if ( is_object( $params ) ) {
2262
				$params = get_object_vars( $params );
2263
			}
2264
2265
			if ( 0 < $id ) {
2266 View Code Duplication
				if ( isset( $params['where'] ) && ! empty( $params['where'] ) ) {
2267
					$params['where']   = (array) $params['where'];
2268
					$params['where'][] = "{$id} < `t`.`{$this->data->field_id}`";
2269
				} else {
2270
					$params['where'] = "{$id} < `t`.`{$this->data->field_id}`";
2271
				}
2272
			} elseif ( ! isset( $params['offset'] ) ) {
2273
				if ( ! empty( $this->params ) && - 1 < $this->row_number ) {
2274
					$params['offset'] = $this->row_number + 1;
2275
				} else {
2276
					$params['offset'] = 1;
2277
				}
2278
			} else {
2279
				$params['offset'] ++;
2280
			}
2281
2282
			$params['select'] = "`t`.`{$this->data->field_id}`";
2283
			$params['limit']  = 1;
2284
		}
2285
2286
		$pod = pods( $this->pod, $params );
2287
2288
		$new_id = 0;
2289
2290
		if ( $pod->fetch() ) {
2291
			$new_id = $pod->id();
2292
		}
2293
2294
		$new_id = $this->do_hook( 'next_id', $new_id, $id, $pod, $params_override );
2295
2296
		return $new_id;
2297
	}
2298
2299
	/**
2300
	 * Return the first item ID
2301
	 *
2302
	 * @param array|object|null $params_override
2303
	 *
2304
	 * @return int
2305
	 * @since 2.3
2306
	 */
2307
	public function first_id( $params_override = null ) {
2308
2309
		$params = array(
2310
			'select'  => "`t`.`{$this->data->field_id}`",
2311
			'orderby' => "`t`.`{$this->data->field_id}` ASC",
2312
			'limit'   => 1
2313
		);
2314
2315
		if ( ! empty( $params_override ) || ! empty( $this->params ) ) {
2316 View Code Duplication
			if ( ! empty( $params_override ) ) {
2317
				$params = $params_override;
2318
			} elseif ( ! empty( $this->params ) ) {
2319
				$params = $this->params;
2320
			}
2321
2322
			if ( is_object( $params ) ) {
2323
				$params = get_object_vars( $params );
2324
			}
2325
2326
			$params['select'] = "`t`.`{$this->data->field_id}`";
2327
			$params['offset'] = 0;
2328
			$params['limit']  = 1;
2329
		}
2330
2331
		$pod = pods( $this->pod, $params );
2332
2333
		$new_id = 0;
2334
2335
		if ( $pod->fetch() ) {
2336
			$new_id = $pod->id();
2337
		}
2338
2339
		$new_id = $this->do_hook( 'first_id', $new_id, $pod, $params_override );
2340
2341
		return $new_id;
2342
	}
2343
2344
	/**
2345
	 * Return the last item ID
2346
	 *
2347
	 * @param array|object|null $params_override
2348
	 *
2349
	 * @return int
2350
	 * @since 2.3
2351
	 */
2352
	public function last_id( $params_override = null ) {
2353
2354
		$params = array(
2355
			'select'  => "`t`.`{$this->data->field_id}`",
2356
			'orderby' => "`t`.`{$this->data->field_id}` DESC",
2357
			'limit'   => 1
2358
		);
2359
2360
		if ( ! empty( $params_override ) || ! empty( $this->params ) ) {
2361 View Code Duplication
			if ( ! empty( $params_override ) ) {
2362
				$params = $params_override;
2363
			} elseif ( ! empty( $this->params ) ) {
2364
				$params = $this->params;
2365
			}
2366
2367
			if ( is_object( $params ) ) {
2368
				$params = get_object_vars( $params );
2369
			}
2370
2371
			if ( isset( $params['total_found'] ) ) {
2372
				$params['offset'] = $params['total_found'] - 1;
2373
			} else {
2374
				$params['offset'] = $this->total_found() - 1;
2375
			}
2376
2377 View Code Duplication
			if ( isset( $params['orderby'] ) && ! empty( $params['orderby'] ) ) {
2378
				if ( is_array( $params['orderby'] ) ) {
2379
					foreach ( $params['orderby'] as $orderby => $dir ) {
2380
						$dir = strtoupper( $dir );
2381
2382
						if ( ! in_array( $dir, array( 'ASC', 'DESC' ), true ) ) {
2383
							continue;
2384
						}
2385
2386
						if ( 'ASC' === $dir ) {
2387
							$params['orderby'][ $orderby ] = 'DESC';
2388
						} else {
2389
							$params['orderby'][ $orderby ] = 'ASC';
2390
						}
2391
					}
2392
2393
					$params['orderby'][ $this->data->field_id ] = 'DESC';
2394
				} elseif ( "`t`.`{$this->data->field_id}` DESC" !== $params['orderby'] ) {
2395
					$params['orderby'] .= ", `t`.`{$this->data->field_id}` DESC";
2396
				}
2397
			}
2398
2399
			$params['select'] = "`t`.`{$this->data->field_id}`";
2400
			$params['limit']  = 1;
2401
		}
2402
2403
		$pod = pods( $this->pod, $params );
2404
2405
		$new_id = 0;
2406
2407
		if ( $pod->fetch() ) {
2408
			$new_id = $pod->id();
2409
		}
2410
2411
		$new_id = $this->do_hook( 'last_id', $new_id, $pod, $params_override );
2412
2413
		return $new_id;
2414
	}
2415
2416
	/**
2417
	 * Return the item name
2418
	 *
2419
	 * @return string
2420
	 * @since 2.0
2421
	 */
2422
	public function index() {
2423
2424
		return $this->field( $this->data->field_index );
2425
	}
2426
2427
	/**
2428
	 * Find items of a pod, much like WP_Query, but with advanced table handling.
2429
	 *
2430
	 * @param array|object $params An associative array of parameters
2431
	 * @param int          $limit  (optional) (deprecated) Limit the number of items to find, use -1 to return all items with
2432
	 *                             no limit
2433
	 * @param string       $where  (optional) (deprecated) SQL WHERE declaration to use
2434
	 * @param string       $sql    (optional) (deprecated) For advanced use, a custom SQL query to run
2435
	 *
2436
	 * @return \Pods The pod object
2437
	 * @since 2.0
2438
	 * @link  https://pods.io/docs/find/
2439
	 */
2440
	public function find( $params = null, $limit = 15, $where = null, $sql = null ) {
2441
2442
		$tableless_field_types    = PodsForm::tableless_field_types();
2443
		$simple_tableless_objects = PodsForm::simple_tableless_objects();
2444
2445
		$this->params = $params;
2446
2447
		$select = '`t`.*';
2448
2449
		if ( 'table' === $this->pod_data['storage'] && ! in_array( $this->pod_data['type'], array(
2450
				'pod',
2451
				'table',
2452
			), true ) ) {
2453
			$select .= ', `d`.*';
2454
		}
2455
2456
		if ( empty( $this->data->table ) ) {
2457
			return $this;
2458
		}
2459
2460
		$defaults = array(
2461
			'table'  => $this->data->table,
2462
			'select' => $select,
2463
			'join'   => null,
2464
2465
			'where'   => $where,
2466
			'groupby' => null,
2467
			'having'  => null,
2468
			'orderby' => null,
2469
2470
			'limit'      => (int) $limit,
2471
			'offset'     => null,
2472
			'page'       => (int) $this->page,
2473
			'page_var'   => $this->page_var,
2474
			'pagination' => (boolean) $this->pagination,
2475
2476
			'search'              => (boolean) $this->search,
2477
			'search_var'          => $this->search_var,
2478
			'search_query'        => null,
2479
			'search_mode'         => $this->search_mode,
2480
			'search_across'       => false,
2481
			'search_across_picks' => false,
2482
			'search_across_files' => false,
2483
2484
			'filters' => $this->filters,
2485
			'sql'     => $sql,
2486
2487
			'expires'    => null,
2488
			'cache_mode' => 'cache',
2489
		);
2490
2491
		if ( is_array( $params ) ) {
2492
			$params = (object) array_merge( $defaults, $params );
2493
		} elseif ( is_object( $params ) ) {
2494
			$params = (object) array_merge( $defaults, get_object_vars( $params ) );
2495
		} else {
2496
			$defaults['orderby'] = $params;
2497
			$params              = (object) $defaults;
2498
		}
2499
2500
		/**
2501
		 * Filter the Pods::find() parameters.
2502
		 *
2503
		 * @param object $params Parameters to make lookup with.
2504
		 */
2505
		$params = apply_filters( 'pods_pods_find', $params );
2506
2507
		$params->limit = (int) $params->limit;
2508
2509
		if ( 0 === $params->limit ) {
2510
			$params->limit = - 1;
2511
		}
2512
2513
		$this->limit      = (int) $params->limit;
2514
		$this->offset     = (int) $params->offset;
2515
		$this->page       = (int) $params->page;
2516
		$this->page_var   = $params->page_var;
2517
		$this->pagination = (boolean) $params->pagination;
2518
		$this->search     = (boolean) $params->search;
2519
		$this->search_var = $params->search_var;
2520
		$params->join     = (array) $params->join;
2521
2522
		if ( empty( $params->search_query ) ) {
2523
			$params->search_query = pods_v_sanitized( $this->search_var, 'get', '' );
2524
		}
2525
2526
		// Allow orderby array ( 'field' => 'asc|desc' )
0 ignored issues
show
Unused Code Comprehensibility introduced by
38% 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...
2527
		if ( ! empty( $params->orderby ) && is_array( $params->orderby ) ) {
2528
			foreach ( $params->orderby as $k => &$orderby ) {
2529
				if ( ! is_numeric( $k ) ) {
2530
					$key = '';
2531
2532
					$order = 'ASC';
2533
2534
					if ( 'DESC' === strtoupper( $orderby ) ) {
2535
						$order = 'DESC';
2536
					}
2537
2538
					if ( isset( $this->fields[ $k ] ) && in_array( $this->fields[ $k ]['type'], $tableless_field_types, true ) ) {
2539
						if ( in_array( $this->fields[ $k ]['pick_object'], $simple_tableless_objects, true ) ) {
2540
							if ( 'table' === $this->pod_data['storage'] ) {
2541
								if ( ! in_array( $this->pod_data['type'], array( 'pod', 'table' ), true ) ) {
2542
									$key = "`d`.`{$k}`";
2543
								} else {
2544
									$key = "`t`.`{$k}`";
2545
								}
2546
							} else {
2547
								$key = "`{$k}`.`meta_value`";
2548
							}
2549
						} else {
2550
							$pick_val = $this->fields[ $k ]['pick_val'];
2551
2552
							if ( '__current__' === $pick_val ) {
2553
								$pick_val = $this->pod;
2554
							}
2555
2556
							$table = $this->api->get_table_info( $this->fields[ $k ]['pick_object'], $pick_val );
2557
2558
							if ( ! empty( $table ) ) {
2559
								$key = "`{$k}`.`" . $table['field_index'] . '`';
2560
							}
2561
						}
2562
					}
2563
2564
					if ( empty( $key ) ) {
2565 View Code Duplication
						if ( ! in_array( $this->pod_data['type'], array( 'pod', 'table' ), true ) ) {
2566
							if ( isset( $this->pod_data['object_fields'][ $k ] ) ) {
2567
								$key = "`t`.`{$k}`";
2568
							} elseif ( isset( $this->fields[ $k ] ) ) {
2569
								if ( 'table' === $this->pod_data['storage'] ) {
2570
									$key = "`d`.`{$k}`";
2571
								} else {
2572
									$key = "`{$k}`.`meta_value`";
2573
								}
2574
							} else {
2575
								$object_fields = (array) $this->pod_data['object_fields'];
2576
2577
								foreach ( $object_fields as $object_field => $object_field_opt ) {
2578
									if ( $object_field === $k || in_array( $k, $object_field_opt['alias'], true ) ) {
2579
										$key = "`t`.`{$object_field}`";
2580
									}
2581
								}
2582
							}
2583
						} elseif ( isset( $this->fields[ $k ] ) ) {
2584
							if ( 'table' === $this->pod_data['storage'] ) {
2585
								$key = "`t`.`{$k}`";
2586
							} else {
2587
								$key = "`{$k}`.`meta_value`";
2588
							}
2589
						}
2590
2591
						if ( empty( $key ) ) {
2592
							$key = $k;
2593
2594
							if ( false === strpos( $key, ' ' ) && false === strpos( $key, '`' ) ) {
2595
								$key = '`' . str_replace( '.', '`.`', $key ) . '`';
2596
							}
2597
						}
2598
					}
2599
2600
					$orderby = $key;
2601
2602
					if ( false === strpos( $orderby, ' ' ) ) {
2603
						$orderby .= ' ' . $order;
2604
					}
2605
				}
2606
			}
2607
		}
2608
2609
		// Add prefix to $params->orderby if needed
2610
		if ( ! empty( $params->orderby ) ) {
2611
			if ( ! is_array( $params->orderby ) ) {
2612
				$params->orderby = array( $params->orderby );
2613
			}
2614
2615
			foreach ( $params->orderby as &$prefix_orderby ) {
2616
				if ( false === strpos( $prefix_orderby, ',' ) && false === strpos( $prefix_orderby, '(' ) && false === stripos( $prefix_orderby, ' AS ' ) && false === strpos( $prefix_orderby, '`' ) && false === strpos( $prefix_orderby, '.' ) ) {
2617
					if ( false !== stripos( $prefix_orderby, ' DESC' ) ) {
2618
						$k   = trim( str_ireplace( array( '`', ' DESC' ), '', $prefix_orderby ) );
2619
						$dir = 'DESC';
2620
					} else {
2621
						$k   = trim( str_ireplace( array( '`', ' ASC' ), '', $prefix_orderby ) );
2622
						$dir = 'ASC';
2623
					}
2624
2625
					$key = $k;
2626
2627 View Code Duplication
					if ( ! in_array( $this->pod_data['type'], array( 'pod', 'table' ), true ) ) {
2628
						if ( isset( $this->pod_data['object_fields'][ $k ] ) ) {
2629
							$key = "`t`.`{$k}`";
2630
						} elseif ( isset( $this->fields[ $k ] ) ) {
2631
							if ( 'table' === $this->pod_data['storage'] ) {
2632
								$key = "`d`.`{$k}`";
2633
							} else {
2634
								$key = "`{$k}`.`meta_value`";
2635
							}
2636
						} else {
2637
							$object_fields = (array) $this->pod_data['object_fields'];
2638
2639
							foreach ( $object_fields as $object_field => $object_field_opt ) {
2640
								if ( $object_field === $k || in_array( $k, $object_field_opt['alias'], true ) ) {
2641
									$key = "`t`.`{$object_field}`";
2642
								}
2643
							}
2644
						}
2645
					} elseif ( isset( $this->fields[ $k ] ) ) {
2646
						if ( 'table' === $this->pod_data['storage'] ) {
2647
							$key = "`t`.`{$k}`";
2648
						} else {
2649
							$key = "`{$k}`.`meta_value`";
2650
						}
2651
					}
2652
2653
					$prefix_orderby = "{$key} {$dir}";
2654
				}
2655
			}
2656
		}
2657
2658
		$this->data->select( $params );
2659
2660
		return $this;
2661
	}
2662
2663
	/**
2664
	 * Fetch an item from a Pod. If $id is null, it will return the next item in the list after running find().
2665
	 * You can rewind the list back to the start by using reset().
2666
	 *
2667
	 * Providing an $id will fetch a specific item from a Pod, much like a call to pods(), and can handle either an id
2668
	 * or slug.
2669
	 *
2670
	 * @see   PodsData::fetch
2671
	 *
2672
	 * @param int  $id           ID or slug of the item to fetch
2673
	 * @param bool $explicit_set Whether to set explicitly (use false when in loop)
2674
	 *
2675
	 * @return array An array of fields from the row
2676
	 *
2677
	 * @since 2.0
2678
	 * @link  https://pods.io/docs/fetch/
2679
	 */
2680
	public function fetch( $id = null, $explicit_set = true ) {
2681
2682
		/**
2683
		 * Runs directly before an item is fetched by fetch()
2684
		 *
2685
		 * @since unknown
2686
		 *
2687
		 * @param int|string|null $id   Item ID being fetched or null.
2688
		 * @param object|Pods     $this Current Pods object.
2689
		 */
2690
		do_action( 'pods_pods_fetch', $id, $this );
2691
2692
		if ( ! empty( $id ) ) {
2693
			$this->params = array();
2694
		}
2695
2696
		$this->data->fetch( $id, $explicit_set );
2697
2698
		return $this->row;
2699
	}
2700
2701
	/**
2702
	 * (Re)set the MySQL result pointer
2703
	 *
2704
	 * @see   PodsData::reset
2705
	 *
2706
	 * @param int $row ID of the row to reset to
2707
	 *
2708
	 * @return \Pods The pod object
2709
	 *
2710
	 * @since 2.0
2711
	 * @link  https://pods.io/docs/reset/
2712
	 */
2713
	public function reset( $row = null ) {
2714
2715
		/**
2716
		 * Runs directly before the Pods object is reset by reset()
2717
		 *
2718
		 * @since unknown
2719
		 *
2720
		 * @param int|string|null The ID of the row being reset to or null if being reset to the beginning.
2721
		 * @param object|Pods $this Current Pods object.
2722
		 */
2723
		do_action( 'pods_pods_reset', $row, $this );
2724
2725
		$this->data->reset( $row );
2726
2727
		return $this;
2728
	}
2729
2730
	/**
2731
	 * Fetch the total row count returned by the last call to find(), based on the 'limit' parameter set.
2732
	 *
2733
	 * This is different than the total number of rows found in the database, which you can get with total_found().
2734
	 *
2735
	 * @see   PodsData::total
2736
	 *
2737
	 * @return int Number of rows returned by find(), based on the 'limit' parameter set
2738
	 * @since 2.0
2739
	 * @link  https://pods.io/docs/total/
2740
	 */
2741
	public function total() {
2742
2743
		do_action( 'pods_pods_total', $this );
2744
2745
		$this->data->total();
0 ignored issues
show
Unused Code introduced by
The call to the method PodsData::total() seems un-needed as the method has no side-effects.

PHP Analyzer performs a side-effects analysis of your code. A side-effect is basically anything that might be visible after the scope of the method is left.

Let’s take a look at an example:

class User
{
    private $email;

    public function getEmail()
    {
        return $this->email;
    }

    public function setEmail($email)
    {
        $this->email = $email;
    }
}

If we look at the getEmail() method, we can see that it has no side-effect. Whether you call this method or not, no future calls to other methods are affected by this. As such code as the following is useless:

$user = new User();
$user->getEmail(); // This line could safely be removed as it has no effect.

On the hand, if we look at the setEmail(), this method _has_ side-effects. In the following case, we could not remove the method call:

$user = new User();
$user->setEmail('email@domain'); // This line has a side-effect (it changes an
                                 // instance variable).
Loading history...
2746
2747
		$this->total =& $this->data->total;
2748
2749
		return $this->total;
2750
	}
2751
2752
	/**
2753
	 * Fetch the total amount of rows found by the last call to find(), regardless of the 'limit' parameter set.
2754
	 *
2755
	 * This is different than the total number of rows limited by the current call, which you can get with total().
2756
	 *
2757
	 * @see   PodsData::total_found
2758
	 *
2759
	 * @return int Number of rows returned by find(), regardless of the 'limit' parameter
2760
	 * @since 2.0
2761
	 * @link  https://pods.io/docs/total-found/
2762
	 */
2763
	public function total_found() {
2764
2765
		/**
2766
		 * Runs directly before the value of total_found() is determined and returned.
2767
		 *
2768
		 * @since unknown
2769
		 *
2770
		 * @param object|Pods $this Current Pods object.
2771
		 *
2772
		 */
2773
		do_action( 'pods_pods_total_found', $this );
2774
2775
		$this->data->total_found();
2776
2777
		$this->total_found =& $this->data->total_found;
2778
2779
		return $this->total_found;
2780
	}
2781
2782
	/**
2783
	 * Fetch the total number of pages, based on total rows found and the last find() limit
2784
	 *
2785
	 * @param null|int $limit  Rows per page
2786
	 * @param null|int $offset Offset of rows
2787
	 * @param null|int $total  Total rows
2788
	 *
2789
	 * @return int Number of pages
2790
	 * @since 2.3.10
2791
	 */
2792
	public function total_pages( $limit = null, $offset = null, $total = null ) {
2793
2794
		$this->do_hook( 'total_pages' );
2795
2796
		if ( null === $limit ) {
2797
			$limit = $this->limit;
2798
		}
2799
2800
		if ( null === $offset ) {
2801
			$offset = $this->offset;
2802
		}
2803
2804
		if ( null === $total ) {
2805
			$total = $this->total_found();
2806
		}
2807
2808
		return ceil( ( $total - $offset ) / $limit );
2809
2810
	}
2811
2812
	/**
2813
	 * Fetch the zebra switch
2814
	 *
2815
	 * @see   PodsData::zebra
2816
	 *
2817
	 * @return bool Zebra state
2818
	 * @since 1.12
2819
	 */
2820
	public function zebra() {
2821
2822
		$this->do_hook( 'zebra' );
2823
2824
		return $this->data->zebra();
2825
	}
2826
2827
	/**
2828
	 * Fetch the nth state
2829
	 *
2830
	 * @see   PodsData::nth
2831
	 *
2832
	 * @param int|string $nth The $nth to match on the PodsData::row_number
2833
	 *
2834
	 * @return bool Whether $nth matches
2835
	 * @since 2.3
2836
	 */
2837
	public function nth( $nth = null ) {
2838
2839
		$this->do_hook( 'nth', $nth );
2840
2841
		return $this->data->nth( $nth );
2842
	}
2843
2844
	/**
2845
	 * Fetch the current position in the loop (starting at 1)
2846
	 *
2847
	 * @see   PodsData::position
2848
	 *
2849
	 * @return int Current row number (+1)
2850
	 * @since 2.3
2851
	 */
2852
	public function position() {
2853
2854
		$this->do_hook( 'position' );
2855
2856
		return $this->data->position();
2857
	}
2858
2859
	/**
2860
	 * Add an item to a Pod by giving an array of field data or set a specific field to
2861
	 * a specific value if you're just wanting to add a new item but only set one field.
2862
	 *
2863
	 * You may be looking for save() in most cases where you're setting a specific field.
2864
	 *
2865
	 * @see   PodsAPI::save_pod_item
2866
	 *
2867
	 * @param array|string $data  Either an associative array of field information or a field name
2868
	 * @param mixed        $value (optional) Value of the field, if $data is a field name
2869
	 *
2870
	 * @return int The item ID
2871
	 *
2872
	 * @since 2.0
2873
	 * @link  https://pods.io/docs/add/
2874
	 */
2875
	public function add( $data = null, $value = null ) {
2876
2877
		if ( null !== $value ) {
2878
			$data = array( $data => $value );
2879
		}
2880
2881
		$data = (array) $this->do_hook( 'add', $data );
2882
2883
		if ( empty( $data ) ) {
2884
			return 0;
2885
		}
2886
2887
		$params = array(
2888
			'pod'                 => $this->pod,
2889
			'data'                => $data,
2890
			'allow_custom_fields' => true
2891
		);
2892
2893
		return $this->api->save_pod_item( $params );
2894
	}
2895
2896
	/**
2897
	 * Add an item to the values of a relationship field, add a value to a number field (field+1), add time to a date
2898
	 * field, or add text to a text field
2899
	 *
2900
	 * @see   PodsAPI::save_pod_item
2901
	 *
2902
	 * @param string $field Field name
2903
	 * @param mixed  $value ID(s) to add, int|float to add to number field, string for dates (+1 week), or string for
2904
	 *                      text
2905
	 * @param int    $id    (optional) ID of the pod item to update
2906
	 *
2907
	 * @return int The item ID
2908
	 *
2909
	 * @since 2.3
2910
	 */
2911
	public function add_to( $field, $value, $id = null ) {
2912
2913
		$pod =& $this;
2914
2915
		$fetch = false;
2916
2917 View Code Duplication
		if ( null === $id ) {
2918
			$fetch = true;
2919
2920
			$id = $pod->id();
2921
		} elseif ( $id != $this->id() ) {
2922
			$pod = pods( $this->pod, $id );
2923
		}
2924
2925
		$this->do_hook( 'add_to', $field, $value, $id );
2926
2927
		if ( ! isset( $this->fields[ $field ] ) ) {
2928
			return $id;
2929
		}
2930
2931
		// Tableless fields
2932
		if ( in_array( $this->fields[ $field ]['type'], PodsForm::tableless_field_types(), true ) ) {
2933
			if ( ! is_array( $value ) ) {
2934
				$value = explode( ',', $value );
2935
			}
2936
2937
			if ( 'pick' === $this->fields[ $field ]['type'] && in_array( $this->fields[ $field ]['pick_object'], PodsForm::simple_tableless_objects(), true ) ) {
2938
				$current_value = $pod->raw( $field );
2939
2940
				if ( ! empty( $current_value ) || ( ! is_array( $current_value ) && 0 < strlen( $current_value ) ) ) {
2941
					$current_value = (array) $current_value;
2942
				} else {
2943
					$current_value = array();
2944
				}
2945
2946
				$value = array_merge( $current_value, $value );
2947
			} else {
2948
				$related_ids = $this->api->lookup_related_items( $this->fields[ $field ]['id'], $this->pod_data['id'], $id, $this->fields[ $field ], $this->pod_data );
2949
2950
				foreach ( $value as $k => $v ) {
2951
					if ( ! preg_match( '/[^\D]/', $v ) ) {
2952
						$value[ $k ] = (int) $v;
2953
					}
2954
				}
2955
2956
				$value = array_merge( $related_ids, $value );
2957
			}
2958
2959
			if ( ! empty( $value ) ) {
2960
				$value = array_filter( array_unique( $value ) );
2961
			} else {
2962
				$value = array();
2963
			}
2964
2965
			if ( empty( $value ) ) {
2966
				return $id;
2967
			}
2968
		} // Number fields
2969 View Code Duplication
		elseif ( in_array( $this->fields[ $field ]['type'], PodsForm::number_field_types(), true ) ) {
2970
			$current_value = (float) $pod->raw( $field );
2971
2972
			$value = ( $current_value + (float) $value );
2973
		} // Date fields
2974
		elseif ( in_array( $this->fields[ $field ]['type'], PodsForm::date_field_types(), true ) ) {
2975
			$current_value = $pod->raw( $field );
2976
2977 View Code Duplication
			if ( 0 < strlen( $current_value ) ) {
2978
				$value = strtotime( $value, strtotime( $current_value ) );
2979
			} else {
2980
				$value = strtotime( $value );
2981
			}
2982
		} // Text fields
2983 View Code Duplication
		elseif ( in_array( $this->fields[ $field ]['type'], PodsForm::text_field_types(), true ) ) {
2984
			$current_value = $pod->raw( $field );
2985
2986
			if ( 0 < strlen( $current_value ) ) {
2987
				$value = $current_value . $value;
2988
			}
2989
		}
2990
2991
		// @todo handle object fields and taxonomies
2992
2993
		$params = array(
2994
			'pod'  => $this->pod,
2995
			'id'   => $id,
2996
			'data' => array(
2997
				$field => $value
2998
			)
2999
		);
3000
3001
		$id = $this->api->save_pod_item( $params );
3002
3003 View Code Duplication
		if ( 0 < $id && $fetch ) {
3004
			// Clear local var cache of field values
3005
			$pod->data->row = array();
3006
3007
			$pod->fetch( $id, false );
3008
		}
3009
3010
		return $id;
3011
	}
3012
3013
	/**
3014
	 * Remove an item from the values of a relationship field, remove a value from a number field (field-1), remove
3015
	 * time to a date field
3016
	 *
3017
	 * @see   PodsAPI::save_pod_item
3018
	 *
3019
	 * @param string $field Field name
3020
	 * @param mixed  $value ID(s) to add, int|float to add to number field, string for dates (-1 week), or string for
3021
	 *                      text
3022
	 * @param int    $id    (optional) ID of the pod item to update
3023
	 *
3024
	 * @return int The item ID
3025
	 *
3026
	 * @since 2.3.3
3027
	 */
3028
	public function remove_from( $field, $value = null, $id = null ) {
3029
3030
		$pod =& $this;
3031
3032
		$fetch = false;
3033
3034 View Code Duplication
		if ( null === $id ) {
3035
			$fetch = true;
3036
3037
			$id = $this->id();
3038
		} elseif ( $id != $this->id() ) {
3039
			$pod = pods( $this->pod, $id );
3040
		}
3041
3042
		$this->do_hook( 'remove_from', $field, $value, $id );
3043
3044
		if ( ! isset( $this->fields[ $field ] ) ) {
3045
			return $id;
3046
		}
3047
3048
		// Tableless fields
3049
		if ( in_array( $this->fields[ $field ]['type'], PodsForm::tableless_field_types(), true ) ) {
3050
			if ( empty( $value ) ) {
3051
				$value = array();
3052
			}
3053
3054
			if ( ! empty( $value ) ) {
3055
				if ( ! is_array( $value ) ) {
3056
					$value = explode( ',', $value );
3057
				}
3058
3059
				if ( 'pick' === $this->fields[ $field ]['type'] && in_array( $this->fields[ $field ]['pick_object'], PodsForm::simple_tableless_objects(), true ) ) {
3060
					$current_value = $pod->raw( $field );
3061
3062
					if ( ! empty( $current_value ) ) {
3063
						$current_value = (array) $current_value;
3064
					}
3065
3066
					foreach ( $current_value as $k => $v ) {
3067
						if ( in_array( $v, $value ) ) {
3068
							unset( $current_value[ $k ] );
3069
						}
3070
					}
3071
3072
					$value = $current_value;
3073
				} else {
3074
					$related_ids = $this->api->lookup_related_items( $this->fields[ $field ]['id'], $this->pod_data['id'], $id, $this->fields[ $field ], $this->pod_data );
3075
3076
					foreach ( $value as $k => $v ) {
3077
						if ( ! preg_match( '/[^\D]/', $v ) ) {
3078
							$value[ $k ] = (int) $v;
3079
						}
3080
3081
						// @todo Convert slugs into IDs
3082
					}
3083
3084
					foreach ( $related_ids as $k => $v ) {
3085
						if ( in_array( $v, $value ) ) {
3086
							unset( $related_ids[ $k ] );
3087
						}
3088
					}
3089
3090
					$value = $related_ids;
3091
				}
3092
3093
				if ( ! empty( $value ) ) {
3094
					$value = array_filter( array_unique( $value ) );
3095
				} else {
3096
					$value = array();
3097
				}
3098
			}
3099
		} // Number fields
3100 View Code Duplication
		elseif ( in_array( $this->fields[ $field ]['type'], PodsForm::number_field_types(), true ) ) {
3101
			// Date fields don't support empty for removing
3102
			if ( empty( $value ) ) {
3103
				return $id;
3104
			}
3105
3106
			$current_value = (float) $pod->raw( $field );
3107
3108
			$value = ( $current_value - (float) $value );
3109
		} // Date fields
3110
		elseif ( in_array( $this->fields[ $field ]['type'], PodsForm::date_field_types(), true ) ) {
3111
			// Date fields don't support empty for removing
3112
			if ( empty( $value ) ) {
3113
				return $id;
3114
			}
3115
3116
			$current_value = $pod->raw( $field );
3117
3118 View Code Duplication
			if ( 0 < strlen( $current_value ) ) {
3119
				$value = strtotime( $value, strtotime( $current_value ) );
3120
			} else {
3121
				$value = strtotime( $value );
3122
			}
3123
3124
			$value = date_i18n( 'Y-m-d h:i:s', $value );
3125
		}
3126
3127
		// @todo handle object fields and taxonomies
3128
3129
		$params = array(
3130
			'pod'  => $this->pod,
3131
			'id'   => $id,
3132
			'data' => array(
3133
				$field => $value
3134
			)
3135
		);
3136
3137
		$id = $this->api->save_pod_item( $params );
3138
3139 View Code Duplication
		if ( 0 < $id && $fetch ) {
3140
			// Clear local var cache of field values
3141
			$pod->data->row = array();
3142
3143
			$pod->fetch( $id, false );
3144
		}
3145
3146
		return $id;
3147
3148
	}
3149
3150
	/**
3151
	 * Save an item by giving an array of field data or set a specific field to a specific value.
3152
	 *
3153
	 * Though this function has the capacity to add new items, best practice should direct you
3154
	 * to use add() for that instead.
3155
	 *
3156
	 * @see   PodsAPI::save_pod_item
3157
	 *
3158
	 * @param array|string $data   Either an associative array of field information or a field name
3159
	 * @param mixed        $value  (optional) Value of the field, if $data is a field name
3160
	 * @param int          $id     (optional) ID of the pod item to update
3161
	 * @param array        $params (optional) Additional params to send to save_pod_item
3162
	 *
3163
	 * @return int The item ID
3164
	 *
3165
	 * @since 2.0
3166
	 * @link  https://pods.io/docs/save/
3167
	 */
3168
	public function save( $data = null, $value = null, $id = null, $params = null ) {
3169
3170
		if ( null !== $value ) {
3171
			$data = array( $data => $value );
3172
		}
3173
3174
		$fetch = false;
3175
3176
		if ( null === $id || ( $this->row && $id == $this->id() ) ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->row of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
3177
			$fetch = true;
3178
3179
			if ( null === $id ) {
3180
				$id = $this->id();
3181
			}
3182
		}
3183
3184
		$data = (array) $this->do_hook( 'save', $data, $id );
3185
3186
		if ( empty( $data ) && empty( $params['is_new_item'] ) ) {
3187
			return $id;
3188
		}
3189
3190
		$default = array();
3191
3192
		if ( ! empty( $params ) && is_array( $params ) ) {
3193
			$default = $params;
3194
		}
3195
3196
		$params = array(
3197
			'pod'                 => $this->pod,
3198
			'id'                  => $id,
3199
			'data'                => $data,
3200
			'allow_custom_fields' => true,
3201
			'clear_slug_cache'    => false
3202
		);
3203
3204
		if ( ! empty( $default ) ) {
3205
			$params = array_merge( $params, $default );
3206
		}
3207
3208
		$id = $this->api->save_pod_item( $params );
3209
3210 View Code Duplication
		if ( 0 < $id && $fetch ) {
3211
			// Clear local var cache of field values
3212
			$this->data->row = array();
3213
3214
			$this->fetch( $id, false );
3215
		}
3216
3217
		if ( ! empty( $this->pod_data['field_slug'] ) ) {
3218
			if ( 0 < $id && $fetch ) {
3219
				$slug = $this->field( $this->pod_data['field_slug'] );
3220
			} else {
3221
				$slug = pods( $this->pod, $id )->field( $this->pod_data['field_slug'] );
3222
			}
3223
3224
			if ( 0 < strlen( $slug ) ) {
3225
				pods_cache_clear( $slug, 'pods_items_' . $this->pod );
3226
			}
3227
		}
3228
3229
		return $id;
3230
	}
3231
3232
	/**
3233
	 * Delete an item
3234
	 *
3235
	 * @see   PodsAPI::delete_pod_item
3236
	 *
3237
	 * @param int $id ID of the Pod item to delete
3238
	 *
3239
	 * @return bool Whether the item was successfully deleted
3240
	 *
3241
	 * @since 2.0
3242
	 * @link  https://pods.io/docs/delete/
3243
	 */
3244 View Code Duplication
	public function delete( $id = null ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
3245
3246
		if ( null === $id ) {
3247
			$id = $this->id();
3248
		}
3249
3250
		$id = (int) $this->do_hook( 'delete', $id );
3251
3252
		if ( empty( $id ) ) {
3253
			return false;
3254
		}
3255
3256
		$params = array(
3257
			'pod' => $this->pod,
3258
			'id'  => $id
3259
		);
3260
3261
		return $this->api->delete_pod_item( $params );
3262
	}
3263
3264
	/**
3265
	 * Reset Pod
3266
	 *
3267
	 * @see   PodsAPI::reset_pod
3268
	 *
3269
	 * @return bool Whether the Pod was successfully reset
3270
	 *
3271
	 * @since 2.1.1
3272
	 */
3273
	public function reset_pod() {
3274
3275
		$params = array( 'id' => $this->pod_id );
3276
3277
		$this->data->id   = null;
3278
		$this->data->row  = array();
3279
		$this->data->data = array();
3280
3281
		$this->data->total       = 0;
3282
		$this->data->total_found = 0;
3283
3284
		return $this->api->reset_pod( $params );
3285
	}
3286
3287
	/**
3288
	 * Duplicate an item
3289
	 *
3290
	 * @see   PodsAPI::duplicate_pod_item
3291
	 *
3292
	 * @param int $id ID of the pod item to duplicate
3293
	 *
3294
	 * @return int|bool ID of the new pod item
3295
	 *
3296
	 * @since 2.0
3297
	 * @link  https://pods.io/docs/duplicate/
3298
	 */
3299 View Code Duplication
	public function duplicate( $id = null ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
3300
3301
		if ( null === $id ) {
3302
			$id = $this->id();
3303
		}
3304
3305
		$id = (int) $this->do_hook( 'duplicate', $id );
3306
3307
		if ( empty( $id ) ) {
3308
			return false;
3309
		}
3310
3311
		$params = array(
3312
			'pod' => $this->pod,
3313
			'id'  => $id
3314
		);
3315
3316
		return $this->api->duplicate_pod_item( $params );
3317
	}
3318
3319
	/**
3320
	 * Import data / Save multiple rows of data at once
3321
	 *
3322
	 * @see   PodsAPI::import
3323
	 *
3324
	 * @param mixed  $import_data  PHP associative array or CSV input
3325
	 * @param bool   $numeric_mode Use IDs instead of the name field when matching
3326
	 * @param string $format       Format of import data, options are php or csv
3327
	 *
3328
	 * @return array IDs of imported items
3329
	 *
3330
	 * @since 2.3
3331
	 */
3332
	public function import( $import_data, $numeric_mode = false, $format = null ) {
3333
3334
		return $this->api->import( $import_data, $numeric_mode, $format );
3335
	}
3336
3337
	/**
3338
	 * Export an item's data
3339
	 *
3340
	 * @see   PodsAPI::export_pod_item
3341
	 *
3342
	 * @param array       $fields (optional) Fields to export
3343
	 * @param int         $id     (optional) ID of the pod item to export
3344
	 * @param null|string $format (optional) The format of the export (php | json)
3345
	 *
3346
	 * @return array|bool Data array of the exported pod item
3347
	 *
3348
	 * @since 2.0
3349
	 * @link  https://pods.io/docs/export/
3350
	 */
3351
	public function export( $fields = null, $id = null, $format = null ) {
3352
3353
		$params = array(
3354
			'pod'     => $this->pod,
3355
			'id'      => $id,
3356
			'fields'  => null,
3357
			'depth'   => 2,
3358
			'flatten' => false,
3359
			'context' => null,
3360
			'format'  => $format,
3361
		);
3362
3363 View Code Duplication
		if ( is_array( $fields ) && ( isset( $fields['fields'] ) || isset( $fields['depth'] ) ) ) {
3364
			$params = array_merge( $params, $fields );
3365
		} else {
3366
			$params['fields'] = $fields;
3367
		}
3368
3369
		if ( isset( $params['fields'] ) && is_array( $params['fields'] ) && ! in_array( $this->pod_data['field_id'], $params['fields'], true ) ) {
3370
			$params['fields'] = array_merge( array( $this->pod_data['field_id'] ), $params['fields'] );
3371
		}
3372
3373
		if ( null === $params['id'] ) {
3374
			$params['id'] = $this->id();
3375
		}
3376
3377
		$params = (array) $this->do_hook( 'export', $params );
3378
3379
		if ( empty( $params['id'] ) ) {
3380
			return false;
3381
		}
3382
3383
		$data = $this->api->export_pod_item( $params );
3384
3385
		if ( ! empty( $params['format'] ) && 'json' === $params['format'] ) {
3386
			$data = json_encode( (array) $data );
3387
		}
3388
3389
		return $data;
3390
	}
3391
3392
	/**
3393
	 * Export data from all items
3394
	 *
3395
	 * @see   PodsAPI::export
3396
	 *
3397
	 * @param array $params An associative array of parameters
3398
	 *
3399
	 * @return array Data arrays of all exported pod items
3400
	 *
3401
	 * @since 2.3
3402
	 */
3403
	public function export_data( $params = null ) {
3404
3405
		$defaults = array(
3406
			'fields' => null,
3407
			'depth'  => 2,
3408
			'params' => null
3409
		);
3410
3411
		if ( empty( $params ) ) {
3412
			$params = $defaults;
3413
		} else {
3414
			$params = array_merge( $defaults, (array) $params );
3415
		}
3416
3417
		return $this->api->export( $this, $params );
3418
	}
3419
3420
	/**
3421
	 * Display the pagination controls, types supported by default
3422
	 * are simple, paginate and advanced. The base and format parameters
3423
	 * are used only for the paginate view.
3424
	 *
3425
	 * @var array|object $params Associative array of parameters
3426
	 *
3427
	 * @return string Pagination HTML
3428
	 * @since 2.0
3429
	 * @link  https://pods.io/docs/pagination/
3430
	 */
3431
	public function pagination( $params = null ) {
3432
3433
		if ( empty( $params ) ) {
3434
			$params = array();
3435
		} elseif ( ! is_array( $params ) ) {
3436
			$params = array( 'label' => $params );
3437
		}
3438
3439
		$this->page_var = pods_v( 'page_var', $params, $this->page_var );
3440
3441
		$url = pods_query_arg( null, null, $this->page_var );
3442
3443
		$append = '?';
3444
3445
		if ( false !== strpos( $url, '?' ) ) {
3446
			$append = '&';
3447
		}
3448
3449
		$defaults = array(
3450
			'type'        => 'advanced',
3451
			'label'       => __( 'Go to page:', 'pods' ),
3452
			'show_label'  => true,
3453
			'first_text'  => __( '&laquo; First', 'pods' ),
3454
			'prev_text'   => __( '&lsaquo; Previous', 'pods' ),
3455
			'next_text'   => __( 'Next &rsaquo;', 'pods' ),
3456
			'last_text'   => __( 'Last &raquo;', 'pods' ),
3457
			'prev_next'   => true,
3458
			'first_last'  => true,
3459
			'limit'       => (int) $this->limit,
3460
			'offset'      => (int) $this->offset,
3461
			'page'        => max( 1, (int) $this->page ),
3462
			'mid_size'    => 2,
3463
			'end_size'    => 1,
3464
			'total_found' => $this->total_found(),
3465
			'page_var'    => $this->page_var,
3466
			'base'        => "{$url}{$append}%_%",
3467
			'format'      => "{$this->page_var}=%#%",
3468
			'class'       => '',
3469
			'link_class'  => '',
3470
		);
3471
3472
		if ( is_object( $params ) ) {
3473
			$params = get_object_vars( $params );
3474
		}
3475
3476
		$params = (object) array_merge( $defaults, (array) $params );
3477
3478
		$params->total = $this->total_pages( $params->limit, $params->offset, $params->total_found );
3479
3480
		if ( $params->limit < 1 || $params->total_found < 1 || 1 === $params->total || $params->total_found <= $params->offset ) {
3481
			return $this->do_hook( 'pagination', $this->do_hook( 'pagination_' . $params->type, '', $params ), $params );
3482
		}
3483
3484
		$pagination = $params->type;
3485
3486
		if ( ! in_array( $params->type, array( 'simple', 'advanced', 'paginate', 'list' ), true ) ) {
3487
			$pagination = 'advanced';
3488
		}
3489
3490
		ob_start();
3491
3492
		pods_view( PODS_DIR . 'ui/front/pagination/' . $pagination . '.php', compact( array_keys( get_defined_vars() ) ) );
3493
3494
		$output = ob_get_clean();
3495
3496
		return $this->do_hook( 'pagination', $this->do_hook( 'pagination_' . $params->type, $output, $params ), $params );
3497
3498
	}
3499
3500
	/**
3501
	 * Return a filter form for searching a Pod
3502
	 *
3503
	 * @var array|string $params Comma-separated list of fields or array of parameters
3504
	 *
3505
	 * @return string Filters HTML
3506
	 *
3507
	 * @since 2.0
3508
	 * @link  https://pods.io/docs/filters/
3509
	 */
3510
	public function filters( $params = null ) {
3511
3512
		$defaults = array(
3513
			'fields' => $params,
3514
			'label'  => '',
3515
			'action' => '',
3516
			'search' => '',
3517
		);
3518
3519
		if ( is_array( $params ) ) {
3520
			$params = array_merge( $defaults, $params );
3521
		} else {
3522
			$params = $defaults;
3523
		}
3524
3525
		$pod =& $this;
3526
3527
		/**
3528
		 * Filter the Pods::filters() parameters.
3529
		 *
3530
		 * @param array $params Parameters to filter with.
3531
		 * @param Pods  $pod    Pods object.
3532
		 */
3533
		$params = apply_filters( 'pods_filters_params', $params, $pod );
3534
3535
		$fields = $params['fields'];
3536
3537 View Code Duplication
		if ( null !== $fields && ! is_array( $fields ) && 0 < strlen( $fields ) ) {
3538
			$fields = explode( ',', $fields );
3539
		}
3540
3541
		$object_fields = (array) pods_v( 'object_fields', $this->pod_data, array(), true );
3542
3543
		// Force array
3544
		if ( empty( $fields ) ) {
3545
			$fields = array();
3546
		} else {
3547
			$filter_fields = $fields; // Temporary
3548
3549
			$fields = array();
3550
3551
			foreach ( $filter_fields as $k => $field ) {
3552
				$name = $k;
3553
3554
				$defaults = array(
3555
					'name' => $name
3556
				);
3557
3558
				if ( ! is_array( $field ) ) {
3559
					$name = $field;
3560
3561
					$field = array(
3562
						'name' => $name
3563
					);
3564
				}
3565
3566
				$field = array_merge( $defaults, $field );
3567
3568
				$field['name'] = trim( $field['name'] );
3569
3570
				if ( pods_v( 'hidden', $field, false, true ) ) {
3571
					$field['type'] = 'hidden';
3572
				}
3573
3574
				if ( isset( $object_fields[ $field['name'] ] ) ) {
3575
					$fields[ $field['name'] ] = array_merge( $object_fields[ $field['name'] ], $field );
3576
				} elseif ( isset( $this->fields[ $field['name'] ] ) ) {
3577
					$fields[ $field['name'] ] = array_merge( $this->fields[ $field['name'] ], $field );
3578
				}
3579
			}
3580
3581
			unset( $filter_fields ); // Cleanup
3582
		}
3583
3584
		$this->filters = array_keys( $fields );
3585
3586
		$label = $params['label'];
3587
3588
		if ( '' === $label ) {
3589
			$label = __( 'Search', 'pods' );
3590
		}
3591
3592
		$action = $params['action'];
3593
3594
		$search = trim( $params['search'] );
3595
3596
		if ( '' === $search ) {
3597
			$search = pods_v_sanitized( $pod->search_var, 'get', '' );
3598
		}
3599
3600
		ob_start();
3601
3602
		pods_view( PODS_DIR . 'ui/front/filters.php', compact( array_keys( get_defined_vars() ) ) );
3603
3604
		$output = ob_get_clean();
3605
3606
		/**
3607
		 * Filter the HTML output of filters()
3608
		 *
3609
		 * @since unknown
3610
		 *
3611
		 * @param string      $output
3612
		 * @param array       $params Params array passed to filters().
3613
		 * @param object|Pods $this   Current Pods object.
3614
		 */
3615
		return apply_filters( 'pods_pods_filters', $output, $params, $this );
3616
	}
3617
3618
	/**
3619
	 * Run a helper within a Pod Page or WP Template
3620
	 *
3621
	 * @see   Pods_Helpers::helper
3622
	 *
3623
	 * @param string|array $helper Helper name
3624
	 * @param string       $value  Value to run the helper on
3625
	 * @param string       $name   Field name
3626
	 *
3627
	 * @return mixed Anything returned by the helper
3628
	 * @since 2.0
3629
	 */
3630
	public function helper( $helper, $value = null, $name = null ) {
3631
3632
		$params = array(
3633
			'helper'     => $helper,
3634
			'value'      => $value,
3635
			'name'       => $name,
3636
			'deprecated' => false
3637
		);
3638
3639
		if ( class_exists( 'Pods_Templates' ) ) {
3640
			$params['deprecated'] = Pods_Templates::$deprecated;
3641
		}
3642
3643
		if ( is_array( $helper ) ) {
3644
			$params = array_merge( $params, $helper );
3645
		}
3646
3647
		if ( class_exists( 'Pods_Helpers' ) ) {
3648
			$value = Pods_Helpers::helper( $params, $this );
3649
		} elseif ( function_exists( $params['helper'] ) ) {
3650
			$disallowed = array(
3651
				'system',
3652
				'exec',
3653
				'popen',
3654
				'eval',
3655
				'preg_replace',
3656
				'create_function',
3657
				'include',
3658
				'include_once',
3659
				'require',
3660
				'require_once',
3661
			);
3662
3663
			$allowed = array();
3664
3665
			/**
3666
			 * Allows adjusting the disallowed callbacks as needed.
3667
			 *
3668
			 * @param array $disallowed List of callbacks not allowed.
3669
			 * @param array $params     Parameters used by Pods::helper() method.
3670
			 *
3671
			 * @since 2.7
3672
			 */
3673
			$disallowed = apply_filters( 'pods_helper_disallowed_callbacks', $disallowed, $params );
3674
3675
			/**
3676
			 * Allows adjusting the allowed allowed callbacks as needed.
3677
			 *
3678
			 * @param array $allowed List of callbacks explicitly allowed.
3679
			 * @param array $params  Parameters used by Pods::helper() method.
3680
			 *
3681
			 * @since 2.7
3682
			 */
3683
			$allowed = apply_filters( 'pods_helper_allowed_callbacks', $allowed, $params );
3684
3685
			// Clean up helper callback (if string)
3686
			if ( is_string( $params['helper'] ) ) {
3687
				$params['helper'] = strip_tags( str_replace( array( '`', chr( 96 ) ), "'", $params['helper'] ) );
3688
			}
3689
3690
			$is_allowed = false;
3691
3692
			if ( ! empty( $allowed ) ) {
3693
				if ( in_array( $params['helper'], $allowed, true ) ) {
3694
					$is_allowed = true;
3695
				}
3696
			} elseif ( ! in_array( $params['helper'], $disallowed, true ) ) {
3697
				$is_allowed = true;
3698
			}
3699
3700
			if ( $is_allowed ) {
3701
				$value = call_user_func( $params['helper'], $value );
3702
			}
3703
		} else {
3704
			$value = apply_filters( $params['helper'], $value );
3705
		}
3706
3707
		return $value;
3708
	}
3709
3710
	/**
3711
	 * Display the page template
3712
	 *
3713
	 * @see   Pods_Templates::template
3714
	 *
3715
	 * @param string      $template_name The template name
3716
	 * @param string|null $code          Custom template code to use instead
3717
	 * @param bool        $deprecated    Whether to use deprecated functionality based on old function usage
3718
	 *
3719
	 * @return mixed Template output
3720
	 *
3721
	 * @since 2.0
3722
	 * @link  https://pods.io/docs/template/
3723
	 */
3724
	public function template( $template_name, $code = null, $deprecated = false ) {
3725
3726
		$out = null;
3727
3728
		$obj =& $this;
3729
3730
		if ( ! empty( $code ) ) {
3731
			$code = str_replace( '$this->', '$obj->', $code ); // backwards compatibility
3732
3733
			/**
3734
			 * Filter the template code before running it.
3735
			 *
3736
			 * @param string $code          Template code.
3737
			 * @param string $template_name Template name.
3738
			 * @param Pods  $pod            Pods object.
3739
			 */
3740
			$code = apply_filters( 'pods_templates_pre_template', $code, $template_name, $this );
3741
3742
			/**
3743
			 * Filter the template code before running it.
3744
			 *
3745
			 * @param string $code          Template code.
3746
			 * @param string $template_name Template name.
3747
			 * @param Pods  $pod            Pods object.
3748
			 */
3749
			$code = apply_filters( "pods_templates_pre_template_{$template_name}", $code, $template_name, $this );
3750
3751
			ob_start();
3752
3753
			if ( ! empty( $code ) ) {
3754
				// Only detail templates need $this->id
3755
				if ( empty( $this->id ) ) {
3756
					while ( $this->fetch() ) {
3757
						echo $this->do_magic_tags( $code );
3758
					}
3759
				} else {
3760
					echo $this->do_magic_tags( $code );
3761
				}
3762
			}
3763
3764
			$out = ob_get_clean();
3765
3766
			/**
3767
			 * Filter the template output.
3768
			 *
3769
			 * @param string $out           Template output.
3770
			 * @param string $code          Template code.
3771
			 * @param string $template_name Template name.
3772
			 * @param Pods   $pod           Pods object.
3773
			 */
3774
			$out = apply_filters( 'pods_templates_post_template', $out, $code, $template_name, $this );
3775
3776
			/**
3777
			 * Filter the template output.
3778
			 *
3779
			 * @param string $out           Template output.
3780
			 * @param string $code          Template code.
3781
			 * @param string $template_name Template name.
3782
			 * @param Pods   $pod           Pods object.
3783
			 */
3784
			$out = apply_filters( "pods_templates_post_template_{$template_name}", $out, $code, $template_name, $this );
3785
		} elseif ( class_exists( 'Pods_Templates' ) ) {
3786
			$out = Pods_Templates::template( $template_name, $code, $this, $deprecated );
3787
		} elseif ( $template_name === trim( preg_replace( '/[^a-zA-Z0-9_\-\/]/', '', $template_name ), ' /-' ) ) {
3788
			ob_start();
3789
3790
			$default_templates = array(
3791
				'pods/' . $template_name,
3792
				'pods-' . $template_name,
3793
				$template_name
3794
			);
3795
3796
			/**
3797
			 * Filter the default Pods Template files.
3798
			 *
3799
			 * @param array $default_templates Default Pods Template files.
3800
			 */
3801
			$default_templates = apply_filters( 'pods_template_default_templates', $default_templates );
3802
3803
			// Only detail templates need $this->id
3804 View Code Duplication
			if ( empty( $this->id ) ) {
3805
				while ( $this->fetch() ) {
3806
					pods_template_part( $default_templates, compact( array_keys( get_defined_vars() ) ) );
3807
				}
3808
			} else {
3809
				pods_template_part( $default_templates, compact( array_keys( get_defined_vars() ) ) );
3810
			}
3811
3812
			$out = ob_get_clean();
3813
3814
			/**
3815
			 * Filter the template output.
3816
			 *
3817
			 * @param string $out           Template output.
3818
			 * @param string $code          Template code.
3819
			 * @param string $template_name Template name.
3820
			 * @param Pods   $pod           Pods object.
3821
			 */
3822
			$out = apply_filters( 'pods_templates_post_template', $out, $code, $template_name, $this );
3823
3824
			/**
3825
			 * Filter the template output.
3826
			 *
3827
			 * @param string $out           Template output.
3828
			 * @param string $code          Template code.
3829
			 * @param string $template_name Template name.
3830
			 * @param Pods   $pod           Pods object.
3831
			 */
3832
			$out = apply_filters( "pods_templates_post_template_{$template_name}", $out, $code, $template_name, $this );
3833
		}
3834
3835
		return $out;
3836
	}
3837
3838
	/**
3839
	 * Embed a form to add / edit a pod item from within your theme. Provide an array of $fields to include
3840
	 * and override options where needed. For WP object based Pods, you can pass through the WP object
3841
	 * field names too, such as "post_title" or "post_content" for example.
3842
	 *
3843
	 * @param array  $params    (optional) Fields to show on the form, defaults to all fields
3844
	 * @param string $label     (optional) Save button label, defaults to "Save Changes"
3845
	 * @param string $thank_you (optional) Thank you URL to send to upon success
3846
	 *
3847
	 * @return bool|mixed
3848
	 * @since 2.0
3849
	 * @link  https://pods.io/docs/form/
3850
	 */
3851
	public function form( $params = null, $label = null, $thank_you = null ) {
3852
3853
		$defaults = array(
3854
			'fields'      => $params,
3855
			'label'       => $label,
3856
			'thank_you'   => $thank_you,
3857
			'fields_only' => false
3858
		);
3859
3860
		if ( is_array( $params ) ) {
3861
			$params = array_merge( $defaults, $params );
3862
		} else {
3863
			$params = $defaults;
3864
		}
3865
3866
		$pod =& $this;
3867
3868
		$params = $this->do_hook( 'form_params', $params );
3869
3870
		$fields = $params['fields'];
3871
3872 View Code Duplication
		if ( null !== $fields && ! is_array( $fields ) && 0 < strlen( $fields ) ) {
3873
			$fields = explode( ',', $fields );
3874
		}
3875
3876
		$object_fields = (array) pods_v( 'object_fields', $this->pod_data, array(), true );
3877
3878
		if ( empty( $fields ) ) {
3879
			// Add core object fields if $fields is empty
3880
			$fields = array_merge( $object_fields, $this->fields );
3881
		}
3882
3883
		$form_fields = $fields; // Temporary
3884
3885
		$fields = array();
3886
3887
		foreach ( $form_fields as $k => $field ) {
3888
			$name = $k;
3889
3890
			$defaults = array(
3891
				'name' => $name
3892
			);
3893
3894
			if ( ! is_array( $field ) ) {
3895
				$name = $field;
3896
3897
				$field = array(
3898
					'name' => $name
3899
				);
3900
			}
3901
3902
			$field = array_merge( $defaults, $field );
3903
3904
			$field['name'] = trim( $field['name'] );
3905
3906
			$default_value = pods_v( 'default', $field );
3907
			$value         = pods_v( 'value', $field );
3908
3909
			if ( empty( $field['name'] ) ) {
3910
				$field['name'] = trim( $name );
3911
			}
3912
3913 View Code Duplication
			if ( isset( $object_fields[ $field['name'] ] ) ) {
3914
				$field = array_merge( $object_fields[ $field['name'] ], $field );
3915
			} elseif ( isset( $this->fields[ $field['name'] ] ) ) {
3916
				$field = array_merge( $this->fields[ $field['name'] ], $field );
3917
			}
3918
3919
			if ( pods_v( 'hidden', $field, false, true ) ) {
3920
				$field['type'] = 'hidden';
3921
			}
3922
3923
			$fields[ $field['name'] ] = $field;
3924
3925 View Code Duplication
			if ( empty( $this->id ) && null !== $default_value ) {
3926
				$this->row_override[ $field['name'] ] = $default_value;
3927
			} elseif ( ! empty( $this->id ) && null !== $value ) {
3928
				$this->row[ $field['name'] ] = $value;
3929
			}
3930
		}
3931
3932
		unset( $form_fields ); // Cleanup
3933
3934
		$fields = $this->do_hook( 'form_fields', $fields, $params );
3935
3936
		$label = $params['label'];
3937
3938
		if ( empty( $label ) ) {
3939
			$label = __( 'Save Changes', 'pods' );
3940
		}
3941
3942
		$thank_you   = $params['thank_you'];
3943
		$fields_only = $params['fields_only'];
3944
3945
		PodsForm::$form_counter ++;
3946
3947
		ob_start();
3948
3949
		if ( empty( $thank_you ) ) {
3950
			$success = 'success';
3951
3952
			if ( 1 < PodsForm::$form_counter ) {
3953
				$success .= PodsForm::$form_counter;
3954
			}
3955
3956
			$thank_you = pods_query_arg( array( 'success*' => null, $success => 1 ) );
3957
3958
			if ( 1 === (int) pods_v( $success, 'get', 0 ) ) {
3959
				$message = __( 'Form submitted successfully', 'pods' );
3960
3961
				/**
3962
				 * Change the text of the message that appears on successful form submission.
3963
				 *
3964
				 * @param string $message
3965
				 *
3966
				 * @returns string the message
3967
				 *
3968
				 * @since 3.0.0
3969
				 */
3970
				$message = apply_filters( 'pods_pod_form_success_message', $message );
3971
3972
				echo '<div id="message" class="pods-form-front-success">' . $message . '</div>';
3973
			}
3974
		}
3975
3976
		pods_view( PODS_DIR . 'ui/front/form.php', compact( array_keys( get_defined_vars() ) ) );
3977
3978
		$output = ob_get_clean();
3979
3980
		if ( empty( $this->id ) ) {
3981
			$this->row_override = array();
3982
		}
3983
3984
		return $this->do_hook( 'form', $output, $fields, $label, $thank_you, $this, $this->id() );
3985
	}
3986
3987
	/**
3988
	 * @param array|string|null $fields (optional) Fields to show in the view, defaults to all fields
3989
	 *
3990
	 * @return mixed
3991
	 * @since 2.3.10
3992
	 */
3993
	public function view( $fields = null ) {
3994
3995
		$pod =& $this;
3996
3997
		// Convert comma separated list of fields to an array
3998 View Code Duplication
		if ( null !== $fields && ! is_array( $fields ) && 0 < strlen( $fields ) ) {
3999
			$fields = explode( ',', $fields );
4000
		}
4001
4002
		$object_fields = (array) pods_v( 'object_fields', $this->pod_data, array(), true );
4003
4004
		if ( empty( $fields ) ) {
4005
			// Add core object fields if $fields is empty
4006
			$fields = array_merge( $object_fields, $this->fields );
4007
		}
4008
4009
		$view_fields = $fields; // Temporary
4010
4011
		$fields = array();
4012
4013
		foreach ( $view_fields as $name => $field ) {
0 ignored issues
show
Bug introduced by
The expression $view_fields of type array|string 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...
4014
4015
			$defaults = array(
4016
				'name' => $name
4017
			);
4018
4019
			if ( ! is_array( $field ) ) {
4020
				$name = $field;
4021
4022
				$field = array(
4023
					'name' => $name
4024
				);
4025
			}
4026
4027
			$field = array_merge( $defaults, $field );
4028
4029
			$field['name'] = trim( $field['name'] );
4030
4031
			if ( empty( $field['name'] ) ) {
4032
				$field['name'] = trim( $name );
4033
			}
4034
4035 View Code Duplication
			if ( isset( $object_fields[ $field['name'] ] ) ) {
4036
				$field = array_merge( $field, $object_fields[ $field['name'] ] );
4037
			} elseif ( isset( $this->fields[ $field['name'] ] ) ) {
4038
				$field = array_merge( $this->fields[ $field['name'] ], $field );
4039
			}
4040
4041 View Code Duplication
			if ( pods_v( 'hidden', $field, false, true ) || 'hidden' === $field['type'] ) {
4042
				continue;
4043
			} elseif ( ! PodsForm::permission( $field['type'], $field['name'], $field['options'], $fields, $pod, $pod->id() ) ) {
4044
				continue;
4045
			}
4046
4047
			$fields[ $field['name'] ] = $field;
4048
		}
4049
4050
		unset( $view_fields ); // Cleanup
4051
4052
		$output = pods_view( PODS_DIR . 'ui/front/view.php', compact( array_keys( get_defined_vars() ) ), false, 'cache', true );
4053
4054
		return $this->do_hook( 'view', $output, $fields, $this->id() );
4055
4056
	}
4057
4058
	/**
4059
	 * Replace magic tags with their values
4060
	 *
4061
	 * @param string $code The content to evaluate
4062
	 *
4063
	 * @return string Code with Magic Tags evaluated
4064
	 *
4065
	 * @since 2.0
4066
	 */
4067
	public function do_magic_tags( $code ) {
4068
4069
		/**
4070
		 * Filters the Pods magic tags content before the default function.
4071
		 * Allows complete replacement of the Pods magic tag engine.
4072
		 *
4073
		 * @param null   $pre  Default is null which processes magic tags normally. Return any other value to override.
4074
		 * @param string $code The content to evaluate
4075
		 * @param Pods   $pods The Pods Object
4076
		 *
4077
		 * @since 2.7
4078
		 */
4079
		$pre = apply_filters( 'pods_pre_do_magic_tags', null, $code, $this );
4080
		if ( null !== $pre ) {
4081
			return $pre;
4082
		}
4083
4084
		return preg_replace_callback( '/({@(.*?)})/m', array( $this, 'process_magic_tags' ), $code );
4085
	}
4086
4087
	/**
4088
	 * Replace magic tags with their values
4089
	 *
4090
	 * @param string|array $tag The magic tag to process
4091
	 *
4092
	 * @return string Code with Magic Tags evaluated
4093
	 *
4094
	 * @since 2.0.2
4095
	 */
4096
	private function process_magic_tags( $tag ) {
4097
4098
		if ( is_array( $tag ) ) {
4099
			if ( ! isset( $tag[2] ) && '' === trim( $tag[2] ) ) {
4100
				return '';
4101
			}
4102
4103
			$tag = $tag[2];
4104
		}
4105
4106
		$tag = trim( $tag, ' {@}' );
4107
		$tag = explode( ',', $tag );
4108
4109
		if ( empty( $tag ) || ! isset( $tag[0] ) || '' === trim( $tag[0] ) ) {
4110
			return '';
4111
		}
4112
4113
		foreach ( $tag as $k => $v ) {
4114
			$tag[ $k ] = trim( $v );
4115
		}
4116
4117
		$field_name = $tag[0];
4118
4119
		$helper_name = $before = $after = '';
4120
4121
		if ( isset( $tag[1] ) && ! empty( $tag[1] ) ) {
4122
			$value = $this->field( $field_name );
4123
4124
			$helper_name = $tag[1];
4125
4126
			$value = $this->helper( $helper_name, $value, $field_name );
4127
		} else {
4128
			$value = $this->display( $field_name );
4129
		}
4130
4131
		if ( isset( $tag[2] ) && ! empty( $tag[2] ) ) {
4132
			$before = $tag[2];
4133
		}
4134
4135
		if ( isset( $tag[3] ) && ! empty( $tag[3] ) ) {
4136
			$after = $tag[3];
4137
		}
4138
4139
		/**
4140
		 * Filter the magic tag output for a value.
4141
		 *
4142
		 * @param string $value      Magic tag output for value.
4143
		 * @param string $field_name Magic tag field name.
4144
		 * @param string $before     Before content.
4145
		 * @param string $after      After content.
4146
		 */
4147
		$value = apply_filters( 'pods_do_magic_tags', $value, $field_name, $helper_name, $before, $after );
4148
4149 View Code Duplication
		if ( is_array( $value ) ) {
4150
			$value = pods_serial_comma( $value, array( 'field' => $field_name, 'fields' => $this->fields ) );
4151
		}
4152
4153 View Code Duplication
		if ( null !== $value && false !== $value ) {
4154
			return $before . $value . $after;
4155
		}
4156
4157
		return '';
4158
	}
4159
4160
	/**
4161
	 *
4162
	 * Generate UI for Data Management
4163
	 *
4164
	 * @param mixed $options Array or String containing Pod or Options to be used
4165
	 * @param bool  $amend   Whether to amend the default UI options or replace entirely
4166
	 *
4167
	 * @return PodsUI|null UI object or null if custom UI used
4168
	 *
4169
	 * @since 2.3.10
4170
	 */
4171
	public function ui( $options = null, $amend = false ) {
4172
4173
		$num = '';
4174
4175
		if ( empty( $options ) ) {
4176
			$options = array();
4177
		} else {
4178
			$num = pods_v_sanitized( 'num', $options, '' );
4179
4180
			if ( empty( $num ) ) {
4181
				$num = '';
4182
			}
4183
		}
4184
4185
		if ( $this->id() != pods_v( 'id' . $num, 'get', true ) ) {
4186
			$this->fetch( pods_v( 'id' . $num, 'get', true ) );
4187
		}
4188
4189
		if ( ! empty( $options ) && ! $amend ) {
4190
			$this->ui = $options;
4191
4192
			return pods_ui( $this );
4193
		} elseif ( ! empty( $options ) || 'custom' !== pods_v( 'ui_style', $this->pod_data['options'], 'post_type', true ) ) {
4194
			$actions_enabled = pods_v( 'ui_actions_enabled', $this->pod_data['options'] );
4195
4196
			if ( ! empty( $actions_enabled ) ) {
4197
				$actions_enabled = (array) $actions_enabled;
4198
			} else {
4199
				$actions_enabled = array();
4200
			}
4201
4202
			$available_actions = array(
4203
				'add',
4204
				'edit',
4205
				'duplicate',
4206
				'delete',
4207
				'reorder',
4208
				'export',
4209
			);
4210
4211
			if ( ! empty( $actions_enabled ) ) {
4212
				$actions_disabled = array(
4213
					'view' => 'view',
4214
				);
4215
4216
				foreach ( $available_actions as $action ) {
4217
					if ( ! in_array( $action, $actions_enabled, true ) ) {
4218
						$actions_disabled[ $action ] = $action;
4219
					}
4220
				}
4221
			} else {
4222
				$actions_disabled = array(
4223
					'duplicate' => 'duplicate',
4224
					'view'      => 'view',
4225
					'export'    => 'export',
4226
				);
4227
4228
				if ( 1 === pods_v( 'ui_export', $this->pod_data['options'], 0 ) ) {
4229
					unset( $actions_disabled['export'] );
4230
				}
4231
			}
4232
4233
			if ( empty( $options ) ) {
4234
				$author_restrict = false;
4235
4236
				if ( isset( $this->fields['author'] ) && 'pick' === $this->fields['author']['type'] && 'user' === $this->fields['author']['pick_object'] ) {
4237
					$author_restrict = 'author.ID';
4238
				}
4239
4240
				if ( ! pods_is_admin( array( 'pods', 'pods_content' ) ) ) {
4241
					if ( ! current_user_can( 'pods_add_' . $this->pod ) ) {
4242
						$actions_disabled['add'] = 'add';
4243
4244
						if ( 'add' === pods_v( 'action' . $num, 'get' ) ) {
4245
							$_GET[ 'action' . $num ] = 'manage';
4246
						}
4247
					}
4248
4249 View Code Duplication
					if ( ! $author_restrict && ! current_user_can( 'pods_edit_' . $this->pod ) && ! current_user_can( 'pods_edit_others_' . $this->pod ) ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $author_restrict of type string|false is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
4250
						$actions_disabled['edit'] = 'edit';
4251
					}
4252
4253 View Code Duplication
					if ( ! $author_restrict && ! current_user_can( 'pods_delete_' . $this->pod ) && ! current_user_can( 'pods_delete_others_' . $this->pod ) ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $author_restrict of type string|false is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
4254
						$actions_disabled['delete'] = 'delete';
4255
					}
4256
4257
					if ( ! current_user_can( 'pods_reorder_' . $this->pod ) ) {
4258
						$actions_disabled['reorder'] = 'reorder';
4259
					}
4260
4261
					if ( ! current_user_can( 'pods_export_' . $this->pod ) ) {
4262
						$actions_disabled['export'] = 'export';
4263
					}
4264
				}
4265
			}
4266
4267
			$_GET[ 'action' . $num ] = pods_v_sanitized( 'action' . $num, 'get', pods_v( 'action', $options, 'manage' ) );
4268
4269
			$index = $this->pod_data['field_id'];
4270
			$label = __( 'ID', 'pods' );
4271
4272
			if ( isset( $this->pod_data['fields'][ $this->pod_data['field_index'] ] ) ) {
4273
				$index = $this->pod_data['field_index'];
4274
				$label = $this->pod_data['fields'][ $this->pod_data['field_index'] ];
4275
			}
4276
4277
			$manage = array(
4278
				$index => $label
4279
			);
4280
4281
			if ( isset( $this->pod_data['fields']['modified'] ) ) {
4282
				$manage['modified'] = $this->pod_data['fields']['modified']['label'];
4283
			}
4284
4285
			$manage_fields = (array) pods_v( 'ui_fields_manage', $this->pod_data['options'] );
4286
4287
			if ( ! empty( $manage_fields ) ) {
4288
				$manage_new = array();
4289
4290
				foreach ( $manage_fields as $manage_field ) {
4291
					if ( isset( $this->pod_data['fields'][ $manage_field ] ) ) {
4292
						$manage_new[ $manage_field ] = $this->pod_data['fields'][ $manage_field ];
4293
					} elseif ( isset( $this->pod_data['object_fields'][ $manage_field ] ) ) {
4294
						$manage_new[ $manage_field ] = $this->pod_data['object_fields'][ $manage_field ];
4295
					} elseif ( $manage_field === $this->pod_data['field_id'] ) {
4296
						$field = array(
4297
							'name'  => $manage_field,
4298
							'label' => 'ID',
4299
							'type'  => 'number',
4300
							'width' => '8%',
4301
						);
4302
4303
						$manage_new[ $manage_field ] = PodsForm::field_setup( $field, null, $field['type'] );
4304
					}
4305
				}
4306
4307
				if ( ! empty( $manage_new ) ) {
4308
					$manage = $manage_new;
4309
				}
4310
			}
4311
4312
			$manage = apply_filters( 'pods_admin_ui_fields_' . $this->pod, apply_filters( 'pods_admin_ui_fields', $manage, $this->pod, $this ), $this->pod, $this );
4313
4314
			$icon = pods_v( 'ui_icon', $this->pod_data['options'] );
4315
4316
			if ( ! empty( $icon ) ) {
4317
				$icon = pods_image_url( $icon, '32x32' );
4318
			}
4319
4320
			$filters = pods_v( 'ui_filters', $this->pod_data['options'] );
4321
4322
			if ( ! empty( $filters ) ) {
4323
				$filters_new = array();
4324
4325
				$filters = (array) $filters;
4326
4327
				foreach ( $filters as $filter_field ) {
4328
					if ( isset( $this->pod_data['fields'][ $filter_field ] ) ) {
4329
						$filters_new[ $filter_field ] = $this->pod_data['fields'][ $filter_field ];
4330
					} elseif ( isset( $this->pod_data['object_fields'][ $filter_field ] ) ) {
4331
						$filters_new[ $filter_field ] = $this->pod_data['object_fields'][ $filter_field ];
4332
					}
4333
				}
4334
4335
				$filters = $filters_new;
4336
			}
4337
4338
			$ui = array(
4339
				'fields'           => array(
4340
					'manage'    => $manage,
4341
					'add'       => $this->pod_data['fields'],
4342
					'edit'      => $this->pod_data['fields'],
4343
					'duplicate' => $this->pod_data['fields']
4344
				),
4345
				'icon'             => $icon,
4346
				'actions_disabled' => $actions_disabled,
4347
				'actions_bulk'     => array(),
4348
			);
4349
4350
			if ( ! empty( $filters ) ) {
4351
				$ui['fields']['search'] = $filters;
4352
				$ui['filters']          = array_keys( $filters );
4353
				$ui['filters_enhanced'] = true;
4354
			}
4355
4356
			$reorder_field = pods_v( 'ui_reorder_field', $this->pod_data['options'] );
4357
4358
			if ( ! empty( $reorder_field ) && in_array( 'reorder', $actions_enabled, true ) && ! in_array( 'reorder', $actions_disabled, true ) && ( ( ! empty( $this->pod_data['object_fields'] ) && isset( $this->pod_data['object_fields'][ $reorder_field ] ) ) || isset( $this->pod_data['fields'][ $reorder_field ] ) ) ) {
4359
				$ui['reorder']     = array( 'on' => $reorder_field );
4360
				$ui['orderby']     = $reorder_field;
4361
				$ui['orderby_dir'] = 'ASC';
4362
			}
4363
4364
			if ( ! empty( $author_restrict ) ) {
4365
				$ui['restrict'] = array( 'author_restrict' => $author_restrict );
4366
			}
4367
4368 View Code Duplication
			if ( ! in_array( 'export', $ui['actions_disabled'], true ) ) {
4369
				$ui['actions_bulk']['export'] = array(
4370
					'label' => __( 'Export', 'pods' )
4371
					// callback not needed, Pods has this built-in for export
4372
				);
4373
			}
4374
4375 View Code Duplication
			if ( ! in_array( 'delete', $ui['actions_disabled'], true ) ) {
4376
				$ui['actions_bulk']['delete'] = array(
4377
					'label' => __( 'Delete', 'pods' )
4378
					// callback not needed, Pods has this built-in for delete
4379
				);
4380
			}
4381
4382
			$detail_url = pods_v( 'detail_url', $this->pod_data['options'] );
4383
4384
			if ( 0 < strlen( $detail_url ) ) {
4385
				$ui['actions_custom'] = array(
4386
					'view_url' => array(
4387
						'label' => 'View',
4388
						'link'  => get_site_url() . '/' . $detail_url
4389
					)
4390
				);
4391
			}
4392
4393
			// @todo Customize the Add New / Manage links to point to their correct menu items
4394
4395
			$ui = apply_filters( 'pods_admin_ui_' . $this->pod, apply_filters( 'pods_admin_ui', $ui, $this->pod, $this ), $this->pod, $this );
4396
4397
			// Override UI options
4398
			foreach ( $options as $option => $value ) {
4399
				$ui[ $option ] = $value;
4400
			}
4401
4402
			$this->ui = $ui;
4403
4404
			return pods_ui( $this );
4405
		}
4406
4407
		do_action( 'pods_admin_ui_custom', $this );
4408
		do_action( 'pods_admin_ui_custom_' . $this->pod, $this );
4409
4410
		return null;
4411
	}
4412
4413
	/**
4414
	 * Handle filters / actions for the class
4415
	 *
4416
	 * @see   pods_do_hook
4417
	 *
4418
	 * @return mixed Value filtered
4419
	 *
4420
	 * @since 2.0
4421
	 */
4422 View Code Duplication
	private function do_hook() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
4423
4424
		$args = func_get_args();
4425
4426
		if ( empty( $args ) ) {
4427
			return false;
4428
		}
4429
4430
		$name = array_shift( $args );
4431
4432
		return pods_do_hook( 'pods', $name, $args, $this );
4433
	}
4434
4435
	/**
4436
	 * Handle variables that have been deprecated and PodsData vars
4437
	 *
4438
	 * @var $name
4439
	 *
4440
	 * @return mixed
4441
	 *
4442
	 * @since 2.0
4443
	 */
4444
	public function __get( $name ) {
4445
4446
		$name = (string) $name;
4447
4448
		// PodsData vars
4449
		if ( isset( $this->data->{$name} ) && 0 === strpos( $name, 'field_' ) ) {
4450
			return $this->data->{$name};
4451
		}
4452
4453
		if ( ! $this->deprecated ) {
4454
			require_once PODS_DIR . 'deprecated/classes/Pods.php';
4455
4456
			$this->deprecated = new Pods_Deprecated( $this );
4457
		}
4458
4459
		$var = null;
4460
4461
		$pod_class_exists = class_exists( 'Pod' );
4462
4463
		if ( isset( $this->deprecated->{$name} ) ) {
4464
			if ( ! $pod_class_exists || Pod::$deprecated_notice ) {
4465
				pods_deprecated( "Pods->{$name}", '2.0' );
4466
			}
4467
4468
			$var = $this->deprecated->{$name};
4469
		} elseif ( ! $pod_class_exists || Pod::$deprecated_notice ) {
4470
			pods_deprecated( "Pods->{$name}", '2.0' );
4471
		}
4472
4473
		return $var;
4474
	}
4475
4476
	/**
4477
	 * Handle methods that have been deprecated and any aliasing
4478
	 *
4479
	 * @var $name
4480
	 * @var $args
4481
	 *
4482
	 * @return mixed|null
4483
	 *
4484
	 * @since 2.0
4485
	 */
4486
	public function __call( $name, $args ) {
4487
4488
		$name = (string) $name;
4489
4490
		// select > find alias
4491
		if ( 'select' === $name ) {
4492
			return call_user_func_array( array( $this, 'find' ), $args );
4493
		}
4494
4495
		if ( ! $this->deprecated ) {
4496
			require_once PODS_DIR . 'deprecated/classes/Pods.php';
4497
4498
			$this->deprecated = new Pods_Deprecated( $this );
4499
		}
4500
4501
		$pod_class_exists = class_exists( 'Pod' );
4502
4503 View Code Duplication
		if ( method_exists( $this->deprecated, $name ) ) {
4504
			return call_user_func_array( array( $this->deprecated, $name ), $args );
4505
		} elseif ( ! $pod_class_exists || Pod::$deprecated_notice ) {
4506
			pods_deprecated( "Pods::{$name}", '2.0' );
4507
		}
4508
4509
		return null;
4510
	}
4511
4512
	/**
4513
	 * Handle casting a Pods() object to string
4514
	 *
4515
	 * @return string Pod type and name in CURIE notation
4516
	 */
4517
	public function __toString() {
4518
4519
		$string = '';
4520
4521
		if ( ! empty( $this->pod_data ) ) {
4522
			$string = sprintf( '%s:%s', $this->pod_data['type'], $this->pod_data['name'] );
4523
		}
4524
4525
		return $string;
4526
4527
	}
4528
}
4529