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

Pods::display()   C

Complexity

Conditions 9
Paths 15

Size

Total Lines 46
Code Lines 27

Duplication

Lines 10
Ratio 21.74 %

Importance

Changes 0
Metric Value
cc 9
eloc 27
nc 15
nop 2
dl 10
loc 46
rs 5.0942
c 0
b 0
f 0
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
				if ( isset( $queried_object->post_type ) ) {
292
					// Post Type Singular.
293
					$pod = $queried_object->post_type;
294
				} elseif ( isset( $queried_object->taxonomy ) ) {
295
					// Term Archive.
296
					$pod = $queried_object->taxonomy;
297
				} elseif ( isset( $queried_object->user_login ) ) {
298
					// Author Archive.
299
					$pod = 'user';
300
				} elseif ( isset( $queried_object->public, $queried_object->name ) ) {
301
					// Post Type Archive.
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
			}//end if
311
		}//end if
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
		if ( is_array( $field ) ) {
563
			// Field data override.
564
			$field_data = $field;
565
566
			$field = pods_v( 'name', $field );
567
		} else {
568
			// Get field data from field name.
569
			$field_data = $this->fields( $field );
570
		}
571
572
		if ( ! empty( $field_data ) ) {
573
			$field_type = pods_v( 'type', $field_data );
574
575
			if ( empty( $input_name ) ) {
576
				$input_name = $field;
577
			}
578
579
			if ( '__null' === $value ) {
580
				$value = $this->field( array(
581
					'name'    => $field,
582
					'in_form' => true,
583
				) );
584
			}
585
586
			return PodsForm::field( $input_name, $value, $field_type, $field_data, $this, $this->id() );
587
		}
588
589
		return '';
590
591
	}
592
593
	/**
594
	 * Return field array from a Pod, a field's data, or a field option
595
	 *
596
	 * @param null $field  Field name.
597
	 * @param null $option Option name.
598
	 *
599
	 * @return bool|mixed
600
	 *
601
	 * @since 2.0
602
	 */
603
	public function fields( $field = null, $option = null ) {
604
605
		$field_data = null;
606
607
		if ( empty( $this->fields ) ) {
608
			// No fields found.
609
			$field_data = array();
610
		} elseif ( empty( $field ) ) {
611
			// Return all fields.
612
			$field_data = (array) $this->fields;
613
		} elseif ( ! isset( $this->fields[ $field ] ) && ! isset( $this->pod_data['object_fields'][ $field ] ) ) {
614
			// Field not found.
615
			$field_data = array();
616
		} elseif ( empty( $option ) ) {
617
			// Return all field data.
618
			if ( isset( $this->fields[ $field ] ) ) {
619
				$field_data = $this->fields[ $field ];
620
			} elseif ( isset( $this->pod_data['object_fields'] ) ) {
621
				$field_data = $this->pod_data['object_fields'][ $field ];
622
			}
623
		} else {
624
			$options = array();
625
626
			// Merge options.
627
			if ( isset( $this->fields[ $field ] ) ) {
628
				$options = array_merge( $this->fields[ $field ], $this->fields[ $field ]['options'] );
629
			} elseif ( isset( $this->pod_data['object_fields'] ) ) {
630
				$options = array_merge( $this->pod_data['object_fields'][ $field ], $this->pod_data['object_fields'][ $field ]['options'] );
631
			}
632
633
			if ( 'data' === $option && in_array( pods_v( 'type', $options ), PodsForm::tableless_field_types(), true ) ) {
634
				// Get a list of available items from a relationship field.
635
				$field_data = PodsForm::field_method( 'pick', 'get_field_data', $options );
636
			} elseif ( isset( $options[ $option ] ) ) {
637
				// Return option.
638
				$field_data = $options[ $option ];
639
			}
640
		}//end if
641
642
		/**
643
		 * Modify the field data before returning
644
		 *
645
		 * @since unknown
646
		 *
647
		 * @param array       $field_data The data for the field.
648
		 * @param string|null $field      The specific field that data is being return for, if set when method is called or null.
649
		 * @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.
650
		 * @param Pods|object $this       The current Pods class instance.
651
		 */
652
		return apply_filters( 'pods_pods_fields', $field_data, $field, $option, $this );
653
654
	}
655
656
	/**
657
	 * Return row array for an item
658
	 *
659
	 * @return array|false
660
	 *
661
	 * @since 2.0
662
	 */
663
	public function row() {
664
665
		do_action( 'pods_pods_row', $this );
666
667
		if ( ! is_array( $this->row ) ) {
668
			return false;
669
		}
670
671
		return (array) $this->row;
672
	}
673
674
	/**
675
	 * Return the output for a field. If you want the raw value for use in PHP for custom manipulation,
676
	 * you will want to use field() instead. This function will automatically convert arrays into a
677
	 * list of text such as "Rick, John, and Gary"
678
	 *
679
	 * @param string|array|object  $name   The field name, or an associative array of parameters.
680
	 * @param boolean|array|object $single (optional) For tableless fields, to return an array or the first.
681
	 *
682
	 * @return string|null|false The output from the field, null if the field doesn't exist, false if no value returned
683
	 *                           for tableless fields
684
	 * @since 2.0
685
	 * @link  https://pods.io/docs/display/
686
	 */
687
	public function display( $name, $single = null ) {
688
689
		$defaults = array(
690
			'name'          => $name,
691
			'single'        => $single,
692
			'display'       => true,
693
			'serial_params' => null,
694
		);
695
696 View Code Duplication
		if ( is_array( $name ) || is_object( $name ) ) {
697
			$defaults['name'] = null;
698
699
			$params = (object) array_merge( $defaults, (array) $name );
700
		} elseif ( is_array( $single ) || is_object( $single ) ) {
701
			$defaults['single'] = null;
702
703
			$params = (object) array_merge( $defaults, (array) $single );
704
		} else {
705
			$params = $defaults;
706
		}
707
708
		$params = (object) $params;
709
710
		$value = $this->field( $params );
711
712
		if ( is_array( $value ) ) {
713
			$fields = $this->fields;
714
715
			if ( isset( $this->pod_data['object_fields'] ) ) {
716
				$fields = array_merge( $fields, $this->pod_data['object_fields'] );
717
			}
718
719
			$serial_params = array(
720
				'field'  => $params->name,
721
				'fields' => $fields,
722
			);
723
724
			if ( ! empty( $params->serial_params ) && is_array( $params->serial_params ) ) {
725
				$serial_params = array_merge( $serial_params, $params->serial_params );
726
			}
727
728
			$value = pods_serial_comma( $value, $serial_params );
729
		}
730
731
		return $value;
732
	}
733
734
	/**
735
	 * Return the raw output for a field If you want the raw value for use in PHP for custom manipulation,
736
	 * you will want to use field() instead. This function will automatically convert arrays into a
737
	 * list of text such as "Rick, John, and Gary"
738
	 *
739
	 * @param string|array|object  $name   The field name, or an associative array of parameters.
740
	 * @param boolean|array|object $single (optional) For tableless fields, to return an array or the first.
741
	 *
742
	 * @return string|null|false The output from the field, null if the field doesn't exist, false if no value returned
743
	 *                           for tableless fields
744
	 * @since 2.0
745
	 * @link  https://pods.io/docs/display/
746
	 */
747
	public function raw( $name, $single = null ) {
748
749
		$defaults = array(
750
			'name'   => $name,
751
			'single' => $single,
752
			'raw'    => true,
753
		);
754
755 View Code Duplication
		if ( is_array( $name ) || is_object( $name ) ) {
756
			$defaults['name'] = null;
757
758
			$params = (object) array_merge( $defaults, (array) $name );
759
		} elseif ( is_array( $single ) || is_object( $single ) ) {
760
			$defaults['single'] = null;
761
762
			$params = (object) array_merge( $defaults, (array) $single );
763
		} else {
764
			$params = (object) $defaults;
765
		}
766
767
		return $this->field( $params );
768
	}
769
770
	/**
771
	 * Return the value for a field.
772
	 *
773
	 * If you are getting a field for output in a theme, most of the time you will want to use display() instead.
774
	 *
775
	 * This function will return arrays for relationship and file fields.
776
	 *
777
	 * @param string|array|object  $name   The field name, or an associative array of parameters.
778
	 * @param boolean|array|object $single For tableless fields, to return the whole array or the just the first item,
779
	 *                                     or an associative array of parameters.
780
	 * @param boolean|array|object $raw    Whether to return the raw value, or to run through the field type's display
781
	 *                                     method, or an associative array of parameters.
782
	 *
783
	 * @return mixed|null Value returned depends on the field type, null if the field doesn't exist, false if no value
784
	 *                    returned for tableless fields.
785
	 * @since 2.0
786
	 * @link  https://pods.io/docs/field/
787
	 */
