PageRenderTime 56ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/classes/Pods.php

https://github.com/ElmsPark/pods
PHP | 2144 lines | 1218 code | 424 blank | 502 comment | 346 complexity | 90263c31ee632c475bd9879b94480c5b MD5 | raw file
Possible License(s): AGPL-1.0

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /**
  3. * @package Pods
  4. */
  5. class Pods {
  6. /**
  7. * @var PodsAPI
  8. */
  9. public $api;
  10. /**
  11. * @var PodsData
  12. */
  13. public $data;
  14. /**
  15. * @var Array of pod item arrays
  16. */
  17. public $rows;
  18. /**
  19. * @var Current pod item array
  20. */
  21. public $row;
  22. /**
  23. * @var bool
  24. */
  25. public $display_errors = false;
  26. /**
  27. * @var array|bool|mixed|null|void
  28. */
  29. public $pod_data;
  30. /**
  31. * @var array
  32. */
  33. public $params = array();
  34. /**
  35. * @var
  36. */
  37. public $pod;
  38. /**
  39. * @var
  40. */
  41. public $pod_id;
  42. /**
  43. * @var
  44. */
  45. public $fields;
  46. /**
  47. * @var
  48. */
  49. public $detail_page;
  50. /**
  51. * @var int
  52. */
  53. public $id;
  54. /**
  55. * @var int
  56. */
  57. public $limit = 15;
  58. /**
  59. * @var string
  60. */
  61. public $page_var = 'pg';
  62. /**
  63. * @var int|mixed
  64. */
  65. public $page = 1;
  66. /**
  67. * @var bool
  68. */
  69. public $pagination = true;
  70. /**
  71. * @var bool
  72. */
  73. public $search = true;
  74. /**
  75. * @var string
  76. */
  77. public $search_var = 'search';
  78. /**
  79. * @var string
  80. */
  81. public $search_mode = 'int'; // int | text | text_like
  82. /**
  83. * @var int
  84. */
  85. public $total = 0;
  86. /**
  87. * @var int
  88. */
  89. public $total_found = 0;
  90. /**
  91. * @var
  92. */
  93. public $ui = array();
  94. /**
  95. * @var
  96. */
  97. public $deprecated;
  98. public $datatype;
  99. public $datatype_id;
  100. public $page_template;
  101. public $body_classes;
  102. public $meta = array();
  103. public $meta_properties = array();
  104. public $meta_extra = '';
  105. public $sql;
  106. /**
  107. * Constructor - Pods Framework core
  108. *
  109. * @param string $pod The pod name
  110. * @param mixed $id (optional) The ID or slug, to load a single record; Provide array of $params to run 'find'
  111. *
  112. * @license http://www.gnu.org/licenses/gpl-2.0.html
  113. * @since 1.0.0
  114. * @link http://podsframework.org/docs/pods/
  115. */
  116. public function __construct ( $pod = null, $id = null ) {
  117. if ( null === $pod ) {
  118. $pod = get_post_type();
  119. if ( null === $id )
  120. $id = get_the_ID();
  121. }
  122. $this->api = pods_api( $pod );
  123. $this->api->display_errors =& $this->display_errors;
  124. $this->data = pods_data( $this->api, $id, false );
  125. PodsData::$display_errors =& $this->display_errors;
  126. // Set up page variable
  127. if ( defined( 'PODS_STRICT_MODE' ) && PODS_STRICT_MODE ) {
  128. $this->page = 1;
  129. $this->pagination = false;
  130. $this->search = false;
  131. }
  132. else {
  133. // Get the page variable
  134. $this->page = pods_var( $this->page_var, 'get' );
  135. $this->page = ( empty( $this->page ) ? 1 : max( pods_absint( $this->page ), 1 ) );
  136. }
  137. // Set default pagination handling to on/off
  138. if ( defined( 'PODS_GLOBAL_POD_PAGINATION' ) ) {
  139. if ( !PODS_GLOBAL_POD_PAGINATION ) {
  140. $this->page = 1;
  141. $this->pagination = false;
  142. }
  143. else
  144. $this->pagination = true;
  145. }
  146. // Set default search to on/off
  147. if ( defined( 'PODS_GLOBAL_POD_SEARCH' ) ) {
  148. if ( PODS_GLOBAL_POD_SEARCH )
  149. $this->search = true;
  150. else
  151. $this->search = false;
  152. }
  153. // Set default search mode
  154. $allowed_search_modes = array( 'int', 'text', 'text_like' );
  155. if ( defined( 'PODS_GLOBAL_POD_SEARCH_MODE' ) && in_array( PODS_GLOBAL_POD_SEARCH_MODE, $allowed_search_modes ) )
  156. $this->search_mode = PODS_GLOBAL_POD_SEARCH_MODE;
  157. // Sync Settings
  158. $this->data->page =& $this->page;
  159. $this->data->limit =& $this->limit;
  160. $this->data->pagination =& $this->pagination;
  161. $this->data->search =& $this->search;
  162. $this->data->search_mode =& $this->search_mode;
  163. // Sync Pod Data
  164. $this->api->pod_data =& $this->data->pod_data;
  165. $this->pod_data =& $this->api->pod_data;
  166. $this->api->pod_id =& $this->data->pod_id;
  167. $this->pod_id =& $this->api->pod_id;
  168. $this->datatype_id =& $this->pod_id;
  169. $this->api->pod =& $this->data->pod;
  170. $this->pod =& $this->api->pod;
  171. $this->datatype =& $this->pod;
  172. $this->api->fields =& $this->data->fields;
  173. $this->fields =& $this->api->fields;
  174. $this->detail_page =& $this->data->detail_page;
  175. $this->id =& $this->data->id;
  176. $this->row =& $this->data->row;
  177. $this->rows =& $this->data->data;
  178. if ( is_array( $id ) || is_object( $id ) )
  179. $this->find( $id );
  180. }
  181. /**
  182. * Whether this Pod object is valid or not
  183. *
  184. * @return bool
  185. *
  186. * @since 2.0.0
  187. */
  188. public function valid () {
  189. if ( empty( $this->pod_id ) )
  190. return false;
  191. return true;
  192. }
  193. /**
  194. * Whether a Pod item exists or not when using fetch() or construct with an ID or slug
  195. *
  196. * @return bool
  197. *
  198. * @since 2.0.0
  199. */
  200. public function exists () {
  201. if ( empty( $this->row ) )
  202. return false;
  203. return true;
  204. }
  205. /**
  206. * Return an array of all rows returned from a find() call.
  207. *
  208. * Most of the time, you will want to loop through data using fetch()
  209. * instead of using this function.
  210. *
  211. * @return array|bool An array of all rows returned from a find() call, or false if no items returned
  212. *
  213. * @since 2.0.0
  214. * @link http://podsframework.org/docs/data/
  215. */
  216. public function data () {
  217. $this->do_hook( 'data' );
  218. if ( empty( $this->rows ) )
  219. return false;
  220. return (array) $this->rows;
  221. }
  222. /**
  223. * Return field array from a Pod
  224. *
  225. * @return array
  226. *
  227. * @since 2.0.0
  228. */
  229. public function fields () {
  230. $this->do_hook( 'fields' );
  231. if ( empty( $this->fields ) )
  232. return false;
  233. return (array) $this->fields;
  234. }
  235. /**
  236. * Return row array for an item
  237. *
  238. * @return array
  239. *
  240. * @since 2.0.0
  241. */
  242. public function row () {
  243. $this->do_hook( 'row' );
  244. if ( empty( $this->row ) )
  245. return false;
  246. return (array) $this->row;
  247. }
  248. /**
  249. * Return the output for a field. If you want the raw value for use in PHP for custom manipulation,
  250. * you will want to use field() instead. This function will automatically convert arrays into a
  251. * list of text such as "Rick, John, and Gary"
  252. *
  253. * @param string|array $name The field name, or an associative array of parameters
  254. * @param boolean $single (optional) For tableless fields, to return an array or the first
  255. *
  256. * @return string|null|false The output from the field, null if the field doesn't exist, false if no value returned for tableless fields
  257. * @since 2.0.0
  258. * @link http://podsframework.org/docs/display/
  259. */
  260. public function display ( $name, $single = null ) {
  261. $simple_tableless_objects = PodsForm::field_method( 'pick', 'simple_objects' );
  262. $defaults = array(
  263. 'name' => $name,
  264. 'orderby' => null,
  265. 'single' => $single,
  266. 'args' => array(),
  267. 'in_form' => false
  268. );
  269. if ( is_array( $name ) || is_object( $name ) )
  270. $params = (object) array_merge( $defaults, (array) $name );
  271. else
  272. $params = (object) $defaults;
  273. if ( is_array( $params->single ) ) {
  274. $params->args = $params->single;
  275. $params->single = null;
  276. }
  277. $value = $this->field( $params );
  278. if ( false === $params->in_form && isset( $this->fields[ $params->name ] ) ) {
  279. if ( 'pick' == $this->fields[ $params->name ][ 'type' ] && in_array( $this->fields[ $params->name ][ 'pick_object' ], $simple_tableless_objects ) )
  280. $value = PodsForm::field_method( 'pick', 'simple_value', $value, $this->fields[ $params->name ] );
  281. if ( 0 < strlen( pods_var( 'display_filter', $this->fields[ $params->name ] ) ) )
  282. $value = apply_filters( pods_var( 'display_filter', $this->fields[ $params->name ] ), $value );
  283. else {
  284. $value = PodsForm::display(
  285. $this->fields[ $params->name ][ 'type' ],
  286. $value,
  287. $params->name,
  288. array_merge( $this->fields[ $params->name ][ 'options' ], $this->fields[ $params->name ] ),
  289. $this->pod_data,
  290. $this->id(),
  291. $params
  292. );
  293. }
  294. }
  295. if ( is_array( $value ) )
  296. $value = pods_serial_comma( $value, $params->name, $this->fields );
  297. return $value;
  298. }
  299. /**
  300. * Return the raw output for a field If you want the raw value for use in PHP for custom manipulation,
  301. * you will want to use field() instead. This function will automatically convert arrays into a
  302. * list of text such as "Rick, John, and Gary"
  303. *
  304. * @param string|array $name The field name, or an associative array of parameters
  305. * @param boolean $single (optional) For tableless fields, to return an array or the first
  306. *
  307. * @return string|null|false The output from the field, null if the field doesn't exist, false if no value returned for tableless fields
  308. * @since 2.0.0
  309. * @link http://podsframework.org/docs/display/
  310. */
  311. public function raw ( $name, $single = null ) {
  312. $defaults = array(
  313. 'name' => $name,
  314. 'orderby' => null,
  315. 'single' => $single,
  316. 'in_form' => false,
  317. 'raw' => true
  318. );
  319. if ( is_array( $name ) || is_object( $name ) )
  320. $params = (object) array_merge( $defaults, (array) $name );
  321. else
  322. $params = (object) $defaults;
  323. $value = $this->field( $params );
  324. return $value;
  325. }
  326. /**
  327. * Return the value for a field.
  328. *
  329. * If you are getting a field for output in a theme, most of the time you will want to use display() instead.
  330. *
  331. * This function will return arrays for relationship and file fields.
  332. *
  333. * @param string|array $name The field name, or an associative array of parameters
  334. * @param boolean $single (optional) For tableless fields, to return the whole array or the just the first item
  335. * @param boolean $raw (optional) Whether to return the raw value, or to run through the field type's display method
  336. *
  337. * @return mixed|null Value returned depends on the field type, null if the field doesn't exist, false if no value returned for tableless fields
  338. * @since 2.0.0
  339. * @link http://podsframework.org/docs/field/
  340. */
  341. public function field ( $name, $single = null, $raw = false ) {
  342. $defaults = array(
  343. 'name' => $name,
  344. 'orderby' => null,
  345. 'single' => $single,
  346. 'in_form' => false,
  347. 'raw' => $raw,
  348. 'deprecated' => false
  349. );
  350. if ( is_array( $name ) || is_object( $name ) )
  351. $params = (object) array_merge( $defaults, (array) $name );
  352. else
  353. $params = (object) $defaults;
  354. // Support old $orderby variable
  355. if ( null !== $params->single && !is_bool( $params->single ) && empty( $params->orderby ) ) {
  356. pods_deprecated( 'Pods::field', '2.0.0', 'Use $params[ \'orderby\' ] instead' );
  357. $params->orderby = $params->single;
  358. $params->single = false;
  359. }
  360. if ( null !== $params->single )
  361. $params->single = (boolean) $params->single;
  362. $single = $params->single;
  363. if ( is_array( $params->name ) || strlen( $params->name ) < 1 )
  364. return null;
  365. if ( false === $this->row() ) {
  366. if ( false !== $this->data() )
  367. $this->fetch();
  368. else
  369. return null;
  370. }
  371. if ( $this->data->field_id == $params->name ) {
  372. if ( isset( $this->row[ $params->name ] ) )
  373. return $this->row[ $params->name ];
  374. return 0;
  375. }
  376. $value = null;
  377. $tableless_field_types = apply_filters( 'pods_tableless_field_types', array( 'pick', 'file', 'avatar', 'taxonomy' ) );
  378. $simple_tableless_objects = PodsForm::field_method( 'pick', 'simple_objects' );
  379. $params->traverse = array();
  380. if ( 'detail_url' == $params->name || ( in_array( $params->name, array( 'permalink', 'the_permalink' ) ) && in_array( $this->pod_data[ 'type' ], array( 'post_type', 'media' ) ) ) ) {
  381. if ( 0 < strlen( $this->detail_page ) )
  382. $value = get_bloginfo( 'url' ) . '/' . $this->do_magic_tags( $this->detail_page );
  383. elseif ( in_array( $this->pod_data[ 'type' ], array( 'post_type', 'media' ) ) )
  384. $value = get_permalink( $this->id() );
  385. elseif ( 'taxonomy' == $this->pod_data[ 'type' ] )
  386. $value = get_term_link( $this->id(), $this->pod_data[ 'name' ] );
  387. elseif ( 'user' == $this->pod_data[ 'type' ] )
  388. $value = get_author_posts_url( $this->id() );
  389. elseif ( 'comment' == $this->pod_data[ 'type' ] )
  390. $value = get_comment_link( $this->id() );
  391. }
  392. if ( empty( $value ) && isset( $this->row[ $params->name ] ) ) {
  393. if ( !isset( $this->fields[ $params->name ] ) || in_array( $this->fields[ $params->name ][ 'type' ], array( 'boolean', 'number', 'currency' ) ) || in_array( $this->fields[ $params->name ][ 'type' ], $tableless_field_types ) )
  394. $params->raw = true;
  395. $value = $this->row[ $params->name ];
  396. if ( !is_array( $value ) && isset( $this->fields[ $params->name ] ) && 'pick' == $this->fields[ $params->name ][ 'type' ] && in_array( $this->fields[ $params->name ][ 'pick_object' ], $simple_tableless_objects ) )
  397. $value = PodsForm::field_method( 'pick', 'simple_value', $value, $this->fields[ $params->name ], true );
  398. }
  399. elseif ( empty( $value ) ) {
  400. $object_field_found = false;
  401. $first_field = explode( '.', $params->name );
  402. $first_field = $first_field[ 0 ];
  403. // @todo Handle Author WP object fields like they are pick fields
  404. foreach ( $this->pod_data[ 'object_fields' ] as $object_field => $object_field_opt ) {
  405. if ( $object_field == $first_field || in_array( $first_field, $object_field_opt[ 'alias' ] ) ) {
  406. if ( isset( $this->row[ $object_field ] ) ) {
  407. $value = $this->row[ $object_field ];
  408. $object_field_found = true;
  409. }
  410. elseif ( in_array( $object_field_opt[ 'type' ], $tableless_field_types ) )
  411. $this->fields[ $object_field ] = $object_field_opt;
  412. else
  413. return null;
  414. }
  415. }
  416. if ( 'post_type' == $this->pod_data[ 'type' ] ) {
  417. if ( 'post_thumbnail' == $params->name || 0 === strpos( $params->name, 'post_thumbnail.' ) ) {
  418. $size = 'thumbnail';
  419. if ( 0 === strpos( $params->name, 'post_thumbnail.' ) ) {
  420. $field_names = explode( '.', $params->name );
  421. if ( isset( $field_names[ 1 ] ) )
  422. $size = $field_names[ 1 ];
  423. }
  424. // Pods will auto-get the thumbnail ID if this isn't an attachment
  425. $value = pods_image( $this->id(), $size );
  426. $object_field_found = true;
  427. }
  428. elseif ( 'post_thumbnail_url' == $params->name || 0 === strpos( $params->name, 'post_thumbnail_url.' ) ) {
  429. $size = 'thumbnail';
  430. if ( 0 === strpos( $params->name, 'post_thumbnail_url.' ) ) {
  431. $field_names = explode( '.', $params->name );
  432. if ( isset( $field_names[ 1 ] ) )
  433. $size = $field_names[ 1 ];
  434. }
  435. // Pods will auto-get the thumbnail ID if this isn't an attachment
  436. $value = pods_image_url( $this->id(), $size );
  437. $object_field_found = true;
  438. }
  439. }
  440. elseif ( 'image_attachment' == $params->name || 0 === strpos( $params->name, 'image_attachment.' ) ) {
  441. $size = 'thumbnail';
  442. $image_id = 0;
  443. if ( 0 === strpos( $params->name, 'image_attachment.' ) ) {
  444. $field_names = explode( '.', $params->name );
  445. if ( isset( $field_names[ 1 ] ) )
  446. $image_id = $field_names[ 1 ];
  447. if ( isset( $field_names[ 2 ] ) )
  448. $size = $field_names[ 2 ];
  449. }
  450. if ( !empty( $image_id ) )
  451. $value = pods_image_url( $image_id, $size );
  452. $object_field_found = true;
  453. }
  454. elseif ( 'image_attachment_url' == $params->name || 0 === strpos( $params->name, 'image_attachment_url.' ) ) {
  455. $size = 'thumbnail';
  456. $image_id = 0;
  457. if ( 0 === strpos( $params->name, 'image_attachment_url.' ) ) {
  458. $field_names = explode( '.', $params->name );
  459. if ( isset( $field_names[ 1 ] ) )
  460. $image_id = $field_names[ 1 ];
  461. if ( isset( $field_names[ 2 ] ) )
  462. $size = $field_names[ 2 ];
  463. }
  464. if ( !empty( $image_id ) )
  465. $value = pods_image_url( $image_id, $size );
  466. $object_field_found = true;
  467. }
  468. if ( false === $object_field_found ) {
  469. $params->traverse = array( $params->name );
  470. if ( false !== strpos( $params->name, '.' ) ) {
  471. $params->traverse = explode( '.', $params->name );
  472. $params->name = $params->traverse[ 0 ];
  473. }
  474. if ( isset( $this->fields[ $params->name ] ) && isset( $this->fields[ $params->name ][ 'type' ] ) ) {
  475. $v = $this->do_hook( 'field_' . $this->fields[ $params->name ][ 'type' ], null, $this->fields[ $params->name ], $this->row, $params );
  476. if ( null !== $v )
  477. return $v;
  478. }
  479. $simple = false;
  480. $simple_data = array();
  481. if ( isset( $this->fields[ $params->name ] ) ) {
  482. if ( 'meta' == $this->pod_data[ 'storage' ] ) {
  483. if ( !in_array( $this->fields[ $params->name ][ 'type' ], $tableless_field_types ) )
  484. $simple = true;
  485. }
  486. if ( in_array( $this->fields[ $params->name ][ 'type' ], $tableless_field_types ) ) {
  487. $params->raw = true;
  488. if ( in_array( $this->fields[ $params->name ][ 'pick_object' ], $simple_tableless_objects ) ) {
  489. $simple = true;
  490. $params->single = true;
  491. }
  492. }
  493. elseif ( in_array( $this->fields[ $params->name ][ 'type' ], array( 'boolean', 'number', 'currency' ) ) )
  494. $params->raw = true;
  495. }
  496. if ( !isset( $this->fields[ $params->name ] ) || !in_array( $this->fields[ $params->name ][ 'type' ], $tableless_field_types ) || $simple ) {
  497. if ( null === $params->single ) {
  498. if ( isset( $this->fields[ $params->name ] ) && !in_array( $this->fields[ $params->name ][ 'type' ], $tableless_field_types ) )
  499. $params->single = true;
  500. else
  501. $params->single = false;
  502. }
  503. $no_conflict = pods_no_conflict_check( $this->pod_data[ 'type' ] );
  504. if ( !$no_conflict )
  505. pods_no_conflict_on( $this->pod_data[ 'type' ] );
  506. if ( in_array( $this->pod_data[ 'type' ], array( 'post_type', 'media' ) ) ) {
  507. $id = $this->id();
  508. if ( function_exists( 'icl_get_languages' ) ) {
  509. $master_post_id = (int) get_post_meta( $id, '_icl_lang_duplicate_of', true );
  510. if ( 0 < $master_post_id )
  511. $id = $master_post_id;
  512. }
  513. $value = get_post_meta( $id, $params->name, $params->single );
  514. }
  515. elseif ( 'user' == $this->pod_data[ 'type' ] )
  516. $value = get_user_meta( $this->id(), $params->name, $params->single );
  517. elseif ( 'comment' == $this->pod_data[ 'type' ] )
  518. $value = get_comment_meta( $this->id(), $params->name, $params->single );
  519. // Handle Simple Relationships
  520. if ( $simple ) {
  521. if ( null === $single )
  522. $params->single = false;
  523. $value = PodsForm::field_method( 'pick', 'simple_value', $value, $this->fields[ $params->name ], true );
  524. }
  525. if ( !$no_conflict )
  526. pods_no_conflict_off( $this->pod_data[ 'type' ] );
  527. }
  528. else {
  529. // Dot-traversal
  530. $pod = $this->pod;
  531. $ids = array( $this->id() );
  532. $all_fields = array(
  533. $this->pod => $this->fields
  534. );
  535. $lookup = $params->traverse;
  536. if ( !empty( $lookup ) )
  537. unset( $lookup[ 0 ] );
  538. // Get fields matching traversal names
  539. if ( !empty( $lookup ) ) {
  540. $fields = $this->api->load_fields( array(
  541. 'name' => $lookup,
  542. 'type' => $tableless_field_types
  543. ) );
  544. if ( !empty( $fields ) ) {
  545. foreach ( $fields as $field ) {
  546. if ( !empty( $field ) ) {
  547. if ( !isset( $all_fields[ $field[ 'pod' ] ] ) )
  548. $all_fields[ $field[ 'pod' ] ] = array();
  549. $all_fields[ $field[ 'pod' ] ][ $field[ 'name' ] ] = $field;
  550. }
  551. }
  552. }
  553. }
  554. $last_type = $last_object = $last_pick_val = '';
  555. $single_multi = pods_var( $this->fields[ $params->name ][ 'type' ] . '_format_type', $this->fields[ $params->name ][ 'options' ], 'single' );
  556. if ( 'multi' == $single_multi )
  557. $limit = (int) pods_var( $this->fields[ $params->name ][ 'type' ] . '_limit', $this->fields[ $params->name ][ 'options' ], 0 );
  558. else
  559. $limit = 1;
  560. $last_limit = 0;
  561. // Loop through each traversal level
  562. foreach ( $params->traverse as $key => $field ) {
  563. $last_loop = false;
  564. if ( count( $params->traverse ) <= ( $key + 1 ) )
  565. $last_loop = true;
  566. $field_exists = isset( $all_fields[ $pod ][ $field ] );
  567. $simple = false;
  568. $simple_options = array();
  569. if ( $field_exists && 'pick' == $all_fields[ $pod ][ $field ][ 'type' ] && in_array( $all_fields[ $pod ][ $field ][ 'pick_object' ], $simple_tableless_objects ) ) {
  570. $simple = true;
  571. $simple_options = $all_fields[ $pod ][ $field ];
  572. }
  573. // Tableless handler
  574. if ( $field_exists && ( 'pick' != $all_fields[ $pod ][ $field ][ 'type' ] || !$simple ) ) {
  575. $type = $all_fields[ $pod ][ $field ][ 'type' ];
  576. $pick_object = $all_fields[ $pod ][ $field ][ 'pick_object' ];
  577. $pick_val = $all_fields[ $pod ][ $field ][ 'pick_val' ];
  578. $last_limit = 0;
  579. if ( in_array( $type, $tableless_field_types ) ) {
  580. $single_multi = pods_var( "{$type}_format_type", $all_fields[ $pod ][ $field ][ 'options' ], 'single' );
  581. if ( 'multi' == $single_multi )
  582. $last_limit = (int) pods_var( "{$type}_limit", $all_fields[ $pod ][ $field ][ 'options' ], 0 );
  583. else
  584. $last_limit = 1;
  585. }
  586. $last_type = $type;
  587. $last_object = $pick_object;
  588. $last_pick_val = $pick_val;
  589. $last_options = $all_fields[ $pod ][ $field ];
  590. // Get related IDs
  591. $ids = $this->api->lookup_related_items(
  592. $all_fields[ $pod ][ $field ][ 'id' ],
  593. $all_fields[ $pod ][ $field ][ 'pod_id' ],
  594. $ids,
  595. $all_fields[ $pod ][ $field ]
  596. );
  597. // No items found
  598. if ( empty( $ids ) )
  599. return false;
  600. elseif ( 0 < $last_limit )
  601. $ids = array_slice( $ids, 0, $last_limit );
  602. // Get $pod if related to a Pod
  603. if ( !empty( $pick_object ) && !empty( $pick_val ) ) {
  604. if ( 'pod' == $pick_object )
  605. $pod = $pick_val;
  606. else {
  607. $check = $this->api->get_table_info( $pick_object, $pick_val );
  608. if ( !empty( $check ) && !empty( $check[ 'pod' ] ) )
  609. $pod = $check[ 'pod' ][ 'name' ];
  610. }
  611. }
  612. }
  613. // Assume last iteration
  614. else {
  615. // Invalid field
  616. if ( 0 == $key )
  617. return false;
  618. $last_loop = true;
  619. }
  620. if ( $last_loop ) {
  621. $object_type = $last_object;
  622. $object = $last_pick_val;
  623. if ( in_array( $last_type, apply_filters( 'pods_file_field_types', array( 'file', 'avatar' ) ) ) ) {
  624. $object_type = 'media';
  625. $object = 'attachment';
  626. }
  627. $data = array();
  628. $table = $this->api->get_table_info( $object_type, $object );
  629. $join = $where = array();
  630. if ( !empty( $table[ 'join' ] ) )
  631. $join = (array) $table[ 'join' ];
  632. if ( !empty( $table[ 'where' ] ) || !empty( $ids ) ) {
  633. foreach ( $ids as $id ) {
  634. $where[ $id ] = '`t`.`' . $table[ 'field_id' ] . '` = ' . (int) $id;
  635. }
  636. if ( !empty( $where ) )
  637. $where = array( '( ' . implode( ' OR ', $where ) . ' )' );
  638. if ( !empty( $table[ 'where' ] ) )
  639. $where = array_merge( $where, array_values( (array) $table[ 'where' ] ) );
  640. }
  641. if ( !empty( $table[ 'table' ] ) ) {
  642. $sql = array(
  643. 'select' => '*, `t`.`' . $table[ 'field_id' ] . '` AS `pod_item_id`',
  644. 'table' => $table[ 'table' ],
  645. 'join' => $join,
  646. 'where' => $where,
  647. 'orderby' => $params->orderby
  648. );
  649. $item_data = pods_data()->select( $sql );
  650. $items = array();
  651. foreach ( $item_data as $item ) {
  652. if ( empty( $item->pod_item_id ) )
  653. continue;
  654. // Get Item ID
  655. $item_id = $item->pod_item_id;
  656. // Cleanup
  657. unset( $item->pod_item_id );
  658. // Pass item data into $data
  659. $items[ $item_id ] = $item;
  660. }
  661. // Cleanup
  662. unset( $item_data );
  663. // Return all of the data in the order expected
  664. if ( empty( $params->orderby ) ) {
  665. foreach ( $ids as $id ) {
  666. if ( isset( $items[ $id ] ) )
  667. $data[ $id ] = $items[ $id ];
  668. }
  669. }
  670. }
  671. if ( in_array( $last_type, $tableless_field_types ) || in_array( $last_type, array( 'boolean', 'number', 'currency' ) ) )
  672. $params->raw = true;
  673. if ( empty( $data ) )
  674. $value = false;
  675. else {
  676. foreach ( $data as &$item_value ) {
  677. $item_value = get_object_vars( (object) $item_value );
  678. }
  679. $object_type = $table[ 'type' ];
  680. if ( in_array( $table[ 'type' ], array( 'post_type', 'attachment' ) ) )
  681. $object_type = 'post';
  682. if ( in_array( $object_type, array( 'post', 'user', 'comment' ) ) ) {
  683. $no_conflict = pods_no_conflict_check( $object_type );
  684. if ( !$no_conflict )
  685. pods_no_conflict_on( $object_type );
  686. }
  687. // Return entire array
  688. if ( false === $params->in_form && false !== $field_exists && in_array( $last_type, $tableless_field_types ) )
  689. $value = $data;
  690. // Return an array of single column values
  691. else {
  692. $value = array();
  693. if ( false !== $params->in_form )
  694. $field = $table[ 'field_id' ];
  695. foreach ( $data as $item_id => $item ) {
  696. if ( isset( $item[ $field ] ) )
  697. $value[] = $item[ $field ];
  698. elseif ( in_array( $object_type, array( 'post', 'user', 'comment' ) ) )
  699. $value[] = get_metadata( $object_type, $item_id, $field, true );
  700. }
  701. }
  702. if ( in_array( $object_type, array( 'post', 'user', 'comment' ) ) && !$no_conflict )
  703. pods_no_conflict_off( $object_type );
  704. // Handle Simple Relationships
  705. if ( $simple ) {
  706. if ( null === $single )
  707. $params->single = false;
  708. $value = PodsForm::field_method( 'pick', 'simple_value', $value, $simple_options, true );
  709. }
  710. // Return a single column value
  711. if ( false === $params->in_form && 1 == $limit && !empty( $value ) && is_array( $value ) && isset( $value[ 0 ] ) )
  712. $value = $value[ 0 ];
  713. }
  714. break;
  715. }
  716. }
  717. }
  718. }
  719. }
  720. if ( !empty( $params->traverse ) && 1 < count( $params->traverse ) ) {
  721. $field_names = implode( '.', $params->traverse );
  722. $this->row[ $field_names ] = $value;
  723. }
  724. else
  725. $this->row[ $params->name ] = $value;
  726. if ( true === $params->single && is_array( $value ) && isset( $value[ 0 ] ) )
  727. $value = $value[ 0 ];
  728. // @todo Expand this into traversed fields too
  729. if ( false === $params->raw && false === $params->in_form && isset( $this->fields[ $params->name ] ) ) {
  730. if ( 0 < strlen( pods_var( 'display_filter', $this->fields[ $params->name ] ) ) )
  731. $value = apply_filters( pods_var( 'display_filter', $this->fields[ $params->name ] ), $value );
  732. else {
  733. $value = PodsForm::display(
  734. $this->fields[ $params->name ][ 'type' ],
  735. $value,
  736. $params->name,
  737. array_merge( $this->fields[ $params->name ][ 'options' ], $this->fields[ $params->name ] ),
  738. $this->pod_data,
  739. $this->id()
  740. );
  741. }
  742. }
  743. $value = $this->do_hook( 'field', $value, $this->row, $params );
  744. return $value;
  745. }
  746. /**
  747. * Return the item ID
  748. *
  749. * @return int
  750. * @since 2.0.0
  751. */
  752. public function id () {
  753. return $this->field( $this->data->field_id );
  754. }
  755. /**
  756. * Return the previous item ID, loops at the last id to return the first
  757. *
  758. * @param int $id
  759. * @param array $params_override
  760. *
  761. * @return int
  762. * @since 2.0.0
  763. */
  764. public function prev_id ( $id = null, $params_override = null ) {
  765. if ( null === $id )
  766. $id = $this->field( 'id' );
  767. $id = (int) $id;
  768. $params = array(
  769. 'select' => "`t`.{$this->data->field_id}`",
  770. 'where' => "`t`.{$this->data->field_id}` < {$id}",
  771. 'orderby' => "`t`.{$this->data->field_id}` DESC",
  772. 'limit' => 1
  773. );
  774. if ( !empty( $params_override ) || !empty( $this->params ) ) {
  775. if ( !empty( $params_override ) )
  776. $params = $params_override;
  777. elseif ( !empty( $this->params ) )
  778. $params = $this->params;
  779. if ( 0 < $id )
  780. $params[ 'where' ] = "`t`.{$this->data->field_id}` < {$id}";
  781. elseif ( isset( $params[ 'offset' ] ) && 0 < $params[ 'offset' ] )
  782. $params[ 'offset' ] -= 1;
  783. elseif ( !isset( $params[ 'offset' ] ) && !empty( $this->params ) && 0 < $this->row )
  784. $params[ 'offset' ] = $this->row - 1;
  785. else
  786. return 0;
  787. $params[ 'select' ] = "`t`.{$this->data->field_id}`";
  788. $params[ 'limit' ] = 1;
  789. }
  790. $pod = pods( $this->pod, $params );
  791. if ( $pod->fetch() )
  792. return $pod->id();
  793. return 0;
  794. }
  795. /**
  796. * Return the next item ID, loops at the first id to return the last
  797. *
  798. * @param int $id
  799. * @param array $find_params
  800. *
  801. * @return int
  802. * @since 2.0.0
  803. */
  804. public function next_id ( $id = null, $params_override = null ) {
  805. if ( null === $id )
  806. $id = $this->field( 'id' );
  807. $id = (int) $id;
  808. $params = array(
  809. 'select' => "`t`.{$this->data->field_id}`",
  810. 'where' => "{$id} < `t`.{$this->data->field_id}`",
  811. 'orderby' => "`t`.{$this->data->field_id}` ASC",
  812. 'limit' => 1
  813. );
  814. if ( !empty( $params_override ) || !empty( $this->params ) ) {
  815. if ( !empty( $params_override ) )
  816. $params = $params_override;
  817. elseif ( !empty( $this->params ) )
  818. $params = $this->params;
  819. if ( 0 < $id )
  820. $params[ 'where' ] = "{$id} < `t`.{$this->data->field_id}`";
  821. elseif ( !isset( $params[ 'offset' ] ) ) {
  822. if ( !empty( $this->params ) && -1 < $this->row )
  823. $params[ 'offset' ] = $this->row + 1;
  824. else
  825. $params[ 'offset' ] = 1;
  826. }
  827. else
  828. $params[ 'offset' ] += 1;
  829. $params[ 'select' ] = "`t`.{$this->data->field_id}`";
  830. $params[ 'limit' ] = 1;
  831. }
  832. $pod = pods( $this->pod, $params );
  833. if ( $pod->fetch() )
  834. return $pod->id();
  835. return 0;
  836. }
  837. /**
  838. * Return the first item ID
  839. *
  840. * @param array $params_override
  841. *
  842. * @return int
  843. * @since 2.3.0
  844. */
  845. public function first_id ( $params_override = null ) {
  846. $params = array(
  847. 'select' => "`t`.{$this->data->field_id}`",
  848. 'orderby' => "`t`.{$this->data->field_id}` ASC",
  849. 'limit' => 1
  850. );
  851. if ( !empty( $params_override ) || !empty( $this->params ) ) {
  852. if ( !empty( $params_override ) )
  853. $params = $params_override;
  854. elseif ( !empty( $this->params ) )
  855. $params = $this->params;
  856. $params[ 'select' ] = "`t`.{$this->data->field_id}`";
  857. $params[ 'offset' ] = 0;
  858. $params[ 'limit' ] = 1;
  859. }
  860. $pod = pods( $this->pod, $params );
  861. if ( $pod->fetch() )
  862. return $pod->id();
  863. return 0;
  864. }
  865. /**
  866. * Return the last item ID
  867. *
  868. * @param array $params_override
  869. *
  870. * @return int
  871. * @since 2.3.0
  872. */
  873. public function last_id ( $params_override = null ) {
  874. $params = array(
  875. 'select' => "`t`.{$this->data->field_id}`",
  876. 'orderby' => "`t`.{$this->data->field_id}` DESC",
  877. 'limit' => 1
  878. );
  879. if ( !empty( $params_override ) || !empty( $this->params ) ) {
  880. if ( !empty( $params_override ) )
  881. $params = $params_override;
  882. elseif ( !empty( $this->params ) )
  883. $params = $this->params;
  884. if ( isset( $params[ 'total_found' ] ) )
  885. $params[ 'offset' ] = $params[ 'total_found' ] - 1;
  886. else
  887. $params[ 'offset' ] = $this->total_found() - 1;
  888. $params[ 'select' ] = "`t`.{$this->data->field_id}`";
  889. $params[ 'limit' ] = 1;
  890. }
  891. $pod = pods( $this->pod, $params );
  892. if ( $pod->fetch() )
  893. return $pod->id();
  894. return 0;
  895. }
  896. /**
  897. * Return the item name
  898. *
  899. * @return string
  900. * @since 2.0.0
  901. */
  902. public function index () {
  903. return $this->field( $this->data->field_index );
  904. }
  905. /**
  906. * Find items of a pod, much like WP_Query, but with advanced table handling.
  907. *
  908. * @param array $params An associative array of parameters
  909. * @param int $limit (optional) (deprecated) Limit the number of items to find, use -1 to return all items with no limit
  910. * @param string $where (optional) (deprecated) SQL WHERE declaration to use
  911. * @param string $sql (optional) (deprecated) For advanced use, a custom SQL query to run
  912. *
  913. * @return \Pods The pod object
  914. * @since 2.0.0
  915. * @link http://podsframework.org/docs/find/
  916. */
  917. public function find ( $params = null, $limit = 15, $where = null, $sql = null ) {
  918. $tableless_field_types = apply_filters( 'pods_tableless_field_types', array( 'pick', 'file', 'avatar', 'taxonomy' ) );
  919. $simple_tableless_objects = PodsForm::field_method( 'pick', 'simple_objects' );
  920. $select = '`t`.*';
  921. $pod_table_prefix = 't';
  922. if ( !in_array( $this->pod_data[ 'type' ], array( 'pod', 'table' ) ) && 'table' == $this->pod_data[ 'storage' ] ) {
  923. $select .= ', `d`.*';
  924. $pod_table_prefix = 'd';
  925. }
  926. if ( empty( $this->data->table ) )
  927. return $this;
  928. $defaults = array(
  929. 'table' => $this->data->table,
  930. 'select' => $select,
  931. 'join' => null,
  932. 'where' => $where,
  933. 'groupby' => null,
  934. 'having' => null,
  935. 'orderby' => null,
  936. 'limit' => (int) $limit,
  937. 'offset' => null,
  938. 'page' => (int) $this->page,
  939. 'page_var' => $this->page_var,
  940. 'pagination' => (boolean) $this->pagination,
  941. 'search' => (boolean) $this->search,
  942. 'search_var' => $this->search_var,
  943. 'search_query' => null,
  944. 'search_mode' => $this->search_mode,
  945. 'search_across' => false,
  946. 'search_across_picks' => false,
  947. 'search_across_files' => false,
  948. 'fields' => $this->fields,
  949. 'sql' => $sql,
  950. 'expires' => null,
  951. 'cache_mode' => 'cache'
  952. );
  953. if ( is_array( $params ) )
  954. $params = (object) array_merge( $defaults, $params );
  955. if ( is_object( $params ) )
  956. $params = (object) array_merge( $defaults, get_object_vars( $params ) );
  957. else {
  958. $defaults[ 'orderby' ] = $params;
  959. $params = (object) $defaults;
  960. }
  961. $params = $this->do_hook( 'find', $params );
  962. $params->limit = (int) $params->limit;
  963. if ( 0 == $params->limit )
  964. $params->limit = -1;
  965. $this->limit = $params->limit;
  966. $this->page = (int) $params->page;
  967. $this->page_var = $params->page_var;
  968. $this->pagination = (boolean) $params->pagination;
  969. $this->search = (boolean) $params->search;
  970. $this->search_var = $params->search_var;
  971. $params->join = (array) $params->join;
  972. if ( empty( $params->search_query ) )
  973. $params->search_query = pods_var( $this->search_var, 'get', '' );
  974. // Allow orderby array ( 'field' => 'asc|desc' )
  975. if ( !empty( $params->orderby ) && is_array( $params->orderby ) ) {
  976. foreach ( $params->orderby as $k => &$orderby ) {
  977. if ( !is_numeric( $k ) ) {
  978. $key = '';
  979. $order = 'ASC';
  980. if ( 'DESC' == strtoupper( $orderby ) )
  981. $order = 'DESC';
  982. if ( isset( $this->fields[ $k ] ) && in_array( $this->fields[ $k ][ 'type' ], $tableless_field_types ) ) {
  983. if ( in_array( $this->fields[ $k ][ 'pick_object' ], $simple_tableless_objects ) ) {
  984. if ( 'table' == $this->pod_data[ 'storage' ] )
  985. $key = "`t`.`{$k}`";
  986. else
  987. $key = "`{$k}`.`meta_value`";
  988. }
  989. else {
  990. $table = $this->api->get_table_info( $this->fields[ $k ][ 'pick_object' ], $this->fields[ $k ][ 'pick_val' ] );
  991. if ( !empty( $table ) )
  992. $key = "`{$k}`.`" . $table[ 'field_index' ] . '`';
  993. }
  994. }
  995. if ( empty( $key ) ) {
  996. if ( !in_array( $this->pod_data[ 'type' ], array( 'pod', 'table' ) ) ) {
  997. if ( isset( $this->pod_data[ 'object_fields' ][ $k ] ) )
  998. $key = "`t`.`{$k}`";
  999. elseif ( isset( $this->fields[ $k ] ) ) {
  1000. if ( 'table' == $this->pod_data[ 'storage' ] )
  1001. $key = "`d`.`{$k}`";
  1002. else
  1003. $key = "`{$k}`.`meta_value`";
  1004. }
  1005. else {
  1006. foreach ( $this->pod_data[ 'object_fields' ] as $object_field => $object_field_opt ) {
  1007. if ( $object_field == $k || in_array( $k, $object_field_opt[ 'alias' ] ) )
  1008. $key = "`t`.`{$object_field}`";
  1009. }
  1010. }
  1011. }
  1012. elseif ( isset( $this->fields[ $k ] ) ) {
  1013. if ( 'table' == $this->pod_data[ 'storage' ] )
  1014. $key = "`t`.`{$k}`";
  1015. else
  1016. $key = "`{$k}`.`meta_value`";
  1017. }
  1018. if ( empty( $key ) ) {
  1019. $key = $k;
  1020. if ( false === strpos( $key, ' ' ) && false === strpos( $key, '`' ) )
  1021. $key = '`' . str_replace( '.', '`.`', $key ) . '`';
  1022. }
  1023. }
  1024. $orderby = $key;
  1025. if ( false === strpos( $orderby, ' ' ) )
  1026. $orderby .= ' ' . $order;
  1027. }
  1028. }
  1029. }
  1030. // Add prefix to $params->orderby if needed
  1031. if ( !empty( $params->orderby ) ) {
  1032. if ( !is_array( $params->orderby ) )
  1033. $params->orderby = array( $params->orderby );
  1034. foreach ( $params->orderby as &$prefix_orderby ) {
  1035. if ( false === strpos( $prefix_orderby, ',' ) && false === strpos( $prefix_orderby, '(' ) && false === stripos( $prefix_orderby, ' AS ' ) && false === strpos( $prefix_orderby, '`' ) && false === strpos( $prefix_orderby, '.' ) ) {
  1036. if ( false !== stripos( $prefix_orderby, ' ASC' ) ) {
  1037. $k = trim( str_ireplace( array( '`', ' ASC' ), '', $prefix_orderby ) );
  1038. $dir = 'ASC';
  1039. }
  1040. else {
  1041. $k = trim( str_ireplace( array( '`', ' DESC' ), '', $prefix_orderby ) );
  1042. $dir = 'DESC';
  1043. }
  1044. $key = $k;
  1045. if ( !in_array( $this->pod_data[ 'type' ], array( 'pod', 'table' ) ) ) {
  1046. if ( isset( $this->pod_data[ 'object_fields' ][ $k ] ) )
  1047. $key = "`t`.`{$k}`";
  1048. elseif ( isset( $this->fields[ $k ] ) ) {
  1049. if ( 'table' == $this->pod_data[ 'storage' ] )
  1050. $key = "`d`.`{$k}`";
  1051. else
  1052. $key = "`{$k}`.`meta_value`";
  1053. }
  1054. else {
  1055. foreach ( $this->pod_data[ 'object_fields' ] as $object_field => $object_field_opt ) {
  1056. if ( $object_field == $k || in_array( $k, $object_field_opt[ 'alias' ] ) )
  1057. $key = "`t`.`{$object_field}`";
  1058. }
  1059. }
  1060. }
  1061. elseif ( isset( $this->fields[ $k ] ) ) {
  1062. if ( 'table' == $this->pod_data[ 'storage' ] )
  1063. $key = "`t`.`{$k}`";
  1064. else
  1065. $key = "`{$k}`.`meta_value`";
  1066. }
  1067. $prefix_orderby = "{$key} {$dir}";
  1068. }
  1069. }
  1070. }
  1071. $this->params = $params;
  1072. $this->data->select( $params );
  1073. $this->sql = $this->data->sql;
  1074. return $this;
  1075. }
  1076. /**
  1077. * Fetch an item from a Pod. If $id is null, it will return the next item in the list after running find().
  1078. * You can rewind the list back to the start by using reset().
  1079. *
  1080. * Providing an $id will fetch a specific item from a Pod, much like a call to pods(), and can handle either an id or slug.
  1081. *
  1082. * @see PodsData::fetch
  1083. *
  1084. * @param int $id ID or slug of the item to fetch
  1085. *
  1086. * @return array An array of fields from the row
  1087. *
  1088. * @since 2.0.0
  1089. * @link http://podsframework.org/docs/fetch/
  1090. */
  1091. public function fetch ( $id = null ) {
  1092. $this->do_hook( 'fetch', $id );
  1093. if ( !empty( $id ) )
  1094. $this->params = array();
  1095. $this->data->fetch( $id );
  1096. $this->sql = $this->data->sql;
  1097. return $this->row;
  1098. }
  1099. /**
  1100. * (Re)set the MySQL result pointer
  1101. *
  1102. * @see PodsData::reset
  1103. *
  1104. * @param int $row ID of the row to reset to
  1105. *
  1106. * @retur…

Large files files are truncated, but you can click here to view the full file