PageRenderTime 69ms CodeModel.GetById 25ms RepoModel.GetById 0ms 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
  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. * @return \Pods The pod object
  1107. *
  1108. * @since 2.0.0
  1109. * @link http://podsframework.org/docs/reset/
  1110. */
  1111. public function reset ( $row = null ) {
  1112. $this->do_hook( 'reset', $row );
  1113. $this->data->reset( $row );
  1114. $this->sql = $this->data->sql;
  1115. return $this;
  1116. }
  1117. /**
  1118. * Fetch the total row count returned by the last call to find(), based on the 'limit' parameter set.
  1119. *
  1120. * This is different than the total number of rows found in the database, which you can get with total_found().
  1121. *
  1122. * @see PodsData::total
  1123. *
  1124. * @return int Number of rows returned by find(), based on the 'limit' parameter set
  1125. * @since 2.0.0
  1126. * @link http://podsframework.org/docs/total/
  1127. */
  1128. public function total () {
  1129. $this->do_hook( 'total' );
  1130. $this->total =& $this->data->total();
  1131. return $this->total;
  1132. }
  1133. /**
  1134. * Fetch the total amount of rows found by the last call to find(), regardless of the 'limit' parameter set.
  1135. *
  1136. * This is different than the total number of rows limited by the current call, which you can get with total().
  1137. *
  1138. * @see PodsData::total_found
  1139. *
  1140. * @return int Number of rows returned by find(), regardless of the 'limit' parameter
  1141. * @since 2.0.0
  1142. * @link http://podsframework.org/docs/total-found/
  1143. */
  1144. public function total_found () {
  1145. $this->do_hook( 'total_found' );
  1146. $this->total_found =& $this->data->total_found();
  1147. return $this->total_found;
  1148. }
  1149. /**
  1150. * Fetch the zebra switch
  1151. *
  1152. * @see PodsData::zebra
  1153. *
  1154. * @return bool Zebra state
  1155. * @since 1.12
  1156. */
  1157. public function zebra () {
  1158. $this->do_hook( 'zebra' );
  1159. return $this->data->zebra();
  1160. }
  1161. /**
  1162. * Add an item to a Pod by giving an array of field data or set a specific field to
  1163. * a specific value if you're just wanting to add a new item but only set one field.
  1164. *
  1165. * You may be looking for save() in most cases where you're setting a specific field.
  1166. *
  1167. * @see PodsAPI::save_pod_item
  1168. *
  1169. * @param array|string $data Either an associative array of field information or a field name
  1170. * @param mixed $value (optional) Value of the field, if $data is a field name
  1171. *
  1172. * @return int The item ID
  1173. *
  1174. * @since 2.0.0
  1175. * @link http://podsframework.org/docs/add/
  1176. */
  1177. public function add ( $data = null, $value = null ) {
  1178. if ( null !== $value )
  1179. $data = array( $data => $value );
  1180. $data = (array) $this->do_hook( 'add', $data );
  1181. if ( empty( $data ) )
  1182. return false;
  1183. $params = array(
  1184. 'pod' => $this->pod,
  1185. 'data' => $data,
  1186. 'allow_custom_fields' => true
  1187. );
  1188. return $this->api->save_pod_item( $params );
  1189. }
  1190. /**
  1191. * Save an item by giving an array of field data or set a specific field to a specific value.
  1192. *
  1193. * Though this function has the capacity to add new items, best practice should direct you
  1194. * to use add() for that instead.
  1195. *
  1196. * @see PodsAPI::save_pod_item
  1197. *
  1198. * @param array|string $data Either an associative array of field information or a field name
  1199. * @param mixed $value (optional) Value of the field, if $data is a field name
  1200. * @param int $id (optional) ID of the pod item to update
  1201. *
  1202. * @return int The item ID
  1203. *
  1204. * @since 2.0.0
  1205. * @link http://podsframework.org/docs/save/
  1206. */
  1207. public function save ( $data = null, $value = null, $id = null ) {
  1208. if ( null !== $value )
  1209. $data = array( $data => $value );
  1210. if ( null === $id )
  1211. $id = $this->id();
  1212. $data = (array) $this->do_hook( 'save', $data, $id );
  1213. if ( empty( $data ) )
  1214. return false;
  1215. $params = array(
  1216. 'pod' => $this->pod,
  1217. 'id' => $id,
  1218. 'data' => $data,
  1219. 'allow_custom_fields' => true
  1220. );
  1221. return $this->api->save_pod_item( $params );
  1222. }
  1223. /**
  1224. * Delete an item
  1225. *
  1226. * @see PodsAPI::delete_pod_item
  1227. *
  1228. * @param int $id ID of the Pod item to delete
  1229. *
  1230. * @return bool Whether the item was successfully deleted
  1231. *
  1232. * @since 2.0.0
  1233. * @link http://podsframework.org/docs/delete/
  1234. */
  1235. public function delete ( $id = null ) {
  1236. if ( null === $id )
  1237. $id = $this->id();
  1238. $id = (int) $this->do_hook( 'delete', $id );
  1239. if ( empty( $id ) )
  1240. return false;
  1241. $params = array(
  1242. 'pod' => $this->pod,
  1243. 'id' => $id
  1244. );
  1245. return $this->api->delete_pod_item( $params );
  1246. }
  1247. /**
  1248. * Reset Pod
  1249. *
  1250. * @see PodsAPI::reset_pod
  1251. *
  1252. * @return bool Whether the Pod was successfully reset
  1253. *
  1254. * @since 2.1.1
  1255. */
  1256. public function reset_pod () {
  1257. $params = array( 'id' => $this->pod_id );
  1258. $this->data->id = null;
  1259. $this->data->row = array();
  1260. $this->data->data = array();
  1261. $this->data->total = 0;
  1262. $this->data->total_found = 0;
  1263. return $this->api->reset_pod( $params );
  1264. }
  1265. /**
  1266. * Duplicate an item
  1267. *
  1268. * @see PodsAPI::duplicate_pod_item
  1269. *
  1270. * @param int $id ID of the pod item to duplicate
  1271. *
  1272. * @return int|bool ID of the new pod item
  1273. *
  1274. * @since 2.0.0
  1275. * @link http://podsframework.org/docs/duplicate/
  1276. */
  1277. public function duplicate ( $id = null ) {
  1278. if ( null === $id )
  1279. $id = $this->id();
  1280. $id = (int) $this->do_hook( 'duplicate', $id );
  1281. if ( empty( $id ) )
  1282. return false;
  1283. $params = array(
  1284. 'pod' => $this->pod,
  1285. 'id' => $id
  1286. );
  1287. return $this->api->duplicate_pod_item( $params );
  1288. }
  1289. /**
  1290. * Export an item's data
  1291. *
  1292. * @see PodsAPI::export_pod_item
  1293. *
  1294. * @param array $fields (optional) Fields to export
  1295. * @param int $id (optional) ID of the pod item to export
  1296. *
  1297. * @return array|bool Data array of the exported pod item
  1298. *
  1299. * @since 2.0.0
  1300. * @link http://podsframework.org/docs/export/
  1301. */
  1302. public function export ( $fields = null, $id = null ) {
  1303. $params = array(
  1304. 'pod' => $this->pod,
  1305. 'id' => $id,
  1306. 'fields' => null,
  1307. 'depth' => 2
  1308. );
  1309. if ( !isset( $fields[ 'fields' ] ) && !isset( $fields[ 'depth' ] ) )
  1310. $params = array( 'fields' => $fields );
  1311. if ( null === $params[ 'id' ] )
  1312. $params[ 'id' ] = $this->id();
  1313. $params = (array) $this->do_hook( 'export', $params );
  1314. if ( empty( $params[ 'id' ] ) )
  1315. return false;
  1316. return $this->api->export_pod_item( $params );
  1317. }
  1318. /**
  1319. * Export data from all items
  1320. *
  1321. * @see PodsAPI::export
  1322. *
  1323. * @param array $params An associative array of parameters
  1324. *
  1325. * @return array Data arrays of all exported pod items
  1326. *
  1327. * @since 2.3.0
  1328. */
  1329. public function export_data ( $params = null ) {
  1330. $defaults = array(
  1331. 'fields' => null,
  1332. 'depth' => 2,
  1333. 'params' => null
  1334. );
  1335. if ( empty( $params ) )
  1336. $params = $defaults;
  1337. else
  1338. $params = array_merge( $defaults, (array) $params );
  1339. return $this->api->export( $this, $params );
  1340. }
  1341. /**
  1342. * Display the pagination controls, types supported by default
  1343. * are simple, paginate and advanced. The base and format parameters
  1344. * are used only for the paginate view.
  1345. *
  1346. * @var array $params Associative array of parameters
  1347. *
  1348. * @return string Pagination HTML
  1349. * @since 2.0.0
  1350. * @link http://podsframework.org/docs/pagination/
  1351. */
  1352. public function pagination ( $params = null ) {
  1353. if ( empty( $params ) )
  1354. $params = array();
  1355. elseif ( !is_array( $params ) )
  1356. $params = array( 'label' => $params );
  1357. $this->page_var = pods_var_raw( 'page_var', $params, $this->page_var );
  1358. $url = pods_var_update( null, null, $this->page_var );
  1359. $append = '?';
  1360. if ( false !== strpos( $url, '?' ) )
  1361. $append = '&';
  1362. $defaults = array(
  1363. 'type' => 'advanced',
  1364. 'label' => __( 'Go to page:', 'pods' ),
  1365. 'show_label' => true,
  1366. 'first_text' => __( '&laquo; First', 'pods' ),
  1367. 'prev_text' => __( '&lsaquo; Previous', 'pods' ),
  1368. 'next_text' => __( 'Next &rsaquo;', 'pods' ),
  1369. 'last_text' => __( 'Last &raquo;', 'pods' ),
  1370. 'prev_next' => true,
  1371. 'first_last' => true,
  1372. 'limit' => (int) $this->limit,
  1373. 'page' => max( 1, (int) $this->page ),
  1374. 'mid_size' => 2,
  1375. 'end_size' => 1,
  1376. 'total_found' => $this->total_found(),
  1377. 'page_var' => $this->page_var,
  1378. 'base' => "{$url}{$append}%_%",
  1379. 'format' => "{$this->page_var}=%#%",
  1380. 'class' => "",
  1381. 'link_class'
  1382. );
  1383. $params = (object) array_merge( $defaults, $params );
  1384. $params->total = ceil( $params->total_found / $params->limit );
  1385. if ( $params->limit < 1 || $params->total_found < 1 || 1 == $params->total )
  1386. return $this->do_hook( 'pagination', $this->do_hook( 'pagination_' . $params->type, '', $params ), $params );
  1387. $pagination = $params->type;
  1388. if ( !in_array( $params->type, array( 'simple', 'advanced', 'paginate' ) ) )
  1389. $pagination = 'advanced';
  1390. ob_start();
  1391. pods_view( PODS_DIR . 'ui/front/pagination/' . $pagination . '.php', compact( array_keys( get_defined_vars() ) ) );
  1392. $output = ob_get_clean();
  1393. return $this->do_hook( 'pagination', $this->do_hook( 'pagination_' . $params->type, $output, $params ), $params );
  1394. }
  1395. /**
  1396. * Output a filter form for searching a Pod
  1397. *
  1398. * @var array|string $params Comma-separated list of fields or array of parameters
  1399. *
  1400. * @since 2.0.0
  1401. * @link http://podsframework.org/docs/filters/
  1402. */
  1403. public function filters ( $params = null ) {
  1404. $defaults = array(
  1405. 'fields' => $params,
  1406. 'label' => '',
  1407. 'action' => '',
  1408. 'search' => ''
  1409. );
  1410. if ( is_array( $params ) )
  1411. $params = array_merge( $defaults, $params );
  1412. else
  1413. $params = $defaults;
  1414. $pod =& $this;
  1415. $params = apply_filters( 'pods_filters_params', $params, $pod );
  1416. $fields = $params[ 'fields' ];
  1417. if ( null !== $fields && !is_array( $fields ) && 0 < strlen( $fields ) )
  1418. $fields = explode( ',', $fields );
  1419. $object_fields = (array) pods_var_raw( 'object_fields', $this->pod_data, array(), null, true );
  1420. // Force array
  1421. if ( empty( $fields ) )
  1422. $fields = array();
  1423. else {
  1424. $filter_fields = $fields; // Temporary
  1425. $fields = array();
  1426. foreach ( $filter_fields as $k => $field ) {
  1427. $name = $k;
  1428. $defaults = array(
  1429. 'name' => $name
  1430. );
  1431. if ( !is_array( $field ) ) {
  1432. $name = $field;
  1433. $field = array(
  1434. 'name' => $name
  1435. );
  1436. }
  1437. $field = array_merge( $defaults, $field );
  1438. $field[ 'name' ] = trim( $field[ 'name' ] );
  1439. if ( pods_var_raw( 'hidden', $field, false, null, true ) )
  1440. $field[ 'type' ] = 'hidden';
  1441. if ( isset( $object_fields[ $field[ 'name' ] ] ) )
  1442. $fields[ $field[ 'name' ] ] = array_merge( $object_fields[ $field[ 'name' ] ], $field );
  1443. elseif ( isset( $this->fields[ $field[ 'name' ] ] ) )
  1444. $fields[ $field[ 'name' ] ] = array_merge( $this->fields[ $field[ 'name' ] ], $field );
  1445. }
  1446. unset( $filter_fields ); // Cleanup
  1447. }
  1448. $label = $params[ 'label' ];
  1449. if ( strlen( $label ) < 1 )
  1450. $label = __( 'Search', 'pods' );
  1451. $action = $params[ 'action' ];
  1452. $search = trim( $params[ 'search' ] );
  1453. if ( strlen( $search ) < 1 )
  1454. $search = pods_var_raw( $pod->search_var, 'get', '' );
  1455. ob_start();
  1456. pods_view( PODS_DIR . 'ui/front/filters.php', compact( array_keys( get_defined_vars() ) ) );
  1457. $output = ob_get_clean();
  1458. return $this->do_hook( 'filters', $output, $params );
  1459. }
  1460. /**
  1461. * Run a helper within a Pod Page or WP Template
  1462. *
  1463. * @see Pods_Helpers::helper
  1464. *
  1465. * @param string $helper Helper name
  1466. * @param string $value Value to run the helper on
  1467. * @param string $name Field name
  1468. * @internal param array $params An associative array of parameters
  1469. *
  1470. * @return mixed Anything returned by the helper
  1471. * @since 2.0.0
  1472. */
  1473. public function helper ( $helper, $value = null, $name = null ) {
  1474. $params = array(
  1475. 'helper' => $helper,
  1476. 'value' => $value,
  1477. 'name' => $name,
  1478. 'deprecated' => false
  1479. );
  1480. if ( is_array( $helper ) )
  1481. $params = array_merge( $params, $helper );
  1482. if ( class_exists( 'Pods_Helpers' ) )
  1483. return Pods_Helpers::helper( $params, $this );
  1484. }
  1485. /**
  1486. * Display the page template
  1487. *
  1488. * @see Pods_Templates::template
  1489. *
  1490. * @param string $template The template name
  1491. * @param string $code Custom template code to use instead
  1492. * @param bool $deprecated Whether to use deprecated functionality based on old function usage
  1493. *
  1494. * @return mixed Template output
  1495. *
  1496. * @since 2.0.0
  1497. * @link http://podsframework.org/docs/template/
  1498. */
  1499. public function template ( $template, $code = null, $deprecated = false ) {
  1500. if ( !empty( $code ) ) {
  1501. $code = apply_filters( 'pods_templates_pre_template', $code, $template, $this );
  1502. $code = apply_filters( "pods_templates_pre_template_{$template}", $code, $template, $this );
  1503. ob_start();
  1504. if ( !empty( $code ) ) {
  1505. // Only detail templates need $this->id
  1506. if ( empty( $this->id ) ) {
  1507. while ( $this->fetch() ) {
  1508. echo $this->do_magic_tags( $code );
  1509. }
  1510. }
  1511. else
  1512. echo $this->do_magic_tags( $code, $this );
  1513. }
  1514. $out = ob_get_clean();
  1515. $out = apply_filters( 'pods_templates_post_template', $out, $code, $template, $this );
  1516. $out = apply_filters( "pods_templates_post_template_{$template}", $out, $code, $template, $this );
  1517. return $out;
  1518. }
  1519. elseif ( class_exists( 'Pods_Templates' ) )
  1520. return Pods_Templates::template( $template, $code, $this, $deprecated );
  1521. }
  1522. /**
  1523. * Embed a form to add / edit a pod item from within your theme. Provide an array of $fields to include
  1524. * and override options where needed. For WP object based Pods, you can pass through the WP object
  1525. * field names too, such as "post_title" or "post_content" for example.
  1526. *
  1527. * @param array $params (optional) Fields to show on the form, defaults to all fields
  1528. * @param string $label (optional) Save button label, defaults to "Save Changes"
  1529. * @param string $thank_you (optional) Thank you URL to send to upon success
  1530. *
  1531. * @return bool|mixed
  1532. * @since 2.0.0
  1533. * @link http://podsframework.org/docs/form/
  1534. */
  1535. public function form ( $params = null, $label = null, $thank_you = null ) {
  1536. $defaults = array(
  1537. 'fields' => $params,
  1538. 'label' => $label,
  1539. 'thank_you' => $thank_you
  1540. );
  1541. if ( is_array( $params ) )
  1542. $params = array_merge( $defaults, $params );
  1543. else
  1544. $params = $defaults;
  1545. $pod =& $this;
  1546. $params = $this->do_hook( 'form_params', $params );
  1547. $fields = $params[ 'fields' ];
  1548. if ( null !== $fields && !is_array( $fields ) && 0 < strlen( $fields ) )
  1549. $fields = explode( ',', $fields );
  1550. $object_fields = (array) pods_var_raw( 'object_fields', $this->pod_data, array(), null, true );
  1551. if ( empty( $fields ) ) {
  1552. // Add core object fields if $fields is empty
  1553. $fields = array_merge( $object_fields, $this->fields );
  1554. }
  1555. $form_fields = $fields; // Temporary
  1556. $fields = array();
  1557. foreach ( $form_fields as $k => $field ) {
  1558. $name = $k;
  1559. $defaults = array(
  1560. 'name' => $name
  1561. );
  1562. if ( !is_array( $field ) ) {
  1563. $name = $field;
  1564. $field = array(
  1565. 'name' => $name
  1566. );
  1567. }
  1568. $field = array_merge( $defaults, $field );
  1569. $field[ 'name' ] = trim( $field[ 'name' ] );
  1570. if ( empty( $field[ 'name' ] ) )
  1571. $field[ 'name' ] = trim( $name );
  1572. if ( pods_var_raw( 'hidden', $field, false, null, true ) )
  1573. continue;
  1574. elseif ( isset( $object_fields[ $field[ 'name' ] ] ) )
  1575. $fields[ $field[ 'name' ] ] = array_merge( $object_fields[ $field[ 'name' ] ], $field );
  1576. elseif ( isset( $this->fields[ $field[ 'name' ] ] ) )
  1577. $fields[ $field[ 'name' ] ] = array_merge( $this->fields[ $field[ 'name' ] ], $field );
  1578. }
  1579. unset( $form_fields ); // Cleanup
  1580. $fields = $this->do_hook( 'form_fields', $fields, $params );
  1581. $label = $params[ 'label' ];
  1582. if ( empty( $label ) )
  1583. $label = __( 'Save Changes', 'pods' );
  1584. $thank_you = $params[ 'thank_you' ];
  1585. PodsForm::$form_counter++;
  1586. ob_start();
  1587. if ( empty( $thank_you ) ) {
  1588. $success = 'success';
  1589. if ( 1 < PodsForm::$form_counter )
  1590. $success .= PodsForm::$form_counter;
  1591. $thank_you = pods_var_update( array( 'success*' => null, $success => 1 ) );
  1592. if ( 1 == pods_var( $success, 'get', 0 ) ) {
  1593. echo '<div id="message" class="pods-form-front-success">'
  1594. . __( 'Form submitted successfully', 'pods' ) . '</div>';
  1595. }
  1596. }
  1597. pods_view( PODS_DIR . 'ui/front/form.php', compact( array_keys( get_defined_vars() ) ) );
  1598. $output = ob_get_clean();
  1599. return $this->do_hook( 'form', $output, $fields, $label, $thank_you, $this, $this->id() );
  1600. }
  1601. /**
  1602. * Replace magic tags with their values
  1603. *
  1604. * @param string $code The content to evaluate
  1605. * @param object $obj The Pods object
  1606. *
  1607. * @since 2.0.0
  1608. */
  1609. public function do_magic_tags ( $code ) {
  1610. return preg_replace_callback( '/({@(.*?)})/m', array( $this, 'process_magic_tags' ), $code );
  1611. }
  1612. /**
  1613. * Replace magic tags with their values
  1614. *
  1615. * @param string $tag The magic tag to process
  1616. * @param object $obj The Pods object
  1617. *
  1618. * @since 2.0.2
  1619. */
  1620. private function process_magic_tags ( $tag ) {
  1621. if ( is_array( $tag ) ) {
  1622. if ( !isset( $tag[ 2 ] ) && strlen( trim( $tag[ 2 ] ) ) < 1 )
  1623. return;
  1624. $tag = $tag[ 2 ];
  1625. }
  1626. $tag = trim( $tag, ' {@}' );
  1627. $tag = explode( ',', $tag );
  1628. if ( empty( $tag ) || !isset( $tag[ 0 ] ) || strlen( trim( $tag[ 0 ] ) ) < 1 )
  1629. return;
  1630. foreach ( $tag as $k => $v ) {
  1631. $tag[ $k ] = trim( $v );
  1632. }
  1633. $field_name = $tag[ 0 ];
  1634. $helper_name = $before = $after = '';
  1635. if ( isset( $tag[ 1 ] ) && !empty( $tag[ 1 ] ) && class_exists( 'Pods_Helpers' ) ) {
  1636. $value = $this->field( $field_name );
  1637. $helper_name = $tag[ 1 ];
  1638. $params = array(
  1639. 'helper' => $helper_name,
  1640. 'value' => $value,
  1641. 'name' => $field_name,
  1642. 'deprecated' => false
  1643. );
  1644. if ( class_exists( 'Pods_Templates' ) )
  1645. $params[ 'deprecated' ] = Pods_Templates::$deprecated;
  1646. $value = Pods_Helpers::helper( $params, $this );
  1647. }
  1648. else
  1649. $value = $this->display( $field_name );
  1650. if ( isset( $tag[ 2 ] ) && !empty( $tag[ 2 ] ) )
  1651. $before = $tag[ 2 ];
  1652. if ( isset( $tag[ 3 ] ) && !empty( $tag[ 3 ] ) )
  1653. $after = $tag[ 3 ];
  1654. $value = apply_filters( 'pods_do_magic_tags', $value, $field_name, $helper_name, $before, $after );
  1655. if ( is_array( $value ) )
  1656. $value = pods_serial_comma( $value, $field_name, $this->fields );
  1657. if ( null !== $value && false !== $value )
  1658. return $before . $value . $after;
  1659. return;
  1660. }
  1661. /**
  1662. * Handle filters / actions for the class
  1663. *
  1664. * @see pods_do_hook
  1665. *
  1666. * @since 2.0.0
  1667. */
  1668. private function do_hook () {
  1669. $args = func_get_args();
  1670. if ( empty( $args ) )
  1671. return false;
  1672. $name = array_shift( $args );
  1673. return pods_do_hook( 'pods', $name, $args, $this );
  1674. }
  1675. /**
  1676. * Handle variables that have been deprecated
  1677. *
  1678. * @var $name
  1679. *
  1680. * @return mixed
  1681. *
  1682. * @since 2.0.0
  1683. */
  1684. public function __get ( $name ) {
  1685. $name = (string) $name;
  1686. if ( !isset( $this->deprecated ) ) {
  1687. require_once( PODS_DIR . 'deprecated/classes/Pods.php' );
  1688. $this->deprecated = new Pods_Deprecated( $this );
  1689. }
  1690. $var = null;
  1691. if ( isset( $this->deprecated->{$name} ) ) {
  1692. pods_deprecated( "Pods->{$name}", '2.0.0' );
  1693. $var = $this->deprecated->{$name};
  1694. }
  1695. else
  1696. pods_deprecated( "Pods->{$name}", '2.0.0' );
  1697. return $var;
  1698. }
  1699. /**
  1700. * Handle methods that have been deprecated
  1701. *
  1702. * @var $name
  1703. * @var $args
  1704. *
  1705. * @return mixed
  1706. *
  1707. * @since 2.0.0
  1708. */
  1709. public function __call ( $name, $args ) {
  1710. $name = (string) $name;
  1711. if ( !isset( $this->deprecated ) ) {
  1712. require_once( PODS_DIR . 'deprecated/classes/Pods.php' );
  1713. $this->deprecated = new Pods_Deprecated( $this );
  1714. }
  1715. if ( method_exists( $this->deprecated, $name ) )
  1716. return call_user_func_array( array( $this->deprecated, $name ), $args );
  1717. else
  1718. pods_deprecated( "Pods::{$name}", '2.0.0' );
  1719. }
  1720. }