788
	public function field( $name, $single = null, $raw = false ) {
789
790
		$defaults = array(
791
			'name'        => $name,
792
			'orderby'     => null,
793
			'single'      => $single,
794
			'params'      => null,
795
			'in_form'     => false,
796
			'raw'         => $raw,
797
			'raw_display' => false,
798
			'display'     => false,
799
			'get_meta'    => false,
800
			'output'      => null,
801
			'deprecated'  => false,
802
			// extra data to send to field handlers.
803
			'args'        => array(),
804
		);
805
806
		$is_name_object   = is_object( $name );
807
		$is_single_object = is_object( $single );
808
		$is_raw_object    = is_object( $raw );
809
810
		if ( is_array( $name ) || $is_name_object ) {
811
			if ( $is_name_object ) {
812
				$name = get_object_vars( $name );
813
			}
814
815
			$defaults['name'] = null;
816
817
			$params = (object) array_merge( $defaults, (array) $name );
818
		} elseif ( is_array( $single ) || $is_single_object ) {
819
			if ( $is_single_object ) {
820
				$single = get_object_vars( $single );
821
			}
822
823
			$defaults['single'] = null;
824
825
			$params = (object) array_merge( $defaults, (array) $single );
826
		} elseif ( is_array( $raw ) || $is_raw_object ) {
827
			if ( $is_raw_object ) {
828
				$raw = get_object_vars( $raw );
829
			}
830
831
			$defaults['raw'] = false;
832
833
			$params = (object) array_merge( $defaults, (array) $raw );
834
		} else {
835
			$params = (object) $defaults;
836
		}//end if
837
838
		if ( $params->in_form ) {
839
			$params->output = 'ids';
840
		} elseif ( null === $params->output ) {
841
			/**
842
			 * Override the way related fields are output
843
			 *
844
			 * @param string       $output How to output related fields. Default is 'arrays'. Options: ids|names|objects|arrays|pods|find
845
			 * @param array|object $row    Current row being outputted.
846
			 * @param array        $params Params array passed to field().
847
			 * @param Pods         $this   Current Pods object.
848
			 */
849
			$params->output = apply_filters( 'pods_pods_field_related_output_type', 'arrays', $this->row, $params, $this );
850
		}
851
852
		if ( in_array( $params->output, array( 'id', 'name', 'object', 'array', 'pod' ), true ) ) {
853
			$params->output .= 's';
854
		}
855
856
		// Support old $orderby variable.
857
		if ( null !== $params->single && is_string( $params->single ) && empty( $params->orderby ) ) {
858
			if ( ! class_exists( 'Pod' ) || Pod::$deprecated_notice ) {
859
				pods_deprecated( 'Pods::field', '2.0', 'Use $params[ \'orderby\' ] instead' );
860
			}
861
862
			$params->orderby = $params->single;
863
			$params->single  = false;
864
		}
865
866
		if ( null !== $params->single ) {
867
			$params->single = (boolean) $params->single;
868
		}
869
870
		$params->name = trim( $params->name );
871
		if ( is_array( $params->name ) || '' === $params->name ) {
872
			return null;
873
		}
874
875
		$params->full_name = $params->name;
876
877
		$value = null;
878
879
		if ( isset( $this->row_override[ $params->name ] ) ) {
880
			$value = $this->row_override[ $params->name ];
881
		}
882
883
		if ( false === $this->row() ) {
884
			if ( false !== $this->data() ) {
885
				$this->fetch();
886
			} else {
887
				return $value;
888
			}
889
		}
890
891
		if ( $this->data->field_id === $params->name ) {
892 View Code Duplication
			if ( isset( $this->row[ $params->name ] ) ) {
893
				return $this->row[ $params->name ];
894
				// @codingStandardsIgnoreLine.
895
			} elseif ( null !== $value ) {
896
				return $value;
897
			}
898
899
			return 0;
900
		}
901
902
		$tableless_field_types    = PodsForm::tableless_field_types();
903
		$simple_tableless_objects = PodsForm::simple_tableless_objects();
904
905
		$params->traverse = array();
906
907
		if ( in_array( $params->name, array(
908
			'_link',
909
			'detail_url',
910
		), true ) || ( in_array( $params->name, array(
911
			'permalink',
912
			'the_permalink',
913
		), true ) && in_array( $this->pod_data['type'], array(
914
			'post_type',
915
			'taxonomy',
916
			'media',
917
			'user',
918
			'comment',
919
		), true ) ) ) {
920
			if ( 0 < strlen( $this->detail_page ) ) {
921
				$value = get_home_url() . '/' . $this->do_magic_tags( $this->detail_page );
922
			} elseif ( in_array( $this->pod_data['type'], array( 'post_type', 'media' ), true ) ) {
923
				$value = get_permalink( $this->id() );
924
			} elseif ( 'taxonomy' === $this->pod_data['type'] ) {
925
				$value = get_term_link( $this->id(), $this->pod_data['name'] );
926
			} elseif ( 'user' === $this->pod_data['type'] ) {
927
				$value = get_author_posts_url( $this->id() );
928
			} elseif ( 'comment' === $this->pod_data['type'] ) {
929
				$value = get_comment_link( $this->id() );
930
			}
931
		}
932
933
		$field_data      = false;
934
		$last_field_data = false;
935
		$field_type      = false;
936
937
		$first_field = explode( '.', $params->name );
938
		$first_field = $first_field[0];
939
940
		if ( isset( $this->fields[ $first_field ] ) ) {
941
			$field_data = $this->fields[ $first_field ];
942
			$field_type = 'field';
943
		} elseif ( ! empty( $this->pod_data['object_fields'] ) ) {
944
			if ( isset( $this->pod_data['object_fields'][ $first_field ] ) ) {
945
				$field_data = $this->pod_data['object_fields'][ $first_field ];
946
				$field_type = 'object_field';
947
			} else {
948
				$object_fields = (array) $this->pod_data['object_fields'];
949
950
				foreach ( $object_fields as $object_field => $object_field_opt ) {
951
					if ( in_array( $first_field, $object_field_opt['alias'], true ) ) {
952
						if ( $first_field === $params->name ) {
953
							$params->name = $object_field;
954
						}
955
956
						$first_field = $object_field;
957
						$field_data  = $object_field_opt;
958
						$field_type  = 'object_field';
959
960
						break;
961
					}
962
				}
963
			}
964
		}//end if
965
966
		// Simple fields have no other output options.
967
		if ( 'pick' === $field_data['type'] && in_array( $field_data['pick_object'], $simple_tableless_objects, true ) ) {
968
			$params->output = 'arrays';
969
		}
970
971
		if ( empty( $value ) && in_array( $field_data['type'], $tableless_field_types, true ) ) {
972
			$params->raw = true;
973
974
			$value = false;
975
976
			$row_key = sprintf( '_%s_%s', $params->output, $params->name );
977
978
			if ( 'arrays' !== $params->output && isset( $this->row[ $row_key ] ) ) {
979
				$value = $this->row[ '_' . $params->output . '_' . $params->name ];
980
			} elseif ( 'arrays' === $params->output && isset( $this->row[ $params->name ] ) ) {
981
				$value = $this->row[ $params->name ];
982
			}
983
984
			if ( false !== $value && ! is_array( $value ) && 'pick' === $field_data['type'] && in_array( $field_data['pick_object'], $simple_tableless_objects, true ) ) {
985
				$value = PodsForm::field_method( 'pick', 'simple_value', $params->name, $value, $field_data, $this->pod_data, $this->id(), true );
986
			}
987
		}
988
989
		if ( empty( $value ) && isset( $this->row[ $params->name ] ) && ( ! in_array( $field_data['type'], $tableless_field_types, true ) || 'arrays' === $params->output ) ) {
990
			if ( empty( $field_data ) || in_array( $field_data['type'], array(
991
				'boolean',
992
				'number',
993
				'currency',
994
			), true ) ) {
995
				$params->raw = true;
996
			}
997
998
			if ( null === $params->single ) {
999
				if ( isset( $this->fields[ $params->name ] ) && ! in_array( $this->fields[ $params->name ]['type'], $tableless_field_types, true ) ) {
1000
					$params->single = true;
1001
				} else {
1002
					$params->single = false;
1003
				}
1004
			}
1005
1006
			$value = $this->row[ $params->name ];
1007
		} elseif ( empty( $value ) ) {
1008
			$object_field_found = false;
1009
1010
			if ( 'object_field' === $field_type ) {
1011
				$object_field_found = true;
1012
1013
				if ( isset( $this->row[ $first_field ] ) ) {
1014
					$value = $this->row[ $first_field ];
1015
				} elseif ( in_array( $field_data['type'], $tableless_field_types, true ) ) {
1016
					$this->fields[ $first_field ] = $field_data;
1017
1018
					$object_field_found = false;
1019
				} else {
1020
					return null;
1021
				}
1022
			}
1023
1024
			if ( 'post_type' === $this->pod_data['type'] && ! isset( $this->fields[ $params->name ] ) ) {
1025
				if ( ! isset( $this->fields['post_thumbnail'] ) && ( 'post_thumbnail' === $params->name || 0 === strpos( $params->name, 'post_thumbnail.' ) ) ) {
1026
					$size = 'thumbnail';
1027
1028 View Code Duplication
					if ( 0 === strpos( $params->name, 'post_thumbnail.' ) ) {
1029
						$field_names = explode( '.', $params->name );
1030
1031
						if ( isset( $field_names[1] ) ) {
1032
							$size = $field_names[1];
1033
						}
1034
					}
1035
1036
					// Pods will auto-get the thumbnail ID if this isn't an attachment.
1037
					$value = pods_image( $this->id(), $size, 0, null, true );
1038
1039
					$object_field_found = true;
1040
				} elseif ( ! isset( $this->fields['post_thumbnail_url'] ) && ( 'post_thumbnail_url' === $params->name || 0 === strpos( $params->name, 'post_thumbnail_url.' ) ) ) {
1041
					$size = 'thumbnail';
1042
1043 View Code Duplication
					if ( 0 === strpos( $params->name, 'post_thumbnail_url.' ) ) {
1044
						$field_names = explode( '.', $params->name );
1045
1046
						if ( isset( $field_names[1] ) ) {
1047
							$size = $field_names[1];
1048
						}
1049
					}
1050
1051
					// Pods will auto-get the thumbnail ID if this isn't an attachment.
1052
					$value = pods_image_url( $this->id(), $size, 0, true );
1053
1054
					$object_field_found = true;
1055 View Code Duplication
				} elseif ( 0 === strpos( $params->name, 'image_attachment.' ) ) {
1056
					$size = 'thumbnail';
1057
1058
					$image_id = 0;
1059
1060
					$field_names = explode( '.', $params->name );
1061
1062
					if ( isset( $field_names[1] ) ) {
1063
						$image_id = $field_names[1];
1064
					}
1065
1066
					if ( isset( $field_names[2] ) ) {
1067
						$size = $field_names[2];
1068
					}
1069
1070
					if ( ! empty( $image_id ) ) {
1071
						$value = pods_image( $image_id, $size, 0, null, true );
1072
1073
						if ( ! empty( $value ) ) {
1074
							$object_field_found = true;
1075
						}
1076
					}
1077
				} elseif ( 0 === strpos( $params->name, 'image_attachment_url.' ) ) {
1078
					$size = 'thumbnail';
1079
1080
					$image_id = 0;
1081
1082
					$field_names = explode( '.', $params->name );
1083
1084
					if ( isset( $field_names[1] ) ) {
1085
						$image_id = $field_names[1];
1086
					}
1087
1088
					if ( isset( $field_names[2] ) ) {
1089
						$size = $field_names[2];
1090
					}
1091
1092
					if ( ! empty( $image_id ) ) {
1093
						$value = pods_image_url( $image_id, $size, 0, true );
1094
1095
						if ( ! empty( $value ) ) {
1096
							$object_field_found = true;
1097
						}
1098
					}
1099
				}//end if
1100
			} elseif ( 'user' === $this->pod_data['type'] && ! isset( $this->fields[ $params->name ] ) ) {
1101
				if ( ! isset( $this->fields['avatar'] ) && ( 'avatar' === $params->name || 0 === strpos( $params->name, 'avatar.' ) ) ) {
1102
					$size = null;
1103
1104 View Code Duplication
					if ( 0 === strpos( $params->name, 'avatar.' ) ) {
1105
						$field_names = explode( '.', $params->name );
1106
1107
						if ( isset( $field_names[1] ) ) {
1108
							$size = (int) $field_names[1];
1109
						}
1110
					}
1111
1112
					if ( 0 < $size ) {
1113
						$value = get_avatar( $this->id(), $size );
1114
					} else {
1115
						$value = get_avatar( $this->id() );
1116
					}
1117
1118
					$object_field_found = true;
1119
				}
1120 View Code Duplication
			} elseif ( 0 === strpos( $params->name, 'image_attachment.' ) ) {
1121
				$size = 'thumbnail';
1122
1123
				$image_id = 0;
1124
1125
				$field_names = explode( '.', $params->name );
1126
1127
				if ( isset( $field_names[1] ) ) {
1128
					$image_id = $field_names[1];
1129
				}
1130
1131
				if ( isset( $field_names[2] ) ) {
1132
					$size = $field_names[2];
1133
				}
1134
1135
				if ( ! empty( $image_id ) ) {
1136
					$value = pods_image( $image_id, $size, 0, null, true );
1137
1138
					if ( ! empty( $value ) ) {
1139
						$object_field_found = true;
1140
					}
1141
				}
1142
			} elseif ( 0 === strpos( $params->name, 'image_attachment_url.' ) ) {
1143
				$size = 'thumbnail';
1144
1145
				$image_id = 0;
1146
1147
				$field_names = explode( '.', $params->name );
1148
1149
				if ( isset( $field_names[1] ) ) {
1150
					$image_id = $field_names[1];
1151
				}
1152
1153
				if ( isset( $field_names[2] ) ) {
1154
					$size = $field_names[2];
1155
				}
1156
1157
				if ( ! empty( $image_id ) ) {
1158
					$value = pods_image_url( $image_id, $size, 0, true );
1159
1160
					if ( ! empty( $value ) ) {
1161
						$object_field_found = true;
1162
					}
1163
				}
1164
			}//end if
1165
1166
			if ( false === $object_field_found ) {
1167
				$params->traverse = array( $params->name );
1168
1169
				if ( false !== strpos( $params->name, '.' ) ) {
1170
					$params->traverse = explode( '.', $params->name );
1171
1172
					$params->name = $params->traverse[0];
1173
				}
1174
1175
				if ( isset( $this->fields[ $params->name ], $this->fields[ $params->name ]['type'] ) ) {
1176
					/**
1177
					 * Modify value returned by field() after its retrieved, but before its validated or formatted
1178
					 *
1179
					 * Filter name is set dynamically with name of field: "pods_pods_field_{field_name}"
1180
					 *
1181
					 * @since unknown
1182
					 *
1183
					 * @param array|string|null $value  Value retrieved.
1184
					 * @param array|object      $row    Current row being outputted.
1185
					 * @param array             $params Params array passed to field().
1186
					 * @param object|Pods       $this   Current Pods object.
1187
					 */
1188
					$v = apply_filters( 'pods_pods_field_' . $this->fields[ $params->name ]['type'], null, $this->fields[ $params->name ], $this->row, $params, $this );
1189
1190
					if ( null !== $v ) {
1191
						return $v;
1192
					}
1193
				}
1194
1195
				$simple = false;
1196
1197
				if ( isset( $this->fields[ $params->name ] ) ) {
1198
					if ( 'meta' === $this->pod_data['storage'] && ! in_array( $this->fields[ $params->name ]['type'], $tableless_field_types, true ) ) {
1199
						$simple = true;
1200
					}
1201
1202
					if ( in_array( $this->fields[ $params->name ]['type'], $tableless_field_types, true ) ) {
1203
						$params->raw = true;
1204
1205
						if ( 'pick' === $this->fields[ $params->name ]['type'] && in_array( $this->fields[ $params->name ]['pick_object'], $simple_tableless_objects, true ) ) {
1206
							$simple         = true;
1207
							$params->single = true;
1208
						}
1209
					} elseif ( in_array( $this->fields[ $params->name ]['type'], array(
1210
						'boolean',
1211
						'number',
1212
						'currency',
1213
					), true ) ) {
1214
						$params->raw = true;
1215
					}
1216
				}
1217
1218
				$is_field_set       = isset( $this->fields[ $params->name ] );
1219
				$is_tableless_field = in_array( $this->fields[ $params->name ]['type'], $tableless_field_types, true );
1220
1221
				if ( $simple || ! $is_field_set || ! $is_tableless_field ) {
1222
					if ( null === $params->single ) {
1223
						if ( $is_field_set && $is_tableless_field ) {
1224
							$params->single = true;
1225
						} else {
1226
							$params->single = false;
1227
						}
1228
					}
1229
1230
					$no_conflict = pods_no_conflict_check( $this->pod_data['type'] );
1231
1232
					if ( ! $no_conflict ) {
1233
						pods_no_conflict_on( $this->pod_data['type'] );
1234
					}
1235
1236
					if ( in_array( $this->pod_data['type'], array(
1237
						'post_type',
1238
						'media',
1239
						'taxonomy',
1240
						'user',
1241
						'comment',
1242
					), true ) ) {
1243
						$id = $this->id();
1244
1245
						$metadata_type = $this->pod_data['type'];
1246
1247
						if ( in_array( $this->pod_data['type'], array( 'post_type', 'media' ), true ) ) {
1248
							$metadata_type = 'post';
1249
1250
							// Support for WPML 'duplicated' translation handling.
1251 View Code Duplication
							if ( did_action( 'wpml_loaded' ) && apply_filters( 'wpml_is_translated_post_type', false, $this->pod_data['name'] ) ) {
1252
								$master_post_id = (int) apply_filters( 'wpml_master_post_from_duplicate', $id );
1253
1254
								if ( 0 < $master_post_id ) {
1255
									$id = $master_post_id;
1256
								}
1257
							}
1258
						} elseif ( 'taxonomy' === $this->pod_data['type'] ) {
1259
							$metadata_type = 'term';
1260
						}
1261
1262
						$value = get_metadata( $metadata_type, $id, $params->name, $params->single );
1263
1264
						$single_multi = 'single';
1265
1266
						if ( isset( $this->fields[ $params->name ] ) ) {
1267
							$single_multi = pods_v( $this->fields[ $params->name ]['type'] . '_format_type', $this->fields[ $params->name ]['options'], 'single' );
1268
						}
1269
1270
						if ( $simple && ! is_array( $value ) && 'single' !== $single_multi ) {
1271
							$value = get_metadata( $metadata_type, $id, $params->name );
1272
						}
1273
					} elseif ( 'settings' === $this->pod_data['type'] ) {
1274
						$value = get_option( $this->pod_data['name'] . '_' . $params->name, null );
1275
					}//end if
1276
1277
					// Handle Simple Relationships.
1278
					if ( $simple ) {
1279
						if ( null === $params->single ) {
1280
							$params->single = false;
1281
						}
1282
1283
						$value = PodsForm::field_method( 'pick', 'simple_value', $params->name, $value, $this->fields[ $params->name ], $this->pod_data, $this->id(), true );
1284
					}
1285
1286
					if ( ! $no_conflict ) {
1287
						pods_no_conflict_off( $this->pod_data['type'] );
1288
					}
1289
				} else {
1290
					// Dot-traversal.
1291
					$pod        = $this->pod;
1292
					$ids        = array( $this->id() );
1293
					$all_fields = array();
1294
1295
					$lookup = $params->traverse;
1296
1297
					// Get fields matching traversal names.
1298
					if ( ! empty( $lookup ) ) {
1299
						$fields = $this->api->load_fields( array(
1300
							'name'          => $lookup,
1301
							'type'          => $tableless_field_types,
1302
							'object_fields' => true,
1303
							// @todo support object fields too.
1304
						) );
1305
1306
						if ( ! empty( $fields ) ) {
1307
							foreach ( $fields as $field ) {
1308
								if ( ! empty( $field ) ) {
1309
									if ( ! isset( $all_fields[ $field['pod'] ] ) ) {
1310
										$all_fields[ $field['pod'] ] = array();
1311
									}
1312
1313
									$all_fields[ $field['pod'] ][ $field['name'] ] = $field;
1314
								}
1315
							}
1316
						}
1317
1318
						if ( ! empty( $this->pod_data['object_fields'] ) ) {
1319
							$object_fields = (array) $this->pod_data['object_fields'];
1320
1321
							foreach ( $object_fields as $object_field => $object_field_opt ) {
1322
								if ( in_array( $object_field_opt['type'], $tableless_field_types, true ) ) {
1323
									$all_fields[ $this->pod ][ $object_field ] = $object_field_opt;
1324
								}
1325
							}
1326
						}
1327
					}//end if
1328
1329
					$last_type     = '';
1330
					$last_object   = '';
1331
					$last_pick_val = '';
1332
1333
					$single_multi = pods_v( $this->fields[ $params->name ]['type'] . '_format_type', $this->fields[ $params->name ]['options'], 'single' );
1334
1335
					if ( 'multi' === $single_multi ) {
1336
						$limit = (int) pods_v( $this->fields[ $params->name ]['type'] . '_limit', $this->fields[ $params->name ]['options'], 0 );
1337
					} else {
1338
						$limit = 1;
1339
					}
1340
1341
					// Loop through each traversal level.
1342
					foreach ( $params->traverse as $key => $field ) {
1343
						$last_loop = false;
1344
1345
						if ( count( $params->traverse ) <= ( $key + 1 ) ) {
1346
							$last_loop = true;
1347
						}
1348
1349
						$field_exists = isset( $all_fields[ $pod ][ $field ] );
1350
1351
						$simple       = false;
1352
						$last_options = array();
1353
1354
						if ( $field_exists && 'pick' === $all_fields[ $pod ][ $field ]['type'] && in_array( $all_fields[ $pod ][ $field ]['pick_object'], $simple_tableless_objects, true ) ) {
1355
							$simple       = true;
1356
							$last_options = $all_fields[ $pod ][ $field ];
1357
						}
1358
1359
						// Tableless handler.
1360
						if ( $field_exists && ( ! $simple || ! in_array( $all_fields[ $pod ][ $field ]['type'], array(
1361
							'pick',
1362
							'taxonomy',
1363
							'comment',
1364
						), true ) ) ) {
1365
							$type        = $all_fields[ $pod ][ $field ]['type'];
1366
							$pick_object = $all_fields[ $pod ][ $field ]['pick_object'];
1367
							$pick_val    = $all_fields[ $pod ][ $field ]['pick_val'];
1368
1369
							if ( 'table' === $pick_object ) {
1370
								$pick_val = pods_v( 'pick_table', $all_fields[ $pod ][ $field ]['options'], $pick_val, true );
1371
							} elseif ( '__current__' === $pick_val ) {
1372
								$pick_val = $pod;
1373
							}
1374
1375
							$last_limit = 0;
1376
1377
							if ( in_array( $type, $tableless_field_types, true ) ) {
1378
								$single_multi = pods_v( "{$type}_format_type", $all_fields[ $pod ][ $field ]['options'], 'single' );
1379
1380
								if ( 'multi' === $single_multi ) {
1381
									$last_limit = (int) pods_v( "{$type}_limit", $all_fields[ $pod ][ $field ]['options'], 0 );
1382
								} else {
1383
									$last_limit = 1;
1384
								}
1385
							}
1386
1387
							$last_type     = $type;
1388
							$last_object   = $pick_object;
1389
							$last_pick_val = $pick_val;
1390
							$last_options  = $all_fields[ $pod ][ $field ];
1391
1392
							// Temporary hack until there's some better handling here.
1393
							$last_limit *= count( $ids );
1394
1395
							// Get related IDs.
1396
							if ( ! isset( $all_fields[ $pod ][ $field ]['pod_id'] ) ) {
1397
								$all_fields[ $pod ][ $field ]['pod_id'] = 0;
1398
							}
1399
1400
							if ( isset( $all_fields[ $pod ][ $field ]['id'] ) ) {
1401
								$ids = $this->api->lookup_related_items( $all_fields[ $pod ][ $field ]['id'], $all_fields[ $pod ][ $field ]['pod_id'], $ids, $all_fields[ $pod ][ $field ] );
1402
							}
1403
1404
							// No items found.
1405
							if ( empty( $ids ) ) {
1406
								return false;
1407
							} elseif ( 0 < $last_limit ) {
1408
								// @todo This should return array() if not $params->single.
1409
								$ids = array_slice( $ids, 0, $last_limit );
1410
							}
1411
1412
							// Get $pod if related to a Pod.
1413
							if ( ! empty( $pick_object ) && ( ! empty( $pick_val ) || in_array( $pick_object, array(
1414
								'user',
1415
								'media',
1416
								'comment',
1417
							), true ) ) ) {
1418
								if ( 'pod' === $pick_object ) {
1419
									$pod = $pick_val;
1420
								} else {
1421
									$check = $this->api->get_table_info( $pick_object, $pick_val );
1422
1423
									if ( ! empty( $check ) && ! empty( $check['pod'] ) ) {
1424
										$pod = $check['pod']['name'];
1425
									}
1426
								}
1427
							}
1428
						} else {
1429
							// Assume last iteration.
1430
							if ( 0 === $key ) {
1431
								// Invalid field.
1432
								return false;
1433
							}
1434
1435
							$last_loop = true;
1436
						}//end if
1437
1438
						if ( $last_loop ) {
1439
							$object_type = $last_object;
1440
							$object      = $last_pick_val;
1441
1442
							if ( in_array( $last_type, PodsForm::file_field_types(), true ) ) {
1443
								$object_type = 'media';
1444
								$object      = 'attachment';
1445
							}
1446
1447
							$data = array();
1448
1449
							$table = $this->api->get_table_info( $object_type, $object, null, null, $last_options );
1450
1451
							$join  = array();
1452
							$where = array();
1453
1454
							if ( ! empty( $table['join'] ) ) {
1455
								$join = (array) $table['join'];
1456
							}
1457
1458
							if ( ! empty( $ids ) || ! empty( $table['where'] ) ) {
1459
								foreach ( $ids as $id ) {
1460
									$where[ $id ] = '`t`.`' . $table['field_id'] . '` = ' . (int) $id;
1461
								}
1462
1463
								if ( ! empty( $where ) ) {
1464
									$where = array( implode( ' OR ', $where ) );
1465
								}
1466
1467
								if ( ! empty( $table['where'] ) ) {
1468
									// @codingStandardsIgnoreLine.
1469
									$where = array_merge( $where, array_values( (array) $table['where'] ) );
1470
								}
1471
							}
1472
1473
							/**
1474
							 * Related object.
1475
							 *
1476
							 * @var $related_obj Pods|false
1477
							 */
1478
							$related_obj = false;
1479
1480
							// Check if we can return the full object/array or if we need to traverse into it.
1481
							$is_field_output_full = false;
1482
1483
							if ( false !== $field_exists && ( in_array( $last_type, $tableless_field_types, true ) && ! $simple ) ) {
1484
								$is_field_output_full = true;
1485
							}
1486
1487
							if ( 'pod' === $object_type ) {
1488
								$related_obj = pods( $object, null, false );
1489
							} elseif ( ! empty( $table['pod'] ) ) {
1490
								$related_obj = pods( $table['pod']['name'], null, false );
1491
							}
1492
1493
							if ( $related_obj || ! empty( $table['table'] ) ) {
1494
								$sql = array(
1495
									'select'     => '*, `t`.`' . $table['field_id'] . '` AS `pod_item_id`',
1496
									'table'      => $table['table'],
1497
									'join'       => $join,
1498
									'where'      => $where,
1499
									'orderby'    => $params->orderby,
1500
									'pagination' => false,
1501
									'search'     => false,
1502
									'limit'      => - 1,
1503
									'expires'    => 180,
1504
									// @todo This could potentially cause issues if someone changes the data within this time and persistent storage is used.
1505
								);
1506
1507
								if ( ! empty( $table['where_default'] ) ) {
1508
									$sql['where_default'] = $table['where_default'];
1509
								}
1510
1511
								// Output types.
1512
								if ( in_array( $params->output, array( 'ids', 'objects', 'pods' ), true ) ) {
1513
									$sql['select'] = '`t`.`' . $table['field_id'] . '` AS `pod_item_id`';
1514 View Code Duplication
								} elseif ( 'names' === $params->output && ! empty( $table['field_index'] ) ) {
1515
									$sql['select'] = '`t`.`' . $table['field_index'] . '` AS `pod_item_index`, `t`.`' . $table['field_id'] . '` AS `pod_item_id`';
1516
								}
1517
1518
								if ( ! empty( $params->params ) && is_array( $params->params ) ) {
1519
									$where = $sql['where'];
1520
1521
									// @codingStandardsIgnoreLine.
1522
									$sql = array_merge( $sql, $params->params );
1523
1524
									if ( isset( $params->params['where'] ) ) {
1525
										// @codingStandardsIgnoreLine.
1526
										$sql['where'] = array_merge( (array) $where, (array) $params->params['where'] );
1527
									}
1528
								}
1529
1530
								$item_data = array();
1531
1532
								if ( ! $related_obj ) {
1533
									if ( ! is_object( $this->alt_data ) ) {
1534
										$this->alt_data = pods_data( null, 0, true, true );
1535
									}
1536
1537
									$item_data = $this->alt_data->select( $sql );
1538
								} else {
1539
									// Support 'find' output ordering.
1540
									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...
1541
										// Handle default orderby for ordering by the IDs.
1542
										$order_ids = implode( ', ', array_map( 'absint', $ids ) );
1543
1544
										$sql['orderby'] = 'FIELD( `t`.`' . $table['field_id'] . '`, ' . $order_ids . ' )';
1545
									}
1546
1547
									$related_obj->find( $sql );
1548
1549
									// Support 'find' output.
1550
									if ( 'find' === $params->output && $is_field_output_full ) {
1551
										$data = $related_obj;
1552
1553
										$is_field_output_full = true;
1554
									} else {
1555
										$item_data = $related_obj->data();
1556
									}
1557
								}//end if
1558
1559
								$items = array();
1560
1561
								if ( ! empty( $item_data ) ) {
1562
									foreach ( $item_data as $item ) {
1563
										if ( is_array( $item ) ) {
1564
											$item = (object) $item;
1565
										}
1566
1567
										if ( empty( $item->pod_item_id ) ) {
1568
											continue;
1569
										}
1570
1571
										// Bypass pass field.
1572
										if ( isset( $item->user_pass ) ) {
1573
											unset( $item->user_pass );
1574
										}
1575
1576
										// Get Item ID.
1577
										$item_id = $item->pod_item_id;
1578
1579
										// Output types.
1580
										if ( 'ids' === $params->output ) {
1581
											$item = (int) $item_id;
1582
										} elseif ( 'names' === $params->output && ! empty( $table['field_index'] ) ) {
1583
											$item = $item->pod_item_index;
1584
										} elseif ( 'objects' === $params->output ) {
1585
											if ( in_array( $object_type, array( 'post_type', 'media' ), true ) ) {
1586
												$item = get_post( $item_id );
1587
											} elseif ( 'taxonomy' === $object_type ) {
1588
												$item = get_term( $item_id, $object );
1589
											} elseif ( 'user' === $object_type ) {
1590
												$item = get_userdata( $item_id );
1591
1592
												if ( ! empty( $item ) ) {
1593
													// Get other vars.
1594
													$roles   = $item->roles;
1595
													$caps    = $item->caps;
1596
													$allcaps = $item->allcaps;
1597
1598
													$item = $item->data;
1599
1600
													// Set other vars.
1601
													$item->roles   = $roles;
1602
													$item->caps    = $caps;
1603
													$item->allcaps = $allcaps;
1604
1605
													unset( $item->user_pass );
1606
												}
1607
											} elseif ( 'comment' === $object_type ) {
1608
												$item = get_comment( $item_id );
1609
											} else {
1610
												$item = (object) $item;
1611
											}//end if
1612
										} elseif ( 'pods' === $params->output ) {
1613
											if ( in_array( $object_type, array( 'user', 'media' ), true ) ) {
1614
												$item = pods( $object_type, (int) $item_id );
1615
											} else {
1616
												$item = pods( $object, (int) $item_id );
1617
											}
1618
										} else {
1619
											// arrays.
1620
											$item = get_object_vars( (object) $item );
1621
										}//end if
1622
1623
										// Pass item data into $data.
1624
										$items[ $item_id ] = $item;
1625
									}//end foreach
1626
1627
									// Cleanup.
1628
									unset( $item_data );
1629
1630
									// Return all of the data in the order expected.
1631
									if ( empty( $params->orderby ) ) {
1632
										foreach ( $ids as $id ) {
1633
											if ( isset( $items[ $id ] ) ) {
1634
												$data[ $id ] = $items[ $id ];
1635
											}
1636
										}
1637
									} else {
1638
										// Use order set by orderby.
1639
										foreach ( $items as $id => $v ) {
1640
											// @codingStandardsIgnoreLine.
1641
											if ( in_array( $id, $ids ) ) {
1642
												$data[ $id ] = $v;
1643
											}
1644
										}
1645
									}
1646
								}//end if
1647
							}//end if
1648
1649
							if ( in_array( $last_type, $tableless_field_types, true ) || in_array( $last_type, array(
1650
								'boolean',
1651
								'number',
1652
								'currency',
1653
							), true ) ) {
1654
								$params->raw = true;
1655
							}
1656
1657
							if ( empty( $data ) ) {
1658
								$value = false;
1659
							} else {
1660
								$object_type = $table['type'];
1661
1662
								if ( in_array( $table['type'], array( 'post_type', 'attachment', 'media' ), true ) ) {
1663
									$object_type = 'post';
1664
								}
1665
1666
								$no_conflict = true;
1667
1668 View Code Duplication
								if ( in_array( $object_type, array(
1669
									'post',
1670
									'taxonomy',
1671
									'user',
1672
									'comment',
1673
									'settings',
1674
								), true ) ) {
1675
									$no_conflict = pods_no_conflict_check( $object_type );
1676
1677
									if ( ! $no_conflict ) {
1678
										pods_no_conflict_on( $object_type );
1679
									}
1680
								}
1681
1682
								if ( $is_field_output_full ) {
1683
									// Return entire array.
1684
									$value = $data;
1685
								} else {
1686
									// Return an array of single column values.
1687
									$value = array();
1688
1689
									foreach ( $data as $item_id => $item ) {
1690
										// $field is 123x123, needs to be _src.123x123
1691
										$full_field = implode( '.', array_splice( $params->traverse, $key ) );
1692
1693
										if ( is_array( $item ) && isset( $item[ $field ] ) ) {
1694 View Code Duplication
											if ( $table['field_id'] === $field ) {
1695
												$value[] = (int) $item[ $field ];
1696
											} else {
1697
												$value[] = $item[ $field ];
1698
											}
1699
										} elseif ( is_object( $item ) && isset( $item->{$field} ) ) {
1700 View Code Duplication
											if ( $table['field_id'] === $field ) {
1701
												$value[] = (int) $item->{$field};
1702
											} else {
1703
												$value[] = $item->{$field};
1704
											}
1705
										} elseif ( ( ( false !== strpos( $full_field, '_src' ) || 'guid' === $field ) && ( in_array( $table['type'], array(
1706
											'attachment',
1707
											'media',
1708
										), true ) || in_array( $last_type, PodsForm::file_field_types(), true ) ) ) || ( in_array( $field, array(
1709
											'_link',
1710
											'detail_url',
1711
										), true ) || in_array( $field, array(
1712
											'permalink',
1713
											'the_permalink',
1714
										), true ) && in_array( $last_type, PodsForm::file_field_types(), true ) ) ) {
1715
											// @todo Refactor the above condition statement.
1716
											$size = 'full';
1717
1718
											if ( false === strpos( 'image', get_post_mime_type( $item_id ) ) ) {
1719
												// No default sizes for non-images.
1720
												// When a size is defined this will be overwritten.
1721
												$size = null;
1722
											}
1723
1724
											if ( false !== strpos( $full_field, '_src.' ) && 5 < strlen( $full_field ) ) {
1725
												$size = substr( $full_field, 5 );
1726 View Code Duplication
											} elseif ( false !== strpos( $full_field, '_src_relative.' ) && 14 < strlen( $full_field ) ) {
1727
												$size = substr( $full_field, 14 );
1728
											} elseif ( false !== strpos( $full_field, '_src_schemeless.' ) && 16 < strlen( $full_field ) ) {
1729
												$size = substr( $full_field, 16 );
1730
											}
1731
1732
											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...
1733
												$value_url = pods_image_url( $item_id, $size );
1734
											} else {
1735
												$value_url = wp_get_attachment_url( $item_id );
1736
											}
1737
1738
											if ( ! empty( $value_url ) ) {
1739
												if ( false !== strpos( $full_field, '_src_relative' ) ) {
1740
													$value_url_parsed = wp_parse_url( $value_url );
1741
													$value_url        = $value_url_parsed['path'];
1742
												} elseif ( false !== strpos( $full_field, '_src_schemeless' ) ) {
1743
													$value_url = str_replace( array(
1744
														'http://',
1745
														'https://',
1746
													), '//', $value_url );
1747
												}
1748
											}
1749
1750
											if ( ! empty( $value_url ) ) {
1751
												$value[] = $value_url;
1752
											}
1753
1754
											$params->raw_display = true;
1755
										} elseif ( false !== strpos( $full_field, '_img' ) && ( in_array( $table['type'], array(
1756
											'attachment',
1757
											'media',
1758
										), true ) || in_array( $last_type, PodsForm::file_field_types(), true ) ) ) {
1759
											$size = 'full';
1760
1761 View Code Duplication
											if ( false !== strpos( $full_field, '_img.' ) && 5 < strlen( $full_field ) ) {
1762
												$size = substr( $full_field, 5 );
1763
											}
1764
1765
											$value[] = pods_image( $item_id, $size );
1766
1767
											$params->raw_display = true;
1768
										} elseif ( in_array( $field, array(
1769
											'_link',
1770
											'detail_url',
1771
										), true ) || in_array( $field, array( 'permalink', 'the_permalink' ), true ) ) {
1772
											if ( 'pod' === $object_type ) {
1773
												if ( is_object( $related_obj ) ) {
1774
													$related_obj->fetch( $item_id );
1775
1776
													$value[] = $related_obj->field( 'detail_url' );
1777
												} else {
1778
													$value[] = '';
1779
												}
1780
											} elseif ( 'post' === $object_type ) {
1781
												$value[] = get_permalink( $item_id );
1782
											} elseif ( 'taxonomy' === $object_type ) {
1783
												$value[] = get_term_link( $item_id, $object );
1784
											} elseif ( 'user' === $object_type ) {
1785
												$value[] = get_author_posts_url( $item_id );
1786
											} elseif ( 'comment' === $object_type ) {
1787
												$value[] = get_comment_link( $item_id );
1788
											} else {
1789
												$value[] = '';
1790
											}
1791
1792
											$params->raw_display = true;
1793
										} elseif ( in_array( $object_type, array(
1794
											'post',
1795
											'taxonomy',
1796
											'user',
1797
											'comment',
1798
										), true ) ) {
1799
											$metadata_object_id = $item_id;
1800
1801
											$metadata_type = $object_type;
1802
1803
											if ( 'post' === $object_type ) {
1804
												// Support for WPML 'duplicated' translation handling.
1805 View Code Duplication
												if ( did_action( 'wpml_loaded' ) && apply_filters( 'wpml_is_translated_post_type', false, $object ) ) {
1806
													$master_post_id = (int) apply_filters( 'wpml_master_post_from_duplicate', $metadata_object_id );
1807
1808
													if ( 0 < $master_post_id ) {
1809
														$metadata_object_id = $master_post_id;
1810
													}
1811
												}
1812
											} elseif ( 'taxonomy' === $object_type ) {
1813
												$metadata_type = 'term';
1814
											}
1815
1816
											$value[] = get_metadata( $metadata_type, $metadata_object_id, $field, true );
1817
										} elseif ( 'settings' === $object_type ) {
1818
											$value[] = get_option( $object . '_' . $field );
1819
										}//end if
1820
									}//end foreach
1821
								}//end if
1822
1823 View Code Duplication
								if ( ! $no_conflict && in_array( $object_type, array(
1824
									'post',
1825
									'taxonomy',
1826
									'user',
1827
									'comment',
1828
									'settings',
1829
								), true ) ) {
1830
									pods_no_conflict_off( $object_type );
1831
								}
1832
1833
								// Handle Simple Relationships.
1834
								if ( $simple ) {
1835
									if ( null === $params->single ) {
1836
										$params->single = false;
1837
									}
1838
1839
									$value = PodsForm::field_method( 'pick', 'simple_value', $field, $value, $last_options, $all_fields[ $pod ], 0, true );
1840
								} elseif ( false === $params->in_form && ! empty( $value ) && is_array( $value ) ) {
1841
									$value = array_values( $value );
1842
								}
1843
1844
								// Return a single column value.
1845
								if ( false === $params->in_form && 1 === $limit && ! empty( $value ) && is_array( $value ) && 1 === count( $value ) ) {
1846
									$value = current( $value );
1847
								}
1848
							}//end if
1849
1850
							if ( $last_options ) {
1851
								$last_field_data = $last_options;
1852
							}
1853
1854
							break;
1855
						}//end if
1856
					}//end foreach
1857
				}//end if
1858
			}//end if
1859
		}//end if
1860
1861
		if ( ! empty( $params->traverse ) && 1 < count( $params->traverse ) ) {
1862
			$field_names = implode( '.', $params->traverse );
1863
1864
			$this->row[ $field_names ] = $value;
1865
		} elseif ( 'arrays' !== $params->output && in_array( $field_data['type'], $tableless_field_types, true ) ) {
1866
			$this->row[ '_' . $params->output . '_' . $params->full_name ] = $value;
1867
		} elseif ( 'arrays' === $params->output || ! in_array( $field_data['type'], $tableless_field_types, true ) ) {
1868
			$this->row[ $params->full_name ] = $value;
1869
		}
1870
1871
		if ( $params->single && is_array( $value ) && 1 === count( $value ) ) {
1872
			$value = current( $value );
1873
		}
1874
1875
		if ( ! empty( $last_field_data ) ) {
1876
			$field_data = $last_field_data;
1877
		}
1878
1879
		// @todo Expand this into traversed fields too.
1880
		if ( ! empty( $field_data ) && ( $params->display || ! $params->raw ) && ! $params->in_form && ! $params->raw_display ) {
1881
			if ( $params->display || ( ( $params->get_meta || $params->deprecated ) && ! in_array( $field_data['type'], $tableless_field_types, true ) ) ) {
1882
				$field_data['options'] = pods_v( 'options', $field_data, array(), true );
1883
1884
				$post_temp   = false;
1885
				$old_post    = null;
1886
				$old_post_id = null;
1887
1888
				if ( empty( $GLOBALS['post'] ) && 'post_type' === pods_v( 'type', $this->pod_data ) && 0 < $this->id() ) {
1889
					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...
1890
1891
					$post_temp = true;
1892
1893
					$old_post    = $post;
1894
					$old_post_id = $post_ID;
1895
1896
					// @codingStandardsIgnoreLine.
1897
					$post    = get_post( $this->id() );
1898
					// @codingStandardsIgnoreLine.
1899
					$post_ID = $this->id();
1900
				}
1901
1902
				$filter = pods_v( 'display_filter', $field_data['options'] );
1903
1904
				if ( 0 < strlen( $filter ) ) {
1905
					$args = array(
1906
						$filter,
1907
						$value,
1908
					);
1909
1910
					$filter_args = pods_v( 'display_filter_args', $field_data['options'] );
1911
1912
					if ( ! empty( $filter_args ) ) {
1913
						$args = array_merge( $args, compact( $filter_args ) );
1914
					}
1915
1916
					$value = call_user_func_array( 'apply_filters', $args );
1917
				} elseif ( 1 === (int) pods_v( 'display_process', $field_data['options'], 1 ) ) {
1918
					$value = PodsForm::display( $field_data['type'], $value, $params->name, array_merge( $field_data, $field_data['options'] ), $this->pod_data, $this->id() );
1919
				}
1920
1921
				if ( $post_temp ) {
1922
					// @codingStandardsIgnoreLine.
1923
					$post    = $old_post;
1924
					// @codingStandardsIgnoreLine.
1925
					$post_ID = $old_post_id;
1926
				}
1927
			} else {
1928
				$value = PodsForm::value( $field_data['type'], $value, $params->name, array_merge( $field_data, $field_data['options'] ), $this->pod_data, $this->id() );
1929
			}//end if
1930
		}//end if
1931
1932
		/**
1933
		 * Modify value returned by field() directly before output.
1934
		 *
1935
		 * Will not run if value was null
1936
		 *
1937
		 * @since unknown
1938
		 *
1939
		 * @param array|string|null $value  Value to be returned.
1940
		 * @param array|object      $row    Current row being outputted.
1941
		 * @param array             $params Params array passed to field().
1942
		 * @param object|Pods       $this   Current Pods object.
1943
		 */
1944
		$value = apply_filters( 'pods_pods_field', $value, $this->row, $params, $this );
1945
1946
		return $value;
1947
	}
1948
1949
	/**
1950
	 * Check if an item field has a specific value in it
1951
	 *
1952
	 * @param string $field Field name.
1953
	 * @param mixed  $value Value to check.
1954
	 * @param int    $id    (optional) ID of the pod item to check.
1955
	 *
1956
	 * @return bool Whether the value was found
1957
	 *
1958
	 * @since 2.3.3
1959
	 */
1960
	public function has( $field, $value, $id = null ) {
1961
1962
		$pod =& $this;
1963
1964 View Code Duplication
		if ( null === $id ) {
1965
			$id = $this->id();
1966
			// @codingStandardsIgnoreLine.
1967
		} elseif ( $id != $this->id() ) {
1968
			$pod = pods( $this->pod, $id );
1969
		}
1970
1971
		$this->do_hook( 'has', $field, $value, $id );
1972
1973
		if ( ! isset( $this->fields[ $field ] ) ) {
1974
			return false;
1975
		}
1976
1977
		// Tableless fields.
1978
		if ( in_array( $this->fields[ $field ]['type'], PodsForm::tableless_field_types(), true ) ) {
1979
			if ( ! is_array( $value ) ) {
1980
				$value = explode( ',', $value );
1981
			}
1982
1983 View Code Duplication
			if ( 'pick' === $this->fields[ $field ]['type'] && in_array( $this->fields[ $field ]['pick_object'], PodsForm::simple_tableless_objects(), true ) ) {
1984
				$current_value = $pod->raw( $field );
1985
1986
				if ( ! empty( $current_value ) ) {
1987
					$current_value = (array) $current_value;
1988
				}
1989
1990
				foreach ( $current_value as $v ) {
1991
					// @codingStandardsIgnoreLine.
1992
					if ( in_array( $v, $value ) ) {
1993
						return true;
1994
					}
1995
				}
1996
			} else {
1997
				$related_ids = $this->api->lookup_related_items( $this->fields[ $field ]['id'], $this->pod_data['id'], $id, $this->fields[ $field ], $this->pod_data );
1998
1999
				foreach ( $value as $k => $v ) {
2000
					if ( ! preg_match( '/[^\D]/', $v ) ) {
2001
						$value[ $k ] = (int) $v;
2002
					}
2003
2004
					// @todo Convert slugs into IDs.
2005
				}
2006
2007
				foreach ( $related_ids as $v ) {
2008
					// @codingStandardsIgnoreLine.
2009
					if ( in_array( $v, $value ) ) {
2010
						return true;
2011
					}
2012
				}
2013
			}//end if
2014 View Code Duplication
		} elseif ( in_array( $this->fields[ $field ]['type'], PodsForm::text_field_types(), true ) ) {
2015
			// Text fields.
2016
			$current_value = $pod->raw( $field );
2017
2018
			if ( 0 < strlen( $current_value ) ) {
2019
				return stripos( $current_value, $value );
2020
			}
2021
		} else {
2022
			// All other fields.
2023
			return $this->is( $field, $value, $id );
2024
		}//end if
2025
2026
		return false;
2027
	}
2028
2029
	/**
2030
	 * Check if an item field is a specific value
2031
	 *
2032
	 * @param string $field Field name.
2033
	 * @param mixed  $value Value to check.
2034
	 * @param int    $id    (optional) ID of the pod item to check.
2035
	 *
2036
	 * @return bool Whether the value was found
2037
	 *
2038
	 * @since 2.3.3
2039
	 */
2040
	public function is( $field, $value, $id = null ) {
2041
2042
		$pod =& $this;
2043
2044 View Code Duplication
		if ( null === $id ) {
2045
			$id = $this->id();
2046
			// @codingStandardsIgnoreLine.
2047
		} elseif ( $id != $this->id() ) {
2048
			$pod = pods( $this->pod, $id );
2049
		}
2050
2051
		$this->do_hook( 'is', $field, $value, $id );
2052
2053
		if ( ! isset( $this->fields[ $field ] ) ) {
2054
			return false;
2055
		}
2056
2057
		// Tableless fields.
2058
		if ( in_array( $this->fields[ $field ]['type'], PodsForm::tableless_field_types(), true ) ) {
2059
			if ( ! is_array( $value ) ) {
2060
				$value = explode( ',', $value );
2061
			}
2062
2063
			$current_value = array();
2064
2065 View Code Duplication
			if ( 'pick' === $this->fields[ $field ]['type'] && in_array( $this->fields[ $field ]['pick_object'], PodsForm::simple_tableless_objects(), true ) ) {
2066
				$current_value = $pod->raw( $field );
2067
2068
				if ( ! empty( $current_value ) ) {
2069
					$current_value = (array) $current_value;
2070
				}
2071
2072
				foreach ( $current_value as $v ) {
2073
					// @codingStandardsIgnoreLine.
2074
					if ( in_array( $v, $value ) ) {
2075
						return true;
2076
					}
2077
				}
2078
			} else {
2079
				$related_ids = $this->api->lookup_related_items( $this->fields[ $field ]['id'], $this->pod_data['id'], $id, $this->fields[ $field ], $this->pod_data );
2080
2081
				foreach ( $value as $k => $v ) {
2082
					if ( ! preg_match( '/[^\D]/', $v ) ) {
2083
						$value[ $k ] = (int) $v;
2084
					}
2085
2086
					// @todo Convert slugs into IDs.
2087
				}
2088
2089
				foreach ( $related_ids as $v ) {
2090
					// @codingStandardsIgnoreLine.
2091
					if ( in_array( $v, $value ) ) {
2092
						return true;
2093
					}
2094
				}
2095
			}//end if
2096
2097
			if ( ! empty( $current_value ) ) {
2098
				$current_value = array_filter( array_unique( $current_value ) );
2099
			} else {
2100
				$current_value = array();
2101
			}
2102
2103
			if ( ! empty( $value ) ) {
2104
				$value = array_filter( array_unique( $value ) );
2105
			} else {
2106
				$value = array();
2107
			}
2108
2109
			sort( $current_value );
2110
			sort( $value );
2111
2112
			if ( $value === $current_value ) {
2113
				return true;
2114
			}
2115
		} elseif ( in_array( $this->fields[ $field ]['type'], PodsForm::number_field_types(), true ) ) {
2116
			// Number fields.
2117
			$current_value = $pod->raw( $field );
2118
2119
			if ( (float) $current_value === (float) $value ) {
2120
				return true;
2121
			}
2122
		} elseif ( in_array( $this->fields[ $field ]['type'], PodsForm::date_field_types(), true ) ) {
2123
			// Date fields.
2124
			$current_value = $pod->raw( $field );
2125
2126
			if ( 0 < strlen( $current_value ) ) {
2127
				if ( strtotime( $current_value ) === strtotime( $value ) ) {
2128
					return true;
2129
				}
2130
			} elseif ( empty( $value ) ) {
2131
				return true;
2132
			}
2133
		} elseif ( in_array( $this->fields[ $field ]['type'], PodsForm::text_field_types(), true ) ) {
2134
			// Text fields.
2135
			$current_value = $pod->raw( $field );
2136
2137
			if ( (string) $current_value === (string) $value ) {
2138
				return true;
2139
			}
2140
		} else {
2141
			// All other fields.
2142
			$current_value = $pod->raw( $field );
2143
2144
			if ( $current_value === $value ) {
2145
				return true;
2146
			}
2147
		}//end if
2148
2149
		return false;
2150
	}
2151
2152
	/**
2153
	 * Return the item ID
2154
	 *
2155
	 * @return int
2156
	 * @since 2.0
2157
	 */
2158
	public function id() {
2159
2160
		if ( isset( $this->data->row, $this->data->row['id'] ) ) {
2161
			// If we already have data loaded return that ID.
2162
			return $this->data->row['id'];
2163
		}
2164
2165
		return $this->field( $this->data->field_id );
2166
	}
2167
2168
	/**
2169
	 * Return the previous item ID, loops at the last id to return the first
2170
	 *
2171
	 * @param int|null          $id              ID to start from.
2172
	 * @param array|object|null $params_override Override the find() parameters.
2173
	 *
2174
	 * @return int
2175
	 * @since 2.0
2176
	 */
2177
	public function prev_id( $id = null, $params_override = null ) {
2178
2179
		if ( null === $id ) {
2180
			$id = $this->id();
2181
		}
2182
2183
		$id = (int) $id;
2184
2185
		$params = array(
2186
			'select'  => "`t`.`{$this->data->field_id}`",
2187
			'where'   => "`t`.`{$this->data->field_id}` < {$id}",
2188
			'orderby' => "`t`.`{$this->data->field_id}` DESC",
2189
			'limit'   => 1,
2190
		);
2191
2192
		if ( ! empty( $params_override ) || ! empty( $this->params ) ) {
2193 View Code Duplication
			if ( ! empty( $params_override ) ) {
2194
				$params = $params_override;
2195
			} elseif ( ! empty( $this->params ) ) {
2196
				$params = $this->params;
2197
			}
2198
2199
			if ( is_object( $params ) ) {
2200
				$params = get_object_vars( $params );
2201
			}
2202
2203
			if ( 0 < $id ) {
2204 View Code Duplication
				if ( isset( $params['where'] ) && ! empty( $params['where'] ) ) {
2205
					$params['where']   = (array) $params['where'];
2206
					$params['where'][] = "`t`.`{$this->data->field_id}` < {$id}";
2207
				} else {
2208
					$params['where'] = "`t`.`{$this->data->field_id}` < {$id}";
2209
				}
2210
			} elseif ( isset( $params['offset'] ) && 0 < $params['offset'] ) {
2211
				$params['offset'] --;
2212
			} elseif ( 0 < $this->row_number && ! isset( $params['offset'] ) && ! empty( $this->params ) ) {
2213
				$params['offset'] = $this->row_number - 1;
2214
			} else {
2215
				return 0;
2216
			}
2217
2218 View Code Duplication
			if ( isset( $params['orderby'] ) && ! empty( $params['orderby'] ) ) {
2219
				if ( is_array( $params['orderby'] ) ) {
2220
					foreach ( $params['orderby'] as $orderby => $dir ) {
2221
						$dir = strtoupper( $dir );
2222
2223
						if ( ! in_array( $dir, array( 'ASC', 'DESC' ), true ) ) {
2224
							continue;
2225
						}
2226
2227
						if ( 'ASC' === $dir ) {
2228
							$params['orderby'][ $orderby ] = 'DESC';
2229
						} else {
2230
							$params['orderby'][ $orderby ] = 'ASC';
2231
						}
2232
					}
2233
2234
					$params['orderby'][ $this->data->field_id ] = 'DESC';
2235
				} elseif ( "`t`.`{$this->data->field_id}` DESC" !== $params['orderby'] ) {
2236
					$params['orderby'] .= ", `t`.`{$this->data->field_id}` DESC";
2237
				}
2238
			}//end if
2239
2240
			$params['select'] = "`t`.`{$this->data->field_id}`";
2241
			$params['limit']  = 1;
2242
		}//end if
2243
2244
		$pod = pods( $this->pod, $params );
2245
2246
		$new_id = 0;
2247
2248
		if ( $pod->fetch() ) {
2249
			$new_id = $pod->id();
2250
		}
2251
2252
		$new_id = $this->do_hook( 'prev_id', $new_id, $id, $pod, $params_override );
2253
2254
		return $new_id;
2255
	}
2256
2257
	/**
2258
	 * Return the next item ID, loops at the first id to return the last
2259
	 *
2260
	 * @param int|null          $id              ID to start from.
2261
	 * @param array|object|null $params_override Override the find() parameters.
2262
	 *
2263
	 * @return int
2264
	 * @since 2.0
2265
	 */
2266
	public function next_id( $id = null, $params_override = null ) {
2267
2268
		if ( null === $id ) {
2269
			$id = $this->id();
2270
		}
2271
2272
		$id = (int) $id;
2273
2274
		$params = array(
2275
			'select'  => "`t`.`{$this->data->field_id}`",
2276
			'where'   => "{$id} < `t`.`{$this->data->field_id}`",
2277
			'orderby' => "`t`.`{$this->data->field_id}` ASC",
2278
			'limit'   => 1,
2279
		);
2280
2281
		if ( ! empty( $params_override ) || ! empty( $this->params ) ) {
2282 View Code Duplication
			if ( ! empty( $params_override ) ) {
2283
				$params = $params_override;
2284
			} elseif ( ! empty( $this->params ) ) {
2285
				$params = $this->params;
2286
			}
2287
2288
			if ( is_object( $params ) ) {
2289
				$params = get_object_vars( $params );
2290
			}
2291
2292
			if ( 0 < $id ) {
2293 View Code Duplication
				if ( isset( $params['where'] ) && ! empty( $params['where'] ) ) {
2294
					$params['where']   = (array) $params['where'];
2295
					$params['where'][] = "{$id} < `t`.`{$this->data->field_id}`";
2296
				} else {
2297
					$params['where'] = "{$id} < `t`.`{$this->data->field_id}`";
2298
				}
2299
			} elseif ( ! isset( $params['offset'] ) ) {
2300
				if ( ! empty( $this->params ) && - 1 < $this->row_number ) {
2301
					$params['offset'] = $this->row_number + 1;
2302
				} else {
2303
					$params['offset'] = 1;
2304
				}
2305
			} else {
2306
				$params['offset'] ++;
2307
			}
2308
2309
			$params['select'] = "`t`.`{$this->data->field_id}`";
2310
			$params['limit']  = 1;
2311
		}//end if
2312
2313
		$pod = pods( $this->pod, $params );
2314
2315
		$new_id = 0;
2316
2317
		if ( $pod->fetch() ) {
2318
			$new_id = $pod->id();
2319
		}
2320
2321
		$new_id = $this->do_hook( 'next_id', $new_id, $id, $pod, $params_override );
2322
2323
		return $new_id;
2324
	}
2325
2326
	/**
2327
	 * Return the first item ID
2328
	 *
2329
	 * @param array|object|null $params_override Override the find() parameters.
2330
	 *
2331
	 * @return int
2332
	 * @since 2.3
2333
	 */
2334
	public function first_id( $params_override = null ) {
2335
2336
		$params = array(
2337
			'select'  => "`t`.`{$this->data->field_id}`",
2338
			'orderby' => "`t`.`{$this->data->field_id}` ASC",
2339
			'limit'   => 1,
2340
		);
2341
2342
		if ( ! empty( $params_override ) || ! empty( $this->params ) ) {
2343 View Code Duplication
			if ( ! empty( $params_override ) ) {
2344
				$params = $params_override;
2345
			} elseif ( ! empty( $this->params ) ) {
2346
				$params = $this->params;
2347
			}
2348
2349
			if ( is_object( $params ) ) {
2350
				$params = get_object_vars( $params );
2351
			}
2352
2353
			$params['select'] = "`t`.`{$this->data->field_id}`";
2354
			$params['offset'] = 0;
2355
			$params['limit']  = 1;
2356
		}
2357
2358
		$pod = pods( $this->pod, $params );
2359
2360
		$new_id = 0;
2361
2362
		if ( $pod->fetch() ) {
2363
			$new_id = $pod->id();
2364
		}
2365
2366
		$new_id = $this->do_hook( 'first_id', $new_id, $pod, $params_override );
2367
2368
		return $new_id;
2369
	}
2370
2371
	/**
2372
	 * Return the last item ID
2373
	 *
2374
	 * @param array|object|null $params_override Override the find() parameters.
2375
	 *
2376
	 * @return int
2377
	 * @since 2.3
2378
	 */
2379
	public function last_id( $params_override = null ) {
2380
2381
		$params = array(
2382
			'select'  => "`t`.`{$this->data->field_id}`",
2383
			'orderby' => "`t`.`{$this->data->field_id}` DESC",
2384
			'limit'   => 1,
2385
		);
2386
2387
		if ( ! empty( $params_override ) || ! empty( $this->params ) ) {
2388 View Code Duplication
			if ( ! empty( $params_override ) ) {
2389
				$params = $params_override;
2390
			} elseif ( ! empty( $this->params ) ) {
2391
				$params = $this->params;
2392
			}
2393
2394
			if ( is_object( $params ) ) {
2395
				$params = get_object_vars( $params );
2396
			}
2397
2398
			if ( isset( $params['total_found'] ) ) {
2399
				$params['offset'] = $params['total_found'] - 1;
2400
			} else {
2401
				$params['offset'] = $this->total_found() - 1;
2402
			}
2403
2404 View Code Duplication
			if ( isset( $params['orderby'] ) && ! empty( $params['orderby'] ) ) {
2405
				if ( is_array( $params['orderby'] ) ) {
2406
					foreach ( $params['orderby'] as $orderby => $dir ) {
2407
						$dir = strtoupper( $dir );
2408
2409
						if ( ! in_array( $dir, array( 'ASC', 'DESC' ), true ) ) {
2410
							continue;
2411
						}
2412
2413
						if ( 'ASC' === $dir ) {
2414
							$params['orderby'][ $orderby ] = 'DESC';
2415
						} else {
2416
							$params['orderby'][ $orderby ] = 'ASC';
2417
						}
2418
					}
2419
2420
					$params['orderby'][ $this->data->field_id ] = 'DESC';
2421
				} elseif ( "`t`.`{$this->data->field_id}` DESC" !== $params['orderby'] ) {
2422
					$params['orderby'] .= ", `t`.`{$this->data->field_id}` DESC";
2423
				}
2424
			}//end if
2425
2426
			$params['select'] = "`t`.`{$this->data->field_id}`";
2427
			$params['limit']  = 1;
2428
		}//end if
2429
2430
		$pod = pods( $this->pod, $params );
2431
2432
		$new_id = 0;
2433
2434
		if ( $pod->fetch() ) {
2435
			$new_id = $pod->id();
2436
		}
2437
2438
		$new_id = $this->do_hook( 'last_id', $new_id, $pod, $params_override );
2439
2440
		return $new_id;
2441
	}
2442
2443
	/**
2444
	 * Return the item name
2445
	 *
2446
	 * @return string
2447
	 * @since 2.0
2448
	 */
2449
	public function index() {
2450
2451
		return $this->field( $this->data->field_index );
2452
	}
2453
2454
	/**
2455
	 * Find items of a pod, much like WP_Query, but with advanced table handling.
2456
	 *
2457
	 * @param array|object $params An associative array of parameters.
2458
	 * @param int          $limit  (deprecated) Limit the number of items to find, -1 to return all items with no limit.
2459
	 * @param string       $where  (deprecated) SQL WHERE declaration to use.
2460
	 * @param string       $sql    (deprecated) For advanced use, a custom SQL query to run.
2461
	 *
2462
	 * @return \Pods The pod object
2463
	 * @since 2.0
2464
	 * @link  https://pods.io/docs/find/
2465
	 */
2466
	public function find( $params = null, $limit = 15, $where = null, $sql = null ) {
2467
2468
		$tableless_field_types    = PodsForm::tableless_field_types();
2469
		$simple_tableless_objects = PodsForm::simple_tableless_objects();
2470
2471
		$this->params = $params;
2472
2473
		$select = '`t`.*';
2474
2475
		if ( 'table' === $this->pod_data['storage'] && ! in_array( $this->pod_data['type'], array(
2476
			'pod',
2477
			'table',
2478
		), true ) ) {
2479
			$select .= ', `d`.*';
2480
		}
2481
2482
		if ( empty( $this->data->table ) ) {
2483
			return $this;
2484
		}
2485
2486
		$defaults = array(
2487
			// Optimization parameters.
2488
			'table'               => $this->data->table,
2489
			'select'              => $select,
2490
			'join'                => null,
2491
			// Main query parameters.
2492
			'where'               => $where,
2493
			'groupby'             => null,
2494
			'having'              => null,
2495
			'orderby'             => null,
2496
			// Pagination parameters.
2497
			'limit'               => (int) $limit,
2498
			'offset'              => null,
2499
			'page'                => (int) $this->page,
2500
			'page_var'            => $this->page_var,
2501
			'pagination'          => (boolean) $this->pagination,
2502
			// Search parameters.
2503
			'search'              => (boolean) $this->search,
2504
			'search_var'          => $this->search_var,
2505
			'search_query'        => null,
2506
			'search_mode'         => $this->search_mode,
2507
			'search_across'       => false,
2508
			'search_across_picks' => false,
2509
			'search_across_files' => false,
2510
			// Advanced parameters.
2511
			'filters'             => $this->filters,
2512
			'sql'                 => $sql,
2513
			// Caching parameters.
2514
			'expires'             => null,
2515
			'cache_mode'          => 'cache',
2516
		);
2517
2518
		if ( is_array( $params ) ) {
2519
			$params = (object) array_merge( $defaults, $params );
2520
		} elseif ( is_object( $params ) ) {
2521
			$params = (object) array_merge( $defaults, get_object_vars( $params ) );
2522
		} else {
2523
			$defaults['orderby'] = $params;
2524
2525
			$params = (object) $defaults;
2526
		}
2527
2528
		/**
2529
		 * Filter the Pods::find() parameters.
2530
		 *
2531
		 * @param object $params Parameters to make lookup with.
2532
		 */
2533
		$params = apply_filters( 'pods_pods_find', $params );
2534
2535
		$params->limit = (int) $params->limit;
2536
2537
		if ( 0 === $params->limit ) {
2538
			$params->limit = - 1;
2539
		}
2540
2541
		$this->limit      = (int) $params->limit;
2542
		$this->offset     = (int) $params->offset;
2543
		$this->page       = (int) $params->page;
2544
		$this->page_var   = $params->page_var;
2545
		$this->pagination = (boolean) $params->pagination;
2546
		$this->search     = (boolean) $params->search;
2547
		$this->search_var = $params->search_var;
2548
		$params->join     = (array) $params->join;
2549
2550
		if ( empty( $params->search_query ) ) {
2551
			$params->search_query = pods_v_sanitized( $this->search_var, 'get', '' );
2552
		}
2553
2554
		// Allow orderby array ( 'field' => 'asc|desc' ).
0 ignored issues
show
Unused Code Comprehensibility introduced by
36% 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...
2555
		if ( ! empty( $params->orderby ) && is_array( $params->orderby ) ) {
2556
			foreach ( $params->orderby as $k => $orderby ) {
2557
				if ( ! is_numeric( $k ) ) {
2558
					$key = '';
2559
2560
					$order = 'ASC';
2561
2562
					if ( 'DESC' === strtoupper( $orderby ) ) {
2563
						$order = 'DESC';
2564
					}
2565
2566
					if ( isset( $this->fields[ $k ] ) && in_array( $this->fields[ $k ]['type'], $tableless_field_types, true ) ) {
2567
						if ( in_array( $this->fields[ $k ]['pick_object'], $simple_tableless_objects, true ) ) {
2568
							if ( 'table' === $this->pod_data['storage'] ) {
2569
								if ( ! in_array( $this->pod_data['type'], array( 'pod', 'table' ), true ) ) {
2570
									$key = "`d`.`{$k}`";
2571
								} else {
2572
									$key = "`t`.`{$k}`";
2573
								}
2574
							} else {
2575
								$key = "`{$k}`.`meta_value`";
2576
							}
2577
						} else {
2578
							$pick_val = $this->fields[ $k ]['pick_val'];
2579
2580
							if ( '__current__' === $pick_val ) {
2581
								$pick_val = $this->pod;
2582
							}
2583
2584
							$table = $this->api->get_table_info( $this->fields[ $k ]['pick_object'], $pick_val );
2585
2586
							if ( ! empty( $table ) ) {
2587
								$key = "`{$k}`.`" . $table['field_index'] . '`';
2588
							}
2589
						}//end if
2590
					}//end if
2591
2592
					if ( empty( $key ) ) {
2593 View Code Duplication
						if ( ! in_array( $this->pod_data['type'], array( 'pod', 'table' ), true ) ) {
2594
							if ( isset( $this->pod_data['object_fields'][ $k ] ) ) {
2595
								$key = "`t`.`{$k}`";
2596
							} elseif ( isset( $this->fields[ $k ] ) ) {
2597
								if ( 'table' === $this->pod_data['storage'] ) {
2598
									$key = "`d`.`{$k}`";
2599
								} else {
2600
									$key = "`{$k}`.`meta_value`";
2601
								}
2602
							} else {
2603
								$object_fields = (array) $this->pod_data['object_fields'];
2604
2605
								foreach ( $object_fields as $object_field => $object_field_opt ) {
2606
									if ( $object_field === $k || in_array( $k, $object_field_opt['alias'], true ) ) {
2607
										$key = "`t`.`{$object_field}`";
2608
									}
2609
								}
2610
							}
2611
						} elseif ( isset( $this->fields[ $k ] ) ) {
2612
							if ( 'table' === $this->pod_data['storage'] ) {
2613
								$key = "`t`.`{$k}`";
2614
							} else {
2615
								$key = "`{$k}`.`meta_value`";
2616
							}
2617
						}//end if
2618
2619
						if ( empty( $key ) ) {
2620
							$key = $k;
2621
2622
							if ( false === strpos( $key, ' ' ) && false === strpos( $key, '`' ) ) {
2623
								$key = '`' . str_replace( '.', '`.`', $key ) . '`';
2624
							}
2625
						}
2626
					}//end if
2627
2628
					$orderby = $key;
2629
2630
					if ( false === strpos( $orderby, ' ' ) ) {
2631
						$orderby .= ' ' . $order;
2632
					}
2633
2634
					$params->orderby[ $k ] = $orderby;
2635
				}//end if
2636
			}//end foreach
2637
		}//end if
2638
2639
		// Add prefix to $params->orderby if needed.
2640
		if ( ! empty( $params->orderby ) ) {
2641
			if ( ! is_array( $params->orderby ) ) {
2642
				$params->orderby = array( $params->orderby );
2643
			}
2644
2645
			foreach ( $params->orderby as $ok => $prefix_orderby ) {
2646
				if ( false === strpos( $prefix_orderby, ',' ) && false === strpos( $prefix_orderby, '(' ) && false === stripos( $prefix_orderby, ' AS ' ) && false === strpos( $prefix_orderby, '`' ) && false === strpos( $prefix_orderby, '.' ) ) {
2647
					if ( false !== stripos( $prefix_orderby, ' DESC' ) ) {
2648
						$k   = trim( str_ireplace( array( '`', ' DESC' ), '', $prefix_orderby ) );
2649
						$dir = 'DESC';
2650
					} else {
2651
						$k   = trim( str_ireplace( array( '`', ' ASC' ), '', $prefix_orderby ) );
2652
						$dir = 'ASC';
2653
					}
2654
2655
					$key = $k;
2656
2657 View Code Duplication
					if ( ! in_array( $this->pod_data['type'], array( 'pod', 'table' ), true ) ) {
2658
						if ( isset( $this->pod_data['object_fields'][ $k ] ) ) {
2659
							$key = "`t`.`{$k}`";
2660
						} elseif ( isset( $this->fields[ $k ] ) ) {
2661
							if ( 'table' === $this->pod_data['storage'] ) {
2662
								$key = "`d`.`{$k}`";
2663
							} else {
2664
								$key = "`{$k}`.`meta_value`";
2665
							}
2666
						} else {
2667
							$object_fields = (array) $this->pod_data['object_fields'];
2668
2669
							foreach ( $object_fields as $object_field => $object_field_opt ) {
2670
								if ( $object_field === $k || in_array( $k, $object_field_opt['alias'], true ) ) {
2671
									$key = "`t`.`{$object_field}`";
2672
								}
2673
							}
2674
						}
2675
					} elseif ( isset( $this->fields[ $k ] ) ) {
2676
						if ( 'table' === $this->pod_data['storage'] ) {
2677
							$key = "`t`.`{$k}`";
2678
						} else {
2679
							$key = "`{$k}`.`meta_value`";
2680
						}
2681
					}//end if
2682
2683
					$prefix_orderby = "{$key} {$dir}";
2684
2685
					$params->orderby[ $ok ] = $prefix_orderby;
2686
				}//end if
2687
			}//end foreach
2688
		}//end if
2689
2690
		$this->data->select( $params );
2691
2692
		return $this;
2693
	}
2694
2695
	/**
2696
	 * Fetch an item from a Pod. If $id is null, it will return the next item in the list after running find().
2697
	 * You can rewind the list back to the start by using reset().
2698
	 *
2699
	 * Providing an $id will fetch a specific item from a Pod, much like a call to pods(), and can handle either an id
2700
	 * or slug.
2701
	 *
2702
	 * @see   PodsData::fetch
2703
	 *
2704
	 * @param int  $id           ID or slug of the item to fetch.
2705
	 * @param bool $explicit_set Whether to set explicitly (use false when in loop).
2706
	 *
2707
	 * @return array An array of fields from the row
2708
	 *
2709
	 * @since 2.0
2710
	 * @link  https://pods.io/docs/fetch/
2711
	 */
2712
	public function fetch( $id = null, $explicit_set = true ) {
2713
2714
		/**
2715
		 * Runs directly before an item is fetched by fetch().
2716
		 *
2717
		 * @since unknown
2718
		 *
2719
		 * @param int|string|null $id   Item ID being fetched or null.
2720
		 * @param object|Pods     $this Current Pods object.
2721
		 */
2722
		do_action( 'pods_pods_fetch', $id, $this );
2723
2724
		if ( ! empty( $id ) ) {
2725
			$this->params = array();
2726
		}
2727
2728
		$this->data->fetch( $id, $explicit_set );
2729
2730
		return $this->row;
2731
	}
2732
2733
	/**
2734
	 * (Re)set the MySQL result pointer
2735
	 *
2736
	 * @see   PodsData::reset
2737
	 *
2738
	 * @param int $row ID of the row to reset to.
2739
	 *
2740
	 * @return \Pods The pod object
2741
	 *
2742
	 * @since 2.0
2743
	 * @link  https://pods.io/docs/reset/
2744
	 */
2745
	public function reset( $row = null ) {
2746
2747
		/**
2748
		 * Runs directly before the Pods object is reset by reset()
2749
		 *
2750
		 * @since unknown
2751
		 *
2752
		 * @param int|string|null The ID of the row being reset to or null if being reset to the beginning.
2753
		 * @param object|Pods $this Current Pods object.
2754
		 */
2755
		do_action( 'pods_pods_reset', $row, $this );
2756
2757
		$this->data->reset( $row );
2758
2759
		return $this;
2760
	}
2761
2762
	/**
2763
	 * Fetch the total row count returned by the last call to find(), based on the 'limit' parameter set.
2764
	 *
2765
	 * This is different than the total number of rows found in the database, which you can get with total_found().
2766
	 *
2767
	 * @see   PodsData::total
2768
	 *
2769
	 * @return int Number of rows returned by find(), based on the 'limit' parameter set
2770
	 * @since 2.0
2771
	 * @link  https://pods.io/docs/total/
2772
	 */
2773
	public function total() {
2774
2775
		do_action( 'pods_pods_total', $this );
2776
2777
		$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...
2778
2779
		$this->total =& $this->data->total;
2780
2781
		return $this->total;
2782
	}
2783
2784
	/**
2785
	 * Fetch the total amount of rows found by the last call to find(), regardless of the 'limit' parameter set.
2786
	 *
2787
	 * This is different than the total number of rows limited by the current call, which you can get with total().
2788
	 *
2789
	 * @see   PodsData::total_found
2790
	 *
2791
	 * @return int Number of rows returned by find(), regardless of the 'limit' parameter
2792
	 * @since 2.0
2793
	 * @link  https://pods.io/docs/total-found/
2794
	 */
2795
	public function total_found() {
2796
2797
		/**
2798
		 * Runs directly before the value of total_found() is determined and returned.
2799
		 *
2800
		 * @since unknown
2801
		 *
2802
		 * @param object|Pods $this Current Pods object.
2803
		 */
2804
		do_action( 'pods_pods_total_found', $this );
2805
2806
		$this->data->total_found();
2807
2808
		$this->total_found =& $this->data->total_found;
2809
2810
		return $this->total_found;
2811
	}
2812
2813
	/**
2814
	 * Fetch the total number of pages, based on total rows found and the last find() limit
2815
	 *
2816
	 * @param null|int $limit  Rows per page.
2817
	 * @param null|int $offset Offset of rows.
2818
	 * @param null|int $total  Total rows.
2819
	 *
2820
	 * @return int Number of pages
2821
	 * @since 2.3.10
2822
	 */
2823
	public function total_pages( $limit = null, $offset = null, $total = null ) {
2824
2825
		$this->do_hook( 'total_pages' );
2826
2827
		if ( null === $limit ) {
2828
			$limit = $this->limit;
2829
		}
2830
2831
		if ( null === $offset ) {
2832
			$offset = $this->offset;
2833
		}
2834
2835
		if ( null === $total ) {
2836
			$total = $this->total_found();
2837
		}
2838
2839
		return ceil( ( $total - $offset ) / $limit );
2840
2841
	}
2842
2843
	/**
2844
	 * Fetch the zebra switch
2845
	 *
2846
	 * @see   PodsData::zebra
2847
	 *
2848
	 * @return bool Zebra state
2849
	 * @since 1.12
2850
	 */
2851
	public function zebra() {
2852
2853
		$this->do_hook( 'zebra' );
2854
2855
		return $this->data->zebra();
2856
	}
2857
2858
	/**
2859
	 * Fetch the nth state
2860
	 *
2861
	 * @see   PodsData::nth
2862
	 *
2863
	 * @param int|string $nth The $nth to match on the PodsData::row_number.
2864
	 *
2865
	 * @return bool Whether $nth matches
2866
	 * @since 2.3
2867
	 */
2868
	public function nth( $nth = null ) {
2869
2870
		$this->do_hook( 'nth', $nth );
2871
2872
		return $this->data->nth( $nth );
2873
	}
2874
2875
	/**
2876
	 * Fetch the current position in the loop (starting at 1)
2877
	 *
2878
	 * @see   PodsData::position
2879
	 *
2880
	 * @return int Current row number (+1)
2881
	 * @since 2.3
2882
	 */
2883
	public function position() {
2884
2885
		$this->do_hook( 'position' );
2886
2887
		return $this->data->position();
2888
	}
2889
2890
	/**
2891
	 * Add an item to a Pod by giving an array of field data or set a specific field to
2892
	 * a specific value if you're just wanting to add a new item but only set one field.
2893
	 *
2894
	 * You may be looking for save() in most cases where you're setting a specific field.
2895
	 *
2896
	 * @see   PodsAPI::save_pod_item
2897
	 *
2898
	 * @param array|string $data  Either an associative array of field information or a field name.
2899
	 * @param mixed        $value (optional) Value of the field, if $data is a field name.
2900
	 *
2901
	 * @return int The item ID
2902
	 *
2903
	 * @since 2.0
2904
	 * @link  https://pods.io/docs/add/
2905
	 */
2906
	public function add( $data = null, $value = null ) {
2907
2908
		if ( null !== $value ) {
2909
			$data = array( $data => $value );
2910
		}
2911
2912
		$data = (array) $this->do_hook( 'add', $data );
2913
2914
		if ( empty( $data ) ) {
2915
			return 0;
2916
		}
2917
2918
		$params = array(
2919
			'pod'                 => $this->pod,
2920
			'data'                => $data,
2921
			'allow_custom_fields' => true,
2922
		);
2923
2924
		return $this->api->save_pod_item( $params );
2925
	}
2926
2927
	/**
2928
	 * Add an item to the values of a relationship field, add a value to a number field (field+1), add time to a date
2929
	 * field, or add text to a text field
2930
	 *
2931
	 * @see   PodsAPI::save_pod_item
2932
	 *
2933
	 * @param string $field Field name.
2934
	 * @param mixed  $value IDs to add, int|float to add to number field, string for dates (+1 day), or string for text.
2935
	 * @param int    $id    (optional) ID of the pod item to update.
2936
	 *
2937
	 * @return int The item ID
2938
	 *
2939
	 * @since 2.3
2940
	 */
2941
	public function add_to( $field, $value, $id = null ) {
2942
2943
		$pod =& $this;
2944
2945
		$fetch = false;
2946
2947 View Code Duplication
		if ( null === $id ) {
2948
			$fetch = true;
2949
2950
			$id = $pod->id();
2951
			// @codingStandardsIgnoreLine
2952
		} elseif ( $id != $this->id() ) {
2953
			$pod = pods( $this->pod, $id );
2954
		}
2955
2956
		$this->do_hook( 'add_to', $field, $value, $id );
2957
2958
		if ( ! isset( $this->fields[ $field ] ) ) {
2959
			return $id;
2960
		}
2961
2962
		// Tableless fields.
2963
		if ( in_array( $this->fields[ $field ]['type'], PodsForm::tableless_field_types(), true ) ) {
2964
			if ( ! is_array( $value ) ) {
2965
				$value = explode( ',', $value );
2966
			}
2967
2968
			if ( 'pick' === $this->fields[ $field ]['type'] && in_array( $this->fields[ $field ]['pick_object'], PodsForm::simple_tableless_objects(), true ) ) {
2969
				$current_value = $pod->raw( $field );
2970
2971
				if ( ! empty( $current_value ) || ( ! is_array( $current_value ) && 0 < strlen( $current_value ) ) ) {
2972
					$current_value = (array) $current_value;
2973
				} else {
2974
					$current_value = array();
2975
				}
2976
2977
				$value = array_merge( $current_value, $value );
2978
			} else {
2979
				$related_ids = $this->api->lookup_related_items( $this->fields[ $field ]['id'], $this->pod_data['id'], $id, $this->fields[ $field ], $this->pod_data );
2980
2981
				foreach ( $value as $k => $v ) {
2982
					if ( ! preg_match( '/[^\D]/', $v ) ) {
2983
						$value[ $k ] = (int) $v;
2984
					}
2985
				}
2986
2987
				$value = array_merge( $related_ids, $value );
2988
			}//end if
2989
2990
			if ( ! empty( $value ) ) {
2991
				$value = array_filter( array_unique( $value ) );
2992
			} else {
2993
				$value = array();
2994
			}
2995
2996
			if ( empty( $value ) ) {
2997
				return $id;
2998
			}
2999 View Code Duplication
		} elseif ( in_array( $this->fields[ $field ]['type'], PodsForm::number_field_types(), true ) ) {
3000
			// Number fields.
3001
			$current_value = (float) $pod->raw( $field );
3002
3003
			$value = ( $current_value + (float) $value );
3004
		} elseif ( in_array( $this->fields[ $field ]['type'], PodsForm::date_field_types(), true ) ) {
3005
			// Date fields.
3006
			$current_value = $pod->raw( $field );
3007
3008 View Code Duplication
			if ( 0 < strlen( $current_value ) ) {
3009
				$value = strtotime( $value, strtotime( $current_value ) );
3010
			} else {
3011
				$value = strtotime( $value );
3012
			}
3013 View Code Duplication
		} elseif ( in_array( $this->fields[ $field ]['type'], PodsForm::text_field_types(), true ) ) {
3014
			// Text fields.
3015
			$current_value = $pod->raw( $field );
3016
3017
			if ( 0 < strlen( $current_value ) ) {
3018
				$value = $current_value . $value;
3019
			}
3020
		}//end if
3021
3022
		// @todo handle object fields and taxonomies.
3023
		$params = array(
3024
			'pod'  => $this->pod,
3025
			'id'   => $id,
3026
			'data' => array(
3027
				$field => $value,
3028
			),
3029
		);
3030
3031
		$id = $this->api->save_pod_item( $params );
3032
3033 View Code Duplication
		if ( 0 < $id && $fetch ) {
3034
			// Clear local var cache of field values.
3035
			$pod->data->row = array();
3036
3037
			$pod->fetch( $id, false );
3038
		}
3039
3040
		return $id;
3041
	}
3042
3043
	/**
3044
	 * Remove an item from the values of a relationship field, remove a value from a number field (field-1), remove
3045
	 * time to a date field
3046
	 *
3047
	 * @see   PodsAPI::save_pod_item
3048
	 *
3049
	 * @param string $field Field name.
3050
	 * @param mixed  $value IDs to add, int|float to add to number field, string for dates (-1 day), or string for text.
3051
	 * @param int    $id    (optional) ID of the pod item to update.
3052
	 *
3053
	 * @return int The item ID
3054
	 *
3055
	 * @since 2.3.3
3056
	 */
3057
	public function remove_from( $field, $value = null, $id = null ) {
3058
3059
		$pod =& $this;
3060
3061
		$fetch = false;
3062
3063 View Code Duplication
		if ( null === $id ) {
3064
			$fetch = true;
3065
3066
			$id = $this->id();
3067
			// @codingStandardsIgnoreLine
3068
		} elseif ( $id != $this->id() ) {
3069
			$pod = pods( $this->pod, $id );
3070
		}
3071
3072
		$this->do_hook( 'remove_from', $field, $value, $id );
3073
3074
		if ( ! isset( $this->fields[ $field ] ) ) {
3075
			return $id;
3076
		}
3077
3078
		// Tableless fields.
3079
		if ( in_array( $this->fields[ $field ]['type'], PodsForm::tableless_field_types(), true ) ) {
3080
			if ( empty( $value ) ) {
3081
				$value = array();
3082
			}
3083
3084
			if ( ! empty( $value ) ) {
3085
				if ( ! is_array( $value ) ) {
3086
					$value = explode( ',', $value );
3087
				}
3088
3089
				if ( 'pick' === $this->fields[ $field ]['type'] && in_array( $this->fields[ $field ]['pick_object'], PodsForm::simple_tableless_objects(), true ) ) {
3090
					$current_value = $pod->raw( $field );
3091
3092
					if ( ! empty( $current_value ) ) {
3093
						$current_value = (array) $current_value;
3094
					}
3095
3096
					foreach ( $current_value as $k => $v ) {
3097
						// @codingStandardsIgnoreLine.
3098
						if ( in_array( $v, $value ) ) {
3099
							unset( $current_value[ $k ] );
3100
						}
3101
					}
3102
3103
					$value = $current_value;
3104
				} else {
3105
					$related_ids = $this->api->lookup_related_items( $this->fields[ $field ]['id'], $this->pod_data['id'], $id, $this->fields[ $field ], $this->pod_data );
3106
3107
					foreach ( $value as $k => $v ) {
3108
						if ( ! preg_match( '/[^\D]/', $v ) ) {
3109
							$value[ $k ] = (int) $v;
3110
						}
3111
3112
						// @todo Convert slugs into IDs.
3113
					}
3114
3115
					foreach ( $related_ids as $k => $v ) {
3116
						// @codingStandardsIgnoreLine.
3117
						if ( in_array( $v, $value ) ) {
3118
							unset( $related_ids[ $k ] );
3119
						}
3120
					}
3121
3122
					$value = $related_ids;
3123
				}//end if
3124
3125
				if ( ! empty( $value ) ) {
3126
					$value = array_filter( array_unique( $value ) );
3127
				} else {
3128
					$value = array();
3129
				}
3130
			}//end if
3131 View Code Duplication
		} elseif ( in_array( $this->fields[ $field ]['type'], PodsForm::number_field_types(), true ) ) {
3132
			// Number fields.
3133
			// Date fields don't support empty for removing.
3134
			if ( empty( $value ) ) {
3135
				return $id;
3136
			}
3137
3138
			$current_value = (float) $pod->raw( $field );
3139
3140
			$value = ( $current_value - (float) $value );
3141
		} elseif ( in_array( $this->fields[ $field ]['type'], PodsForm::date_field_types(), true ) ) {
3142
			// Date fields.
3143
			// Date fields don't support empty for removing.
3144
			if ( empty( $value ) ) {
3145
				return $id;
3146
			}
3147
3148
			$current_value = $pod->raw( $field );
3149
3150 View Code Duplication
			if ( 0 < strlen( $current_value ) ) {
3151
				$value = strtotime( $value, strtotime( $current_value ) );
3152
			} else {
3153
				$value = strtotime( $value );
3154
			}
3155
3156
			$value = date_i18n( 'Y-m-d h:i:s', $value );
3157
		}//end if
3158
3159
		// @todo handle object fields and taxonomies.
3160
		$params = array(
3161
			'pod'  => $this->pod,
3162
			'id'   => $id,
3163
			'data' => array(
3164
				$field => $value,
3165
			),
3166
		);
3167
3168
		$id = $this->api->save_pod_item( $params );
3169
3170 View Code Duplication
		if ( 0 < $id && $fetch ) {
3171
			// Clear local var cache of field values.
3172
			$pod->data->row = array();
3173
3174
			$pod->fetch( $id, false );
3175
		}
3176
3177
		return $id;
3178
3179
	}
3180
3181
	/**
3182
	 * Save an item by giving an array of field data or set a specific field to a specific value.
3183
	 *
3184
	 * Though this function has the capacity to add new items, best practice should direct you
3185
	 * to use add() for that instead.
3186
	 *
3187
	 * @see   PodsAPI::save_pod_item
3188
	 *
3189
	 * @param array|string $data   Either an associative array of field information or a field name.
3190
	 * @param mixed        $value  (optional) Value of the field, if $data is a field name.
3191
	 * @param int          $id     (optional) ID of the pod item to update.
3192
	 * @param array        $params (optional) Additional params to send to save_pod_item.
3193
	 *
3194
	 * @return int The item ID
3195
	 *
3196
	 * @since 2.0
3197
	 * @link  https://pods.io/docs/save/
3198
	 */
3199
	public function save( $data = null, $value = null, $id = null, $params = null ) {
3200
3201
		if ( null !== $value ) {
3202
			$data = array( $data => $value );
3203
		}
3204
3205
		$fetch = false;
3206
3207
		// @codingStandardsIgnoreLine
3208
		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...
3209
			$fetch = true;
3210
3211
			if ( null === $id ) {
3212
				$id = $this->id();
3213
			}
3214
		}
3215
3216
		$data = (array) $this->do_hook( 'save', $data, $id );
3217
3218
		if ( empty( $data ) && empty( $params['is_new_item'] ) ) {
3219
			return $id;
3220
		}
3221
3222
		$default = array();
3223
3224
		if ( ! empty( $params ) && is_array( $params ) ) {
3225
			$default = $params;
3226
		}
3227
3228
		$params = array(
3229
			'pod'                 => $this->pod,
3230
			'id'                  => $id,
3231
			'data'                => $data,
3232
			'allow_custom_fields' => true,
3233
			'clear_slug_cache'    => false,
3234
		);
3235
3236
		if ( ! empty( $default ) ) {
3237
			$params = array_merge( $params, $default );
3238
		}
3239
3240
		$id = $this->api->save_pod_item( $params );
3241
3242 View Code Duplication
		if ( 0 < $id && $fetch ) {
3243
			// Clear local var cache of field values.
3244
			$this->data->row = array();
3245
3246
			$this->fetch( $id, false );
3247
		}
3248
3249
		if ( ! empty( $this->pod_data['field_slug'] ) ) {
3250
			if ( 0 < $id && $fetch ) {
3251
				$slug = $this->field( $this->pod_data['field_slug'] );
3252
			} else {
3253
				$slug = pods( $this->pod, $id )->field( $this->pod_data['field_slug'] );
3254
			}
3255
3256
			if ( 0 < strlen( $slug ) ) {
3257
				pods_cache_clear( $slug, 'pods_items_' . $this->pod );
3258
			}
3259
		}
3260
3261
		return $id;
3262
	}
3263
3264
	/**
3265
	 * Delete an item
3266
	 *
3267
	 * @see   PodsAPI::delete_pod_item
3268
	 *
3269
	 * @param int $id ID of the Pod item to delete.
3270
	 *
3271
	 * @return bool Whether the item was successfully deleted
3272
	 *
3273
	 * @since 2.0
3274
	 * @link  https://pods.io/docs/delete/
3275
	 */
3276 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...
3277
3278
		if ( null === $id ) {
3279
			$id = $this->id();
3280
		}
3281
3282
		$id = (int) $this->do_hook( 'delete', $id );
3283
3284
		if ( empty( $id ) ) {
3285
			return false;
3286
		}
3287
3288
		$params = array(
3289
			'pod' => $this->pod,
3290
			'id'  => $id,
3291
		);
3292
3293
		return $this->api->delete_pod_item( $params );
3294
	}
3295
3296
	/**
3297
	 * Reset Pod
3298
	 *
3299
	 * @see   PodsAPI::reset_pod
3300
	 *
3301
	 * @return bool Whether the Pod was successfully reset
3302
	 *
3303
	 * @since 2.1.1
3304
	 */
3305
	public function reset_pod() {
3306
3307
		$params = array( 'id' => $this->pod_id );
3308
3309
		$this->data->id   = null;
3310
		$this->data->row  = array();
3311
		$this->data->data = array();
3312
3313
		$this->data->total       = 0;
3314
		$this->data->total_found = 0;
3315
3316
		return $this->api->reset_pod( $params );
3317
	}
3318
3319
	/**
3320
	 * Duplicate an item
3321
	 *
3322
	 * @see   PodsAPI::duplicate_pod_item
3323
	 *
3324
	 * @param int $id ID of the pod item to duplicate.
3325
	 *
3326
	 * @return int|bool ID of the new pod item
3327
	 *
3328
	 * @since 2.0
3329
	 * @link  https://pods.io/docs/duplicate/
3330
	 */
3331 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...
3332
3333
		if ( null === $id ) {
3334
			$id = $this->id();
3335
		}
3336
3337
		$id = (int) $this->do_hook( 'duplicate', $id );
3338
3339
		if ( empty( $id ) ) {
3340
			return false;
3341
		}
3342
3343
		$params = array(
3344
			'pod' => $this->pod,
3345
			'id'  => $id,
3346
		);
3347
3348
		return $this->api->duplicate_pod_item( $params );
3349
	}
3350
3351
	/**
3352
	 * Import data / Save multiple rows of data at once
3353
	 *
3354
	 * @see   PodsAPI::import
3355
	 *
3356
	 * @param mixed  $import_data  PHP associative array or CSV input.
3357
	 * @param bool   $numeric_mode Use IDs instead of the name field when matching.
3358
	 * @param string $format       Format of import data, options are php or csv.
3359
	 *
3360
	 * @return array IDs of imported items
3361
	 *
3362
	 * @since 2.3
3363
	 */
3364
	public function import( $import_data, $numeric_mode = false, $format = null ) {
3365
3366
		return $this->api->import( $import_data, $numeric_mode, $format );
3367
	}
3368
3369
	/**
3370
	 * Export an item's data
3371
	 *
3372
	 * @see   PodsAPI::export_pod_item
3373
	 *
3374
	 * @param array       $fields (optional) Fields to export.
3375
	 * @param int         $id     (optional) ID of the pod item to export.
3376
	 * @param null|string $format (optional) The format of the export (php | json).
3377
	 *
3378
	 * @return array|bool Data array of the exported pod item
3379
	 *
3380
	 * @since 2.0
3381
	 * @link  https://pods.io/docs/export/
3382
	 */
3383
	public function export( $fields = null, $id = null, $format = null ) {
3384
3385
		$params = array(
3386
			'pod'     => $this->pod,
3387
			'id'      => $id,
3388
			'fields'  => null,
3389
			'depth'   => 2,
3390
			'flatten' => false,
3391
			'context' => null,
3392
			'format'  => $format,
3393
		);
3394
3395 View Code Duplication
		if ( is_array( $fields ) && ( isset( $fields['fields'] ) || isset( $fields['depth'] ) ) ) {
3396
			$params = array_merge( $params, $fields );
3397
		} else {
3398
			$params['fields'] = $fields;
3399
		}
3400
3401
		if ( isset( $params['fields'] ) && is_array( $params['fields'] ) && ! in_array( $this->pod_data['field_id'], $params['fields'], true ) ) {
3402
			$params['fields'] = array_merge( array( $this->pod_data['field_id'] ), $params['fields'] );
3403
		}
3404
3405
		if ( null === $params['id'] ) {
3406
			$params['id'] = $this->id();
3407
		}
3408
3409
		$params = (array) $this->do_hook( 'export', $params );
3410
3411
		if ( empty( $params['id'] ) ) {
3412
			return false;
3413
		}
3414
3415
		$data = $this->api->export_pod_item( $params );
3416
3417
		if ( ! empty( $params['format'] ) && 'json' === $params['format'] ) {
3418
			$data = wp_json_encode( (array) $data );
3419
		}
3420
3421
		return $data;
3422
	}
3423
3424
	/**
3425
	 * Export data from all items
3426
	 *
3427
	 * @see   PodsAPI::export
3428
	 *
3429
	 * @param array $params An associative array of parameters.
3430
	 *
3431
	 * @return array Data arrays of all exported pod items
3432
	 *
3433
	 * @since 2.3
3434
	 */
3435
	public function export_data( $params = null ) {
3436
3437
		$defaults = array(
3438
			'fields' => null,
3439
			'depth'  => 2,
3440
			'params' => null,
3441
		);
3442
3443
		if ( empty( $params ) ) {
3444
			$params = $defaults;
3445
		} else {
3446
			$params = array_merge( $defaults, (array) $params );
3447
		}
3448
3449
		return $this->api->export( $this, $params );
3450
	}
3451
3452
	/**
3453
	 * Display the pagination controls, types supported by default
3454
	 * are simple, paginate and advanced. The base and format parameters
3455
	 * are used only for the paginate view.
3456
	 *
3457
	 * @param array|object $params Associative array of parameters.
3458
	 *
3459
	 * @return string Pagination HTML
3460
	 * @since 2.0
3461
	 * @link  https://pods.io/docs/pagination/
3462
	 */
3463
	public function pagination( $params = null ) {
3464
3465
		if ( empty( $params ) ) {
3466
			$params = array();
3467
		} elseif ( ! is_array( $params ) ) {
3468
			$params = array( 'label' => $params );
3469
		}
3470
3471
		$this->page_var = pods_v( 'page_var', $params, $this->page_var );
3472
3473
		$url = pods_query_arg( null, null, $this->page_var );
3474
3475
		$append = '?';
3476
3477
		if ( false !== strpos( $url, '?' ) ) {
3478
			$append = '&';
3479
		}
3480
3481
		$defaults = array(
3482
			'type'        => 'advanced',
3483
			'label'       => __( 'Go to page:', 'pods' ),
3484
			'show_label'  => true,
3485
			'first_text'  => __( '&laquo; First', 'pods' ),
3486
			'prev_text'   => __( '&lsaquo; Previous', 'pods' ),
3487
			'next_text'   => __( 'Next &rsaquo;', 'pods' ),
3488
			'last_text'   => __( 'Last &raquo;', 'pods' ),
3489
			'prev_next'   => true,
3490
			'first_last'  => true,
3491
			'limit'       => (int) $this->limit,
3492
			'offset'      => (int) $this->offset,
3493
			'page'        => max( 1, (int) $this->page ),
3494
			'mid_size'    => 2,
3495
			'end_size'    => 1,
3496
			'total_found' => $this->total_found(),
3497
			'page_var'    => $this->page_var,
3498
			'base'        => "{$url}{$append}%_%",
3499
			'format'      => "{$this->page_var}=%#%",
3500
			'class'       => '',
3501
			'link_class'  => '',
3502
		);
3503
3504
		if ( is_object( $params ) ) {
3505
			$params = get_object_vars( $params );
3506
		}
3507
3508
		$params = (object) array_merge( $defaults, (array) $params );
3509
3510
		$params->total = $this->total_pages( $params->limit, $params->offset, $params->total_found );
3511
3512
		if ( $params->limit < 1 || $params->total_found < 1 || 1 === $params->total || $params->total_found <= $params->offset ) {
3513
			return $this->do_hook( 'pagination', $this->do_hook( 'pagination_' . $params->type, '', $params ), $params );
3514
		}
3515
3516
		$pagination = $params->type;
3517
3518
		if ( ! in_array( $params->type, array( 'simple', 'advanced', 'paginate', 'list' ), true ) ) {
3519
			$pagination = 'advanced';
3520
		}
3521
3522
		ob_start();
3523
3524
		pods_view( PODS_DIR . 'ui/front/pagination/' . $pagination . '.php', compact( array_keys( get_defined_vars() ) ) );
3525
3526
		$output = ob_get_clean();
3527
3528
		return $this->do_hook( 'pagination', $this->do_hook( 'pagination_' . $params->type, $output, $params ), $params );
3529
3530
	}
3531
3532
	/**
3533
	 * Return a filter form for searching a Pod
3534
	 *
3535
	 * @param array|string $params Comma-separated list of fields or array of parameters.
3536
	 *
3537
	 * @return string Filters HTML
3538
	 *
3539
	 * @since 2.0
3540
	 * @link  https://pods.io/docs/filters/
3541
	 */
3542
	public function filters( $params = null ) {
3543
3544
		$defaults = array(
3545
			'fields' => $params,
3546
			'label'  => '',
3547
			'action' => '',
3548
			'search' => '',
3549
		);
3550
3551
		if ( is_array( $params ) ) {
3552
			$params = array_merge( $defaults, $params );
3553
		} else {
3554
			$params = $defaults;
3555
		}
3556
3557
		$pod =& $this;
3558
3559
		/**
3560
		 * Filter the Pods::filters() parameters.
3561
		 *
3562
		 * @param array $params Parameters to filter with.
3563
		 * @param Pods  $pod    Pods object.
3564
		 */
3565
		$params = apply_filters( 'pods_filters_params', $params, $pod );
3566
3567
		$fields = $params['fields'];
3568
3569 View Code Duplication
		if ( null !== $fields && ! is_array( $fields ) && 0 < strlen( $fields ) ) {
3570
			$fields = explode( ',', $fields );
3571
		}
3572
3573
		$object_fields = (array) pods_v( 'object_fields', $this->pod_data, array(), true );
3574
3575
		// Force array.
3576
		if ( empty( $fields ) ) {
3577
			$fields = array();
3578
		} else {
3579
			// Temporary.
3580
			$filter_fields = $fields;
3581
3582
			$fields = array();
3583
3584
			foreach ( $filter_fields as $k => $field ) {
3585
				$name = $k;
3586
3587
				$defaults = array(
3588
					'name' => $name,
3589
				);
3590
3591
				if ( ! is_array( $field ) ) {
3592
					$name = $field;
3593
3594
					$field = array(
3595
						'name' => $name,
3596
					);
3597
				}
3598
3599
				// @codingStandardsIgnoreLine.
3600
				$field = array_merge( $defaults, $field );
3601
3602
				$field['name'] = trim( $field['name'] );
3603
3604
				if ( pods_v( 'hidden', $field, false, true ) ) {
3605
					$field['type'] = 'hidden';
3606
				}
3607
3608
				if ( isset( $object_fields[ $field['name'] ] ) ) {
3609
					// @codingStandardsIgnoreLine.
3610
					$fields[ $field['name'] ] = array_merge( $object_fields[ $field['name'] ], $field );
3611
				} elseif ( isset( $this->fields[ $field['name'] ] ) ) {
3612
					// @codingStandardsIgnoreLine.
3613
					$fields[ $field['name'] ] = array_merge( $this->fields[ $field['name'] ], $field );
3614
				}
3615
			}//end foreach
3616
3617
			// Cleanup.
3618
			unset( $filter_fields );
3619
		}//end if
3620
3621
		$this->filters = array_keys( $fields );
3622
3623
		$label = $params['label'];
3624
3625
		if ( '' === $label ) {
3626
			$label = __( 'Search', 'pods' );
3627
		}
3628
3629
		$action = $params['action'];
3630
3631
		$search = trim( $params['search'] );
3632
3633
		if ( '' === $search ) {
3634
			$search = pods_v_sanitized( $pod->search_var, 'get', '' );
3635
		}
3636
3637
		ob_start();
3638
3639
		pods_view( PODS_DIR . 'ui/front/filters.php', compact( array_keys( get_defined_vars() ) ) );
3640
3641
		$output = ob_get_clean();
3642
3643
		/**
3644
		 * Filter the HTML output of filters()
3645
		 *
3646
		 * @since unknown
3647
		 *
3648
		 * @param string      $output Filter output.
3649
		 * @param array       $params Params array passed to filters().
3650
		 * @param object|Pods $this   Current Pods object.
3651
		 */
3652
		return apply_filters( 'pods_pods_filters', $output, $params, $this );
3653
	}
3654
3655
	/**
3656
	 * Run a helper within a Pod Page or WP Template
3657
	 *
3658
	 * @see   Pods_Helpers::helper
3659
	 *
3660
	 * @param string|array $helper Helper name.
3661
	 * @param string       $value  Value to run the helper on.
3662
	 * @param string       $name   Field name.
3663
	 *
3664
	 * @return mixed Anything returned by the helper
3665
	 * @since 2.0
3666
	 */
3667
	public function helper( $helper, $value = null, $name = null ) {
3668
3669
		$params = array(
3670
			'helper'     => $helper,
3671
			'value'      => $value,
3672
			'name'       => $name,
3673
			'deprecated' => false,
3674
		);
3675
3676
		if ( class_exists( 'Pods_Templates' ) ) {
3677
			$params['deprecated'] = Pods_Templates::$deprecated;
3678
		}
3679
3680
		if ( is_array( $helper ) ) {
3681
			$params = array_merge( $params, $helper );
3682
		}
3683
3684
		if ( class_exists( 'Pods_Helpers' ) ) {
3685
			$value = Pods_Helpers::helper( $params, $this );
3686
		} elseif ( function_exists( $params['helper'] ) ) {
3687
			$disallowed = array(
3688
				'system',
3689
				'exec',
3690
				'popen',
3691
				'eval',
3692
				'preg_replace',
3693
				'create_function',
3694
				'include',
3695
				'include_once',
3696
				'require',
3697
				'require_once',
3698
			);
3699
3700
			$allowed = array();
3701
3702
			/**
3703
			 * Allows adjusting the disallowed callbacks as needed.
3704
			 *
3705
			 * @param array $disallowed List of callbacks not allowed.
3706
			 * @param array $params     Parameters used by Pods::helper() method.
3707
			 *
3708
			 * @since 2.7
3709
			 */
3710
			$disallowed = apply_filters( 'pods_helper_disallowed_callbacks', $disallowed, $params );
3711
3712
			/**
3713
			 * Allows adjusting the allowed allowed callbacks as needed.
3714
			 *
3715
			 * @param array $allowed List of callbacks explicitly allowed.
3716
			 * @param array $params  Parameters used by Pods::helper() method.
3717
			 *
3718
			 * @since 2.7
3719
			 */
3720
			$allowed = apply_filters( 'pods_helper_allowed_callbacks', $allowed, $params );
3721
3722
			// Clean up helper callback (if string).
3723
			if ( is_string( $params['helper'] ) ) {
3724
				$params['helper'] = strip_tags( str_replace( array( '`', chr( 96 ) ), "'", $params['helper'] ) );
3725
			}
3726
3727
			$is_allowed = false;
3728
3729
			if ( ! empty( $allowed ) ) {
3730
				if ( in_array( $params['helper'], $allowed, true ) ) {
3731
					$is_allowed = true;
3732
				}
3733
			} elseif ( ! in_array( $params['helper'], $disallowed, true ) ) {
3734
				$is_allowed = true;
3735
			}
3736
3737
			if ( $is_allowed ) {
3738
				$value = call_user_func( $params['helper'], $value );
3739
			}
3740
		} else {
3741
			$value = apply_filters( $params['helper'], $value );
3742
		}//end if
3743
3744
		return $value;
3745
	}
3746
3747
	/**
3748
	 * Display the page template
3749
	 *
3750
	 * @see   Pods_Templates::template
3751
	 *
3752
	 * @param string      $template_name The template name.
3753
	 * @param string|null $code          Custom template code to use instead.
3754
	 * @param bool        $deprecated    Whether to use deprecated functionality based on old function usage.
3755
	 *
3756
	 * @return mixed Template output
3757
	 *
3758
	 * @since 2.0
3759
	 * @link  https://pods.io/docs/template/
3760
	 */
3761
	public function template( $template_name, $code = null, $deprecated = false ) {
3762
3763
		$out = null;
3764
3765
		$obj =& $this;
3766
3767
		if ( ! empty( $code ) ) {
3768
			// backwards compatibility.
3769
			$code = str_replace( '$this->', '$obj->', $code );
3770
3771
			/**
3772
			 * Filter the template code before running it.
3773
			 *
3774
			 * @param string $code          Template code.
3775
			 * @param string $template_name Template name.
3776
			 * @param Pods  $pod            Pods object.
3777
			 */
3778
			$code = apply_filters( 'pods_templates_pre_template', $code, $template_name, $this );
3779
3780
			/**
3781
			 * Filter the template code before running it.
3782
			 *
3783
			 * @param string $code          Template code.
3784
			 * @param string $template_name Template name.
3785
			 * @param Pods  $pod            Pods object.
3786
			 */
3787
			$code = apply_filters( "pods_templates_pre_template_{$template_name}", $code, $template_name, $this );
3788
3789
			ob_start();
3790
3791
			if ( ! empty( $code ) ) {
3792
				// Only detail templates need $this->id.
3793
				if ( empty( $this->id ) ) {
3794
					while ( $this->fetch() ) {
3795
						// @codingStandardsIgnoreLine
3796
						echo $this->do_magic_tags( $code );
3797
					}
3798
				} else {
3799
					// @codingStandardsIgnoreLine
3800
					echo $this->do_magic_tags( $code );
3801
				}
3802
			}
3803
3804
			$out = ob_get_clean();
3805
3806
			/**
3807
			 * Filter the template output.
3808
			 *
3809
			 * @param string $out           Template output.
3810
			 * @param string $code          Template code.
3811
			 * @param string $template_name Template name.
3812
			 * @param Pods   $pod           Pods object.
3813
			 */
3814
			$out = apply_filters( 'pods_templates_post_template', $out, $code, $template_name, $this );
3815
3816
			/**
3817
			 * Filter the template output.
3818
			 *
3819
			 * @param string $out           Template output.
3820
			 * @param string $code          Template code.
3821
			 * @param string $template_name Template name.
3822
			 * @param Pods   $pod           Pods object.
3823
			 */
3824
			$out = apply_filters( "pods_templates_post_template_{$template_name}", $out, $code, $template_name, $this );
3825
		} elseif ( class_exists( 'Pods_Templates' ) ) {
3826
			$out = Pods_Templates::template( $template_name, $code, $this, $deprecated );
3827
		} elseif ( trim( preg_replace( '/[^a-zA-Z0-9_\-\/]/', '', $template_name ), ' /-' ) === $template_name ) {
3828
			ob_start();
3829
3830
			$default_templates = array(
3831
				'pods/' . $template_name,
3832
				'pods-' . $template_name,
3833
				$template_name,
3834
			);
3835
3836
			/**
3837
			 * Filter the default Pods Template files.
3838
			 *
3839
			 * @param array $default_templates Default Pods Template files.
3840
			 */
3841
			$default_templates = apply_filters( 'pods_template_default_templates', $default_templates );
3842
3843
			// Only detail templates need $this->id.
3844 View Code Duplication
			if ( empty( $this->id ) ) {
3845
				while ( $this->fetch() ) {
3846
					pods_template_part( $default_templates, compact( array_keys( get_defined_vars() ) ) );
3847
				}
3848
			} else {
3849
				pods_template_part( $default_templates, compact( array_keys( get_defined_vars() ) ) );
3850
			}
3851
3852
			$out = ob_get_clean();
3853
3854
			/**
3855
			 * Filter the template output.
3856
			 *
3857
			 * @param string $out           Template output.
3858
			 * @param string $code          Template code.
3859
			 * @param string $template_name Template name.
3860
			 * @param Pods   $pod           Pods object.
3861
			 */
3862
			$out = apply_filters( 'pods_templates_post_template', $out, $code, $template_name, $this );
3863
3864
			/**
3865
			 * Filter the template output.
3866
			 *
3867
			 * @param string $out           Template output.
3868
			 * @param string $code          Template code.
3869
			 * @param string $template_name Template name.
3870
			 * @param Pods   $pod           Pods object.
3871
			 */
3872
			$out = apply_filters( "pods_templates_post_template_{$template_name}", $out, $code, $template_name, $this );
3873
		}//end if
3874
3875
		return $out;
3876
	}
3877
3878
	/**
3879
	 * Embed a form to add / edit a pod item from within your theme. Provide an array of $fields to include
3880
	 * and override options where needed. For WP object based Pods, you can pass through the WP object
3881
	 * field names too, such as "post_title" or "post_content" for example.
3882
	 *
3883
	 * @param array  $params    (optional) Fields to show on the form, defaults to all fields.
3884
	 * @param string $label     (optional) Save button label, defaults to "Save Changes".
3885
	 * @param string $thank_you (optional) Thank you URL to send to upon success.
3886
	 *
3887
	 * @return bool|mixed
3888
	 * @since 2.0
3889
	 * @link  https://pods.io/docs/form/
3890
	 */
3891
	public function form( $params = null, $label = null, $thank_you = null ) {
3892
3893
		$defaults = array(
3894
			'fields'      => $params,
3895
			'label'       => $label,
3896
			'thank_you'   => $thank_you,
3897
			'fields_only' => false,
3898
		);
3899
3900
		if ( is_array( $params ) ) {
3901
			$params = array_merge( $defaults, $params );
3902
		} else {
3903
			$params = $defaults;
3904
		}
3905
3906
		$pod =& $this;
3907
3908
		$params = $this->do_hook( 'form_params', $params );
3909
3910
		$fields = $params['fields'];
3911
3912 View Code Duplication
		if ( null !== $fields && ! is_array( $fields ) && 0 < strlen( $fields ) ) {
3913
			$fields = explode( ',', $fields );
3914
		}
3915
3916
		$object_fields = (array) pods_v( 'object_fields', $this->pod_data, array(), true );
3917
3918
		if ( empty( $fields ) ) {
3919
			// Add core object fields if $fields is empty.
3920
			$fields = array_merge( $object_fields, $this->fields );
3921
		}
3922
3923
		// Temporary.
3924
		$form_fields = $fields;
3925
3926
		$fields = array();
3927
3928
		foreach ( $form_fields as $k => $field ) {
3929
			$name = $k;
3930
3931
			$defaults = array(
3932
				'name' => $name,
3933
			);
3934
3935
			if ( ! is_array( $field ) ) {
3936
				$name = $field;
3937
3938
				$field = array(
3939
					'name' => $name,
3940
				);
3941
			}
3942
3943
			// @codingStandardsIgnoreLine.
3944
			$field = array_merge( $defaults, $field );
3945
3946
			$field['name'] = trim( $field['name'] );
3947
3948
			$default_value = pods_v( 'default', $field );
3949
			$value         = pods_v( 'value', $field );
3950
3951
			if ( empty( $field['name'] ) ) {
3952
				$field['name'] = trim( $name );
3953
			}
3954
3955 View Code Duplication
			if ( isset( $object_fields[ $field['name'] ] ) ) {
3956
				// @codingStandardsIgnoreLine.
3957
				$field = array_merge( $object_fields[ $field['name'] ], $field );
3958
			} elseif ( isset( $this->fields[ $field['name'] ] ) ) {
3959
				// @codingStandardsIgnoreLine.
3960
				$field = array_merge( $this->fields[ $field['name'] ], $field );
3961
			}
3962
3963
			if ( pods_v( 'hidden', $field, false, true ) ) {
3964
				$field['type'] = 'hidden';
3965
			}
3966
3967
			$fields[ $field['name'] ] = $field;
3968
3969 View Code Duplication
			if ( empty( $this->id ) && null !== $default_value ) {
3970
				$this->row_override[ $field['name'] ] = $default_value;
3971
			} elseif ( ! empty( $this->id ) && null !== $value ) {
3972
				$this->row[ $field['name'] ] = $value;
3973
			}
3974
		}//end foreach
3975
3976
		// Cleanup.
3977
		unset( $form_fields );
3978
3979
		$fields = $this->do_hook( 'form_fields', $fields, $params );
3980
3981
		$label = $params['label'];
3982
3983
		if ( empty( $label ) ) {
3984
			$label = __( 'Save Changes', 'pods' );
3985
		}
3986
3987
		$thank_you   = $params['thank_you'];
3988
		$fields_only = $params['fields_only'];
3989
3990
		PodsForm::$form_counter ++;
3991
3992
		ob_start();
3993
3994
		if ( empty( $thank_you ) ) {
3995
			$success = 'success';
3996
3997
			if ( 1 < PodsForm::$form_counter ) {
3998
				$success .= PodsForm::$form_counter;
3999
			}
4000
4001
			$thank_you = pods_query_arg( array(
4002
				'success*' => null,
4003
				$success   => 1,
4004
			) );
4005
4006
			if ( 1 === (int) pods_v( $success, 'get', 0 ) ) {
4007
				$message = __( 'Form submitted successfully', 'pods' );
4008
4009
				/**
4010
				 * Change the text of the message that appears on successful form submission.
4011
				 *
4012
				 * @param string $message Success message.
4013
				 *
4014
				 * @returns string the message
4015
				 *
4016
				 * @since 3.0.0
4017
				 */
4018
				$message = apply_filters( 'pods_pod_form_success_message', $message );
4019
4020
				echo '<div id="message" class="pods-form-front-success">' . wp_kses_post( $message ) . '</div>';
4021
			}
4022
		}//end if
4023
4024
		pods_view( PODS_DIR . 'ui/front/form.php', compact( array_keys( get_defined_vars() ) ) );
4025
4026
		$output = ob_get_clean();
4027
4028
		if ( empty( $this->id ) ) {
4029
			$this->row_override = array();
4030
		}
4031
4032
		return $this->do_hook( 'form', $output, $fields, $label, $thank_you, $this, $this->id() );
4033
	}
4034
4035
	/**
4036
	 * Render a singular view for the Pod item content.
4037
	 *
4038
	 * @param array|string|null $fields (optional) Fields to show in the view, defaults to all fields.
4039
	 *
4040
	 * @return mixed
4041
	 * @since 2.3.10
4042
	 */
4043
	public function view( $fields = null ) {
4044
4045
		$pod =& $this;
4046
4047
		// Convert comma separated list of fields to an array.
4048 View Code Duplication
		if ( null !== $fields && ! is_array( $fields ) && 0 < strlen( $fields ) ) {
4049
			$fields = explode( ',', $fields );
4050
		}
4051
4052
		$object_fields = (array) pods_v( 'object_fields', $this->pod_data, array(), true );
4053
4054
		if ( empty( $fields ) ) {
4055
			// Add core object fields if $fields is empty.
4056
			$fields = array_merge( $object_fields, $this->fields );
4057
		}
4058
4059
		// Temporary.
4060
		$view_fields = $fields;
4061
4062
		$fields = array();
4063
4064
		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...
4065
			$defaults = array(
4066
				'name' => $name,
4067
			);
4068
4069
			if ( ! is_array( $field ) ) {
4070
				$name = $field;
4071
4072
				$field = array(
4073
					'name' => $name,
4074
				);
4075
			}
4076
4077
			// @codingStandardsIgnoreLine.
4078
			$field = array_merge( $defaults, $field );
4079
4080
			$field['name'] = trim( $field['name'] );
4081
4082
			if ( empty( $field['name'] ) ) {
4083
				$field['name'] = trim( $name );
4084
			}
4085
4086 View Code Duplication
			if ( isset( $object_fields[ $field['name'] ] ) ) {
4087
				// @codingStandardsIgnoreLine.
4088
				$field = array_merge( $field, $object_fields[ $field['name'] ] );
4089
			} elseif ( isset( $this->fields[ $field['name'] ] ) ) {
4090
				// @codingStandardsIgnoreLine.
4091
				$field = array_merge( $this->fields[ $field['name'] ], $field );
4092
			}
4093
4094 View Code Duplication
			if ( pods_v( 'hidden', $field, false, true ) || 'hidden' === $field['type'] ) {
4095
				continue;
4096
			} elseif ( ! PodsForm::permission( $field['type'], $field['name'], $field['options'], $fields, $pod, $pod->id() ) ) {
4097
				continue;
4098
			}
4099
4100
			$fields[ $field['name'] ] = $field;
4101
		}//end foreach
4102
4103
		// Cleanup.
4104
		unset( $view_fields );
4105
4106
		$output = pods_view( PODS_DIR . 'ui/front/view.php', compact( array_keys( get_defined_vars() ) ), false, 'cache', true );
4107
4108
		return $this->do_hook( 'view', $output, $fields, $this->id() );
4109
4110
	}
4111
4112
	/**
4113
	 * Replace magic tags with their values
4114
	 *
4115
	 * @param string $code The content to evaluate.
4116
	 *
4117
	 * @return string Code with Magic Tags evaluated
4118
	 *
4119
	 * @since 2.0
4120
	 */
4121
	public function do_magic_tags( $code ) {
4122
4123
		/**
4124
		 * Filters the Pods magic tags content before the default function.
4125
		 * Allows complete replacement of the Pods magic tag engine.
4126
		 *
4127
		 * @param null   $pre  Default is null which processes magic tags normally. Return any other value to override.
4128
		 * @param string $code The content to evaluate.
4129
		 * @param Pods   $pods The Pods Object.
4130
		 *
4131
		 * @since 2.7
4132
		 */
4133
		$pre = apply_filters( 'pods_pre_do_magic_tags', null, $code, $this );
4134
		if ( null !== $pre ) {
4135
			return $pre;
4136
		}
4137
4138
		return preg_replace_callback( '/({@(.*?)})/m', array( $this, 'process_magic_tags' ), $code );
4139
	}
4140
4141
	/**
4142
	 * Replace magic tags with their values
4143
	 *
4144
	 * @param string|array $tag The magic tag to process.
4145
	 *
4146
	 * @return string Code with Magic Tags evaluated
4147
	 *
4148
	 * @since 2.0.2
4149
	 */
4150
	private function process_magic_tags( $tag ) {
4151
4152
		if ( is_array( $tag ) ) {
4153
			if ( ! isset( $tag[2] ) && '' === trim( $tag[2] ) ) {
4154
				return '';
4155
			}
4156
4157
			$tag = $tag[2];
4158
		}
4159
4160
		$tag = trim( $tag, ' {@}' );
4161
		$tag = explode( ',', $tag );
4162
4163
		if ( empty( $tag ) || ! isset( $tag[0] ) || '' === trim( $tag[0] ) ) {
4164
			return '';
4165
		}
4166
4167
		foreach ( $tag as $k => $v ) {
4168
			$tag[ $k ] = trim( $v );
4169
		}
4170
4171
		$field_name = $tag[0];
4172
4173
		$helper_name = '';
4174
		$before      = '';
4175
		$after       = '';
4176
4177
		if ( isset( $tag[1] ) && ! empty( $tag[1] ) ) {
4178
			$value = $this->field( $field_name );
4179
4180
			$helper_name = $tag[1];
4181
4182
			$value = $this->helper( $helper_name, $value, $field_name );
4183
		} else {
4184
			$value = $this->display( $field_name );
4185
		}
4186
4187
		if ( isset( $tag[2] ) && ! empty( $tag[2] ) ) {
4188
			$before = $tag[2];
4189
		}
4190
4191
		if ( isset( $tag[3] ) && ! empty( $tag[3] ) ) {
4192
			$after = $tag[3];
4193
		}
4194
4195
		/**
4196
		 * Filter the magic tag output for a value.
4197
		 *
4198
		 * @param string $value      Magic tag output for value.
4199
		 * @param string $field_name Magic tag field name.
4200
		 * @param string $before     Before content.
4201
		 * @param string $after      After content.
4202
		 */
4203
		$value = apply_filters( 'pods_do_magic_tags', $value, $field_name, $helper_name, $before, $after );
4204
4205 View Code Duplication
		if ( is_array( $value ) ) {
4206
			$value = pods_serial_comma( $value, array(
4207
				'field'  => $field_name,
4208
				'fields' => $this->fields,
4209
			) );
4210
		}
4211
4212 View Code Duplication
		if ( null !== $value && false !== $value ) {
4213
			return $before . $value . $after;
4214
		}
4215
4216
		return '';
4217
	}
4218
4219
	/**
4220
	 *
4221
	 * Generate UI for Data Management
4222
	 *
4223
	 * @param mixed $options Array or String containing Pod or Options to be used.
4224
	 * @param bool  $amend   Whether to amend the default UI options or replace entirely.
4225
	 *
4226
	 * @return PodsUI|null UI object or null if custom UI used
4227
	 *
4228
	 * @since 2.3.10
4229
	 */
4230
	public function ui( $options = null, $amend = false ) {
4231
4232
		$num = '';
4233
4234
		if ( empty( $options ) ) {
4235
			$options = array();
4236
		} else {
4237
			$num = pods_v_sanitized( 'num', $options, '' );
4238
4239
			if ( empty( $num ) ) {
4240
				$num = '';
4241
			}
4242
		}
4243
4244
		$check_id = pods_v( 'id' . $num, 'get', null, true );
4245
4246
		// @codingStandardsIgnoreLine
4247
		if ( $this->id() != $check_id ) {
4248
			$this->fetch( $check_id );
4249
		}
4250
4251
		if ( ! empty( $options ) && ! $amend ) {
4252
			$this->ui = $options;
4253
4254
			return pods_ui( $this );
4255
		} elseif ( ! empty( $options ) || 'custom' !== pods_v( 'ui_style', $this->pod_data['options'], 'post_type', true ) ) {
4256
			$actions_enabled = pods_v( 'ui_actions_enabled', $this->pod_data['options'] );
4257
4258
			if ( ! empty( $actions_enabled ) ) {
4259
				$actions_enabled = (array) $actions_enabled;
4260
			} else {
4261
				$actions_enabled = array();
4262
			}
4263
4264
			$available_actions = array(
4265
				'add',
4266
				'edit',
4267
				'duplicate',
4268
				'delete',
4269
				'reorder',
4270
				'export',
4271
			);
4272
4273
			if ( ! empty( $actions_enabled ) ) {
4274
				$actions_disabled = array(
4275
					'view' => 'view',
4276
				);
4277
4278
				foreach ( $available_actions as $action ) {
4279
					if ( ! in_array( $action, $actions_enabled, true ) ) {
4280
						$actions_disabled[ $action ] = $action;
4281
					}
4282
				}
4283
			} else {
4284
				$actions_disabled = array(
4285
					'duplicate' => 'duplicate',
4286
					'view'      => 'view',
4287
					'export'    => 'export',
4288
				);
4289
4290
				if ( 1 === pods_v( 'ui_export', $this->pod_data['options'], 0 ) ) {
4291
					unset( $actions_disabled['export'] );
4292
				}
4293
			}//end if
4294
4295
			if ( empty( $options ) ) {
4296
				$author_restrict = false;
4297
4298
				if ( isset( $this->fields['author'] ) && 'pick' === $this->fields['author']['type'] && 'user' === $this->fields['author']['pick_object'] ) {
4299
					$author_restrict = 'author.ID';
4300
				}
4301
4302
				if ( ! pods_is_admin( array( 'pods', 'pods_content' ) ) ) {
4303
					if ( ! current_user_can( 'pods_add_' . $this->pod ) ) {
4304
						$actions_disabled['add'] = 'add';
4305
4306
						if ( 'add' === pods_v( 'action' . $num, 'get' ) ) {
4307
							$_GET[ 'action' . $num ] = 'manage';
4308
						}
4309
					}
4310
4311 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...
4312
						$actions_disabled['edit'] = 'edit';
4313
					}
4314
4315 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...
4316
						$actions_disabled['delete'] = 'delete';
4317
					}
4318
4319
					if ( ! current_user_can( 'pods_reorder_' . $this->pod ) ) {
4320
						$actions_disabled['reorder'] = 'reorder';
4321
					}
4322
4323
					if ( ! current_user_can( 'pods_export_' . $this->pod ) ) {
4324
						$actions_disabled['export'] = 'export';
4325
					}
4326
				}//end if
4327
			}//end if
4328
4329
			$_GET[ 'action' . $num ] = pods_v_sanitized( 'action' . $num, 'get', pods_v( 'action', $options, 'manage' ), true );
4330
4331
			$index = $this->pod_data['field_id'];
4332
			$label = __( 'ID', 'pods' );
4333
4334
			if ( isset( $this->pod_data['fields'][ $this->pod_data['field_index'] ] ) ) {
4335
				$index = $this->pod_data['field_index'];
4336
				$label = $this->pod_data['fields'][ $this->pod_data['field_index'] ];
4337
			}
4338
4339
			$manage = array(
4340
				$index => $label,
4341
			);
4342
4343
			if ( isset( $this->pod_data['fields']['modified'] ) ) {
4344
				$manage['modified'] = $this->pod_data['fields']['modified']['label'];
4345
			}
4346
4347
			$manage_fields = (array) pods_v( 'ui_fields_manage', $this->pod_data['options'] );
4348
4349
			if ( ! empty( $manage_fields ) ) {
4350
				$manage_new = array();
4351
4352
				foreach ( $manage_fields as $manage_field ) {
4353
					if ( isset( $this->pod_data['fields'][ $manage_field ] ) ) {
4354
						$manage_new[ $manage_field ] = $this->pod_data['fields'][ $manage_field ];
4355
					} elseif ( isset( $this->pod_data['object_fields'][ $manage_field ] ) ) {
4356
						$manage_new[ $manage_field ] = $this->pod_data['object_fields'][ $manage_field ];
4357
					} elseif ( $manage_field === $this->pod_data['field_id'] ) {
4358
						$field = array(
4359
							'name'  => $manage_field,
4360
							'label' => 'ID',
4361
							'type'  => 'number',
4362
							'width' => '8%',
4363
						);
4364
4365
						$manage_new[ $manage_field ] = PodsForm::field_setup( $field, null, $field['type'] );
4366
					}
4367
				}
4368
4369
				if ( ! empty( $manage_new ) ) {
4370
					$manage = $manage_new;
4371
				}
4372
			}//end if
4373
4374
			$manage = apply_filters( 'pods_admin_ui_fields_' . $this->pod, apply_filters( 'pods_admin_ui_fields', $manage, $this->pod, $this ), $this->pod, $this );
4375
4376
			$icon = pods_v( 'ui_icon', $this->pod_data['options'] );
4377
4378
			if ( ! empty( $icon ) ) {
4379
				$icon = pods_image_url( $icon, '32x32' );
4380
			}
4381
4382
			$filters = pods_v( 'ui_filters', $this->pod_data['options'] );
4383
4384
			if ( ! empty( $filters ) ) {
4385
				$filters_new = array();
4386
4387
				$filters = (array) $filters;
4388
4389
				foreach ( $filters as $filter_field ) {
4390
					if ( isset( $this->pod_data['fields'][ $filter_field ] ) ) {
4391
						$filters_new[ $filter_field ] = $this->pod_data['fields'][ $filter_field ];
4392
					} elseif ( isset( $this->pod_data['object_fields'][ $filter_field ] ) ) {
4393
						$filters_new[ $filter_field ] = $this->pod_data['object_fields'][ $filter_field ];
4394
					}
4395
				}
4396
4397
				$filters = $filters_new;
4398
			}
4399
4400
			$ui = array(
4401
				'fields'           => array(
4402
					'manage'    => $manage,
4403
					'add'       => $this->pod_data['fields'],
4404
					'edit'      => $this->pod_data['fields'],
4405
					'duplicate' => $this->pod_data['fields'],
4406
				),
4407
				'icon'             => $icon,
4408
				'actions_disabled' => $actions_disabled,
4409
				'actions_bulk'     => array(),
4410
			);
4411
4412
			if ( ! empty( $filters ) ) {
4413
				$ui['fields']['search'] = $filters;
4414
				$ui['filters']          = array_keys( $filters );
4415
				$ui['filters_enhanced'] = true;
4416
			}
4417
4418
			$reorder_field = pods_v( 'ui_reorder_field', $this->pod_data['options'] );
4419
4420
			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 ] ) ) ) {
4421
				$ui['reorder']     = array( 'on' => $reorder_field );
4422
				$ui['orderby']     = $reorder_field;
4423
				$ui['orderby_dir'] = 'ASC';
4424
			}
4425
4426
			if ( ! empty( $author_restrict ) ) {
4427
				$ui['restrict'] = array( 'author_restrict' => $author_restrict );
4428
			}
4429
4430 View Code Duplication
			if ( ! in_array( 'export', $ui['actions_disabled'], true ) ) {
4431
				$ui['actions_bulk']['export'] = array(
4432
					'label' => __( 'Export', 'pods' ),
4433
					// callback not needed, Pods has this built-in for export.
4434
				);
4435
			}
4436
4437 View Code Duplication
			if ( ! in_array( 'delete', $ui['actions_disabled'], true ) ) {
4438
				$ui['actions_bulk']['delete'] = array(
4439
					'label' => __( 'Delete', 'pods' ),
4440
					// callback not needed, Pods has this built-in for delete.
4441
				);
4442
			}
4443
4444
			$detail_url = pods_v( 'detail_url', $this->pod_data['options'] );
4445
4446
			if ( 0 < strlen( $detail_url ) ) {
4447
				$ui['actions_custom'] = array(
4448
					'view_url' => array(
4449
						'label' => 'View',
4450
						'link'  => get_site_url() . '/' . $detail_url,
4451
					),
4452
				);
4453
			}
4454
4455
			// @todo Customize the Add New / Manage links to point to their correct menu items.
4456
			$ui = apply_filters( 'pods_admin_ui_' . $this->pod, apply_filters( 'pods_admin_ui', $ui, $this->pod, $this ), $this->pod, $this );
4457
4458
			// Override UI options.
4459
			foreach ( $options as $option => $value ) {
4460
				$ui[ $option ] = $value;
4461
			}
4462
4463
			$this->ui = $ui;
4464
4465
			return pods_ui( $this );
4466
		}//end if
4467
4468
		do_action( 'pods_admin_ui_custom', $this );
4469
		do_action( 'pods_admin_ui_custom_' . $this->pod, $this );
4470
4471
		return null;
4472
	}
4473
4474
	/**
4475
	 * Handle filters / actions for the class
4476
	 *
4477
	 * @see   pods_do_hook
4478
	 *
4479
	 * @param string $name Hook name.
4480
	 *
4481
	 * @return mixed Value filtered
4482
	 *
4483
	 * @since 2.0
4484
	 */
4485 View Code Duplication
	private function do_hook( $name ) {
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...
4486
4487
		$args = func_get_args();
4488
4489
		if ( empty( $args ) ) {
4490
			return false;
4491
		}
4492
4493
		// Remove first argument.
4494
		array_shift( $args );
4495
4496
		return pods_do_hook( 'pods', $name, $args, $this );
4497
	}
4498
4499
	/**
4500
	 * Handle variables that have been deprecated and PodsData vars
4501
	 *
4502
	 * @param string $name Property name.
4503
	 *
4504
	 * @return mixed
4505
	 *
4506
	 * @since 2.0
4507
	 */
4508
	public function __get( $name ) {
4509
4510
		$name = (string) $name;
4511
4512
		// PodsData vars.
4513
		if ( isset( $this->data->{$name} ) && 0 === strpos( $name, 'field_' ) ) {
4514
			return $this->data->{$name};
4515
		}
4516
4517
		if ( ! $this->deprecated ) {
4518
			require_once PODS_DIR . 'deprecated/classes/Pods.php';
4519
4520
			$this->deprecated = new Pods_Deprecated( $this );
4521
		}
4522
4523
		$var = null;
4524
4525
		$pod_class_exists = class_exists( 'Pod' );
4526
4527
		if ( isset( $this->deprecated->{$name} ) ) {
4528
			if ( ! $pod_class_exists || Pod::$deprecated_notice ) {
4529
				pods_deprecated( "Pods->{$name}", '2.0' );
4530
			}
4531
4532
			$var = $this->deprecated->{$name};
4533
		} elseif ( ! $pod_class_exists || Pod::$deprecated_notice ) {
4534
			pods_deprecated( "Pods->{$name}", '2.0' );
4535
		}
4536
4537
		return $var;
4538
	}
4539
4540
	/**
4541
	 * Handle methods that have been deprecated and any aliasing.
4542
	 *
4543
	 * @param string $name Function name.
4544
	 * @param array  $args Arguments passed to function.
4545
	 *
4546
	 * @return mixed|null
4547
	 *
4548
	 * @since 2.0
4549
	 */
4550
	public function __call( $name, $args ) {
4551
4552
		$name = (string) $name;
4553
4554
		// select > find alias.
4555
		if ( 'select' === $name ) {
4556
			return call_user_func_array( array( $this, 'find' ), $args );
4557
		}
4558
4559
		if ( ! $this->deprecated ) {
4560
			require_once PODS_DIR . 'deprecated/classes/Pods.php';
4561
4562
			$this->deprecated = new Pods_Deprecated( $this );
4563
		}
4564
4565
		$pod_class_exists = class_exists( 'Pod' );
4566
4567 View Code Duplication
		if ( method_exists( $this->deprecated, $name ) ) {
4568
			return call_user_func_array( array( $this->deprecated, $name ), $args );
4569
			// @codingStandardsIgnoreLine
4570
		} elseif ( ! $pod_class_exists || Pod::$deprecated_notice ) {
4571
			pods_deprecated( "Pods::{$name}", '2.0' );
4572
		}
4573
4574
		return null;
4575
	}
4576
4577
	/**
4578
	 * Handle casting a Pods() object to string
4579
	 *
4580
	 * @return string Pod type and name in CURIE notation
4581
	 */
4582
	public function __toString() {
4583
4584
		$string = '';
4585
4586
		if ( ! empty( $this->pod_data ) ) {
4587
			$string = sprintf( '%s:%s', $this->pod_data['type'], $this->pod_data['name'] );
4588
		}
4589
4590
		return $string;
4591
4592
	}
4593
}
4594