PageRenderTime 472ms CodeModel.GetById 28ms RepoModel.GetById 2ms app.codeStats 12ms

/classes/PodsAPI.php

https://github.com/ElmsPark/pods
PHP | 6128 lines | 3893 code | 1196 blank | 1039 comment | 1248 complexity | ec4c5a41cc728c74d964fb5f059538e3 MD5 | raw file
Possible License(s): AGPL-1.0
  1. <?php
  2. /**
  3. * @package Pods
  4. */
  5. class PodsAPI {
  6. /**
  7. * @var bool
  8. */
  9. public $display_errors = false;
  10. /**
  11. * @var array|bool|mixed|null|void
  12. */
  13. public $pod_data;
  14. /**
  15. * @var
  16. */
  17. public $pod;
  18. /**
  19. * @var
  20. */
  21. public $pod_id;
  22. /**
  23. * @var
  24. */
  25. public $fields;
  26. /**
  27. * @var
  28. * @deprecated 2.0.0
  29. */
  30. public $format = null;
  31. /**
  32. * @var
  33. */
  34. private $deprecated;
  35. /**
  36. * Store and retrieve data programatically
  37. *
  38. * @param string $pod (optional) The pod name
  39. * @param string $format (deprecated) Format for import/export, "php" or "csv"
  40. *
  41. * @license http://www.gnu.org/licenses/gpl-2.0.html
  42. * @since 1.7.1
  43. */
  44. public function __construct ( $pod = null, $format = null ) {
  45. if ( null !== $pod && 0 < strlen( (string) $pod ) ) {
  46. if ( null !== $format ) {
  47. $this->format = $format;
  48. pods_deprecated( 'pods_api( $pod, $format )', '2.0.0', 'pods_api( $pod )' );
  49. }
  50. $pod = pods_clean_name( $pod );
  51. $pod = $this->load_pod( array( 'name' => $pod ), false );
  52. if ( !empty( $pod ) ) {
  53. $this->pod_data = $pod;
  54. $this->pod = $pod[ 'name' ];
  55. $this->pod_id = $pod[ 'id' ];
  56. $this->fields = $pod[ 'fields' ];
  57. }
  58. }
  59. }
  60. /**
  61. * Save a WP object and its meta
  62. *
  63. * @param string $object_type Object type: post|user|comment
  64. * @param array $data All post data to be saved
  65. * @param array $meta (optional) Associative array of meta keys and values
  66. * @param bool $strict (optional) Decides whether the previous saved meta should be deleted or not
  67. * @param bool $sanitized (optional) Will unsanitize the data, should be passed if the data is sanitized before sending.
  68. *
  69. * @return bool|mixed
  70. *
  71. * @since 2.0.0
  72. */
  73. public function save_wp_object ( $object_type, $data, $meta = array(), $strict = false, $sanitized = false ) {
  74. if ( in_array( $object_type, array( 'post_type', 'media' ) ) )
  75. $object_type = 'post';
  76. if ( $sanitized ) {
  77. $data = pods_unsanitize( $data );
  78. $meta = pods_unsanitize( $meta );
  79. }
  80. if ( in_array( $object_type, array( 'post', 'user', 'comment' ) ) )
  81. return call_user_func( array( $this, 'save_' . $object_type ), $data, $meta, $strict, false );
  82. return false;
  83. }
  84. /**
  85. * Delete a WP object
  86. *
  87. * @param string $object_type Object type: post|user|comment
  88. * @param int $id Object ID
  89. * @param bool $force_delete (optional) Force deletion instead of trashing (post types only)
  90. *
  91. * @return bool|mixed
  92. *
  93. * @since 2.0.0
  94. */
  95. public function delete_wp_object ( $object_type, $id, $force_delete = true ) {
  96. if ( in_array( $object_type, array( 'post_type', 'media' ) ) )
  97. $object_type = 'post';
  98. if ( empty( $id ) )
  99. return false;
  100. if ( in_array( $object_type, array( 'post' ) ) )
  101. return wp_delete_post( $id, $force_delete );
  102. if ( function_exists( 'wp_delete_' . $object_type ) )
  103. return call_user_func( 'wp_delete_' . $object_type, $id );
  104. return false;
  105. }
  106. /**
  107. * Save a post and it's meta
  108. *
  109. * @param array $post_data All post data to be saved (using wp_insert_post / wp_update_post)
  110. * @param array $post_meta (optional) All meta to be saved (set value to null to delete)
  111. * @param bool $strict (optional) Whether to delete previously saved meta not in $post_meta
  112. * @param bool $sanitized (optional) Will unsanitize the data, should be passed if the data is sanitized before sending.
  113. * @return mixed|void
  114. */
  115. public function save_post ( $post_data, $post_meta = null, $strict = false, $sanitized = false ) {
  116. pods_no_conflict_on( 'post' );
  117. if ( !is_array( $post_data ) || empty( $post_data ) )
  118. $post_data = array( 'post_title' => '' );
  119. if ( !is_array( $post_meta ) )
  120. $post_meta = array();
  121. if ( $sanitized ) {
  122. $post_data = pods_unsanitize( $post_data );
  123. $post_meta = pods_unsanitize( $post_meta );
  124. }
  125. if ( !isset( $post_data[ 'ID' ] ) || empty( $post_data[ 'ID' ] ) )
  126. $post_data[ 'ID' ] = wp_insert_post( $post_data, true );
  127. elseif ( 2 < count( $post_data ) || !isset( $post_data[ 'post_type' ] ) )
  128. wp_update_post( $post_data );
  129. if ( is_wp_error( $post_data[ 'ID' ] ) ) {
  130. pods_no_conflict_off( 'post' );
  131. /**
  132. * @var $post_error WP_Error
  133. */
  134. $post_error = $post_data[ 'ID' ];
  135. return pods_error( $post_error->get_error_message(), $this );
  136. }
  137. $this->save_post_meta( $post_data[ 'ID' ], $post_meta, $strict );
  138. pods_no_conflict_off( 'post' );
  139. return $post_data[ 'ID' ];
  140. }
  141. /**
  142. * Save a post's meta
  143. *
  144. * @param int $id Post ID
  145. * @param array $post_meta All meta to be saved (set value to null to delete)
  146. * @param bool $strict Whether to delete previously saved meta not in $post_meta
  147. *
  148. * @return int Id of the post with the meta
  149. *
  150. * @since 2.0.0
  151. */
  152. public function save_post_meta ( $id, $post_meta = null, $strict = false ) {
  153. pods_no_conflict_on( 'post' );
  154. if ( !is_array( $post_meta ) )
  155. $post_meta = array();
  156. $id = (int) $id;
  157. $meta = get_post_meta( $id );
  158. foreach ( $meta as &$value ) {
  159. if ( is_array( $value ) && 1 == count( $value ) && isset( $value[ 0 ] ) )
  160. $value = $value[ 0 ];
  161. }
  162. foreach ( $post_meta as $meta_key => $meta_value ) {
  163. if ( null === $meta_value ) {
  164. $old_meta_value = '';
  165. if ( isset( $meta[ $meta_key ] ) )
  166. $old_meta_value = $meta[ $meta_key ];
  167. delete_post_meta( $id, $meta_key, $old_meta_value );
  168. }
  169. else
  170. update_post_meta( $id, $meta_key, $meta_value );
  171. }
  172. if ( $strict ) {
  173. foreach ( $meta as $meta_key => $meta_value ) {
  174. if ( !isset( $post_meta[ $meta_key ] ) )
  175. delete_post_meta( $id, $meta_key, $meta_value );
  176. }
  177. }
  178. pods_no_conflict_off( 'post' );
  179. return $id;
  180. }
  181. /**
  182. * Save a user and it's meta
  183. *
  184. * @param array $user_data All user data to be saved (using wp_insert_user / wp_update_user)
  185. * @param array $user_meta (optional) All meta to be saved (set value to null to delete)
  186. * @param bool $strict (optional) Whether to delete previously saved meta not in $user_meta
  187. * @param bool $sanitized (optional) Will unsanitize the data, should be passed if the data is sanitized before sending.
  188. *
  189. * @return int Returns user id on success
  190. *
  191. * @since 2.0.0
  192. */
  193. public function save_user ( $user_data, $user_meta = null, $strict = false, $sanitized = false ) {
  194. if ( !is_array( $user_data ) || empty( $user_data ) )
  195. return pods_error( __( 'User data is required but is either invalid or empty', 'pods' ), $this );
  196. pods_no_conflict_on( 'user' );
  197. if ( !is_array( $user_meta ) )
  198. $user_meta = array();
  199. if ( $sanitized ) {
  200. $user_data = pods_unsanitize( $user_data );
  201. $user_meta = pods_unsanitize( $user_meta );
  202. }
  203. if ( !isset( $user_data[ 'ID' ] ) || empty( $user_data[ 'ID' ] ) )
  204. $user_data[ 'ID' ] = wp_insert_user( $user_data );
  205. else
  206. wp_update_user( $user_data );
  207. if ( is_wp_error( $user_data[ 'ID' ] ) ) {
  208. pods_no_conflict_off( 'user' );
  209. /**
  210. * @var $user_error WP_Error
  211. */
  212. $user_error = $user_data[ 'ID' ];
  213. return pods_error( $user_error->get_error_message(), $this );
  214. }
  215. $this->save_user_meta( $user_data[ 'ID' ], $user_meta, $strict );
  216. pods_no_conflict_off( 'user' );
  217. return $user_data[ 'ID' ];
  218. }
  219. /**
  220. * Save a user meta
  221. *
  222. * @param int $id User ID
  223. * @param array $user_meta (optional) All meta to be saved (set value to null to delete)
  224. * @param bool $strict (optional) Whether to delete previously saved meta not in $user_meta
  225. *
  226. * @return int User ID
  227. *
  228. * @since 2.0.0
  229. *
  230. */
  231. public function save_user_meta ( $id, $user_meta = null, $strict = false ) {
  232. pods_no_conflict_on( 'user' );
  233. if ( !is_array( $user_meta ) )
  234. $user_meta = array();
  235. $id = (int) $id;
  236. $meta = get_user_meta( $id );
  237. foreach ( $user_meta as $meta_key => $meta_value ) {
  238. if ( null === $meta_value ) {
  239. $old_meta_value = '';
  240. if ( isset( $meta[ $meta_key ] ) )
  241. $old_meta_value = $meta[ $meta_key ];
  242. delete_user_meta( $id, $meta_key, $old_meta_value );
  243. }
  244. else
  245. update_user_meta( $id, $meta_key, $meta_value );
  246. }
  247. if ( $strict ) {
  248. foreach ( $meta as $meta_key => $meta_value ) {
  249. if ( !isset( $user_meta[ $meta_key ] ) )
  250. delete_user_meta( $id, $meta_key, $user_meta[ $meta_key ] );
  251. }
  252. }
  253. pods_no_conflict_off( 'user' );
  254. return $id;
  255. }
  256. /**
  257. * Save a comment and it's meta
  258. *
  259. * @param array $comment_data All comment data to be saved (using wp_insert_comment / wp_update_comment)
  260. * @param array $comment_meta (optional) All meta to be saved (set value to null to delete)
  261. * @param bool $strict (optional) Whether to delete previously saved meta not in $comment_meta
  262. * @param bool $sanitized (optional) Will unsanitize the data, should be passed if the data is sanitized before sending.
  263. *
  264. * @return int Comment ID
  265. *
  266. * @since 2.0.0
  267. */
  268. public function save_comment ( $comment_data, $comment_meta = null, $strict = false, $sanitized = false ) {
  269. if ( !is_array( $comment_data ) || empty( $comment_data ) )
  270. return pods_error( __( 'Comment data is required but is either invalid or empty', 'pods' ), $this );
  271. pods_no_conflict_on( 'comment' );
  272. if ( !is_array( $comment_meta ) )
  273. $comment_meta = array();
  274. if ( $sanitized ) {
  275. $comment_data = pods_unsanitize( $comment_data );
  276. $comment_meta = pods_unsanitize( $comment_meta );
  277. }
  278. if ( !isset( $comment_data[ 'comment_ID' ] ) || empty( $comment_data[ 'comment_ID' ] ) )
  279. $comment_data[ 'comment_ID' ] = wp_insert_comment( $comment_data );
  280. else
  281. wp_update_comment( $comment_data );
  282. if ( is_wp_error( $comment_data[ 'comment_ID' ] ) ) {
  283. pods_no_conflict_off( 'comment' );
  284. /**
  285. * @var $comment_error WP_Error
  286. */
  287. $comment_error = $comment_data[ 'comment_ID' ];
  288. return pods_error( $comment_error->get_error_message(), $this );
  289. }
  290. $this->save_comment_meta( $comment_data[ 'comment_ID' ], $comment_meta, $strict );
  291. pods_no_conflict_off( 'comment' );
  292. return $comment_data[ 'comment_ID' ];
  293. }
  294. /**
  295. * Save a comment meta
  296. *
  297. * @param int $id Comment ID
  298. * @param array $comment_meta (optional) All meta to be saved (set value to null to delete)
  299. * @param bool $strict (optional) Whether to delete previously saved meta not in $comment_meta
  300. *
  301. * @return int Comment ID
  302. *
  303. * @since 2.0.0
  304. */
  305. public function save_comment_meta ( $id, $comment_meta = null, $strict = false ) {
  306. pods_no_conflict_on( 'comment' );
  307. if ( !is_array( $comment_meta ) )
  308. $comment_meta = array();
  309. $id = (int) $id;
  310. $meta = get_comment_meta( $id );
  311. foreach ( $comment_meta as $meta_key => $meta_value ) {
  312. if ( null === $meta_value ) {
  313. $old_meta_value = '';
  314. if ( isset( $meta[ $meta_key ] ) )
  315. $old_meta_value = $meta[ $meta_key ];
  316. delete_comment_meta( $id, $meta_key, $old_meta_value );
  317. }
  318. else
  319. update_comment_meta( $id, $meta_key, $meta_value );
  320. }
  321. if ( $strict ) {
  322. foreach ( $meta as $meta_key => $meta_value ) {
  323. if ( !isset( $comment_meta[ $meta_key ] ) )
  324. delete_comment_meta( (int) $id, $meta_key, $comment_meta[ $meta_key ] );
  325. }
  326. }
  327. pods_no_conflict_off( 'comment' );
  328. return $id;
  329. }
  330. /**
  331. * Save a taxonomy's term
  332. *
  333. * @param int $term_ID Term ID, leave empty to add
  334. * @param string $term Term name
  335. * @param string $taxonomy Taxonomy name
  336. * @param array $term_data All term data to be saved (using wp_insert_term / wp_update_term)
  337. * @param bool $sanitized (optional) Will unsanitize the data, should be passed if the data is sanitized before sending.
  338. *
  339. * @return int Term ID
  340. *
  341. * @since 2.0.0
  342. */
  343. public function save_term ( $term_ID, $term, $taxonomy, $term_data, $sanitized = false ) {
  344. pods_no_conflict_on( 'taxonomy' );
  345. if ( !is_array( $term_data ) )
  346. $term_data = array();
  347. $term_ID = (int) $term_ID;
  348. if ( $sanitized ) {
  349. $term = pods_unsanitize( $term );
  350. $taxonomy = pods_unsanitize( $taxonomy );
  351. $term_data = pods_unsanitize( $term_data );
  352. }
  353. if ( empty( $term_ID ) )
  354. $term_ID = wp_insert_term( $term, $taxonomy, $term_data );
  355. else {
  356. if ( 0 < strlen( $term ) )
  357. $term_data[ 'term' ] = $term;
  358. if ( empty( $term_data ) ) {
  359. pods_no_conflict_off( 'taxonomy' );
  360. return pods_error( __( 'Taxonomy term data is required but is either invalid or empty', 'pods' ), $this );
  361. }
  362. wp_update_term( $term_ID, $taxonomy, $term_data );
  363. }
  364. if ( is_wp_error( $term_ID ) ) {
  365. pods_no_conflict_off( 'taxonomy' );
  366. return pods_error( $term_ID->get_error_message(), $this );
  367. }
  368. elseif ( is_array( $term_ID ) )
  369. $term_ID = $term_ID[ 'term_id' ];
  370. pods_no_conflict_off( 'taxonomy' );
  371. return $term_ID;
  372. }
  373. /**
  374. * Rename a WP object's type
  375. *
  376. * @param string $object_type Object type: post|taxonomy|comment
  377. * @param string $old_name The old name
  378. * @param string $new_name The new name
  379. *
  380. * @return bool
  381. *
  382. * @since 2.0.0
  383. */
  384. public function rename_wp_object_type ( $object_type, $old_name, $new_name ) {
  385. /**
  386. * @var $wpdb wpdb
  387. */
  388. global $wpdb;
  389. if ( 'post_type' == $object_type )
  390. $object_type = 'post';
  391. if ( 'post' == $object_type ) {
  392. pods_query( "UPDATE `{$wpdb->posts}` SET `post_type` = %s WHERE `post_type` = %s", array(
  393. $new_name,
  394. $old_name
  395. ) );
  396. }
  397. elseif ( 'taxonomy' == $object_type ) {
  398. pods_query( "UPDATE `{$wpdb->term_taxonomy}` SET `taxonomy` = %s WHERE `taxonomy` = %s", array(
  399. $new_name,
  400. $old_name
  401. ) );
  402. }
  403. elseif ( 'comment' == $object_type ) {
  404. pods_query( "UPDATE `{$wpdb->comments}` SET `comment_type` = %s WHERE `comment_type` = %s", array(
  405. $new_name,
  406. $old_name
  407. ) );
  408. }
  409. return true;
  410. }
  411. /**
  412. * Get a list of core WP object fields for a specific object
  413. *
  414. * @param string $object The post type to look for, possible values: post_type, user, comment, taxonomy
  415. * @param array $pod Array of Pod data
  416. * @param boolean $refresh Whether to force refresh the information
  417. *
  418. * @return array Array of fields
  419. */
  420. public function get_wp_object_fields ( $object = 'post_type', $pod = null, $refresh = false ) {
  421. $pod_name = pods_var_raw( 'name', $pod );
  422. $fields = pods_transient_get( trim( 'pods_api_object_fields_' . $object . $pod_name . '_', '_' ) );
  423. if ( false !== $fields && !$refresh )
  424. return $this->do_hook( 'get_wp_object_fields', $fields, $object, $pod );
  425. $fields = array();
  426. if ( 'post_type' == $object ) {
  427. $fields = array(
  428. 'post_title' => array(
  429. 'name' => 'post_title',
  430. 'label' => 'Title',
  431. 'type' => 'text',
  432. 'alias' => array( 'title', 'name' )
  433. ),
  434. 'post_content' => array(
  435. 'name' => 'post_content',
  436. 'label' => 'Content',
  437. 'type' => 'wysiwyg',
  438. 'alias' => array( 'content' ),
  439. 'options' => array(
  440. 'wysiwyg_allow_html' => 1,
  441. 'wysiwyg_allowed_html_tags' => '',
  442. 'display_filter' => 'the_content',
  443. 'pre_save' => 0
  444. )
  445. ),
  446. 'post_excerpt' => array(
  447. 'name' => 'post_excerpt',
  448. 'label' => 'Excerpt',
  449. 'type' => 'paragraph',
  450. 'alias' => array( 'excerpt' ),
  451. 'options' => array(
  452. 'paragraph_allow_html' => 1,
  453. 'paragraph_allowed_html_tags' => '',
  454. 'display_filter' => 'the_excerpt',
  455. 'pre_save' => 0
  456. )
  457. ),
  458. 'post_author' => array(
  459. 'name' => 'post_author',
  460. 'label' => 'Author',
  461. 'type' => 'pick',
  462. 'alias' => array( 'author' ),
  463. 'pick_object' => 'user',
  464. 'options' => array(
  465. 'pick_format_type' => 'single',
  466. 'pick_format_single' => 'autocomplete',
  467. 'default_value' => '{@user.ID}'
  468. )
  469. ),
  470. 'post_date' => array(
  471. 'name' => 'post_date',
  472. 'label' => 'Publish Date',
  473. 'type' => 'datetime',
  474. 'alias' => array( 'created', 'date' )
  475. ),
  476. 'post_date_gmt' => array(
  477. 'name' => 'post_date_gmt',
  478. 'label' => 'Publish Date (GMT)',
  479. 'type' => 'datetime',
  480. 'alias' => array(),
  481. 'hidden' => true
  482. ),
  483. 'post_status' => array(
  484. 'name' => 'post_status',
  485. 'label' => 'Status',
  486. 'type' => 'pick',
  487. 'pick_object' => 'post-status',
  488. 'default' => $this->do_hook( 'default_status_' . pods_var_raw( 'name', $pod, $object, null, true ), pods_var( 'default_status', pods_var_raw( 'options', $pod ), 'draft', null, true ), $pod ),
  489. 'alias' => array( 'status' )
  490. ),
  491. 'comment_status' => array(
  492. 'name' => 'comment_status',
  493. 'label' => 'Comment Status',
  494. 'type' => 'text',
  495. 'default' => get_option( 'default_comment_status', 'open' ),
  496. 'alias' => array(),
  497. 'data' => array(
  498. 'open' => __( 'Open', 'pods' ),
  499. 'closed' => __( 'Closed', 'pods' )
  500. )
  501. ),
  502. 'ping_status' => array(
  503. 'name' => 'ping_status',
  504. 'label' => 'Ping Status',
  505. 'default' => get_option( 'default_ping_status', 'open' ),
  506. 'type' => 'text',
  507. 'alias' => array(),
  508. 'data' => array(
  509. 'open' => __( 'Open', 'pods' ),
  510. 'closed' => __( 'Closed', 'pods' )
  511. )
  512. ),
  513. 'post_password' => array(
  514. 'name' => 'post_password',
  515. 'label' => 'Password',
  516. 'type' => 'text',
  517. 'alias' => array()
  518. ),
  519. 'post_name' => array(
  520. 'name' => 'post_name',
  521. 'label' => 'Permalink',
  522. 'type' => 'slug',
  523. 'alias' => array( 'slug', 'permalink' )
  524. ),
  525. 'to_ping' => array(
  526. 'name' => 'to_ping',
  527. 'label' => 'To Ping',
  528. 'type' => 'text',
  529. 'alias' => array(),
  530. 'hidden' => true
  531. ),
  532. 'pinged' => array(
  533. 'name' => 'pinged',
  534. 'label' => 'Pinged',
  535. 'type' => 'text',
  536. 'alias' => array(),
  537. 'hidden' => true
  538. ),
  539. 'post_modified' => array(
  540. 'name' => 'post_modified',
  541. 'label' => 'Last Modified Date',
  542. 'type' => 'datetime',
  543. 'alias' => array( 'modified' ),
  544. 'hidden' => true
  545. ),
  546. 'post_modified_gmt' => array(
  547. 'name' => 'post_modified_gmt',
  548. 'label' => 'Last Modified Date (GMT)',
  549. 'type' => 'datetime',
  550. 'alias' => array(),
  551. 'hidden' => true
  552. ),
  553. 'post_content_filtered' => array(
  554. 'name' => 'post_content_filtered',
  555. 'label' => 'Content (filtered)',
  556. 'type' => 'paragraph',
  557. 'alias' => array(),
  558. 'hidden' => true,
  559. 'options' => array(
  560. 'paragraph_allow_html' => 1,
  561. 'paragraph_oembed' => 1,
  562. 'paragraph_wptexturize' => 1,
  563. 'paragraph_convert_chars' => 1,
  564. 'paragraph_wpautop' => 1,
  565. 'paragraph_allow_shortcode' => 1,
  566. 'paragraph_allowed_html_tags' => ''
  567. )
  568. ),
  569. 'post_parent' => array(
  570. 'name' => 'post_parent',
  571. 'label' => 'Parent',
  572. 'type' => 'pick',
  573. 'pick_object' => 'post_type',
  574. 'alias' => array( 'parent' ),
  575. 'data' => array(),
  576. 'hidden' => true
  577. ),
  578. 'guid' => array(
  579. 'name' => 'guid',
  580. 'label' => 'GUID',
  581. 'type' => 'text',
  582. 'alias' => array(),
  583. 'hidden' => true
  584. ),
  585. 'menu_order' => array(
  586. 'name' => 'menu_order',
  587. 'label' => 'Menu Order',
  588. 'type' => 'number',
  589. 'alias' => array()
  590. ),
  591. 'post_type' => array(
  592. 'name' => 'post_type',
  593. 'label' => 'Type',
  594. 'type' => 'text',
  595. 'alias' => array( 'type' ),
  596. 'hidden' => true
  597. ),
  598. 'post_mime_type' => array(
  599. 'name' => 'post_mime_type',
  600. 'label' => 'Mime Type',
  601. 'type' => 'text',
  602. 'alias' => array(),
  603. 'hidden' => true
  604. ),
  605. 'comment_count' => array(
  606. 'name' => 'comment_count',
  607. 'label' => 'Comment Count',
  608. 'type' => 'number',
  609. 'alias' => array(),
  610. 'hidden' => true
  611. )
  612. );
  613. if ( !empty( $pod ) ) {
  614. $taxonomies = get_object_taxonomies( pods_var_raw( 'name', $pod ), 'objects' );
  615. foreach ( $taxonomies as $taxonomy ) {
  616. $fields[ $taxonomy->name ] = array(
  617. 'name' => $taxonomy->name,
  618. 'label' => $taxonomy->labels->name,
  619. 'type' => 'taxonomy',
  620. 'alias' => array(),
  621. 'hidden' => true
  622. );
  623. }
  624. }
  625. }
  626. elseif ( 'user' == $object ) {
  627. $fields = array(
  628. 'user_login' => array(
  629. 'name' => 'user_login',
  630. 'label' => 'Title',
  631. 'type' => 'text',
  632. 'alias' => array( 'login' ),
  633. 'options' => array(
  634. 'required' => 1
  635. )
  636. ),
  637. 'user_nicename' => array(
  638. 'name' => 'user_nicename',
  639. 'label' => 'Permalink',
  640. 'type' => 'slug',
  641. 'alias' => array( 'nicename', 'slug', 'permalink' )
  642. ),
  643. 'display_name' => array(
  644. 'name' => 'display_name',
  645. 'label' => 'Display Name',
  646. 'type' => 'text',
  647. 'alias' => array( 'title', 'name' )
  648. ),
  649. 'user_pass' => array(
  650. 'name' => 'user_pass',
  651. 'label' => 'Password',
  652. 'type' => 'text',
  653. 'alias' => array( 'password', 'pass' ),
  654. 'options' => array(
  655. 'required' => 1,
  656. 'text_format_type' => 'password'
  657. )
  658. ),
  659. 'user_email' => array(
  660. 'name' => 'user_email',
  661. 'label' => 'E-mail',
  662. 'type' => 'text',
  663. 'alias' => array( 'email' ),
  664. 'options' => array(
  665. 'required' => 1,
  666. 'text_format_type' => 'email'
  667. )
  668. ),
  669. 'user_url' => array(
  670. 'name' => 'user_url',
  671. 'label' => 'URL',
  672. 'type' => 'text',
  673. 'alias' => array( 'url', 'website' ),
  674. 'options' => array(
  675. 'required' => 1,
  676. 'text_format_type' => 'website',
  677. 'text_format_website' => 'normal'
  678. )
  679. ),
  680. 'user_registered' => array(
  681. 'name' => 'user_registered',
  682. 'label' => 'Registration Date',
  683. 'type' => 'date',
  684. 'alias' => array( 'created', 'date', 'registered' ),
  685. 'options' => array(
  686. 'date_format_type' => 'datetime'
  687. )
  688. )
  689. );
  690. }
  691. elseif ( 'comment' == $object ) {
  692. $fields = array(
  693. 'comment_content' => array(
  694. 'name' => 'comment_content',
  695. 'label' => 'Content',
  696. 'type' => 'wysiwyg',
  697. 'alias' => array( 'content' )
  698. ),
  699. 'comment_approved' => array(
  700. 'name' => 'comment_approved',
  701. 'label' => 'Approved',
  702. 'type' => 'number',
  703. 'alias' => array( 'approved' )
  704. ),
  705. 'comment_post_ID' => array(
  706. 'name' => 'comment_post_ID',
  707. 'label' => 'Post',
  708. 'type' => 'pick',
  709. 'alias' => array( 'post', 'post_id' ),
  710. 'data' => array()
  711. ),
  712. 'user_id' => array(
  713. 'name' => 'user_id',
  714. 'label' => 'Author',
  715. 'type' => 'pick',
  716. 'alias' => array( 'author' ),
  717. 'pick_object' => 'user',
  718. 'data' => array()
  719. ),
  720. 'comment_date' => array(
  721. 'name' => 'comment_date',
  722. 'label' => 'Date',
  723. 'type' => 'date',
  724. 'alias' => array( 'created', 'date' ),
  725. 'options' => array(
  726. 'date_format_type' => 'datetime'
  727. )
  728. )
  729. );
  730. }
  731. elseif ( 'taxonomy' == $object ) {
  732. $fields = array(
  733. 'name' => array(
  734. 'name' => 'name',
  735. 'label' => 'Title',
  736. 'type' => 'text',
  737. 'alias' => array( 'title' )
  738. ),
  739. 'slug' => array(
  740. 'name' => 'slug',
  741. 'label' => 'Permalink',
  742. 'type' => 'slug',
  743. 'alias' => array( 'permalink' )
  744. ),
  745. 'description' => array(
  746. 'name' => 'description',
  747. 'label' => 'Description',
  748. 'type' => 'wysiwyg',
  749. 'alias' => array( 'content' )
  750. ),
  751. 'taxonomy' => array(
  752. 'name' => 'taxonomy',
  753. 'label' => 'Taxonomy',
  754. 'type' => 'pick',
  755. 'alias' => array()
  756. )
  757. );
  758. }
  759. $fields = $this->do_hook( 'get_wp_object_fields', $fields, $object, $pod );
  760. foreach ( $fields as $field => $options ) {
  761. if ( !isset( $options[ 'alias' ] ) )
  762. $options[ 'alias' ] = array();
  763. else
  764. $options[ 'alias' ] = (array) $options[ 'alias' ];
  765. if ( !isset( $options[ 'name' ] ) )
  766. $options[ 'name' ] = $field;
  767. $fields[ $field ] = $options;
  768. }
  769. $fields = PodsForm::fields_setup( $fields );
  770. if ( did_action( 'init' ) )
  771. pods_transient_set( trim( 'pods_api_object_fields_' . $object . $pod_name . '_', '_' ), $fields );
  772. return $fields;
  773. }
  774. /**
  775. *
  776. * @see PodsAPI::save_pod
  777. *
  778. * Add a Pod via the Wizard
  779. *
  780. * $params['create_extend'] string Create or Extend a Content Type
  781. * $params['create_pod_type'] string Pod Type (for Creating)
  782. * $params['create_name'] string Pod Name (for Creating)
  783. * $params['create_label_plural'] string Plural Label (for Creating)
  784. * $params['create_label_singular'] string Singular Label (for Creating)
  785. * $params['create_storage'] string Storage Type (for Creating Post Types)
  786. * $params['create_storage_taxonomy'] string Storage Type (for Creating Taxonomies)
  787. * $params['extend_pod_type'] string Pod Type (for Extending)
  788. * $params['extend_post_type'] string Post Type (for Extending Post Types)
  789. * $params['extend_taxonomy'] string Taxonomy (for Extending Taxonomies)
  790. * $params['extend_storage'] string Storage Type (for Extending Post Types / Users / Comments)
  791. *
  792. * @param array $params An associative array of parameters
  793. *
  794. * @return bool|int Pod ID
  795. * @since 2.0.0
  796. */
  797. public function add_pod ( $params ) {
  798. $defaults = array(
  799. 'create_extend' => 'create',
  800. 'create_pod_type' => 'post_type',
  801. 'create_name' => '',
  802. 'create_label_plural' => '',
  803. 'create_label_singular' => '',
  804. 'create_storage' => 'meta',
  805. 'create_storage_taxonomy' => 'none',
  806. 'extend_pod_type' => 'post_type',
  807. 'extend_post_type' => 'post',
  808. 'extend_taxonomy' => 'category',
  809. 'extend_storage_taxonomy' => 'table',
  810. 'extend_storage' => 'meta'
  811. );
  812. $params = (object) array_merge( $defaults, (array) $params );
  813. if ( empty( $params->create_extend ) || !in_array( $params->create_extend, array( 'create', 'extend' ) ) )
  814. return pods_error( __( 'Please choose whether to Create or Extend a Content Type', $this ) );
  815. $pod_params = array(
  816. 'name' => '',
  817. 'label' => '',
  818. 'type' => '',
  819. 'storage' => 'table',
  820. 'object' => '',
  821. 'options' => array()
  822. );
  823. if ( 'create' == $params->create_extend ) {
  824. if ( empty( $params->create_name ) )
  825. return pods_error( 'Please enter a Name for this Pod', $this );
  826. $pod_params[ 'name' ] = $params->create_name;
  827. $pod_params[ 'label' ] = ( !empty( $params->create_label_plural ) ? $params->create_label_plural : ucwords( str_replace( '_', ' ', $params->create_name ) ) );
  828. $pod_params[ 'type' ] = $params->create_pod_type;
  829. $pod_params[ 'options' ] = array(
  830. 'label_singular' => ( !empty( $params->create_label_singular ) ? $params->create_label_singular : ucwords( str_replace( '_', ' ', $params->create_name ) ) ),
  831. 'public' => 1,
  832. 'show_ui' => 1
  833. );
  834. if ( 'post_type' == $pod_params[ 'type' ] ) {
  835. $pod_params[ 'storage' ] = $params->create_storage;
  836. if ( defined( 'PODS_TABLELESS' ) && PODS_TABLELESS )
  837. $pod_params[ 'storage' ] = 'meta';
  838. }
  839. elseif ( 'taxonomy' == $pod_params[ 'type' ] ) {
  840. $pod_params[ 'storage' ] = $params->create_storage_taxonomy;
  841. if ( defined( 'PODS_TABLELESS' ) && PODS_TABLELESS )
  842. $pod_params[ 'storage' ] = 'none';
  843. }
  844. elseif ( defined( 'PODS_TABLELESS' ) && PODS_TABLELESS ) {
  845. $pod_params[ 'type' ] = 'post_type';
  846. $pod_params[ 'storage' ] = 'meta';
  847. }
  848. }
  849. elseif ( 'extend' == $params->create_extend ) {
  850. $pod_params[ 'type' ] = $params->extend_pod_type;
  851. if ( 'post_type' == $pod_params[ 'type' ] ) {
  852. $pod_params[ 'storage' ] = $params->extend_storage;
  853. if ( defined( 'PODS_TABLELESS' ) && PODS_TABLELESS )
  854. $pod_params[ 'storage' ] = 'meta';
  855. $pod_params[ 'name' ] = $params->extend_post_type;
  856. }
  857. elseif ( 'taxonomy' == $pod_params[ 'type' ] ) {
  858. $pod_params[ 'storage' ] = $params->extend_storage_taxonomy;
  859. if ( defined( 'PODS_TABLELESS' ) && PODS_TABLELESS )
  860. $pod_params[ 'storage' ] = 'none';
  861. $pod_params[ 'name' ] = $params->extend_taxonomy;
  862. }
  863. else {
  864. $pod_params[ 'storage' ] = $params->extend_storage;
  865. if ( defined( 'PODS_TABLELESS' ) && PODS_TABLELESS )
  866. $pod_params[ 'storage' ] = 'meta';
  867. $pod_params[ 'name' ] = $params->extend_pod_type;
  868. }
  869. $pod_params[ 'label' ] = ucwords( str_replace( '_', ' ', $pod_params[ 'name' ] ) );
  870. $pod_params[ 'object' ] = $pod_params[ 'name' ];
  871. }
  872. if ( empty( $pod_params[ 'object' ] ) ) {
  873. if ( 'post_type' == $pod_params[ 'type' ] ) {
  874. $check = get_post_type_object( $pod_params[ 'name' ] );
  875. if ( !empty( $check ) )
  876. return pods_error( sprintf( __( 'Post Type %s already exists, try extending it instead', 'pods' ), $pod_params[ 'name' ] ), $this );
  877. $pod_params[ 'options' ][ 'supports_title' ] = 1;
  878. $pod_params[ 'options' ][ 'supports_editor' ] = 1;
  879. }
  880. elseif ( 'taxonomy' == $pod_params[ 'type' ] ) {
  881. $check = get_taxonomy( $pod_params[ 'name' ] );
  882. if ( !empty( $check ) )
  883. return pods_error( sprintf( __( 'Taxonomy %s already exists, try extending it instead', 'pods' ), $pod_params[ 'name' ] ), $this );
  884. }
  885. }
  886. if ( !empty( $pod_params ) )
  887. return $this->save_pod( $pod_params );
  888. return false;
  889. }
  890. /**
  891. * Add or edit a Pod
  892. *
  893. * $params['id'] int The Pod ID
  894. * $params['name'] string The Pod name
  895. * $params['label'] string The Pod label
  896. * $params['type'] string The Pod type
  897. * $params['storage'] string The Pod storage
  898. * $params['options'] array Options
  899. *
  900. * @param array $params An associative array of parameters
  901. * @param bool $sanitized (optional) Decides whether the params have been sanitized before being passed, will sanitize them if false.
  902. * @param bool|int $db (optional) Whether to save into the DB or just return Pod array.
  903. *
  904. * @return int Pod ID
  905. * @since 1.7.9
  906. */
  907. public function save_pod ( $params, $sanitized = false, $db = true ) {
  908. $tableless_field_types = apply_filters( 'pods_tableless_field_types', array( 'pick', 'file', 'avatar', 'taxonomy' ) );
  909. $load_params = (object) $params;
  910. if ( isset( $load_params->id ) && isset( $load_params->name ) )
  911. unset( $load_params->name );
  912. if ( isset( $load_params->old_name ) )
  913. $load_params->name = $load_params->old_name;
  914. $pod = $this->load_pod( $load_params, false );
  915. $params = (object) $params;
  916. if ( false === $sanitized )
  917. $params = pods_sanitize( $params );
  918. $old_id = $old_name = $old_storage = null;
  919. $old_fields = $old_options = array();
  920. if ( isset( $params->name ) )
  921. $params->name = pods_clean_name( $params->name );
  922. if ( !empty( $pod ) ) {
  923. if ( isset( $params->id ) && 0 < $params->id )
  924. $old_id = $params->id;
  925. $params->id = $pod[ 'id' ];
  926. $old_name = $pod[ 'name' ];
  927. $old_storage = $pod[ 'storage' ];
  928. $old_fields = $pod[ 'fields' ];
  929. $old_options = $pod[ 'options' ];
  930. if ( !isset( $params->name ) && empty( $params->name ) )
  931. $params->name = $pod[ 'name' ];
  932. if ( $old_name != $params->name && false !== $this->pod_exists( array( 'name' => $params->name ) ) )
  933. return pods_error( sprintf( __( 'Pod %s already exists, you cannot rename %s to that', 'pods' ), $params->name, $old_name ), $this );
  934. if ( $old_name != $params->name && in_array( $pod[ 'type' ], array( 'user', 'comment', 'media' ) ) && in_array( $pod[ 'object' ], array( 'user', 'comment', 'media' ) ) )
  935. return pods_error( sprintf( __( 'Pod %s cannot be renamed, it extends an existing WP Object', 'pods' ), $old_name ), $this );
  936. if ( $old_name != $params->name && in_array( $pod[ 'type' ], array( 'post_type', 'taxonomy' ) ) && !empty( $pod[ 'object' ] ) && $pod[ 'object' ] != $old_name )
  937. return pods_error( sprintf( __( 'Pod %s cannot be renamed, it extends an existing WP Object', 'pods' ), $old_name ), $this );
  938. if ( $old_id != $params->id ) {
  939. if ( $params->type == $pod[ 'type' ] && isset( $params->object ) && $params->object == $pod[ 'object' ] )
  940. return pods_error( sprintf( __( 'Pod using %s already exists, you can not reuse an object across multiple pods', 'pods' ), $params->object ), $this );
  941. else
  942. return pods_error( sprintf( __( 'Pod %s already exists', 'pods' ), $params->name ), $this );
  943. }
  944. }
  945. else {
  946. $pod = array(
  947. 'id' => 0,
  948. 'name' => $params->name,
  949. 'label' => $params->name,
  950. 'description' => '',
  951. 'type' => 'pod',
  952. 'storage' => 'table',
  953. 'object' => '',
  954. 'alias' => '',
  955. 'options' => array(),
  956. 'fields' => array()
  957. );
  958. }
  959. // Blank out fields and options for AJAX calls (everything should be sent to it for a full overwrite)
  960. if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
  961. $pod[ 'fields' ] = array();
  962. $pod[ 'options' ] = array();
  963. }
  964. // Setup options
  965. $options = get_object_vars( $params );
  966. if ( isset( $options[ 'method' ] ) )
  967. unset( $options[ 'method' ] );
  968. $exclude = array(
  969. 'id',
  970. 'name',
  971. 'label',
  972. 'description',
  973. 'type',
  974. 'storage',
  975. 'object',
  976. 'alias',
  977. 'options',
  978. 'fields'
  979. );
  980. foreach ( $exclude as $k => $exclude_field ) {
  981. $aliases = array( $exclude_field );
  982. if ( is_array( $exclude_field ) ) {
  983. $aliases = array_merge( array( $k ), $exclude_field );
  984. $exclude_field = $k;
  985. }
  986. foreach ( $aliases as $alias ) {
  987. if ( isset( $options[ $alias ] ) ) {
  988. $pod[ $exclude_field ] = pods_trim( $options[ $alias ] );
  989. unset( $options[ $alias ] );
  990. }
  991. }
  992. }
  993. if ( defined( 'PODS_TABLELESS' ) && PODS_TABLELESS ) {
  994. if ( 'pod' == $pod[ 'type' ] )
  995. $pod[ 'type' ] = 'post_type';
  996. if ( 'table' == $pod[ 'storage' ] ) {
  997. if ( 'taxonomy' == $pod[ 'type' ] )
  998. $pod[ 'storage' ] = 'none';
  999. else
  1000. $pod[ 'storage' ] = 'meta';
  1001. }
  1002. }
  1003. $pod[ 'options' ][ 'type' ] = $pod[ 'type' ];
  1004. $pod[ 'options' ][ 'storage' ] = $pod[ 'storage' ];
  1005. $pod[ 'options' ][ 'object' ] = $pod[ 'object' ];
  1006. $pod[ 'options' ][ 'alias' ] = $pod[ 'alias' ];
  1007. $pod[ 'options' ] = array_merge( $pod[ 'options' ], $options );
  1008. if ( strlen( $pod[ 'label' ] ) < 1 )
  1009. $pod[ 'label' ] = $pod[ 'name' ];
  1010. if ( 'post_type' == $pod[ 'type' ] ) {
  1011. // Max length for post types are 20 characters
  1012. $pod[ 'name' ] = substr( $pod[ 'name' ], 0, 20 );
  1013. }
  1014. elseif ( 'taxonomy' == $pod[ 'type' ] ) {
  1015. // Max length for taxonomies are 32 characters
  1016. $pod[ 'name' ] = substr( $pod[ 'name' ], 0, 32 );
  1017. }
  1018. $params->id = $pod[ 'id' ];
  1019. $params->name = $pod[ 'name' ];
  1020. if ( null !== $old_name && $old_name != $params->name && empty( $pod[ 'object' ] ) ) {
  1021. if ( 'post_type' == $pod[ 'type' ] ) {
  1022. $check = get_post_type_object( $params->name );
  1023. if ( !empty( $check ) )
  1024. return pods_error( sprintf( __( 'Post Type %s already exists, you cannot rename %s to that', 'pods' ), $params->name, $old_name ), $this );
  1025. }
  1026. elseif ( 'taxonomy' == $pod[ 'type' ] ) {
  1027. $check = get_taxonomy( $params->name );
  1028. if ( !empty( $check ) )
  1029. return pods_error( sprintf( __( 'Taxonomy %s already exists, you cannot rename %s to that', 'pods' ), $params->name, $old_name ), $this );
  1030. }
  1031. }
  1032. $field_table_operation = true;
  1033. // Add new pod
  1034. if ( empty( $params->id ) ) {
  1035. if ( strlen( $params->name ) < 1 )
  1036. return pods_error( __( 'Pod name cannot be empty', 'pods' ), $this );
  1037. $post_data = array(
  1038. 'post_name' => $pod[ 'name' ],
  1039. 'post_title' => $pod[ 'label' ],
  1040. 'post_content' => $pod[ 'description' ],
  1041. 'post_type' => '_pods_pod',
  1042. 'post_status' => 'publish'
  1043. );
  1044. if ( 'pod' == $pod[ 'type' ] && ( !is_array( $pod[ 'fields' ] ) || empty( $pod[ 'fields' ] ) ) ) {
  1045. $pod[ 'fields' ] = array();
  1046. $pod[ 'fields' ][] = array(
  1047. 'name' => 'name',
  1048. 'label' => 'Name',
  1049. 'type' => 'text',
  1050. 'options' => array(
  1051. 'required' => '1'
  1052. )
  1053. );
  1054. $pod[ 'fields' ][] = array(
  1055. 'name' => 'created',
  1056. 'label' => 'Date Created',
  1057. 'type' => 'datetime',
  1058. 'options' => array(
  1059. 'datetime_format' => 'ymd_slash',
  1060. 'datetime_time_type' => '12',
  1061. 'datetime_time_format' => 'h_mm_ss_A'
  1062. )
  1063. );
  1064. $pod[ 'fields' ][] = array(
  1065. 'name' => 'modified',
  1066. 'label' => 'Date Modified',
  1067. 'type' => 'datetime',
  1068. 'options' => array(
  1069. 'datetime_format' => 'ymd_slash',
  1070. 'datetime_time_type' => '12',
  1071. 'datetime_time_format' => 'h_mm_ss_A'
  1072. )
  1073. );
  1074. $pod[ 'fields' ][] = array(
  1075. 'name' => 'author',
  1076. 'label' => 'Author',
  1077. 'type' => 'pick',
  1078. 'pick_object' => 'user',
  1079. 'options' => array(
  1080. 'pick_format_type' => 'single',
  1081. 'pick_format_single' => 'autocomplete',
  1082. 'default_value' => '{@user.ID}'
  1083. )
  1084. );
  1085. $pod[ 'fields' ][] = array(
  1086. 'name' => 'permalink',
  1087. 'label' => 'Permalink',
  1088. 'type' => 'slug',
  1089. 'description' => 'Leave blank to auto-generate from Name'
  1090. );
  1091. if ( !isset( $pod[ 'options' ][ 'pod_index' ] ) )
  1092. $pod[ 'options' ][ 'pod_index' ] = 'name';
  1093. }
  1094. $field_table_operation = false;
  1095. }
  1096. else {
  1097. $post_data = array(
  1098. 'ID' => $pod[ 'id' ],
  1099. 'post_name' => $pod[ 'name' ],
  1100. 'post_title' => $pod[ 'label' ],
  1101. 'post_content' => $pod[ 'description' ],
  1102. 'post_status' => 'publish'
  1103. );
  1104. }
  1105. if ( true === $db ) {
  1106. $params->id = $this->save_post( $post_data, $pod[ 'options' ], true, true );
  1107. if ( false === $params->id )
  1108. return pods_error( __( 'Cannot save Pod', 'pods' ), $this );
  1109. }
  1110. elseif ( empty( $params->id ) )
  1111. $params->id = (int) $db;
  1112. $pod[ 'id' ] = $params->id;
  1113. // Setup / update tables
  1114. if ( 'table' == $pod[ 'storage' ] && $old_storage != $pod[ 'storage' ] && $db ) {
  1115. $definitions = array( "`id` BIGINT(20) UNSIGNED AUTO_INCREMENT PRIMARY KEY" );
  1116. foreach ( $pod[ 'fields' ] as $field ) {
  1117. if ( !in_array( $field[ 'type' ], $tableless_field_types ) )
  1118. $definitions[] = "`{$field['name']}` " . $this->get_field_definition( $field[ 'type' ], $field[ 'options' ] );
  1119. }
  1120. pods_query( "DROP TABLE IF EXISTS `@wp_pods_{$params->name}`" );
  1121. $result = pods_query( "CREATE TABLE `@wp_pods_{$params->name}` (" . implode( ', ', $definitions ) . ") DEFAULT CHARSET utf8", $this );
  1122. if ( empty( $result ) )
  1123. return pods_error( __( 'Cannot add Database Table for Pod', 'pods' ), $this );
  1124. }
  1125. elseif ( 'table' == $pod[ 'storage' ] && $pod[ 'storage' ] == $old_storage && null !== $old_name && $old_name != $params->name && $db ) {
  1126. $result = pods_query( "ALTER TABLE `@wp_pods_{$old_name}` RENAME `@wp_pods_{$params->name}`", $this );
  1127. if ( empty( $result ) )
  1128. return pods_error( __( 'Cannot update Database Table for Pod', 'pods' ), $this );
  1129. }
  1130. /**
  1131. * @var $wpdb wpdb
  1132. */
  1133. global $wpdb;
  1134. if ( 'post_type' == $pod[ 'type' ] && empty( $pod[ 'object' ] ) && null !== $old_name && $old_name != $params->name && $db )
  1135. $this->rename_wp_object_type( 'post', $old_name, $params->name );
  1136. elseif ( 'taxonomy' == $pod[ 'type' ] && empty( $pod[ 'object' ] ) && null !== $old_name && $old_name != $params->name && $db )
  1137. $this->rename_wp_object_type( 'taxonomy', $old_name, $params->name );
  1138. elseif ( 'comment' == $pod[ 'type' ] && empty( $pod[ 'object' ] ) && null !== $old_name && $old_name != $params->name && $db )
  1139. $this->rename_wp_object_type( 'comment', $old_name, $params->name );
  1140. // Sync any related fields if the name has changed
  1141. if ( null !== $old_name && $old_name != $params->name && $db ) {
  1142. $fields = pods_query( "
  1143. SELECT `p`.`ID`
  1144. FROM `{$wpdb->posts}` AS `p`
  1145. LEFT JOIN `{$wpdb->postmeta}` AS `pm` ON `pm`.`post_id` = `p`.`ID`
  1146. LEFT JOIN `{$wpdb->postmeta}` AS `pm2` ON `pm2`.`post_id` = `p`.`ID`
  1147. WHERE
  1148. `p`.`post_type` = '_pods_field'
  1149. AND `pm`.`meta_key` = 'pick_object'
  1150. AND `pm`.`meta_value` = 'pod'
  1151. AND `pm2`.`meta_key` = 'pick_val'
  1152. AND `pm2`.`meta_value` = '{$old_name}'
  1153. " );
  1154. if ( !empty( $fields ) ) {
  1155. foreach ( $fields as $field ) {
  1156. update_post_meta( $field->ID, 'pick_val', $params->name );
  1157. }
  1158. }
  1159. $fields = pods_query( "
  1160. SELECT `p`.`ID`
  1161. FROM `{$wpdb->posts}` AS `p`
  1162. LEFT JOIN `{$wpdb->postmeta}` AS `pm` ON `pm`.`post_id` = `p`.`ID`
  1163. WHERE
  1164. `p`.`post_type` = '_pods_field'
  1165. AND `pm`.`meta_key` = 'pick_object'
  1166. AND `pm`.`meta_value` = 'pod-{$old_name}'
  1167. " );
  1168. if ( !empty( $fields ) ) {
  1169. foreach ( $fields as $field ) {
  1170. update_post_meta( $field->ID, 'pick_object', 'pod' );
  1171. update_post_meta( $field->ID, 'pick_val', $params->name );
  1172. }
  1173. }
  1174. }
  1175. // Sync built-in options for post types and taxonomies
  1176. if ( in_array( $pod[ 'type' ], array( 'post_type', 'taxonomy' ) ) && empty( $pod[ 'object' ] ) && $db ) {
  1177. // Build list of 'built_in' for later
  1178. $built_in = array();
  1179. foreach ( $pod[ 'options' ] as $key => $val ) {
  1180. if ( false === strpos( $key, 'built_in_' ) )
  1181. continue;
  1182. elseif ( false !== strpos( $key, 'built_in_post_types_' ) )
  1183. $built_in_type = 'post_type';
  1184. elseif ( false !== strpos( $key, 'built_in_taxonomies_' ) )
  1185. $built_in_type = 'taxonomy';
  1186. else
  1187. continue;
  1188. if ( $built_in_type == $pod[ 'type' ] )
  1189. continue;
  1190. if ( !isset( $built_in[ $built_in_type ] ) )
  1191. $built_in[ $built_in_type ] = array();
  1192. $built_in_object = str_replace( array( 'built_in_post_types_', 'built_in_taxonomies_' ), '', $key );
  1193. $built_in[ $built_in_type ][ $built_in_object ] = (int) $val;
  1194. }
  1195. $lookup_option = $lookup_built_in = false;
  1196. $lookup_name = $pod[ 'name' ];
  1197. if ( 'post_type' == $pod[ 'type' ] ) {
  1198. $lookup_option = 'built_in_post_types_' . $lookup_name;
  1199. $lookup_built_in = 'taxonomy';
  1200. }
  1201. elseif ( 'taxonomy' == $pod[ 'type' ] ) {
  1202. $lookup_option = 'built_in_taxonomies_' . $lookup_name;
  1203. $lookup_built_in = 'post_type';
  1204. }
  1205. if ( !empty( $lookup_option ) && !empty( $lookup_built_in ) && isset( $built_in[ $lookup_built_in ] ) ) {
  1206. foreach ( $built_in[ $lookup_built_in ] as $built_in_object => $val ) {
  1207. $search_val = 1;
  1208. if ( 1 == $val )
  1209. $search_val = 0;
  1210. $query = "SELECT p.ID FROM {$wpdb->posts} AS p
  1211. LEFT JOIN {$wpdb->postmeta} AS pm ON pm.post_id = p.ID AND pm.meta_key = '{$lookup_option}'
  1212. LEFT JOIN {$wpdb->postmeta} AS pm2 ON pm2.post_id = p.ID AND pm2.meta_key = 'type' AND pm2.meta_value = '{$lookup_built_in}'
  1213. LEFT JOIN {$wpdb->postmeta} AS pm3 ON pm3.post_id = p.ID AND pm3.meta_key = 'object' AND pm3.meta_value = ''
  1214. WHERE p.post_type = '_pods_pod' AND p.post_name = '{$built_in_object}'
  1215. AND pm2.meta_id IS NOT NULL
  1216. AND ( pm.meta_id IS NULL OR pm.meta_value = {$search_val} )";
  1217. $results = pods_query( $query );
  1218. if ( !empty( $results ) ) {
  1219. foreach ( $results as $the_pod ) {
  1220. delete_post_meta( $the_pod->ID, $lookup_option );
  1221. add_post_meta( $the_pod->ID, $lookup_option, $val );
  1222. }
  1223. }
  1224. }
  1225. }
  1226. }
  1227. $saved = array();
  1228. $errors = array();
  1229. $field_index_change = false;
  1230. $field_index_id = 0;
  1231. $id_required = false;
  1232. $field_index = pods_var( 'pod_index', $pod[ 'options' ], 'id', null, true );
  1233. if ( 'pod' == $pod[ 'type' ] && !empty( $pod[ 'fields' ] ) && isset( $pod[ 'fields' ][ $field_index ] ) )
  1234. $field_index_id = $pod[ 'fields' ][ $field_index ];
  1235. if ( isset( $params->fields ) || ( defined( 'DOING_AJAX' ) && DOING_AJAX ) ) {
  1236. $fields = array();
  1237. if ( isset( $params->fields ) ) {
  1238. $params->fields = (array) $params->fields;
  1239. $weight = 0;
  1240. foreach ( $params->fields as $field ) {
  1241. if ( !is_array( $field ) || !isset( $field[ 'name' ] ) )
  1242. continue;
  1243. if ( !isset( $field[ 'weight' ] ) ) {
  1244. $field[ 'weight' ] = $weight;
  1245. $weight++;
  1246. }
  1247. $fields[ $field[ 'name' ] ] = $field;
  1248. }
  1249. }
  1250. $weight = 0;
  1251. foreach ( $pod[ 'fields' ] as $k => $field ) {
  1252. if ( !empty( $old_id ) && ( !is_array( $field ) || !isset( $field[ 'name' ] ) || !isset( $fields[ $field[ 'name' ] ] ) ) )
  1253. continue;
  1254. if ( !empty( $old_id ) )
  1255. $field = array_merge( $field, $fields[ $field[ 'name' ] ] );
  1256. $field[ 'pod' ] = $pod;
  1257. if ( !isset( $field[ 'weight' ] ) ) {
  1258. $field[ 'weight' ] = $weight;
  1259. $weight++;
  1260. }
  1261. if ( 0 < $field_index_id && pods_var( 'id', $field ) == $field_index_id )
  1262. $field_index_change = $field[ 'name' ];
  1263. if ( 0 < pods_var( 'id', $field ) )
  1264. $id_required = true;
  1265. if ( $id_required )
  1266. $field[ 'id_required' ] = true;
  1267. $field = $this->save_field( $field, $field_table_operation, $sanitized, $db );
  1268. if ( true !== $db )
  1269. $pod[ 'fields' ][ $k ] = $field;
  1270. else {
  1271. if ( !empty( $field ) && 0 < $field )
  1272. $saved[ $field ] = true;
  1273. else
  1274. $errors[] = sprintf( __( 'Cannot save the %s field', 'pods' ), $field[ 'name' ] );
  1275. }
  1276. }
  1277. if ( true === $db ) {
  1278. foreach ( $old_fields as $field ) {
  1279. if ( !isset( $saved[ $field[ 'id' ] ] ) ) {
  1280. if ( $field[ 'id' ] == $field_index_id )
  1281. $field_index_change = 'id';
  1282. elseif ( $field[ 'name' ] == $field_index )
  1283. $field_index_change = 'id';
  1284. $this->delete_field( array(
  1285. 'id' => (int) $field[ 'id' ],
  1286. 'name' => $field[ 'name' ],
  1287. 'pod' => $pod
  1288. ), $field_table_operation );
  1289. }
  1290. }
  1291. }
  1292. // Update field index if the name has changed or the field has been removed
  1293. if ( false !== $field_index_change && true === $db )
  1294. update_post_meta( $pod[ 'id' ], 'pod_index', $field_index_change );
  1295. }
  1296. $this->cache_flush_pods( $pod );
  1297. // Register Post Types / Taxonomies post-registration from PodsInit
  1298. if ( !empty( PodsInit::$content_types_registered ) && in_array( $pod[ 'type' ], array( 'post_type', 'taxonomy' ) ) && empty( $pod[ 'object' ] ) ) {
  1299. global $pods_init;
  1300. $post_types = $taxonomies = array();
  1301. if ( 'post_type' == $pod[ 'type' ] ) {
  1302. $load_pod = $this->load_pod( array( 'name' => $pod[ 'name' ] ), false );
  1303. if ( !empty( $load_pod ) )
  1304. $post_types[] = $load_pod;
  1305. }
  1306. elseif ( 'taxonomy' == $pod[ 'type' ] ) {
  1307. $load_pod = $this->load_pod( array( 'name' => $pod[ 'name' ] ), false );
  1308. if ( !empty( $load_pod ) )
  1309. $taxonomies[] = $load_pod;
  1310. }
  1311. $pods_init->setup_content_types( $post_types, $taxonomies );
  1312. }
  1313. if ( 'post_type' == $pod[ 'type' ] )
  1314. PodsMeta::$post_types[ $pod[ 'id' ] ] = $this->load_pod( array( 'name' => $pod[ 'name' ] ) );
  1315. elseif ( 'taxonomy' == $pod[ 'type' ] )
  1316. PodsMeta::$taxonomies[ $pod[ 'id' ] ] = $this->load_pod( array( 'name' => $pod[ 'name' ] ) );
  1317. elseif ( 'media' == $pod[ 'type' ] )
  1318. PodsMeta::$media[ $pod[ 'id' ] ] = $this->load_pod( array( 'name' => $pod[ 'name' ] ) );
  1319. elseif ( 'user' == $pod[ 'type' ] )
  1320. PodsMeta::$user[ $pod[ 'id' ] ] = $this->load_pod( array( 'name' => $pod[ 'name' ] ) );
  1321. elseif ( 'comment' == $pod[ 'type' ] )
  1322. PodsMeta::$comment[ $pod[ 'id' ] ] = $this->load_pod( array( 'name' => $pod[ 'name' ] ) );
  1323. if ( !empty( $errors ) )
  1324. return pods_error( $errors, $this );
  1325. if ( true === $db )
  1326. return $params->id;
  1327. else
  1328. return $pod;
  1329. }
  1330. /**
  1331. * Add or edit a field within a Pod
  1332. *
  1333. * $params['id'] int The field ID
  1334. * $params['pod_id'] int The Pod ID
  1335. * $params['pod'] string The Pod name
  1336. * $params['name'] string The field name
  1337. * $params['label'] string The field label
  1338. * $params['type'] string The field type ("txt", "desc", "pick", etc)
  1339. * $params['pick_object'] string The related PICK object name
  1340. * $params['pick_val'] string The related PICK object value
  1341. * $params['sister_id'] int (optional) The related field ID
  1342. * $params['weight'] int The field weight
  1343. * $params['options'] array The field options
  1344. *
  1345. * @param array $params An associative array of parameters
  1346. * @param bool $table_operation (optional) Whether or not to handle table operations
  1347. * @param bool $sanitized (optional) Decides wether the params have been sanitized before being passed, will sanitize them if false.
  1348. * @param bool|int $db (optional) Whether to save into the DB or just return field array.
  1349. *
  1350. * @return int The field ID
  1351. * @since 1.7.9
  1352. */
  1353. public function save_field ( $params, $table_operation = true, $sanitized = false, $db = true ) {
  1354. /**
  1355. * @var $wpdb wpdb
  1356. */
  1357. global $wpdb;
  1358. if ( true !== $db )
  1359. $table_operation = false;
  1360. $tableless_field_types = apply_filters( 'pods_tableless_field_types', array( 'pick', 'file', 'avatar', 'taxonomy' ) );
  1361. $simple_tableless_objects = PodsForm::field_method( 'pick', 'simple_objects' );
  1362. $params = (object) $params;
  1363. if ( false === $sanitized )
  1364. $params = pods_sanitize( $params );
  1365. if ( isset( $params->pod_id ) )
  1366. $params->pod_id = pods_absint( $params->pod_id );
  1367. if ( true !== $db )
  1368. $params->pod_id = (int) $db;
  1369. $pod = null;
  1370. $save_pod = false;
  1371. $id_required = false;
  1372. if ( isset( $params->id_required ) ) {
  1373. unset( $params->id_required );
  1374. $id_required = true;
  1375. }
  1376. if ( ( !isset( $params->pod ) || empty( $params->pod ) ) && ( !isset( $params->pod_id ) || empty( $params->pod_id ) ) )
  1377. return pods_error( __( 'Pod ID or name is required', 'pods' ), $this );
  1378. if ( isset( $params->pod ) && is_array( $params->pod ) ) {
  1379. $pod = $params->pod;
  1380. $save_pod = true;
  1381. }
  1382. elseif ( ( !isset( $params->pod_id ) || empty( $params->pod_id ) ) && ( true === $db || 0 < $db ) )
  1383. $pod = $this->load_pod( array( 'name' => $params->pod ) );
  1384. elseif ( !isset( $params->pod ) && ( true === $db || 0 < $db ) )
  1385. $pod = $this->load_pod( array( 'id' => $params->pod_id ) );
  1386. elseif ( true === $db || 0 < $db )
  1387. $pod = $this->load_pod( array( 'id' => $params->pod_id, 'name' => $params->pod ) );
  1388. if ( empty( $pod ) && true === $db )
  1389. return pods_error( __( 'Pod not found', 'pods' ), $this );
  1390. $params->pod_id = $pod[ 'id' ];
  1391. $params->pod = $pod[ 'name' ];
  1392. $params->pod_data = $pod;
  1393. $params->name = pods_clean_name( $params->name, true, ( 'meta' == $pod[ 'storage' ] ? false : true ) );
  1394. if ( !isset( $params->id ) )
  1395. $params->id = 0;
  1396. if ( empty( $params->name ) )
  1397. return pods_error( 'Pod field name is required', $this );
  1398. $field = $this->load_field( $params );
  1399. unset( $params->pod_data );
  1400. $old_id = $old_name = $old_type = $old_definition = $old_simple = $old_options = $old_sister_id = null;
  1401. if ( !empty( $field ) ) {
  1402. $old_id = pods_var( 'id', $field );
  1403. $old_name = pods_clean_name( $field[ 'name' ], true, ( 'meta' == $pod[ 'storage' ] ? false : true ) );
  1404. $old_type = $field[ 'type' ];
  1405. $old_options = $field[ 'options' ];
  1406. $old_sister_id = (int) pods_var( 'sister_id', $old_options, 0 );
  1407. $old_simple = ( 'pick' == $old_type && in_array( pods_var( 'pick_object', $field ), $simple_tableless_objects ) );
  1408. $old_simple = (boolean) $this->do_hook( 'tableless_custom', $old_simple, $field, $pod, $params );
  1409. if ( isset( $params->name ) && !empty( $params->name ) )
  1410. $field[ 'name' ] = $params->name;
  1411. if ( $old_name != $field[ 'name' ] && false !== $this->field_exists( $params ) )
  1412. return pods_error( sprintf( __( 'Field %s already exists, you cannot rename %s to that', 'pods' ), $field[ 'name' ], $old_name ), $this );
  1413. if ( ( $id_required || !empty( $params->id ) ) && ( empty( $old_id ) || $old_id != $params->id ) )
  1414. return pods_error( sprintf( __( 'Field %s already exists', 'pods' ), $field[ 'name' ] ), $this );
  1415. if ( empty( $params->id ) )
  1416. $params->id = $old_id;
  1417. if ( !in_array( $old_type, $tableless_field_types ) || $old_simple )
  1418. $old_definition = '`' . $old_name . '` ' . $this->get_field_definition( $old_type, $old_options );
  1419. }
  1420. else {
  1421. $field = array(
  1422. 'id' => 0,
  1423. 'pod_id' => $params->pod_id,
  1424. 'name' => $params->name,
  1425. 'label' => $params->name,
  1426. 'description' => '',
  1427. 'type' => 'text',
  1428. 'pick_object' => '',
  1429. 'pick_val' => '',
  1430. 'sister_id' => '',
  1431. 'weight' => null,
  1432. 'options' => array()
  1433. );
  1434. }
  1435. // Setup options
  1436. $options = get_object_vars( $params );
  1437. if ( isset( $options[ 'method' ] ) )
  1438. unset( $options[ 'method' ] );
  1439. $exclude = array(
  1440. 'id',
  1441. 'pod_id',
  1442. 'pod',
  1443. 'name',
  1444. 'label',
  1445. 'description',
  1446. 'type',
  1447. 'pick_object',
  1448. 'pick_val',
  1449. 'sister_id',
  1450. 'weight',
  1451. 'options'
  1452. );
  1453. foreach ( $exclude as $k => $exclude_field ) {
  1454. $aliases = array( $exclude_field );
  1455. if ( is_array( $exclude_field ) ) {
  1456. $aliases = array_merge( array( $k ), $exclude_field );
  1457. $exclude_field = $k;
  1458. }
  1459. foreach ( $aliases as $alias ) {
  1460. if ( isset( $options[ $alias ] ) ) {
  1461. $field[ $exclude_field ] = pods_trim( $options[ $alias ] );
  1462. unset( $options[ $alias ] );
  1463. }
  1464. }
  1465. }
  1466. if ( strlen( $field[ 'label' ] ) < 1 )
  1467. $field[ 'label' ] = $field[ 'name' ];
  1468. $field[ 'options' ][ 'type' ] = $field[ 'type' ];
  1469. if ( in_array( $field[ 'options' ][ 'type' ], $tableless_field_types ) ) {
  1470. // Clean up special drop-down in field editor and save out pick_val
  1471. $field[ 'pick_object' ] = pods_var( 'pick_object', $field, '', null, true );
  1472. if ( 0 === strpos( $field[ 'pick_object' ], 'pod-' ) ) {
  1473. $field[ 'pick_val' ] = pods_str_replace( 'pod-', '', $field[ 'pick_object' ], 1 );
  1474. $field[ 'pick_object' ] = 'pod';
  1475. }
  1476. elseif ( 0 === strpos( $field[ 'pick_object' ], 'post_type-' ) ) {
  1477. $field[ 'pick_val' ] = pods_str_replace( 'post_type-', '', $field[ 'pick_object' ], 1 );
  1478. $field[ 'pick_object' ] = 'post_type';
  1479. }
  1480. elseif ( 0 === strpos( $field[ 'pick_object' ], 'taxonomy-' ) ) {
  1481. $field[ 'pick_val' ] = pods_str_replace( 'taxonomy-', '', $field[ 'pick_object' ], 1 );
  1482. $field[ 'pick_object' ] = 'taxonomy';
  1483. }
  1484. elseif ( 'table' == $field[ 'pick_object' ] && 0 < strlen( pods_var_raw( 'pick_table', $field[ 'options' ] ) ) ) {
  1485. $field[ 'pick_val' ] = $field[ 'options' ][ 'pick_table' ];
  1486. $field[ 'pick_object' ] = 'table';
  1487. }
  1488. elseif ( false === strpos( $field[ 'pick_object' ], '-' ) && !in_array( $field[ 'pick_object' ], array( 'pod', 'post_type', 'taxonomy' ) ) )
  1489. $field[ 'pick_val' ] = '';
  1490. $field[ 'options' ][ 'pick_object' ] = $field[ 'pick_object' ];
  1491. $field[ 'options' ][ 'pick_val' ] = $field[ 'pick_val' ];
  1492. $field[ 'options' ][ 'sister_id' ] = pods_var( 'sister_id', $field );
  1493. unset( $field[ 'pick_object' ] );
  1494. unset( $field[ 'pick_val' ] );
  1495. if ( isset( $field[ 'sister_id' ] ) )
  1496. unset( $field[ 'sister_id' ] );
  1497. }
  1498. $field[ 'options' ] = array_merge( $field[ 'options' ], $options );
  1499. $object_fields = (array) pods_var_raw( 'object_fields', $pod, array(), null, true );
  1500. if ( 0 < $old_id && defined( 'PODS_FIELD_STRICT' ) && !PODS_FIELD_STRICT )
  1501. $params->id = $field[ 'id' ] = $old_id;
  1502. // Add new field
  1503. if ( !isset( $params->id ) || empty( $params->id ) || empty( $field ) ) {
  1504. if ( $table_operation && in_array( $field[ 'name' ], array( 'created', 'modified' ) ) && !in_array( $field[ 'type' ], array( 'date', 'datetime' ) ) && ( !defined( 'PODS_FIELD_STRICT' ) || PODS_FIELD_STRICT ) )
  1505. return pods_error( sprintf( __( '%s is reserved for internal Pods usage, please try a different name', 'pods' ), $field[ 'name' ] ), $this );
  1506. if ( $table_operation && 'author' == $field[ 'name' ] && 'pick' == $field[ 'type' ] && ( !defined( 'PODS_FIELD_STRICT' ) || PODS_FIELD_STRICT ) )
  1507. return pods_error( sprintf( __( '%s is reserved for internal Pods usage, please try a different name', 'pods' ), $field[ 'name' ] ), $this );
  1508. if ( in_array( $field[ 'name' ], array( 'id', 'ID' ) ) )
  1509. return pods_error( sprintf( __( '%s is reserved for internal Pods usage, please try a different name', 'pods' ), $field[ 'name' ] ), $this );
  1510. foreach ( $object_fields as $object_field => $object_field_opt ) {
  1511. if ( $object_field == $field[ 'name' ] || in_array( $field[ 'name' ], $object_field_opt[ 'alias' ] ) )
  1512. return pods_error( sprintf( __( '%s is reserved for internal WordPress or Pods usage, please try a different name. Also consider what WordPress and Pods provide you built-in.', 'pods' ), $field[ 'name' ] ), $this );
  1513. }
  1514. if ( in_array( $field[ 'name' ], array( 'rss' ) ) ) // Reserved post_name values that can't be used as field names
  1515. $field[ 'name' ] .= '2';
  1516. if ( 'slug' == $field[ 'type' ] && true === $db ) {
  1517. if ( in_array( $pod[ 'type' ], array( 'post_type', 'taxonomy', 'user' ) ) )
  1518. return pods_error( __( 'This pod already has an internal WordPress permalink field', 'pods' ), $this );
  1519. $slug_field = get_posts( array(
  1520. 'post_type' => '_pods_field',
  1521. 'orderby' => 'menu_order',
  1522. 'order' => 'ASC',
  1523. 'posts_per_page' => 1,
  1524. 'post_parent' => $field[ 'pod_id' ],
  1525. 'meta_query' => array(
  1526. array(
  1527. 'key' => 'type',
  1528. 'value' => 'slug'
  1529. )
  1530. )
  1531. ) );
  1532. if ( !empty( $slug_field ) )
  1533. return pods_error( __( 'This pod already has a permalink field', 'pods' ), $this );
  1534. }
  1535. // Sink the new field to the bottom of the list
  1536. if ( null === $field[ 'weight' ] ) {
  1537. $field[ 'weight' ] = 0;
  1538. $bottom_most_field = get_posts( array(
  1539. 'post_type' => '_pods_field',
  1540. 'orderby' => 'menu_order',
  1541. 'order' => 'DESC',
  1542. 'posts_per_page' => 1,
  1543. 'post_parent' => $field[ 'pod_id' ]
  1544. ) );
  1545. if ( !empty( $bottom_most_field ) )
  1546. $field[ 'weight' ] = pods_absint( $bottom_most_field[ 0 ]->menu_order ) + 1;
  1547. }
  1548. $field[ 'weight' ] = pods_absint( $field[ 'weight' ] );
  1549. $post_data = array(
  1550. 'post_name' => $field[ 'name' ],
  1551. 'post_title' => $field[ 'label' ],
  1552. 'post_content' => $field[ 'description' ],
  1553. 'post_type' => '_pods_field',
  1554. 'post_parent' => $field[ 'pod_id' ],
  1555. 'post_status' => 'publish',
  1556. 'menu_order' => $field[ 'weight' ]
  1557. );
  1558. }
  1559. else {
  1560. if ( in_array( $field[ 'name' ], array( 'id', 'ID' ) ) )
  1561. return pods_error( sprintf( __( '%s is not editable', 'pods' ), $field[ 'name' ] ), $this );
  1562. foreach ( $object_fields as $object_field => $object_field_opt ) {
  1563. if ( $object_field == $field[ 'name' ] || in_array( $field[ 'name' ], $object_field_opt[ 'alias' ] ) )
  1564. return pods_error( sprintf( __( '%s is not editable', 'pods' ), $field[ 'name' ] ), $this );
  1565. }
  1566. if ( null !== $old_name && $field[ 'name' ] != $old_name && in_array( $field[ 'name' ], array( 'id', 'ID' ) ) )
  1567. return pods_error( sprintf( __( '%s is reserved for internal Pods usage, please try a different name', 'pods' ), $field[ 'name' ] ), $this );
  1568. if ( null !== $old_name && $field[ 'name' ] != $old_name && in_array( $field[ 'name' ], array( 'created', 'modified' ) ) && !in_array( $field[ 'type' ], array( 'date', 'datetime' ) ) && ( !defined( 'PODS_FIELD_STRICT' ) || PODS_FIELD_STRICT ) )
  1569. return pods_error( sprintf( __( '%s is reserved for internal Pods usage, please try a different name', 'pods' ), $field[ 'name' ] ), $this );
  1570. if ( null !== $old_name && $field[ 'name' ] != $old_name && 'author' == $field[ 'name' ] && 'pick' != $field[ 'type' ] && ( !defined( 'PODS_FIELD_STRICT' ) || PODS_FIELD_STRICT ) )
  1571. return pods_error( sprintf( __( '%s is reserved for internal Pods usage, please try a different name', 'pods' ), $field[ 'name' ] ), $this );
  1572. foreach ( $object_fields as $object_field => $object_field_opt ) {
  1573. if ( $object_field == $field[ 'name' ] || in_array( $field[ 'name' ], $object_field_opt[ 'alias' ] ) )
  1574. return pods_error( sprintf( __( '%s is reserved for internal WordPress or Pods usage, please try a different name', 'pods' ), $field[ 'name' ] ), $this );
  1575. }
  1576. $post_data = array(
  1577. 'ID' => $field[ 'id' ],
  1578. 'post_name' => $field[ 'name' ],
  1579. 'post_title' => $field[ 'label' ],
  1580. 'post_content' => $field[ 'description' ]
  1581. );
  1582. if ( null !== $field[ 'weight' ] ) {
  1583. $field[ 'weight' ] = pods_absint( $field[ 'weight' ] );
  1584. $post_data[ 'menu_order' ] = $field[ 'weight' ];
  1585. }
  1586. }
  1587. if ( true === $db ) {
  1588. if ( !has_filter( 'wp_unique_post_slug', array( $this, 'save_field_slug_fix' ) ) )
  1589. add_filter( 'wp_unique_post_slug', array( $this, 'save_field_slug_fix' ), 100, 6 );
  1590. $params->id = $this->save_wp_object( 'post', $post_data, $field[ 'options' ], true, true );
  1591. if ( false === $params->id )
  1592. return pods_error( __( 'Cannot save Field', 'pods' ), $this );
  1593. }
  1594. else
  1595. $params->id = $field[ 'name' ];
  1596. $field[ 'id' ] = $params->id;
  1597. $definition = false;
  1598. $simple = ( 'pick' == $field[ 'type' ] && in_array( pods_var( 'pick_object', $field[ 'options' ] ), $simple_tableless_objects ) );
  1599. $simple = (boolean) $this->do_hook( 'tableless_custom', $simple, $field, $pod, $params );
  1600. if ( !in_array( $field[ 'type' ], $tableless_field_types ) || $simple )
  1601. $definition = $this->get_field_definition( $field[ 'type' ], $field[ 'options' ] );
  1602. if ( 0 < strlen( $definition ) )
  1603. $definition = '`' . $field[ 'name' ] . '` ' . $definition;
  1604. $sister_id = (int) pods_var( 'sister_id', $field[ 'options' ], 0 );
  1605. if ( $table_operation && 'table' == $pod[ 'storage' ] ) {
  1606. if ( !empty( $old_id ) ) {
  1607. if ( $field[ 'type' ] != $old_type ) {
  1608. if ( in_array( $field[ 'type' ], $tableless_field_types ) && !$simple && ( !in_array( $old_type, $tableless_field_types ) || $old_simple ) )
  1609. pods_query( "ALTER TABLE `@wp_pods_{$params->pod}` DROP COLUMN `{$old_name}`", false );
  1610. elseif ( 0 < strlen( $definition ) ) {
  1611. if ( in_array( $old_type, $tableless_field_types ) && ( $simple || !$old_simple ) )
  1612. pods_query( "ALTER TABLE `@wp_pods_{$params->pod}` ADD COLUMN {$definition}", __( 'Cannot create new field', 'pods' ) );
  1613. else
  1614. pods_query( "ALTER TABLE `@wp_pods_{$params->pod}` CHANGE `{$old_name}` {$definition}" );
  1615. }
  1616. }
  1617. elseif ( 0 < strlen( $definition ) ) {
  1618. if ( $old_name != $field[ 'name' ] ) {
  1619. $test = pods_query( "ALTER TABLE `@wp_pods_{$params->pod}` CHANGE `{$old_name}` {$definition}", false );
  1620. // If the old field doesn't exist, continue to add a new field
  1621. if ( false === $test )
  1622. pods_query( "ALTER TABLE `@wp_pods_{$params->pod}` ADD COLUMN {$definition}", __( 'Cannot create new field', 'pods' ) );
  1623. }
  1624. elseif ( null !== $old_definition && $definition != $old_definition ) {
  1625. $test = pods_query( "ALTER TABLE `@wp_pods_{$params->pod}` CHANGE `" . $field[ 'name' ] . "` {$definition}", false );
  1626. // If the old field doesn't exist, continue to add a new field
  1627. if ( false === $test )
  1628. pods_query( "ALTER TABLE `@wp_pods_{$params->pod}` ADD COLUMN {$definition}", __( 'Cannot create new field', 'pods' ) );
  1629. }
  1630. }
  1631. }
  1632. elseif ( 0 < strlen( $definition ) )
  1633. $test = pods_query( "ALTER TABLE `@wp_pods_{$params->pod}` ADD COLUMN {$definition}", __( 'Cannot create new field', 'pods' ) );
  1634. }
  1635. if ( $field[ 'type' ] != $old_type && in_array( $old_type, $tableless_field_types ) ) {
  1636. delete_post_meta( $old_sister_id, 'sister_id' );
  1637. if ( true === $db ) {
  1638. pods_query( "
  1639. DELETE pm
  1640. FROM {$wpdb->postmeta} AS pm
  1641. LEFT JOIN {$wpdb->posts} AS p
  1642. ON p.post_type = '_pods_field'
  1643. AND p.ID = pm.post_id
  1644. WHERE
  1645. p.ID IS NOT NULL
  1646. AND pm.meta_key = 'sister_id'
  1647. AND pm.meta_value = %d
  1648. ", array(
  1649. $params->id
  1650. )
  1651. );
  1652. if ( !defined( 'PODS_TABLELESS' ) || !PODS_TABLELESS ) {
  1653. pods_query( "DELETE FROM @wp_podsrel WHERE `field_id` = {$params->id}", false );
  1654. pods_query( "
  1655. UPDATE `@wp_podsrel`
  1656. SET `related_field_id` = 0
  1657. WHERE `field_id` = %d
  1658. ", array(
  1659. $old_sister_id
  1660. )
  1661. );
  1662. }
  1663. }
  1664. }
  1665. elseif ( 0 < $sister_id ) {
  1666. update_post_meta( $sister_id, 'sister_id', $params->id );
  1667. if ( true === $db && ( !defined( 'PODS_TABLELESS' ) || !PODS_TABLELESS ) ) {
  1668. pods_query( "
  1669. UPDATE `@wp_podsrel`
  1670. SET `related_field_id` = %d
  1671. WHERE `field_id` = %d
  1672. ",
  1673. array(
  1674. $params->id,
  1675. $sister_id
  1676. )
  1677. );
  1678. }
  1679. }
  1680. elseif ( 0 < $old_sister_id ) {
  1681. delete_post_meta( $old_sister_id, 'sister_id' );
  1682. if ( true === $db && ( !defined( 'PODS_TABLELESS' ) || !PODS_TABLELESS ) ) {
  1683. pods_query( "
  1684. UPDATE `@wp_podsrel`
  1685. SET `related_field_id` = 0
  1686. WHERE `field_id` = %d
  1687. ", array(
  1688. $old_sister_id
  1689. )
  1690. );
  1691. }
  1692. }
  1693. if ( !empty( $old_id ) && $old_name != $field[ 'name' ] && true === $db ) {
  1694. pods_query( "
  1695. UPDATE `@wp_postmeta`
  1696. SET `meta_value` = %s
  1697. WHERE
  1698. `post_id` = %d
  1699. AND `meta_key` = 'pod_index'
  1700. AND `meta_value` = %s
  1701. ", array(
  1702. $field[' name' ],
  1703. $pod[ 'id' ],
  1704. $old_name
  1705. )
  1706. );
  1707. }
  1708. if ( !$save_pod )
  1709. $this->cache_flush_pods( $pod );
  1710. if ( true === $db )
  1711. return $params->id;
  1712. else
  1713. return $field;
  1714. }
  1715. public function save_field_slug_fix ( $slug, $post_ID, $post_status, $post_type, $post_parent = 0, $original_slug = null ) {
  1716. if ( in_array( $post_type, array( '_pods_field', '_pods_pod' ) ) && false !== strpos( $slug, '-' ) ) {
  1717. $slug = explode( '-', $slug );
  1718. $slug = $slug[ 0 ];
  1719. }
  1720. return $slug;
  1721. }
  1722. /**
  1723. * Add or Edit a Pods Object
  1724. *
  1725. * $params['id'] int The Object ID
  1726. * $params['name'] string The Object name
  1727. * $params['type'] string The Object type
  1728. * $params['options'] Associative array of Object options
  1729. *
  1730. * @param array|object $params An associative array of parameters
  1731. * @param bool $sanitized (optional) Decides whether the params have been sanitized before being passed, will sanitize them if false.
  1732. *
  1733. * @return int The Object ID
  1734. * @since 2.0.0
  1735. */
  1736. public function save_object ( $params, $sanitized = false ) {
  1737. $params = (object) $params;
  1738. if ( false === $sanitized )
  1739. $params = pods_sanitize( $params );
  1740. if ( !isset( $params->name ) || empty( $params->name ) )
  1741. return pods_error( __( 'Name must be given to save an Object', 'pods' ), $this );
  1742. if ( !isset( $params->type ) || empty( $params->type ) )
  1743. return pods_error( __( 'Type must be given to save an Object', 'pods' ), $this );
  1744. $object = array(
  1745. 'id' => 0,
  1746. 'name' => $params->name,
  1747. 'type' => $params->type,
  1748. 'code' => '',
  1749. 'options' => array()
  1750. );
  1751. // Setup options
  1752. $options = get_object_vars( $params );
  1753. if ( isset( $options[ 'method' ] ) )
  1754. unset( $options[ 'method' ] );
  1755. $exclude = array(
  1756. 'id',
  1757. 'name',
  1758. 'helper_type',
  1759. 'code',
  1760. 'options',
  1761. 'status'
  1762. );
  1763. foreach ( $exclude as $k => $exclude_field ) {
  1764. $aliases = array( $exclude_field );
  1765. if ( is_array( $exclude_field ) ) {
  1766. $aliases = array_merge( array( $k ), $exclude_field );
  1767. $exclude_field = $k;
  1768. }
  1769. foreach ( $aliases as $alias ) {
  1770. if ( isset( $options[ $alias ] ) ) {
  1771. $object[ $exclude_field ] = pods_trim( $options[ $alias ] );
  1772. unset( $options[ $alias ] );
  1773. }
  1774. }
  1775. }
  1776. if ( 'helper' == $object[ 'type' ] )
  1777. $object[ 'options' ][ 'helper_type' ] = $object[ 'helper_type' ];
  1778. if ( isset( $object[ 'options' ][ 'code' ] ) )
  1779. unset( $object[ 'options' ][ 'code' ] );
  1780. $object[ 'options' ] = array_merge( $object[ 'options' ], $options );
  1781. $post_data = array(
  1782. 'post_name' => pods_clean_name( $object[ 'name' ], true),
  1783. 'post_title' => $object[ 'name' ],
  1784. 'post_content' => $object[ 'code' ],
  1785. 'post_type' => '_pods_' . $object[ 'type' ],
  1786. 'post_status' => 'publish'
  1787. );
  1788. if ( !empty( $object[ 'id' ] ) )
  1789. $post_data[ 'ID' ] = $object[ 'id' ];
  1790. if ( null !== pods_var( 'status', $object, null, null, true ) )
  1791. $post_data[ 'post_status' ] = pods_var( 'status', $object, null, null, true );
  1792. remove_filter( 'content_save_pre', 'balanceTags', 50 );
  1793. $post_data = pods_sanitize( $post_data );
  1794. $params->id = $this->save_post( $post_data, $object[ 'options' ], true, true );
  1795. pods_transient_clear( 'pods_object_' . $params->type );
  1796. pods_transient_clear( 'pods_object_' . $params->type . '_' . pods_clean_name( $params->name, true ) );
  1797. return $params->id;
  1798. }
  1799. /**
  1800. * @see PodsAPI::save_object
  1801. *
  1802. * Add or edit a Pod Template
  1803. *
  1804. * $params['id'] int The template ID
  1805. * $params['name'] string The template name
  1806. * $params['code'] string The template code
  1807. *
  1808. * @param array|object $params An associative array of parameters
  1809. * @param bool $sanitized (optional) Decides wether the params have been sanitized before being passed, will sanitize them if false.
  1810. *
  1811. * @return int The Template ID
  1812. *
  1813. * @since 1.7.9
  1814. */
  1815. public function save_template ( $params, $sanitized = false ) {
  1816. $params = (object) $params;
  1817. $params->type = 'template';
  1818. return $this->save_object( $params, $sanitized );
  1819. }
  1820. /**
  1821. * @see PodsAPI::save_object
  1822. *
  1823. * Add or edit a Pod Page
  1824. *
  1825. * $params['id'] int The page ID
  1826. * $params['name'] string The page URI
  1827. * $params['code'] string The page code
  1828. *
  1829. * @param array|object $params An associative array of parameters
  1830. * @param bool $sanitized (optional) Decides wether the params have been sanitized before being passed, will sanitize them if false.
  1831. *
  1832. * @return int The page ID
  1833. * @since 1.7.9
  1834. */
  1835. public function save_page ( $params, $sanitized = false ) {
  1836. $params = (object) $params;
  1837. if ( !isset( $params->name ) ) {
  1838. $params->name = $params->uri;
  1839. unset( $params->uri );
  1840. }
  1841. if ( isset( $params->phpcode ) ) {
  1842. $params->code = $params->phpcode;
  1843. unset( $params->phpcode );
  1844. }
  1845. $params->name = trim( $params->name, '/' );
  1846. $params->type = 'page';
  1847. return $this->save_object( $params, $sanitized );
  1848. }
  1849. /**
  1850. * @see PodsAPI::save_object
  1851. *
  1852. * Add or edit a Pod Helper
  1853. *
  1854. * $params['id'] int The helper ID
  1855. * $params['name'] string The helper name
  1856. * $params['helper_type'] string The helper type ("pre_save", "display", etc)
  1857. * $params['code'] string The helper code
  1858. *
  1859. * @param array $params An associative array of parameters
  1860. * @param bool $sanitized (optional) Decides wether the params have been sanitized before being passed, will sanitize them if false.
  1861. *
  1862. * @return int The helper ID
  1863. * @since 1.7.9
  1864. */
  1865. public function save_helper ( $params, $sanitized = false ) {
  1866. $params = (object) $params;
  1867. if ( isset( $params->phpcode ) ) {
  1868. $params->code = $params->phpcode;
  1869. unset( $params->phpcode );
  1870. }
  1871. if ( isset( $params->type ) ) {
  1872. $params->helper_type = $params->type;
  1873. unset( $params->type );
  1874. }
  1875. $params->type = 'helper';
  1876. return $this->save_object( $params, $sanitized );
  1877. }
  1878. /**
  1879. * Add or edit a single pod item
  1880. *
  1881. * $params['pod'] string The Pod name (pod or pod_id is required)
  1882. * $params['pod_id'] string The Pod ID (pod or pod_id is required)
  1883. * $params['id'] int The item ID
  1884. * $params['data'] array (optional) Associative array of field names + values
  1885. * $params['bypass_helpers'] bool Set to true to bypass running pre-save and post-save helpers
  1886. *
  1887. * @param array|object $params An associative array of parameters
  1888. *
  1889. * @return int The item ID
  1890. *
  1891. * @since 1.7.9
  1892. */
  1893. public function save_pod_item ( $params ) {
  1894. $params = (object) pods_str_replace( '@wp_', '{prefix}', $params );
  1895. $tableless_field_types = apply_filters( 'pods_tableless_field_types', array( 'pick', 'file', 'avatar', 'taxonomy' ) );
  1896. $simple_tableless_objects = PodsForm::field_method( 'pick', 'simple_objects' );
  1897. // @deprecated 2.0.0
  1898. if ( isset( $params->datatype ) ) {
  1899. pods_deprecated( '$params->pod instead of $params->datatype', '2.0.0' );
  1900. $params->pod = $params->datatype;
  1901. unset( $params->datatype );
  1902. if ( isset( $params->pod_id ) ) {
  1903. pods_deprecated( '$params->id instead of $params->pod_id', '2.0.0' );
  1904. $params->id = $params->pod_id;
  1905. unset( $params->pod_id );
  1906. }
  1907. if ( isset( $params->data ) && !empty( $params->data ) && is_array( $params->data ) ) {
  1908. $check = current( $params->data );
  1909. if ( is_array( $check ) ) {
  1910. pods_deprecated( 'PodsAPI::save_pod_items', '2.0.0' );
  1911. return $this->save_pod_items( $params, $params->data );
  1912. }
  1913. }
  1914. }
  1915. // @deprecated 2.0.0
  1916. if ( isset( $params->tbl_row_id ) ) {
  1917. pods_deprecated( '$params->id instead of $params->tbl_row_id', '2.0.0' );
  1918. $params->id = $params->tbl_row_id;
  1919. unset( $params->tbl_row_id );
  1920. }
  1921. // @deprecated 2.0.0
  1922. if ( isset( $params->columns ) ) {
  1923. pods_deprecated( '$params->data instead of $params->columns', '2.0.0' );
  1924. $params->data = $params->columns;
  1925. unset( $params->columns );
  1926. }
  1927. if ( !isset( $params->pod ) )
  1928. $params->pod = false;
  1929. if ( isset( $params->pod_id ) )
  1930. $params->pod_id = pods_absint( $params->pod_id );
  1931. else
  1932. $params->pod_id = 0;
  1933. if ( isset( $params->id ) )
  1934. $params->id = pods_absint( $params->id );
  1935. else
  1936. $params->id = 0;
  1937. if ( !isset( $params->from ) )
  1938. $params->from = 'save';
  1939. // Support for bulk edit
  1940. if ( isset( $params->id ) && !empty( $params->id ) && is_array( $params->id ) ) {
  1941. $ids = array();
  1942. $new_params = $params;
  1943. foreach ( $params->id as $id ) {
  1944. $new_params->id = $id;
  1945. $ids[] = $this->save_pod_item( $new_params );
  1946. }
  1947. return $ids;
  1948. }
  1949. // Allow Helpers to know what's going on, are we adding or saving?
  1950. $is_new_item = false;
  1951. if ( empty( $params->id ) )
  1952. $is_new_item = true;
  1953. // Allow Helpers to bypass subsequent helpers in recursive save_pod_item calls
  1954. $bypass_helpers = false;
  1955. if ( isset( $params->bypass_helpers ) && false !== $params->bypass_helpers )
  1956. $bypass_helpers = true;
  1957. // Allow Custom Fields not defined by Pods to be saved
  1958. $allow_custom_fields = false;
  1959. if ( isset( $params->allow_custom_fields ) && false !== $params->allow_custom_fields )
  1960. $allow_custom_fields = true;
  1961. // Get array of Pods
  1962. $pod = $this->load_pod( array( 'id' => $params->pod_id, 'name' => $params->pod ) );
  1963. if ( false === $pod )
  1964. return pods_error( __( 'Pod not found', 'pods' ), $this );
  1965. $params->pod = $pod[ 'name' ];
  1966. $params->pod_id = $pod[ 'id' ];
  1967. $fields = $pod[ 'fields' ];
  1968. $object_fields = (array) pods_var_raw( 'object_fields', $pod, array(), null, true );
  1969. $fields_active = array();
  1970. $custom_data = array();
  1971. // Find the active fields (loop through $params->data to retain order)
  1972. if ( !empty( $params->data ) && is_array( $params->data ) ) {
  1973. $custom_fields = array();
  1974. foreach ( $params->data as $field => $value ) {
  1975. if ( isset( $object_fields[ $field ] ) ) {
  1976. $object_fields[ $field ][ 'value' ] = $value;
  1977. $fields_active[] = $field;
  1978. }
  1979. elseif ( isset( $fields[ $field ] ) ) {
  1980. if ( 'save' == $params->from || true === PodsForm::permission( $fields[ $field ][ 'type' ], $field, $fields[ $field ], $fields, $pod, $params->id, $params ) ) {
  1981. $fields[ $field ][ 'value' ] = $value;
  1982. $fields_active[] = $field;
  1983. }
  1984. }
  1985. else {
  1986. $found = false;
  1987. foreach ( $object_fields as $object_field => $object_field_opt ) {
  1988. if ( in_array( $field, $object_field_opt[ 'alias' ] ) ) {
  1989. $object_fields[ $object_field ][ 'value' ] = $value;
  1990. $fields_active[] = $object_field;
  1991. $found = true;
  1992. break;
  1993. }
  1994. }
  1995. if ( $allow_custom_fields && !$found )
  1996. $custom_fields[] = $field;
  1997. }
  1998. }
  1999. if ( $allow_custom_fields && !empty( $custom_fields ) ) {
  2000. foreach ( $custom_fields as $field ) {
  2001. $custom_data[ $field ] = $params->data[ $field ];
  2002. }
  2003. }
  2004. unset( $params->data );
  2005. }
  2006. if ( 'pod' == $pod[ 'type' ] ) {
  2007. if ( empty( $params->id ) && !in_array( 'created', $fields_active ) && isset( $fields[ 'created' ] ) ) {
  2008. $fields[ 'created' ][ 'value' ] = date_i18n( 'Y-m-d H:i:s' );
  2009. $fields_active[] = 'created';
  2010. }
  2011. if ( !in_array( 'modified', $fields_active ) && isset( $fields[ 'modified' ] ) ) {
  2012. $fields[ 'modified' ][ 'value' ] = date_i18n( 'Y-m-d H:i:s' );
  2013. $fields_active[] = 'modified';
  2014. }
  2015. }
  2016. // Handle hidden fields
  2017. if ( empty( $params->id ) ) {
  2018. foreach ( $fields as $field => $field_data ) {
  2019. if ( in_array( $field, $fields_active ) )
  2020. continue;
  2021. if ( 'save' == $params->from || true === PodsForm::permission( $fields[ $field ][ 'type' ], $field, $fields[ $field ], $fields, $pod, $params->id, $params ) ) {
  2022. $value = PodsForm::default_value( pods_var_raw( $field, 'post' ), $field_data[ 'type' ], $field, pods_var_raw( 'options', $field_data, $field_data, null, true ), $pod, $params->id );
  2023. if ( null !== $value && '' !== $value && false !== $value ) {
  2024. $fields[ $field ][ 'value' ] = $value;
  2025. $fields_active[] = $field;
  2026. }
  2027. }
  2028. }
  2029. }
  2030. $columns =& $fields; // @deprecated 2.0.0
  2031. $active_columns =& $fields_active; // @deprecated 2.0.0
  2032. $params->tbl_row_id =& $params->id;
  2033. $pre_save_helpers = $post_save_helpers = array();
  2034. if ( false === $bypass_helpers ) {
  2035. $pieces = array( 'fields', 'params', 'pod', 'fields_active', 'object_fields' );
  2036. // Plugin hooks
  2037. $hooked = $this->do_hook( 'pre_save_pod_item', compact( $pieces ), $is_new_item );
  2038. if ( is_array( $hooked ) && !empty( $hooked ) )
  2039. extract( $hooked );
  2040. $hooked = $this->do_hook( "pre_save_pod_item_{$params->pod}", compact( $pieces ), $is_new_item );
  2041. if ( is_array( $hooked ) && !empty( $hooked ) )
  2042. extract( $hooked );
  2043. if ( false !== $is_new_item ) {
  2044. $hooked = $this->do_hook( 'pre_create_pod_item', compact( $pieces ) );
  2045. if ( is_array( $hooked ) && !empty( $hooked ) )
  2046. extract( $hooked );
  2047. $hooked = $this->do_hook( "pre_create_pod_item_{$params->pod}", compact( $pieces ) );
  2048. if ( is_array( $hooked ) && !empty( $hooked ) )
  2049. extract( $hooked );
  2050. }
  2051. else {
  2052. $hooked = $this->do_hook( 'pre_edit_pod_item', compact( $pieces ) );
  2053. if ( is_array( $hooked ) && !empty( $hooked ) )
  2054. extract( $hooked );
  2055. $hooked = $this->do_hook( "pre_edit_pod_item_{$params->pod}", compact( $pieces ) );
  2056. if ( is_array( $hooked ) && !empty( $hooked ) )
  2057. extract( $hooked );
  2058. }
  2059. // Call any pre-save helpers (if not bypassed)
  2060. if ( !defined( 'PODS_DISABLE_EVAL' ) || !PODS_DISABLE_EVAL ) {
  2061. if ( !empty( $pod[ 'options' ] ) && is_array( $pod[ 'options' ] ) ) {
  2062. $helpers = array( 'pre_save_helpers', 'post_save_helpers' );
  2063. foreach ( $helpers as $helper ) {
  2064. if ( isset( $pod[ 'options' ][ $helper ] ) && !empty( $pod[ 'options' ][ $helper ] ) )
  2065. ${$helper} = explode( ',', $pod[ 'options' ][ $helper ] );
  2066. }
  2067. }
  2068. if ( !empty( $pre_save_helpers ) ) {
  2069. pods_deprecated( sprintf( __( 'Pre-save helpers are deprecated, use the action pods_pre_save_pod_item_%s instead', 'pods' ), $params->pod ), '2.0.0' );
  2070. foreach ( $pre_save_helpers as $helper ) {
  2071. $helper = $this->load_helper( array( 'name' => $helper ) );
  2072. if ( false !== $helper )
  2073. eval( '?>' . $helper[ 'code' ] );
  2074. }
  2075. }
  2076. }
  2077. }
  2078. $table_data = $table_formats = $update_values = $rel_fields = $rel_field_ids = array();
  2079. $object_type = $pod[ 'type' ];
  2080. $object_ID = 'ID';
  2081. if ( 'comment' == $object_type )
  2082. $object_ID = 'comment_ID';
  2083. $object_data = $object_meta = array();
  2084. if ( !empty( $params->id ) )
  2085. $object_data[ $object_ID ] = $params->id;
  2086. $fields_active = array_unique( $fields_active );
  2087. // Loop through each active field, validating and preparing the table data
  2088. foreach ( $fields_active as $field ) {
  2089. if ( isset( $object_fields[ $field ] ) )
  2090. $field_data = $object_fields[ $field ];
  2091. elseif ( isset( $fields[ $field ] ) )
  2092. $field_data = $fields[ $field ];
  2093. else
  2094. continue;
  2095. $value = $field_data[ 'value' ];
  2096. $type = $field_data[ 'type' ];
  2097. $options = pods_var( 'options', $field_data, array() );
  2098. // WPML AJAX compatibility
  2099. if ( is_admin() && isset( $_GET[ 'page' ] ) && false !== strpos( $_GET[ 'page' ], '/menu/languages.php' ) && isset( $_POST[ 'icl_ajx_action' ] ) && isset( $_POST[ '_icl_nonce' ] ) && wp_verify_nonce( $_POST[ '_icl_nonce' ], $_POST[ 'icl_ajx_action' ] . '_nonce' ) )
  2100. $options[ 'unique' ] = $fields[ $field ][ 'options' ][ 'unique' ] = $options[ 'required' ] = $fields[ $field ][ 'options' ][ 'required' ] = 0;
  2101. else {
  2102. // Validate value
  2103. $validate = $this->handle_field_validation( $value, $field, $object_fields, $fields, $pod, $params );
  2104. if ( false === $validate )
  2105. $validate = sprintf( __( 'There was an issue validating the field %s', 'pods' ), $field_data[ 'label' ] );
  2106. if ( !is_bool( $validate ) && !empty( $validate ) )
  2107. return pods_error( $validate, $this );
  2108. }
  2109. $value = PodsForm::pre_save( $field_data[ 'type' ], $value, $params->id, $field, array_merge( $options, $field_data ), array_merge( $fields, $object_fields ), $pod, $params );
  2110. $field_data[ 'value' ] = $value;
  2111. if ( isset( $object_fields[ $field ] ) )
  2112. $object_data[ $field ] = $value;
  2113. else {
  2114. $simple = ( 'pick' == $type && in_array( pods_var( 'pick_object', $field_data ), $simple_tableless_objects ) );
  2115. $simple = (boolean) $this->do_hook( 'tableless_custom', $simple, $field_data, $field, $fields, $pod, $params );
  2116. // Handle Simple Relationships
  2117. if ( $simple ) {
  2118. $value = (array) $value;
  2119. $custom = pods_var_raw( 'pick_custom', $options, '' );
  2120. $custom = apply_filters( 'pods_form_ui_field_pick_custom_values', $custom, $field_data[ 'name' ], $value, array_merge( $options, $field_data ), $pod, $params->id );
  2121. $pick_limit = (int) pods_var_raw( 'pick_limit', $options, 0 );
  2122. if ( 'single' == pods_var_raw( 'pick_format_type', $options ) )
  2123. $pick_limit = 1;
  2124. if ( empty( $value ) || empty( $custom ) )
  2125. $value = '';
  2126. elseif ( !empty( $custom ) ) {
  2127. if ( !is_array( $custom ) ) {
  2128. $custom = explode( "\n", $custom );
  2129. $custom_values = array();
  2130. foreach ( $custom as $c => $cv ) {
  2131. if ( 0 < strlen( $cv ) ) {
  2132. $custom_label = explode( '|', $cv );
  2133. if ( !isset( $custom_label[ 1 ] ) )
  2134. $custom_label[ 1 ] = $custom_label[ 0 ];
  2135. $custom_values[ $custom_label[ 0 ] ] = $custom_label[ 1 ];
  2136. }
  2137. }
  2138. }
  2139. else
  2140. $custom_values = $custom;
  2141. $values = array();
  2142. foreach ( $value as $k => $v ) {
  2143. $v = pods_unsanitize( $v );
  2144. if ( isset( $custom_values[ $v ] ) )
  2145. $values[ $k ] = $v;
  2146. }
  2147. $value = $values;
  2148. if ( 0 < $pick_limit && !empty( $value ) )
  2149. $value = array_slice( $value, 0, $pick_limit );
  2150. }
  2151. // Don't save an empty array, just make it an empty string
  2152. if ( empty( $value ) )
  2153. $value = '';
  2154. elseif ( is_array( $value ) ) {
  2155. // If there's just one item, don't save as an array, save the string
  2156. if ( 1 == $pick_limit || 1 == count( $value ) )
  2157. $value = implode( '', $value );
  2158. // If storage is set to table, json encode, otherwise WP will serialize automatically
  2159. elseif ( 'table' == pods_var( 'storage', $pod ) )
  2160. $value = version_compare( PHP_VERSION, '5.4.0', '>=' ) ? json_encode( $value, JSON_UNESCAPED_UNICODE ) : json_encode( $value );
  2161. }
  2162. }
  2163. // Prepare all table (non-relational) data
  2164. if ( !in_array( $type, $tableless_field_types ) || $simple ) {
  2165. $table_data[ $field ] = str_replace( array( '{prefix}', '@wp_' ), array( '{/prefix/}', '{prefix}' ), $value ); // Fix for pods_query
  2166. $table_formats[] = PodsForm::prepare( $type, $options );
  2167. $object_meta[ $field ] = $value;
  2168. }
  2169. // Store relational field data to be looped through later
  2170. else {
  2171. $rel_fields[ $type ][ $field ] = $value;
  2172. $rel_field_ids[] = $field_data[ 'id' ];
  2173. }
  2174. }
  2175. }
  2176. if ( 'post_type' == $pod[ 'type' ] ) {
  2177. $post_type = $pod[ 'name' ];
  2178. if ( !empty( $pod[ 'object' ] ) )
  2179. $post_type = $pod[ 'object' ];
  2180. $object_data[ 'post_type' ] = $post_type;
  2181. }
  2182. if ( 'meta' == $pod[ 'storage' ] && !in_array( $pod[ 'type' ], array( 'taxonomy', 'pod', 'table', '' ) ) ) {
  2183. if ( $allow_custom_fields && !empty( $custom_data ) )
  2184. $object_meta = array_merge( $custom_data, $object_meta );
  2185. $params->id = $this->save_wp_object( $object_type, $object_data, $object_meta, false, true );
  2186. }
  2187. else {
  2188. if ( !in_array( $pod[ 'type' ], array( 'taxonomy', 'pod', 'table', '' ) ) )
  2189. $params->id = $this->save_wp_object( $object_type, $object_data, array(), false, true );
  2190. elseif ( 'taxonomy' == $pod[ 'type' ] ) {
  2191. $term = pods_var( $object_fields[ 'name' ][ 'name' ], $object_data, '', null, true );
  2192. $term_data = array();
  2193. if ( empty( $params->id ) || !empty( $term_data ) ) {
  2194. $taxonomy = $pod[ 'name' ];
  2195. if ( !empty( $pod[ 'object' ] ) )
  2196. $taxonomy = $pod[ 'object' ];
  2197. $params->id = $this->save_term( $params->id, $term, $taxonomy, $term_data, true );
  2198. }
  2199. }
  2200. if ( 'table' == $pod[ 'storage' ] ) {
  2201. // Every row should have an id set here, otherwise Pods with nothing
  2202. // but relationship fields won't get properly ID'd
  2203. if ( empty( $params->id ) )
  2204. $params->id = 0;
  2205. $table_data = array( 'id' => $params->id ) + $table_data;
  2206. array_unshift( $table_formats, '%d' );
  2207. if ( !empty( $table_data ) ) {
  2208. $sql = pods_data()->insert_on_duplicate( "@wp_pods_{$params->pod}", $table_data, $table_formats );
  2209. $id = pods_query( $sql, 'Cannot add/save table row' );
  2210. if ( empty( $params->id ) )
  2211. $params->id = $id;
  2212. }
  2213. }
  2214. }
  2215. $no_conflict = pods_no_conflict_check( $pod[ 'type' ] );
  2216. if ( !$no_conflict )
  2217. pods_no_conflict_on( $pod[ 'type' ] );
  2218. // Save relational field data
  2219. if ( !empty( $rel_fields ) ) {
  2220. // E.g. $rel_fields['pick']['related_events'] = '3,15';
  2221. foreach ( $rel_fields as $type => $data ) {
  2222. // Only handle tableless fields
  2223. if ( !in_array( $type, $tableless_field_types ) )
  2224. continue;
  2225. if ( !is_array( $data ) )
  2226. $data = explode( ',', $data );
  2227. foreach ( $data as $field => $values ) {
  2228. $field_id = pods_absint( $fields[ $field ][ 'id' ] );
  2229. // Convert values from a comma-separated string into an array
  2230. if ( !is_array( $values ) )
  2231. $values = explode( ',', $values );
  2232. // Enforce integers / unique values for IDs
  2233. if ( 'pick' != $type || !in_array( $fields[ $field ][ 'pick_object' ], $simple_tableless_objects ) ) {
  2234. $new_values = array();
  2235. foreach ( $values as $k => $v ) {
  2236. if ( !empty( $v ) ) {
  2237. if ( !is_array( $v ) ) {
  2238. $v = (int) $v;
  2239. if ( !empty( $v ) && !in_array( $v, $new_values ) )
  2240. $new_values[] = $v;
  2241. }
  2242. elseif ( 'file' == $type )
  2243. $new_values[] = $v;
  2244. }
  2245. }
  2246. $values = $new_values;
  2247. }
  2248. // Save relationships to meta if meta-based
  2249. if ( in_array( $pod[ 'type' ], array( 'post_type', 'media', 'user', 'comment' ) ) ) {
  2250. $object_type = $pod[ 'type' ];
  2251. if ( 'post_type' == $object_type || 'media' == $object_type )
  2252. $object_type = 'post';
  2253. if ( 'pick' != $type || !in_array( $fields[ $field ][ 'pick_object' ], $simple_tableless_objects ) ) {
  2254. delete_metadata( $object_type, $params->id, $field, '', true );
  2255. if ( !empty( $values ) ) {
  2256. update_metadata( $object_type, $params->id, '_pods_' . $field, $values );
  2257. foreach ( $values as $v ) {
  2258. add_metadata( $object_type, $params->id, $field, $v );
  2259. }
  2260. }
  2261. else
  2262. delete_metadata( $object_type, $params->id, '_pods_' . $field, '', true );
  2263. }
  2264. elseif ( !empty( $values ) )
  2265. update_metadata( $object_type, $params->id, $field, $values );
  2266. else
  2267. delete_metadata( $object_type, $params->id, $field, '', true );
  2268. }
  2269. $related_pod_id = $related_field_id = 0;
  2270. $related_pod = $related_field = false;
  2271. if ( 'pick' == $type && !in_array( $fields[ $field ][ 'pick_object' ], $simple_tableless_objects ) ) {
  2272. $pick_object = pods_var( 'pick_object', $fields[ $field ], '' ); // pod, post_type, taxonomy, etc..
  2273. $pick_val = pods_var( 'pick_val', $fields[ $field ], '' ); // pod name, post type name, taxonomy name, etc..
  2274. $pick_sister_id = (int) pods_var( 'sister_id', $fields[ $field ], 0 );
  2275. if ( 'pod' == $pick_object ) {
  2276. $related_pod = $this->load_pod( array( 'name' => $pick_val ) );
  2277. if ( false !== $related_pod )
  2278. $related_pod_id = $related_pod[ 'id' ];
  2279. if ( 0 < $pick_sister_id ) {
  2280. foreach ( $related_pod[ 'fields' ] as $related_pod_field ) {
  2281. if ( 'pick' == $related_pod_field[ 'type' ] && $pick_sister_id == $related_pod_field[ 'id' ] ) {
  2282. $related_field_id = $related_pod_field[ 'id' ];
  2283. $related_field = $related_pod_field[ 'name' ];
  2284. break;
  2285. }
  2286. }
  2287. }
  2288. // @todo Delete sister relationships in meta
  2289. foreach ( $values as $id ) {
  2290. if ( !empty( $related_pod_id ) && !empty( $related_field_id ) ) {
  2291. if ( in_array( $related_pod[ 'type' ], array( 'post_type', 'media', 'user', 'comment' ) ) ) {
  2292. $object_type = $related_pod[ 'type' ];
  2293. if ( 'post_type' == $object_type || 'media' == $object_type )
  2294. $object_type = 'post';
  2295. $ids = get_metadata( $object_type, $id, '_pods_' . $related_field, true );
  2296. if ( empty( $ids ) )
  2297. $ids = get_metadata( $object_type, $id, $related_field, true );
  2298. if ( empty( $ids ) )
  2299. $ids = array( $params->id );
  2300. else {
  2301. if ( !is_array( $ids ) )
  2302. $ids = array( $ids );
  2303. if ( !in_array( $params->id, $ids ) )
  2304. $ids[] = $params->id;
  2305. }
  2306. delete_metadata( $object_type, $id, $related_field, '', true );
  2307. if ( !empty( $ids ) ) {
  2308. update_metadata( $object_type, $id, '_pods_' . $related_field, $values );
  2309. foreach ( $ids as $rel_id ) {
  2310. add_metadata( $object_type, $id, $related_field, $rel_id );
  2311. }
  2312. }
  2313. else
  2314. delete_metadata( $object_type, $id, '_pods_' . $related_field, '', true );
  2315. }
  2316. }
  2317. }
  2318. }
  2319. }
  2320. if ( 'pick' != $type || !in_array( $fields[ $field ][ 'pick_object' ], $simple_tableless_objects ) ) {
  2321. if ( !defined( 'PODS_TABLELESS' ) || !PODS_TABLELESS ) {
  2322. if ( !empty( $values ) ) {
  2323. $values_to_impode = array();
  2324. foreach ( $values as $id ) {
  2325. if ( is_array( $id ) )
  2326. $values_to_impode[] = $id[ 'id' ];
  2327. else
  2328. $values_to_impode[] = $id;
  2329. }
  2330. $value_ids = implode( ',', $values_to_impode );
  2331. }
  2332. else
  2333. $value_ids = '0';
  2334. // Remove relationships
  2335. $sql = "
  2336. DELETE FROM `@wp_podsrel`
  2337. WHERE
  2338. (
  2339. `pod_id` = {$params->pod_id}
  2340. AND `field_id` = {$field_id}
  2341. AND `item_id` = {$params->id}
  2342. ) OR (
  2343. `related_pod_id` = {$params->pod_id}
  2344. AND `related_field_id` = {$field_id}
  2345. AND `related_item_id` = {$params->id}
  2346. AND `item_id` NOT IN ( {$value_ids} )
  2347. )
  2348. ";
  2349. pods_query( $sql, false );
  2350. }
  2351. if ( empty( $values ) )
  2352. continue;
  2353. // File relationships
  2354. if ( 'file' == $type ) {
  2355. $weight = 0;
  2356. foreach ( $values as $id ) {
  2357. $title = false;
  2358. if ( is_array( $id ) ) {
  2359. if ( isset( $id[ 'title' ] ) && 0 < strlen( trim( $id[ 'title' ] ) ) )
  2360. $title = trim( $id[ 'title' ] );
  2361. if ( isset( $id[ 'id' ] ) )
  2362. $id = $id[ 'id' ];
  2363. else
  2364. $id = 0;
  2365. }
  2366. if ( empty( $id ) )
  2367. continue;
  2368. // Update the title if set
  2369. if ( false !== $title && 1 == pods_var( $fields[ $field ][ 'type' ] . '_edit_title', $fields[ $field ][ 'options' ], 0 ) ) {
  2370. $attachment_data = array(
  2371. 'ID' => $id,
  2372. 'post_title' => $title
  2373. );
  2374. $this->save_wp_object( 'media', $attachment_data );
  2375. }
  2376. if ( !defined( 'PODS_TABLELESS' ) || !PODS_TABLELESS ) {
  2377. pods_query( "INSERT INTO `@wp_podsrel` (`pod_id`, `field_id`, `item_id`, `related_item_id`, `weight`) VALUES (%d, %d, %d, %d, %d)", array(
  2378. $params->pod_id,
  2379. $field_id,
  2380. $params->id,
  2381. $id,
  2382. $weight
  2383. ) );
  2384. $weight++;
  2385. }
  2386. }
  2387. }
  2388. // Pick relationships
  2389. elseif ( 'pick' == $type && ( !defined( 'PODS_TABLELESS' ) || !PODS_TABLELESS ) ) {
  2390. // Add relationship values
  2391. $weight = 0;
  2392. foreach ( $values as $id ) {
  2393. if ( !empty( $related_pod_id ) && !empty( $related_field_id ) ) {
  2394. $related_weight = 0;
  2395. $related_ids = pods_query( "SELECT `related_item_id`, `weight` FROM `@wp_podsrel` WHERE `pod_id` = %d AND `field_id` = %d AND `item_id` = %d ORDER BY `weight` DESC", array(
  2396. $related_pod_id,
  2397. $related_field_id,
  2398. $id
  2399. ) );
  2400. $save_related = true;
  2401. foreach ( $related_ids as $related_id_data ) {
  2402. if ( $params->id == $related_id_data->related_item_id ) {
  2403. $save_related = false;
  2404. break;
  2405. }
  2406. elseif ( empty( $related_weight ) )
  2407. $related_weight = ( (int) $related_id_data->weight ) + 1;
  2408. }
  2409. if ( $save_related ) {
  2410. pods_query( "INSERT INTO `@wp_podsrel` (`pod_id`, `field_id`, `item_id`, `related_pod_id`, `related_field_id`, `related_item_id`, `weight`) VALUES (%d, %d, %d, %d, %d, %d, %d)", array(
  2411. $related_pod_id,
  2412. $related_field_id,
  2413. $id,
  2414. $params->pod_id,
  2415. $field_id,
  2416. $params->id,
  2417. $related_weight
  2418. ) );
  2419. }
  2420. }
  2421. pods_query( "INSERT INTO `@wp_podsrel` (`pod_id`, `field_id`, `item_id`, `related_pod_id`, `related_field_id`, `related_item_id`, `weight`) VALUES (%d, %d, %d, %d, %d, %d, %d)", array(
  2422. $params->pod_id,
  2423. $field_id,
  2424. $params->id,
  2425. $related_pod_id,
  2426. $related_field_id,
  2427. $id,
  2428. $weight
  2429. ) );
  2430. $weight++;
  2431. }
  2432. }
  2433. }
  2434. }
  2435. }
  2436. }
  2437. if ( !$no_conflict )
  2438. pods_no_conflict_off( $pod[ 'type' ] );
  2439. if ( false === $bypass_helpers ) {
  2440. $pieces = array( 'fields', 'params', 'pod', 'fields_active', 'object_fields' );
  2441. $pieces = compact( $pieces );
  2442. // Plugin hooks
  2443. $this->do_hook( 'post_save_pod_item', $pieces, $is_new_item );
  2444. $this->do_hook( "post_save_pod_item_{$params->pod}", $pieces, $is_new_item );
  2445. if ( false !== $is_new_item ) {
  2446. $this->do_hook( 'post_create_pod_item', $pieces );
  2447. $this->do_hook( "post_create_pod_item_{$params->pod}", $pieces );
  2448. }
  2449. else {
  2450. $this->do_hook( 'post_edit_pod_item', $pieces );
  2451. $this->do_hook( "post_edit_pod_item_{$params->pod}", $pieces );
  2452. }
  2453. // Call any post-save helpers (if not bypassed)
  2454. if ( !defined( 'PODS_DISABLE_EVAL' ) || !PODS_DISABLE_EVAL ) {
  2455. if ( !empty( $post_save_helpers ) ) {
  2456. pods_deprecated( sprintf( __( 'Post-save helpers are deprecated, use the action pods_post_save_pod_item_%s instead', 'pods' ), $params->pod ), '2.0.0' );
  2457. foreach ( $post_save_helpers as $helper ) {
  2458. $helper = $this->load_helper( array( 'name' => $helper ) );
  2459. if ( false !== $helper && ( !defined( 'PODS_DISABLE_EVAL' ) || !PODS_DISABLE_EVAL ) )
  2460. eval( '?>' . $helper[ 'code' ] );
  2461. }
  2462. }
  2463. }
  2464. }
  2465. // Clear cache
  2466. pods_cache_clear( $params->id, 'pods_items_' . $params->pod );
  2467. // Success! Return the id
  2468. return $params->id;
  2469. }
  2470. /**
  2471. * @see PodsAPI::save_pod_item
  2472. * Add multiple pod items
  2473. *
  2474. * $params['pod'] string The Pod name (pod or pod_id is required)
  2475. * $params['pod_id'] string The Pod ID (pod or pod_id is required)
  2476. * $params['bypass_helpers'] bool Set to true to bypass running pre-save and post-save helpers
  2477. *
  2478. * $data['id'] int The item ID (optional)
  2479. * $data['data'] array An associative array of field names + values
  2480. *
  2481. * @param array|object $params An associative array of parameters, data excluded
  2482. * @param array $data An associative array of pod ids and field names + values (arrays of field data)
  2483. *
  2484. * @return int The item ID
  2485. * @since 2.0.0
  2486. */
  2487. public function save_pod_items ( $params, $data ) {
  2488. $params = (object) $params;
  2489. $ids = array();
  2490. foreach ( $data as $fields ) {
  2491. $params->data = $fields;
  2492. if ( isset( $fields[ 'id' ] ) && isset( $fields[ 'data' ] ) ) {
  2493. $params->id = $fields[ 'id' ];
  2494. $params->data = $fields[ 'data' ];
  2495. }
  2496. $ids[] = $this->save_pod_item( $params );
  2497. }
  2498. return $ids;
  2499. }
  2500. /**
  2501. * @see PodsAPI::save_pod_item
  2502. *
  2503. * Duplicate a pod item
  2504. *
  2505. * $params['pod'] string The Pod name
  2506. * $params['id'] int The item's ID from the wp_pods_* table
  2507. *
  2508. * @param array $params An associative array of parameters
  2509. *
  2510. * @return int The table row ID
  2511. * @since 1.12
  2512. */
  2513. public function duplicate_pod_item ( $params ) {
  2514. $params = (object) pods_sanitize( $params );
  2515. $pod = $this->load_pod( array( 'name' => $params->pod ) );
  2516. if ( false === $pod )
  2517. return pods_error( __( 'Pod not found', 'pods' ), $this );
  2518. $fields = $pod[ 'fields' ];
  2519. $params->pod = $pod[ 'name' ];
  2520. $params->pod_id = $pod[ 'id' ];
  2521. $pod = pods( $params->pod, $params->id );
  2522. $params = array(
  2523. 'pod' => $params->pod,
  2524. 'data' => array()
  2525. );
  2526. foreach ( $fields as $field ) {
  2527. $field = $field[ 'name' ];
  2528. if ( 'pick' == $field[ 'type' ] ) {
  2529. $field = $field . '.id';
  2530. if ( 'taxonomy' == $field[ 'pick_object' ] )
  2531. $field = $field . '.term_id';
  2532. }
  2533. if ( 'file' == $field[ 'type' ] )
  2534. $field = $field . '.ID';
  2535. $value = $pod->field( $field );
  2536. if ( 0 < strlen( $value ) )
  2537. $params[ 'data' ][ $field[ 'name' ] ] = $value;
  2538. }
  2539. $params = $this->do_hook( 'duplicate_pod_item', $params, $pod->pod, $pod->field( 'id' ) );
  2540. $id = $this->save_pod_item( $params );
  2541. return $id;
  2542. }
  2543. /**
  2544. * @see pods()
  2545. *
  2546. * Export a pod item
  2547. *
  2548. * $params['pod'] string The Pod name
  2549. * $params['id'] int The item's ID from the wp_pods_* table
  2550. * $params['fields'] array The fields to export
  2551. * $params['depth'] int How many levels deep to export data
  2552. *
  2553. * @param array $params An associative array of parameters
  2554. * @param object $pod (optional) Pods object
  2555. *
  2556. * @return int The table row ID
  2557. * @since 1.12
  2558. */
  2559. public function export_pod_item ( $params, $pod = null ) {
  2560. if ( !is_object( $pod ) || 'Pods' != get_class( $pod ) ) {
  2561. if ( empty( $params ) )
  2562. return false;
  2563. $params = (object) pods_sanitize( $params );
  2564. $pod = pods( $params->pod, $params->id, false );
  2565. if ( empty( $pod ) )
  2566. return false;
  2567. }
  2568. $fields = (array) pods_var_raw( 'fields', $params, array(), null, true );
  2569. $depth = (int) pods_var_raw( 'depth', $params, 2, null, true );
  2570. $object_fields = (array) pods_var_raw( 'object_fields', $pod->pod_data, array(), null, true );
  2571. if ( empty( $fields ) ) {
  2572. $fields = $pod->fields;
  2573. $fields = array_merge( $fields, $object_fields );
  2574. }
  2575. $data = $this->export_pod_item_level( $pod, $fields, $depth );
  2576. $data = $this->do_hook( 'export_pod_item', $data, $pod->pod, $pod->id(), $pod, $fields, $depth );
  2577. return $data;
  2578. }
  2579. /**
  2580. * Export a pod item by depth level
  2581. *
  2582. * @param Pods $pod Pods object
  2583. * @param array $fields Fields to export
  2584. * @param int $depth Depth limit
  2585. * @param int $current_depth Current depth level
  2586. *
  2587. * @return array Data array
  2588. */
  2589. private function export_pod_item_level ( $pod, $fields, $depth, $current_depth = 1 ) {
  2590. $tableless_field_types = apply_filters( 'pods_tableless_field_types', array( 'pick', 'file', 'avatar', 'taxonomy' ) );
  2591. $simple_tableless_objects = PodsForm::field_method( 'pick', 'simple_objects' );
  2592. foreach ( $fields as $k => $field ) {
  2593. if ( !is_array( $field ) )
  2594. $field = array( 'name' => $field );
  2595. if ( isset( $pod->fields[ $field[ 'name' ] ] ) ) {
  2596. $field = $pod->fields[ $field[ 'name' ] ];
  2597. $field[ 'lookup_name' ] = $field[ 'name' ];
  2598. if ( in_array( $field[ 'type' ], $tableless_field_types ) && !in_array( pods_var( 'pick_object', $field ), $simple_tableless_objects ) ) {
  2599. if ( 'pick' == $field[ 'type' ] ) {
  2600. if ( empty( $field[ 'table_info' ] ) )
  2601. $field[ 'table_info' ] = $this->get_table_info( pods_var_raw( 'pick_object', $field ), pods_var_raw( 'pick_val', $field ), null, null, $field );
  2602. if ( !empty( $field[ 'table_info' ] ) )
  2603. $field[ 'lookup_name' ] .= '.' . $field[ 'table_info' ][ 'field_id' ];
  2604. }
  2605. elseif ( in_array( $field[ 'type' ], array( 'file', 'avatar' ) ) )
  2606. $field[ 'lookup_name' ] .= '.guid';
  2607. }
  2608. $fields[ $k ] = $field;
  2609. }
  2610. elseif ( isset( $object_fields[ $field[ 'name' ] ] ) ) {
  2611. $field = $object_fields[ $field[ 'name' ] ];
  2612. $field[ 'lookup_name' ] = $field[ 'name' ];
  2613. $fields[ $k ] = $field;
  2614. }
  2615. else
  2616. unset( $fields[ $k ] );
  2617. }
  2618. $data = array();
  2619. foreach ( $fields as $field ) {
  2620. // Return IDs (or guid for files) if only one level deep
  2621. if ( 1 == $depth )
  2622. $data[ $field[ 'name' ] ] = $pod->field( $field[ 'lookup_name' ] );
  2623. // Recurse depth levels for pick fields if $depth allows
  2624. elseif ( ( -1 == $depth || $current_depth < $depth ) && 'pick' == $field[ 'type' ] && !in_array( pods_var( 'pick_object', $field ), $simple_tableless_objects ) ) {
  2625. $related_data = array();
  2626. $related_ids = $pod->field( $field[ 'lookup_name' ] );
  2627. if ( !empty( $related_ids ) ) {
  2628. $related_ids = (array) $related_ids;
  2629. $pick_object = pods_var_raw( 'pick_object', $field );
  2630. $related_pod = pods( pods_var_raw( 'pick_val', $field ), null, false );
  2631. // If this isn't a Pod, return data exactly as Pods does normally
  2632. if ( empty( $related_pod ) || ( 'pod' != $pick_object && $pick_object != $related_pod->pod_data[ 'type' ] ) )
  2633. $related_data = $pod->field( $field[ 'name' ] );
  2634. else {
  2635. foreach ( $related_ids as $related_id ) {
  2636. $object_fields = (array) pods_var_raw( 'object_fields', $related_pod->pod_data, array(), null, true );
  2637. $related_fields = array_merge( $pod->fields, $object_fields );
  2638. $related_data = $this->export_pod_item_level( $related_pod, $related_fields, $depth, ( $current_depth + 1 ) );
  2639. $related_data = $this->do_hook( 'export_pod_item_level', $related_data, $related_pod->pod, $related_pod->id(), $related_pod, $related_fields, $depth, ( $current_depth + 1 ) );
  2640. }
  2641. }
  2642. }
  2643. $data[ $field[ 'name' ] ] = $related_data;
  2644. }
  2645. // Return data exactly as Pods does normally
  2646. else
  2647. $data[ $field[ 'name' ] ] = $pod->field( $field[ 'name' ] );
  2648. }
  2649. return $data;
  2650. }
  2651. /**
  2652. * Reorder a Pod
  2653. *
  2654. * $params['pod'] string The Pod name
  2655. * $params['field'] string The field name of the field to reorder
  2656. * $params['order'] array The key => value array of items to reorder (key should be an integer)
  2657. *
  2658. * @param array $params An associative array of parameters
  2659. *
  2660. * @return bool
  2661. *
  2662. * @since 1.9.0
  2663. */
  2664. public function reorder_pod_item ( $params ) {
  2665. $params = (object) pods_sanitize( $params );
  2666. // @deprecated 2.0.0
  2667. if ( isset( $params->datatype ) ) {
  2668. pods_deprecated( __( '$params->pod instead of $params->datatype', 'pods' ), '2.0.0' );
  2669. $params->pod = $params->datatype;
  2670. unset( $params->datatype );
  2671. }
  2672. if ( null === pods_var_raw( 'pod', $params, null, null, true ) )
  2673. return pods_error( __( '$params->pod is required', 'pods' ), $this );
  2674. if ( !is_array( $params->order ) )
  2675. $params->order = explode( ',', $params->order );
  2676. $pod = $this->load_pod( array( 'name' => $params->pod ) );
  2677. $params->name = $pod[ 'name' ];
  2678. if ( false === $pod )
  2679. return pods_error( __( 'Pod is required', 'pods' ), $this );
  2680. foreach ( $params->order as $order => $id ) {
  2681. if ( isset( $pod[ 'fields' ][ $params->field ] ) || isset( $pod[ 'object_fields' ][ $params->field ] ) ) {
  2682. if ( 'table' == $pod[ 'storage' ] && ( !defined( 'PODS_TABLELESS' ) || !PODS_TABLELESS ) ) {
  2683. if ( isset( $pod[ 'fields' ][ $params->field ] ) )
  2684. pods_query( "UPDATE `@wp_pods_{$params->name}` SET `{$params->field}` = " . pods_absint( $order ) . " WHERE `id` = " . pods_absint( $id ) . " LIMIT 1" );
  2685. else
  2686. pods_query( "UPDATE `{$pod['table']}` SET `{$params->field}` = " . pods_absint( $order ) . " WHERE `{$pod['field_id']}` = " . pods_absint( $id ) . " LIMIT 1" );
  2687. }
  2688. else
  2689. $this->save_pod_item( array( 'pod' => $params->pod, 'pod_id' => $params->pod_id, 'id' => $id, 'data' => array( $params->field => pods_absint( $order ) ) ) );
  2690. }
  2691. }
  2692. return true;
  2693. }
  2694. /**
  2695. *
  2696. * Delete all content for a Pod
  2697. *
  2698. * $params['id'] int The Pod ID
  2699. * $params['name'] string The Pod name
  2700. *
  2701. * @param array $params An associative array of parameters
  2702. * @param array $pod Pod data
  2703. *
  2704. * @return bool
  2705. *
  2706. * @uses pods_query
  2707. * @uses pods_cache_clear
  2708. *
  2709. * @since 1.9.0
  2710. */
  2711. public function reset_pod ( $params, $pod = false ) {
  2712. $params = (object) pods_sanitize( $params );
  2713. if ( empty( $pod ) )
  2714. $pod = $this->load_pod( $params );
  2715. if ( false === $pod )
  2716. return pods_error( __( 'Pod not found', 'pods' ), $this );
  2717. $params->id = $pod[ 'id' ];
  2718. $params->name = $pod[ 'name' ];
  2719. if ( !defined( 'PODS_TABLELESS' ) || !PODS_TABLELESS ) {
  2720. if ( 'table' == $pod[ 'storage' ] ) {
  2721. try {
  2722. pods_query( "TRUNCATE `@wp_pods_{$params->name}`", false );
  2723. }
  2724. catch ( Exception $e ) {
  2725. // Allow pod to be reset if the table doesn't exist
  2726. if ( false === strpos( $e->getMessage(), 'Unknown table' ) )
  2727. return pods_error( $e->getMessage(), $this );
  2728. }
  2729. }
  2730. pods_query( "DELETE FROM `@wp_podsrel` WHERE `pod_id` = {$params->id} OR `related_pod_id` = {$params->id}", false );
  2731. }
  2732. // @todo Delete relationships from tableless relationships
  2733. // Delete all posts/revisions from this post type
  2734. if ( in_array( $pod[ 'type' ], array( 'post_type', 'media' ) ) ) {
  2735. $type = pods_var( 'object', $pod, $pod[ 'name' ], null, true );
  2736. $sql = "
  2737. DELETE `t`, `r`, `m`
  2738. FROM `{$pod['table']}` AS `t`
  2739. LEFT JOIN `{$pod['meta_table']}` AS `m`
  2740. ON `m`.`{$pod['meta_field_id']}` = `t`.`{$pod['field_id']}`
  2741. LEFT JOIN `{$pod['table']}` AS `r`
  2742. ON `r`.`post_parent` = `t`.`{$pod['field_id']}` AND `r`.`post_status` = 'inherit'
  2743. WHERE `t`.`{$pod['field_type']}` = '{$type}'
  2744. ";
  2745. pods_query( $sql, false );
  2746. }
  2747. // Delete all terms from this taxonomy
  2748. elseif ( 'taxonomy' == $pod[ 'type' ] ) {
  2749. $type = pods_var( 'object', $pod, $pod[ 'name' ], null, true );
  2750. $sql = "
  2751. DELETE FROM `{$pod['table']}` AS `t`
  2752. " . $pod['join']['tt'] . "
  2753. WHERE " . implode( ' AND ', $pod['where'] ) . "
  2754. ";
  2755. pods_query( $sql, false );
  2756. }
  2757. // Delete all users except the current one
  2758. elseif ( 'user' == $pod[ 'type' ] ) {
  2759. $sql = "
  2760. DELETE `t`, `m`
  2761. FROM `{$pod['table']}` AS `t`
  2762. LEFT JOIN `{$pod['meta_table']}` AS `m`
  2763. ON `m`.`{$pod['meta_field_id']}` = `t`.`{$pod['field_id']}`
  2764. WHERE `t`.`{$pod['field_id']}` != " . (int) get_current_user_id() . "
  2765. ";
  2766. pods_query( $sql, false );
  2767. }
  2768. // Delete all comments
  2769. elseif ( 'comment' == $pod[ 'type' ] ) {
  2770. $type = pods_var( 'object', $pod, $pod[ 'name' ], null, true );
  2771. $sql = "
  2772. DELETE `t`, `m`
  2773. FROM `{$pod['table']}` AS `t`
  2774. LEFT JOIN `{$pod['meta_table']}` AS `m`
  2775. ON `m`.`{$pod['meta_field_id']}` = `t`.`{$pod['field_id']}`
  2776. WHERE `t`.`{$pod['field_type']}` = '{$type}'
  2777. ";
  2778. pods_query( $sql, false );
  2779. }
  2780. pods_cache_clear( true ); // only way to reliably clear out cached data across an entire group
  2781. return true;
  2782. }
  2783. /**
  2784. * Delete a Pod and all its content
  2785. *
  2786. * $params['id'] int The Pod ID
  2787. * $params['name'] string The Pod name
  2788. *
  2789. * @param array $params An associative array of parameters
  2790. * @param bool $strict (optional) Makes sure a pod exists, if it doesn't throws an error
  2791. * @param bool $delete_all (optional) Whether to delete all content from a WP object
  2792. *
  2793. * @uses PodsAPI::load_pod
  2794. * @uses wp_delete_post
  2795. * @uses pods_query
  2796. *
  2797. * @return bool
  2798. * @since 1.7.9
  2799. */
  2800. public function delete_pod ( $params, $strict = false, $delete_all = false ) {
  2801. /**
  2802. * @var $wpdb wpdb
  2803. */
  2804. global $wpdb;
  2805. if ( !is_object( $params ) && !is_array( $params ) ) {
  2806. if ( is_numeric( $params ) )
  2807. $params = array( 'id' => $params );
  2808. else
  2809. $params = array( 'name' => $params );
  2810. $params = pods_sanitize( $params );
  2811. }
  2812. else
  2813. $params = (object) pods_sanitize( $params );
  2814. $pod = $this->load_pod( $params, $strict );
  2815. if ( empty( $pod ) ) {
  2816. if ( false !== $strict )
  2817. return pods_error( __( 'Pod not found', 'pods' ), $this );
  2818. return false;
  2819. }
  2820. $params->id = (int) $pod[ 'id' ];
  2821. $params->name = $pod[ 'name' ];
  2822. foreach ( $pod[ 'fields' ] as $field ) {
  2823. $field[ 'pod' ] = $pod;
  2824. $this->delete_field( $field, false );
  2825. }
  2826. // Only delete the post once the fields are taken care of, it's not required anymore
  2827. $success = wp_delete_post( $params->id );
  2828. if ( !$success )
  2829. return pods_error( __( 'Pod unable to be deleted', 'pods' ), $this );
  2830. // Reset content
  2831. if ( $delete_all )
  2832. $this->reset_pod( $params, $pod );
  2833. if ( !defined( 'PODS_TABLELESS' ) || !PODS_TABLELESS ) {
  2834. if ( 'table' == $pod[ 'storage' ] ) {
  2835. try {
  2836. pods_query( "DROP TABLE IF EXISTS `@wp_pods_{$params->name}`", false );
  2837. }
  2838. catch ( Exception $e ) {
  2839. // Allow pod to be deleted if the table doesn't exist
  2840. if ( false === strpos( $e->getMessage(), 'Unknown table' ) )
  2841. return pods_error( $e->getMessage(), $this );
  2842. }
  2843. }
  2844. pods_query( "DELETE FROM `@wp_podsrel` WHERE `pod_id` = {$params->id} OR `related_pod_id` = {$params->id}", false );
  2845. }
  2846. // @todo Delete relationships from tableless relationships
  2847. // Delete any relationship references
  2848. $sql = "
  2849. DELETE `pm`
  2850. FROM `{$wpdb->postmeta}` AS `pm`
  2851. LEFT JOIN `{$wpdb->posts}` AS `p`
  2852. ON `p`.`post_type` = '_pods_field'
  2853. AND `p`.`ID` = `pm`.`post_id`
  2854. LEFT JOIN `{$wpdb->postmeta}` AS `pm2`
  2855. ON `pm2`.`meta_key` = 'pick_object'
  2856. AND `pm2`.`meta_value` = 'pod'
  2857. AND `pm2`.`post_id` = `pm`.`post_id`
  2858. WHERE
  2859. `p`.`ID` IS NOT NULL
  2860. AND `pm2`.`meta_id` IS NOT NULL
  2861. AND `pm`.`meta_key` = 'pick_val'
  2862. AND `pm`.`meta_value` = '{$params->name}'
  2863. ";
  2864. pods_query( $sql );
  2865. $this->cache_flush_pods( $pod );
  2866. return true;
  2867. }
  2868. /**
  2869. * Drop a field within a Pod
  2870. *
  2871. * $params['id'] int The field ID
  2872. * $params['name'] int The field name
  2873. * $params['pod'] string The Pod name
  2874. * $params['pod_id'] string The Pod name
  2875. *
  2876. * @param array $params An associative array of parameters
  2877. * @param bool $table_operation Whether or not to handle table operations
  2878. *
  2879. * @uses PodsAPI::load_field
  2880. * @uses wp_delete_post
  2881. * @uses pods_query
  2882. *
  2883. * @return bool
  2884. * @since 1.7.9
  2885. */
  2886. public function delete_field ( $params, $table_operation = true ) {
  2887. /**
  2888. * @var $wpdb wpdb
  2889. */
  2890. global $wpdb;
  2891. $tableless_field_types = apply_filters( 'pods_tableless_field_types', array( 'pick', 'file', 'avatar', 'taxonomy' ) );
  2892. $simple_tableless_objects = PodsForm::field_method( 'pick', 'simple_objects' );
  2893. $params = (object) pods_sanitize( $params );
  2894. if ( !isset( $params->pod ) )
  2895. $params->pod = '';
  2896. if ( !isset( $params->pod_id ) )
  2897. $params->pod_id = 0;
  2898. $pod = $params->pod;
  2899. $save_pod = false;
  2900. if ( !is_array( $pod ) )
  2901. $pod = $this->load_pod( array( 'name' => $pod, 'id' => $params->pod_id ) );
  2902. else
  2903. $save_pod = true;
  2904. if ( empty( $pod ) )
  2905. return pods_error( __( 'Pod not found', 'pods' ), $this );
  2906. $params->pod_id = $pod[ 'id' ];
  2907. $params->pod = $pod[ 'name' ];
  2908. if ( !isset( $params->name ) )
  2909. $params->name = '';
  2910. if ( !isset( $params->id ) )
  2911. $params->id = 0;
  2912. $field = $this->load_field( array( 'name' => $params->name, 'id' => $params->id ) );
  2913. if ( false === $field )
  2914. return pods_error( __( 'Field not found', 'pods' ), $this );
  2915. $params->id = $field[ 'id' ];
  2916. $params->name = $field[ 'name' ];
  2917. $simple = ( 'pick' == $field[ 'type' ] && in_array( pods_var( 'pick_object', $field ), $simple_tableless_objects ) );
  2918. $simple = (boolean) $this->do_hook( 'tableless_custom', $simple, $field, $pod, $params );
  2919. if ( $table_operation && 'table' == $pod[ 'storage' ] && ( !in_array( $field[ 'type' ], $tableless_field_types ) || $simple ) )
  2920. pods_query( "ALTER TABLE `@wp_pods_{$params->pod}` DROP COLUMN `{$params->name}`", false );
  2921. $success = wp_delete_post( $params->id );
  2922. if ( !$success )
  2923. return pods_error( __( 'Field unable to be deleted', 'pods' ), $this );
  2924. $wpdb->query( $wpdb->prepare( "DELETE pm FROM {$wpdb->postmeta} AS pm
  2925. LEFT JOIN {$wpdb->posts} AS p
  2926. ON p.post_type = '_pods_field' AND p.ID = pm.post_id
  2927. WHERE p.ID IS NOT NULL AND pm.meta_key = 'sister_id' AND pm.meta_value = %d", $params->id ) );
  2928. if ( ( !defined( 'PODS_TABLELESS' ) || !PODS_TABLELESS ) && $table_operation ) {
  2929. pods_query( "DELETE FROM `@wp_podsrel` WHERE (`pod_id` = {$params->pod_id} AND `field_id` = {$params->id}) OR (`related_pod_id` = {$params->pod_id} AND `related_field_id` = {$params->id})", false );
  2930. }
  2931. // @todo Delete tableless relationship meta
  2932. if ( true === $save_pod )
  2933. $this->cache_flush_pods( $pod );
  2934. return true;
  2935. }
  2936. /**
  2937. * Drop a Pod Object
  2938. *
  2939. * $params['id'] int The object ID
  2940. * $params['name'] string The object name
  2941. * $params['type'] string The object type
  2942. *
  2943. * @param array|object $params An associative array of parameters
  2944. *
  2945. * @uses wp_delete_post
  2946. *
  2947. * @return bool
  2948. * @since 2.0.0
  2949. */
  2950. public function delete_object ( $params ) {
  2951. $params = (object) $params;
  2952. $object = $this->load_object( $params );
  2953. if ( empty( $object ) )
  2954. return pods_error( sprintf( __( "%s Object not found", 'pods' ), ucwords( $params->type ) ), $this );
  2955. $success = wp_delete_post( $params->id );
  2956. if ( !$success )
  2957. return pods_error( sprintf( __( "%s Object not deleted", 'pods' ), ucwords( $params->type ) ), $this );
  2958. pods_transient_clear( 'pods_object_' . $params->type );
  2959. if ( isset( $params->name ) )
  2960. pods_transient_clear( 'pods_object_' . $params->type . '_' . $object[ 'slug' ] );
  2961. return true;
  2962. }
  2963. /**
  2964. * @see PodsAPI::delete_object
  2965. *
  2966. * Drop a Pod Template
  2967. *
  2968. * $params['id'] int The template ID
  2969. * $params['name'] string The template name
  2970. *
  2971. * @param array $params An associative array of parameters
  2972. *
  2973. * @return bool
  2974. * @since 1.7.9
  2975. */
  2976. public function delete_template ( $params ) {
  2977. $params = (object) $params;
  2978. $params->type = 'template';
  2979. return $this->delete_object( $params );
  2980. }
  2981. /**
  2982. * @see PodsAPI::delete_object
  2983. *
  2984. * Drop a Pod Page
  2985. *
  2986. * $params['id'] int The page ID
  2987. * $params['uri'] string The page URI
  2988. *
  2989. * @param array $params An associative array of parameters
  2990. *
  2991. * @return bool
  2992. * @since 1.7.9
  2993. */
  2994. public function delete_page ( $params ) {
  2995. $params = (object) $params;
  2996. if ( isset( $params->uri ) ) {
  2997. $params->name = $params->uri;
  2998. unset( $params->uri );
  2999. }
  3000. if ( isset( $params->name ) )
  3001. $params->name = trim( $params->name, '/' );
  3002. $params->type = 'page';
  3003. return $this->delete_object( $params );
  3004. }
  3005. /**
  3006. * @see PodsAPI::delete_object
  3007. *
  3008. * Drop a Pod Helper
  3009. *
  3010. * $params['id'] int The helper ID
  3011. * $params['name'] string The helper name
  3012. *
  3013. * @param array $params An associative array of parameters
  3014. *
  3015. * @return bool
  3016. * @since 1.7.9
  3017. */
  3018. public function delete_helper ( $params ) {
  3019. $params = (object) $params;
  3020. $params->type = 'helper';
  3021. return $this->delete_object( $params );
  3022. }
  3023. /**
  3024. * Drop a single pod item
  3025. *
  3026. * $params['id'] int (optional) The item's ID from the wp_pod_* table (used with datatype parameter)
  3027. * $params['pod'] string (optional) The Pod name (used with id parameter)
  3028. * $params['pod_id'] int (optional) The Pod ID (used with id parameter)
  3029. * $params['bypass_helpers'] bool Set to true to bypass running pre-save and post-save helpers
  3030. *
  3031. * @param array $params An associative array of parameters
  3032. * @param bool $wp Whether to run WP object delete action
  3033. *
  3034. * @return bool
  3035. * @since 1.7.9
  3036. */
  3037. public function delete_pod_item ( $params, $wp = true ) {
  3038. $params = (object) pods_sanitize( $params );
  3039. // @deprecated 2.0.0
  3040. if ( isset( $params->datatype_id ) || isset( $params->datatype ) || isset( $params->tbl_row_id ) ) {
  3041. if ( isset( $params->tbl_row_id ) ) {
  3042. pods_deprecated( __( '$params->id instead of $params->tbl_row_id', 'pods' ), '2.0.0' );
  3043. $params->id = $params->tbl_row_id;
  3044. unset( $params->tbl_row_id );
  3045. }
  3046. if ( isset( $params->pod_id ) ) {
  3047. pods_deprecated( __( '$params->id instead of $params->pod_id', 'pods' ), '2.0.0' );
  3048. $params->id = $params->pod_id;
  3049. unset( $params->pod_id );
  3050. }
  3051. if ( isset( $params->dataype_id ) ) {
  3052. pods_deprecated( __( '$params->pod_id instead of $params->datatype_id', 'pods' ), '2.0.0' );
  3053. $params->pod_id = $params->dataype_id;
  3054. unset( $params->dataype_id );
  3055. }
  3056. if ( isset( $params->datatype ) ) {
  3057. pods_deprecated( __( '$params->pod instead of $params->datatype', 'pods' ), '2.0.0' );
  3058. $params->pod = $params->datatype;
  3059. unset( $params->datatype );
  3060. }
  3061. }
  3062. if ( !isset( $params->id ) )
  3063. return pods_error( __( 'Pod Item not found', 'pods' ), $this );
  3064. $params->id = pods_absint( $params->id );
  3065. if ( !isset( $params->pod ) )
  3066. $params->pod = '';
  3067. if ( !isset( $params->pod_id ) )
  3068. $params->pod_id = 0;
  3069. $pod = $this->load_pod( array( 'name' => $params->pod, 'id' => $params->pod_id ) );
  3070. if ( false === $pod )
  3071. return pods_error( __( 'Pod not found', 'pods' ), $this );
  3072. $params->pod_id = $pod[ 'id' ];
  3073. $params->pod = $pod[ 'name' ];
  3074. // Allow Helpers to bypass subsequent helpers in recursive delete_pod_item calls
  3075. $bypass_helpers = false;
  3076. if ( isset( $params->bypass_helpers ) && false !== $params->bypass_helpers )
  3077. $bypass_helpers = true;
  3078. $pre_delete_helpers = $post_delete_helpers = array();
  3079. if ( false === $bypass_helpers ) {
  3080. // Plugin hook
  3081. $this->do_hook( 'pre_delete_pod_item', $params, $pod );
  3082. $this->do_hook( "pre_delete_pod_item_{$params->pod}", $params, $pod );
  3083. // Call any pre-save helpers (if not bypassed)
  3084. if ( !defined( 'PODS_DISABLE_EVAL' ) || !PODS_DISABLE_EVAL ) {
  3085. if ( !empty( $pod[ 'options' ] ) && is_array( $pod[ 'options' ] ) ) {
  3086. $helpers = array( 'pre_delete_helpers', 'post_delete_helpers' );
  3087. foreach ( $helpers as $helper ) {
  3088. if ( isset( $pod[ 'options' ][ $helper ] ) && !empty( $pod[ 'options' ][ $helper ] ) )
  3089. ${$helper} = explode( ',', $pod[ 'options' ][ $helper ] );
  3090. }
  3091. }
  3092. if ( !empty( $pre_delete_helpers ) ) {
  3093. pods_deprecated( sprintf( __( 'Pre-delete helpers are deprecated, use the action pods_pre_delete_pod_item_%s instead', 'pods' ), $params->pod ), '2.0.0' );
  3094. foreach ( $pre_delete_helpers as $helper ) {
  3095. $helper = $this->load_helper( array( 'name' => $helper ) );
  3096. if ( false !== $helper )
  3097. eval( '?>' . $helper[ 'code' ] );
  3098. }
  3099. }
  3100. }
  3101. }
  3102. if ( 'table' == $pod[ 'storage' ] )
  3103. pods_query( "DELETE FROM `@wp_pods_{$params->pod}` WHERE `id` = {$params->id} LIMIT 1" );
  3104. if ( $wp && 'taxonomy' == $pod[ 'type' ] ) {
  3105. $taxonomy = $pod[ 'name' ];
  3106. if ( !empty( $pod[ 'object' ] ) )
  3107. $taxonomy = $pod[ 'object' ];
  3108. wp_delete_term( $params->id, $taxonomy );
  3109. }
  3110. elseif ( $wp && !in_array( $pod[ 'type' ], array( 'pod', 'table', '', 'taxonomy' ) ) )
  3111. $this->delete_wp_object( $pod[ 'type' ], $params->id );
  3112. if ( !defined( 'PODS_TABLELESS' ) || !PODS_TABLELESS )
  3113. pods_query( "DELETE FROM `@wp_podsrel` WHERE (`pod_id` = {$params->pod_id} AND `item_id` = {$params->id}) OR (`related_pod_id` = {$params->pod_id} AND `related_item_id` = {$params->id})", false );
  3114. // @todo Delete tableless relationship meta where related
  3115. if ( false === $bypass_helpers ) {
  3116. // Plugin hook
  3117. $this->do_hook( 'post_delete_pod_item', $params, $pod );
  3118. $this->do_hook( "post_delete_pod_item_{$params->pod}", $params, $pod );
  3119. // Call any post-save helpers (if not bypassed)
  3120. if ( !defined( 'PODS_DISABLE_EVAL' ) || !PODS_DISABLE_EVAL ) {
  3121. if ( !empty( $post_delete_helpers ) ) {
  3122. pods_deprecated( sprintf( __( 'Post-delete helpers are deprecated, use the action pods_post_delete_pod_item_%s instead', 'pods' ), $params->pod ), '2.0.0' );
  3123. foreach ( $post_delete_helpers as $helper ) {
  3124. $helper = $this->load_helper( array( 'name' => $helper ) );
  3125. if ( false !== $helper )
  3126. eval( '?>' . $helper[ 'code' ] );
  3127. }
  3128. }
  3129. }
  3130. }
  3131. pods_cache_clear( $params->id, 'pods_items_' . $params->pod );
  3132. return true;
  3133. }
  3134. /**
  3135. * Check if a Pod exists
  3136. *
  3137. * $params['id'] int The datatype ID
  3138. * $params['name'] string The datatype name
  3139. *
  3140. * @param array $params An associative array of parameters
  3141. *
  3142. * @return bool True if exists
  3143. *
  3144. * @since 1.12
  3145. */
  3146. public function pod_exists ( $params ) {
  3147. $params = (object) pods_sanitize( $params );
  3148. if ( !empty( $params->id ) || !empty( $params->name ) ) {
  3149. if ( !isset( $params->name ) )
  3150. $pod = get_post( $dummy = (int) $params->id );
  3151. else {
  3152. $pod = get_posts( array(
  3153. 'name' => $params->name,
  3154. 'post_type' => '_pods_pod',
  3155. 'posts_per_page' => 1
  3156. ) );
  3157. }
  3158. if ( !empty( $pod ) )
  3159. return true;
  3160. }
  3161. return false;
  3162. }
  3163. /**
  3164. * Load a Pod and all of its fields
  3165. *
  3166. * $params['id'] int The Pod ID
  3167. * $params['name'] string The Pod name
  3168. *
  3169. * @param array|object $params An associative array of parameters or pod name as a string
  3170. * @param bool $strict Makes sure the pod exists, throws an error if it doesn't work
  3171. *
  3172. * @return array|bool|mixed|void
  3173. * @since 1.7.9
  3174. */
  3175. public function load_pod ( $params, $strict = true ) {
  3176. /**
  3177. * @var $sitepress SitePress
  3178. */
  3179. global $sitepress, $icl_adjust_id_url_filter_off;
  3180. $current_language = false;
  3181. // WPML support
  3182. if ( is_object( $sitepress ) && !$icl_adjust_id_url_filter_off )
  3183. $current_language = pods_sanitize( ICL_LANGUAGE_CODE );
  3184. // Polylang support
  3185. elseif ( function_exists( 'pll_current_language' ) )
  3186. $current_language = pll_current_language( 'slug' );
  3187. if ( !is_array( $params ) && !is_object( $params ) )
  3188. $params = array( 'name' => $params );
  3189. if ( is_object( $params ) && isset( $params->post_name ) ) {
  3190. $pod = pods_transient_get( 'pods_pod_' . ( !empty( $current_language ) ? $current_language . '_' : '' ) . $params->post_name );
  3191. if ( false !== $pod )
  3192. return $pod;
  3193. $_pod = get_object_vars( $params );
  3194. }
  3195. else {
  3196. $params = (object) pods_sanitize( $params );
  3197. if ( ( !isset( $params->id ) || empty( $params->id ) ) && ( !isset( $params->name ) || empty( $params->name ) ) )
  3198. return pods_error( 'Either Pod ID or Name are required', $this );
  3199. if ( isset( $params->name ) ) {
  3200. $pod = pods_transient_get( 'pods_pod_' . ( !empty( $current_language ) ? $current_language . '_' : '' ) . $params->name );
  3201. if ( false !== $pod )
  3202. return $pod;
  3203. }
  3204. if ( !isset( $params->name ) )
  3205. $pod = get_post( $dummy = (int) $params->id );
  3206. else {
  3207. $pod = get_posts( array(
  3208. 'name' => $params->name,
  3209. 'post_type' => '_pods_pod',
  3210. 'posts_per_page' => 1
  3211. ) );
  3212. }
  3213. if ( empty( $pod ) ) {
  3214. if ( $strict )
  3215. return pods_error( __( 'Pod not found', 'pods' ), $this );
  3216. return false;
  3217. }
  3218. if ( is_array( $pod ) )
  3219. $pod = $pod[ 0 ];
  3220. $_pod = get_object_vars( $pod );
  3221. }
  3222. $transient = 'pods_pod_' . ( !empty( $current_language ) ? $current_language . '_' : '' ) . $_pod[ 'post_name' ];
  3223. $pod = pods_transient_get( $transient );
  3224. if ( false !== $pod ) {
  3225. if ( in_array( $pod[ 'type' ], array( 'post_type', 'taxonomy' ) ) && is_object( $sitepress ) && !$icl_adjust_id_url_filter_off )
  3226. $pod = array_merge( $pod, $this->get_table_info( $pod[ 'type' ], $pod[ 'object' ], $pod[ 'name' ], $pod ) );
  3227. return $pod;
  3228. }
  3229. $pod = array(
  3230. 'id' => $_pod[ 'ID' ],
  3231. 'name' => $_pod[ 'post_name' ],
  3232. 'label' => $_pod[ 'post_title' ],
  3233. 'description' => $_pod[ 'post_content' ]
  3234. );
  3235. if ( strlen( $pod[ 'label' ] ) < 1 )
  3236. $pod[ 'label' ] = $pod[ 'name' ];
  3237. // @todo update with a method to put all options in
  3238. $defaults = array(
  3239. 'show_in_menu' => 1,
  3240. 'type' => 'post_type',
  3241. 'storage' => 'meta',
  3242. 'object' => '',
  3243. 'alias' => ''
  3244. );
  3245. $pod[ 'options' ] = get_post_meta( $pod[ 'id' ] );
  3246. foreach ( $pod[ 'options' ] as $option => &$value ) {
  3247. if ( is_array( $value ) && 1 == count( $value ) && isset( $value[ 0 ] ) )
  3248. $value = $value[ 0 ];
  3249. }
  3250. $pod[ 'options' ] = array_merge( $defaults, $pod[ 'options' ] );
  3251. $pod[ 'type' ] = $pod[ 'options' ][ 'type' ];
  3252. $pod[ 'storage' ] = $pod[ 'options' ][ 'storage' ];
  3253. $pod[ 'object' ] = $pod[ 'options' ][ 'object' ];
  3254. $pod[ 'alias' ] = $pod[ 'options' ][ 'alias' ];
  3255. unset( $pod[ 'options' ][ 'type' ] );
  3256. unset( $pod[ 'options' ][ 'storage' ] );
  3257. unset( $pod[ 'options' ][ 'object' ] );
  3258. unset( $pod[ 'options' ][ 'alias' ] );
  3259. $pod = array_merge( $this->get_table_info( $pod[ 'type' ], $pod[ 'object' ], $pod[ 'name' ], $pod ), $pod );
  3260. $pod[ 'fields' ] = array();
  3261. $pod[ 'object_fields' ] = array();
  3262. if ( 'pod' != $pod[ 'type' ] )
  3263. $pod[ 'object_fields' ] = $this->get_wp_object_fields( $pod[ 'type' ], $pod );
  3264. $fields = get_posts( array(
  3265. 'post_type' => '_pods_field',
  3266. 'posts_per_page' => -1,
  3267. 'nopaging' => true,
  3268. 'post_parent' => $pod[ 'id' ],
  3269. 'orderby' => 'menu_order',
  3270. 'order' => 'ASC'
  3271. ) );
  3272. if ( !empty( $fields ) ) {
  3273. foreach ( $fields as $field ) {
  3274. $field->pod = $pod[ 'name' ];
  3275. $field = $this->load_field( $field );
  3276. $field = PodsForm::field_setup( $field, null, $field[ 'type' ] );
  3277. $pod[ 'fields' ][ $field[ 'name' ] ] = $field;
  3278. }
  3279. }
  3280. if ( did_action( 'init' ) )
  3281. pods_transient_set( $transient, $pod );
  3282. return $pod;
  3283. }
  3284. /**
  3285. * Load a list of Pods based on filters specified.
  3286. *
  3287. * $params['type'] string/array Pod Type(s) to filter by
  3288. * $params['object'] string/array Pod Object(s) to filter by
  3289. * $params['options'] array Pod Option(s) key=>value array to filter by
  3290. * $params['orderby'] string ORDER BY clause of query
  3291. * $params['limit'] string Number of Pods to return
  3292. * $params['where'] string WHERE clause of query
  3293. * $params['ids'] string|array IDs of Objects
  3294. *
  3295. * @param array $params An associative array of parameters
  3296. *
  3297. * @return array|mixed
  3298. *
  3299. * @uses PodsAPI::load_pod
  3300. *
  3301. * @since 2.0.0
  3302. */
  3303. public function load_pods ( $params = null ) {
  3304. /**
  3305. * @var $sitepress SitePress
  3306. */
  3307. global $sitepress, $icl_adjust_id_url_filter_off;
  3308. $current_language = false;
  3309. // WPML support
  3310. if ( is_object( $sitepress ) && !$icl_adjust_id_url_filter_off )
  3311. $current_language = pods_sanitize( ICL_LANGUAGE_CODE );
  3312. // Polylang support
  3313. elseif ( function_exists( 'pll_current_language' ) )
  3314. $current_language = pll_current_language( 'slug' );
  3315. $params = (object) pods_sanitize( $params );
  3316. $order = 'ASC';
  3317. $orderby = 'menu_order title';
  3318. $limit = -1;
  3319. $ids = false;
  3320. $meta_query = array();
  3321. $cache_key = '';
  3322. if ( isset( $params->type ) && !empty( $params->type ) ) {
  3323. if ( !is_array( $params->type ) )
  3324. $params->type = array( trim( $params->type ) );
  3325. sort( $params->type );
  3326. $meta_query[] = array(
  3327. 'key' => 'type',
  3328. 'value' => $params->type,
  3329. 'compare' => 'IN'
  3330. );
  3331. if ( 1 == count( $params->type ) )
  3332. $cache_key .= '_type_' . trim( implode( '', $params->type ) );
  3333. }
  3334. if ( isset( $params->object ) && !empty( $params->object ) ) {
  3335. if ( !is_array( $params->object ) )
  3336. $params->object = array( $params->object );
  3337. $params->object = pods_trim( $params->object );
  3338. sort( $params->object );
  3339. $meta_query[] = array(
  3340. 'key' => 'object',
  3341. 'value' => $params->object,
  3342. 'compare' => 'IN'
  3343. );
  3344. if ( 1 == count( $params->object ) )
  3345. $cache_key .= '_object_' . trim( implode( '', $params->object ) );
  3346. }
  3347. if ( isset( $params->options ) && !empty( $params->options ) && is_array( $params->options ) ) {
  3348. foreach ( $params->options as $option => $value ) {
  3349. if ( !is_array( $value ) )
  3350. $value = array( $value );
  3351. $value = pods_trim( $value );
  3352. sort( $value );
  3353. $meta_query[] = array(
  3354. 'key' => $option,
  3355. 'value' => pods_sanitize( $value ),
  3356. 'compare' => 'IN'
  3357. );
  3358. }
  3359. $cache_key = '';
  3360. }
  3361. if ( isset( $params->where ) && is_array( $params->where ) )
  3362. $meta_query = array_combine( $meta_query, (array) $params->where );
  3363. if ( isset( $params->order ) && !empty( $params->order ) && in_array( strtoupper( $params->order ), array( 'ASC', 'DESC' ) ) )
  3364. $order = strtoupper( $params->order );
  3365. if ( isset( $params->orderby ) && !empty( $params->orderby ) )
  3366. $orderby = strtoupper( $params->orderby );
  3367. if ( isset( $params->limit ) && !empty( $params->limit ) )
  3368. $limit = pods_absint( $params->limit );
  3369. if ( isset( $params->ids ) && !empty( $params->ids ) ) {
  3370. $ids = $params->ids;
  3371. if ( !is_array( $ids ) )
  3372. $ids = explode( ',', $ids );
  3373. }
  3374. if ( empty( $ids ) )
  3375. $ids = false;
  3376. if ( empty( $cache_key ) )
  3377. $cache_key = 'pods' . ( !empty( $current_language ) ? '_' . $current_language : '' );
  3378. else
  3379. $cache_key = 'pods' . ( !empty( $current_language ) ? '_' . $current_language : '' ) . '_get' . $cache_key;
  3380. if ( !empty( $cache_key ) && ( 'pods' . ( !empty( $current_language ) ? '_' . $current_language : '' ) != $cache_key || empty( $meta_query ) ) && $limit < 1 && ( empty( $orderby ) || 'menu_order title' == $orderby ) && empty( $ids ) ) {
  3381. $the_pods = pods_transient_get( $cache_key );
  3382. if ( false !== $the_pods )
  3383. return $the_pods;
  3384. }
  3385. $the_pods = array();
  3386. $pods = get_posts( array(
  3387. 'post_type' => '_pods_pod',
  3388. 'nopaging' => true,
  3389. 'posts_per_page' => $limit,
  3390. 'order' => $order,
  3391. 'orderby' => $orderby,
  3392. 'meta_query' => $meta_query,
  3393. 'post__in' => $ids
  3394. ) );
  3395. foreach ( $pods as $pod ) {
  3396. $pod = $this->load_pod( $pod );
  3397. $the_pods[ $pod[ 'id' ] ] = $pod;
  3398. }
  3399. if ( did_action( 'init' ) && !empty( $cache_key ) && ( 'pods' != $cache_key || empty( $meta_query ) ) && $limit < 1 && ( empty( $orderby ) || 'menu_order title' == $orderby ) && empty( $ids ) )
  3400. pods_transient_set( $cache_key, $the_pods );
  3401. return $the_pods;
  3402. }
  3403. /**
  3404. * Check if a Pod's field exists
  3405. *
  3406. * $params['pod_id'] int The Pod ID
  3407. * $params['id'] int The field ID
  3408. * $params['name'] string The field name
  3409. *
  3410. * @param array $params An associative array of parameters
  3411. *
  3412. * @return bool
  3413. *
  3414. * @since 1.12
  3415. */
  3416. public function field_exists ( $params ) {
  3417. $params = (object) pods_sanitize( $params );
  3418. if ( ( !empty( $params->id ) || !empty( $params->name ) ) && isset( $params->pod_id ) && !empty( $params->pod_id ) ) {
  3419. if ( !isset( $params->name ) )
  3420. $field = get_post( $dummy = (int) $params->id );
  3421. else {
  3422. $field = get_posts( array(
  3423. 'name' => $params->name,
  3424. 'post_type' => '_pods_field',
  3425. 'posts_per_page' => 1,
  3426. 'post_parent' => $params->pod_id
  3427. ) );
  3428. }
  3429. if ( !empty( $field ) )
  3430. return true;
  3431. }
  3432. return false;
  3433. }
  3434. /**
  3435. * Load a field
  3436. *
  3437. * $params['pod_id'] int The Pod ID
  3438. * $params['pod'] string The Pod name
  3439. * $params['id'] int The field ID
  3440. * $params['name'] string The field name
  3441. * $params['table_info'] boolean Whether to lookup a pick field's table info
  3442. *
  3443. * @param array $params An associative array of parameters
  3444. * @param boolean $strict Whether to require a field exist or not when loading the info
  3445. *
  3446. * @return array|bool Array with field data, false if field not found
  3447. * @since 1.7.9
  3448. */
  3449. public function load_field ( $params, $strict = false ) {
  3450. $params = (object) $params;
  3451. if ( !isset( $params->table_info ) )
  3452. $params->table_info = false;
  3453. $pod = array();
  3454. if ( isset( $params->post_title ) )
  3455. $_field = $params;
  3456. elseif ( isset( $params->id ) && !empty( $params->id ) )
  3457. $_field = get_post( $dumb = (int) $params->id );
  3458. else {
  3459. if ( !isset( $params->pod ) )
  3460. $params->pod = '';
  3461. if ( !isset( $params->pod_id ) )
  3462. $params->pod_id = 0;
  3463. if ( isset( $params->pod_data ) )
  3464. $pod = $params->pod_data;
  3465. else {
  3466. $pod = $this->load_pod( array( 'name' => $params->pod, 'id' => $params->pod_id ) );
  3467. if ( false === $pod )
  3468. return pods_error( __( 'Pod not found', 'pods' ), $this );
  3469. }
  3470. $params->pod_id = $pod[ 'id' ];
  3471. $params->pod = $pod[ 'name' ];
  3472. if ( empty( $params->name ) && empty( $params->pod ) && empty( $params->pod_id ) )
  3473. return pods_error( __( 'Either Field Name or Field ID / Pod ID are required', 'pods' ), $this );
  3474. $params->name = pods_clean_name( $params->name, true, ( 'meta' == $pod[ 'storage' ] ? false : true ) );
  3475. if ( isset( $pod[ 'fields' ][ $params->name ] ) && isset( $pod[ 'fields' ][ $params->name ][ 'id' ] ) )
  3476. return $pod[ 'fields' ][ $params->name ];
  3477. $field = get_posts( array(
  3478. 'name' => $params->name,
  3479. 'post_type' => '_pods_field',
  3480. 'posts_per_page' => 1,
  3481. 'post_parent' => $params->pod_id
  3482. ) );
  3483. if ( empty( $field ) ) {
  3484. if ( $strict )
  3485. return pods_error( __( 'Field not found', 'pods' ), $this );
  3486. return false;
  3487. }
  3488. $_field = $field[ 0 ];
  3489. }
  3490. if ( empty( $_field ) ) {
  3491. if ( $strict )
  3492. return pods_error( __( 'Field not found', 'pods' ), $this );
  3493. return false;
  3494. }
  3495. $_field = get_object_vars( $_field );
  3496. $defaults = array(
  3497. 'type' => 'text'
  3498. );
  3499. $field = array(
  3500. 'id' => $_field[ 'ID' ],
  3501. 'name' => $_field[ 'post_name' ],
  3502. 'label' => $_field[ 'post_title' ],
  3503. 'description' => $_field[ 'post_content' ],
  3504. 'weight' => $_field[ 'menu_order' ],
  3505. 'pod_id' => $_field[ 'post_parent' ],
  3506. 'pick_object' => '',
  3507. 'pick_val' => '',
  3508. 'sister_id' => '',
  3509. 'table_info' => array()
  3510. );
  3511. if ( isset( $pod[ 'name' ] ) )
  3512. $field[ 'pod' ] = $pod[ 'name' ];
  3513. elseif ( isset( $_field[ 'pod' ] ) )
  3514. $field[ 'pod' ] = $_field[ 'pod' ];
  3515. else {
  3516. $pod = $this->load_pod( array( 'id' => $field[ 'pod_id' ] ) );
  3517. $field[ 'pod' ] = $pod[ 'name' ];
  3518. }
  3519. $field[ 'options' ] = get_post_meta( $field[ 'id' ] );
  3520. foreach ( $field[ 'options' ] as $option => &$value ) {
  3521. if ( is_array( $value ) && 1 == count( $value ) && isset( $value[ 0 ] ) )
  3522. $value = $value[ 0 ];
  3523. }
  3524. $field[ 'options' ] = array_merge( $defaults, $field[ 'options' ] );
  3525. $field[ 'type' ] = $field[ 'options' ][ 'type' ];
  3526. unset( $field[ 'options' ][ 'type' ] );
  3527. if ( isset( $field[ 'options' ][ 'pick_object' ] ) ) {
  3528. $field[ 'pick_object' ] = $field[ 'options' ][ 'pick_object' ];
  3529. unset( $field[ 'options' ][ 'pick_object' ] );
  3530. }
  3531. if ( isset( $field[ 'options' ][ 'pick_val' ] ) ) {
  3532. $field[ 'pick_val' ] = $field[ 'options' ][ 'pick_val' ];
  3533. unset( $field[ 'options' ][ 'pick_val' ] );
  3534. }
  3535. if ( isset( $field[ 'options' ][ 'sister_id' ] ) ) {
  3536. $field[ 'sister_id' ] = $field[ 'options' ][ 'sister_id' ];
  3537. unset( $field[ 'options' ][ 'sister_id' ] );
  3538. }
  3539. if ( isset( $field[ 'options' ][ 'sister_field_id' ] ) )
  3540. unset( $field[ 'options' ][ 'sister_field_id' ] );
  3541. $field[ 'table_info' ] = array();
  3542. if ( 'pick' == $field[ 'type' ] && true === $params->table_info )
  3543. $field[ 'table_info' ] = $this->get_table_info( $field[ 'pick_object' ], $field[ 'pick_val' ], null, null, $field );
  3544. return $field;
  3545. }
  3546. /**
  3547. * Load fields by Pod, ID, Name, and/or Type
  3548. *
  3549. * $params['pod_id'] int The Pod ID
  3550. * $params['pod'] string The Pod name
  3551. * $params['id'] array The field IDs
  3552. * $params['name'] array The field names
  3553. * $params['type'] array The field types
  3554. *
  3555. * @param array $params An associative array of parameters
  3556. * @param bool $strict Whether to require a field exist or not when loading the info
  3557. *
  3558. * @return array Array of field data.
  3559. *
  3560. * @since 1.7.9
  3561. */
  3562. public function load_fields ( $params, $strict = false ) {
  3563. $params = (object) pods_sanitize( $params );
  3564. if ( !isset( $params->pod ) || empty( $params->pod ) )
  3565. $params->pod = '';
  3566. if ( !isset( $params->pod_id ) || empty( $params->pod_id ) )
  3567. $params->pod_id = 0;
  3568. if ( !isset( $params->name ) || empty( $params->name ) )
  3569. $params->name = array();
  3570. else
  3571. $params->name = (array) $params->name;
  3572. if ( !isset( $params->id ) || empty( $params->id ) )
  3573. $params->id = array();
  3574. else {
  3575. $params->id = (array) $params->id;
  3576. foreach ( $params->id as &$id ) {
  3577. $id = pods_absint( $id );
  3578. }
  3579. }
  3580. if ( !isset( $params->type ) || empty( $params->type ) )
  3581. $params->type = array();
  3582. else
  3583. $params->type = (array) $params->type;
  3584. if ( !empty( $params->pod ) || !empty( $params->pod_id ) ) {
  3585. $pod = $this->load_pod( array( 'name' => $params->pod, 'id' => $params->pod_id ) );
  3586. if ( false === $pod )
  3587. return pods_error( __( 'Pod not found', 'pods' ), $this );
  3588. $fields = array();
  3589. foreach ( $pod[ 'fields' ] as $field ) {
  3590. if ( empty( $params->name ) && empty( $params->id ) && empty( $params->type ) )
  3591. $fields[ $field[ 'name' ] ] = $field;
  3592. if ( in_array( $fields[ 'name' ], $params->name ) || in_array( $fields[ 'id' ], $params->id ) || in_array( $fields[ 'type' ], $params->type ) )
  3593. $fields[ $field[ 'name' ] ] = $field;
  3594. }
  3595. }
  3596. else {
  3597. if ( empty( $params->name ) && empty( $params->id ) && empty( $params->type ) )
  3598. return pods_error( __( 'Either Field Name / Field ID / Field Type, or Pod Name / Pod ID are required', 'pods' ), $this );
  3599. $lookup = array();
  3600. if ( !empty( $params->name ) ) {
  3601. $fields = implode( "', '", $params->name );
  3602. $lookup[] = "`post_name` IN ( '{$fields}' )";
  3603. }
  3604. if ( !empty( $params->id ) ) {
  3605. $fields = implode( ", ", $params->id );
  3606. $lookup[] = "`ID` IN ( {$fields} )";
  3607. }
  3608. $lookup = implode( ' AND ', $lookup );
  3609. $fields = pods_cache_get( md5( $lookup ), 'pods_load_fields' );
  3610. if ( false !== $fields )
  3611. return $fields;
  3612. $result = pods_query( "SELECT `ID`, `post_name`, `post_parent` FROM `@wp_posts` WHERE `post_type` = '_pods_field' AND ( {$lookup} )" );
  3613. $fields = array();
  3614. if ( !empty( $result ) ) {
  3615. foreach ( $result as $field ) {
  3616. $field = $this->load_field( array(
  3617. 'id' => $field->ID,
  3618. 'name' => $field->post_name,
  3619. 'pod_id' => $field->post_parent
  3620. ) );
  3621. if ( empty( $params->type ) || in_array( $field[ 'type' ], $params->type ) )
  3622. $fields[] = $field;
  3623. }
  3624. }
  3625. pods_cache_set( md5( $lookup ), $fields, 'pods_load_fields' );
  3626. }
  3627. return $fields;
  3628. }
  3629. /**
  3630. * Load a Pods Object
  3631. *
  3632. * $params['id'] int The Object ID
  3633. * $params['name'] string The Object name
  3634. * $params['type'] string The Object type
  3635. *
  3636. * @param array|object $params An associative array of parameters
  3637. * @param bool $strict
  3638. *
  3639. * @return array|bool
  3640. * @since 2.0.0
  3641. */
  3642. public function load_object ( $params, $strict = false ) {
  3643. if ( is_object( $params ) && isset( $params->post_name ) ) {
  3644. $type = str_replace( '_pods_', '', $params->post_type );
  3645. $object = pods_transient_get( 'pods_object_' . $type . '_' . $params->post_name );
  3646. if ( false !== $object )
  3647. return $object;
  3648. $_object = get_object_vars( $params );
  3649. }
  3650. else {
  3651. $params = (object) pods_sanitize( $params );
  3652. if ( !isset( $params->type ) || empty( $params->type ) )
  3653. return pods_error( __( 'Object type is required', 'pods' ), $this );
  3654. if ( ( !isset( $params->id ) || empty( $params->id ) ) && ( !isset( $params->name ) || empty( $params->name ) ) )
  3655. return pods_error( __( 'Either Object ID or Name are required', 'pods' ), $this );
  3656. /**
  3657. * @var $wpdb wpdb
  3658. */
  3659. global $wpdb;
  3660. if ( isset( $params->name ) ) {
  3661. $object = pods_transient_get( 'pods_object_' . $params->type . '_' . pods_clean_name( $params->name, true ) );
  3662. if ( false !== $object )
  3663. return $object;
  3664. $sql = "
  3665. SELECT `ID`
  3666. FROM `{$wpdb->posts}`
  3667. WHERE
  3668. `post_type` = %s
  3669. AND `post_status` = 'publish'
  3670. AND `post_title` = %s
  3671. LIMIT 1
  3672. ";
  3673. $object = $wpdb->get_var( $wpdb->prepare( $sql, '_pods_' . $params->type, $params->name) );
  3674. if ( empty( $object ) ) {
  3675. if ( $strict )
  3676. return pods_error( __( 'Object not found', 'pods' ), $this );
  3677. return false;
  3678. }
  3679. }
  3680. else
  3681. $object = $params->id;
  3682. $_object = get_post( $object );
  3683. if ( empty( $_object ) ) {
  3684. if ( $strict )
  3685. return pods_error( __( 'Object not found', 'pods' ), $this );
  3686. return false;
  3687. }
  3688. $_object = get_object_vars( $_object );
  3689. }
  3690. $object = array(
  3691. 'id' => $_object[ 'ID' ],
  3692. 'name' => $_object[ 'post_title' ],
  3693. 'code' => $_object[ 'post_content' ],
  3694. 'type' => str_replace( '_pods_', '', $_object[ 'post_type' ] ),
  3695. 'slug' => $_object[ 'post_name' ]
  3696. );
  3697. $object[ 'options' ] = get_post_meta( $object[ 'id' ] );
  3698. foreach ( $object[ 'options' ] as $option => &$value ) {
  3699. if ( is_array( $value ) && 1 == count( $value ) && isset( $value[ 0 ] ) )
  3700. $value = $value[ 0 ];
  3701. }
  3702. pods_transient_set( 'pods_object_' . $object[ 'type' ] . '_' . $object[ 'slug' ], $object );
  3703. return $object;
  3704. }
  3705. /**
  3706. * Load Multiple Pods Objects
  3707. *
  3708. * $params['type'] string The Object type
  3709. * $params['options'] array Pod Option(s) key=>value array to filter by
  3710. * $params['orderby'] string ORDER BY clause of query
  3711. * $params['limit'] string Number of objects to return
  3712. * $params['where'] string WHERE clause of query
  3713. * $params['ids'] string|array IDs of Objects
  3714. *
  3715. * @param array|object $params An associative array of parameters
  3716. *
  3717. * @return array
  3718. * @since 2.0.0
  3719. */
  3720. public function load_objects ( $params ) {
  3721. $params = (object) pods_sanitize( $params );
  3722. if ( !isset( $params->type ) || empty( $params->type ) )
  3723. return pods_error( __( 'Pods Object type is required', 'pods' ), $this );
  3724. $order = 'ASC';
  3725. $orderby = 'menu_order';
  3726. $limit = -1;
  3727. $ids = false;
  3728. $meta_query = array();
  3729. $cache_key = '';
  3730. if ( isset( $params->options ) && !empty( $params->options ) && is_array( $params->options ) ) {
  3731. foreach ( $params->options as $option => $value ) {
  3732. if ( !is_array( $value ) )
  3733. $value = array( $value );
  3734. $value = pods_trim( $value );
  3735. sort( $value );
  3736. $meta_query[] = array(
  3737. 'key' => $option,
  3738. 'value' => pods_sanitize( $value ),
  3739. 'compare' => 'IN'
  3740. );
  3741. }
  3742. $cache_key = '';
  3743. }
  3744. if ( isset( $params->where ) && is_array( $params->where ) )
  3745. $meta_query = array_combine( $meta_query, (array) $params->where );
  3746. if ( isset( $params->order ) && !empty( $params->order ) && in_array( strtoupper( $params->order ), array( 'ASC', 'DESC' ) ) )
  3747. $order = strtoupper( $params->order );
  3748. if ( isset( $params->orderby ) && !empty( $params->orderby ) )
  3749. $orderby = strtoupper( $params->orderby );
  3750. if ( isset( $params->limit ) && !empty( $params->limit ) )
  3751. $limit = pods_absint( $params->limit );
  3752. if ( isset( $params->ids ) && !empty( $params->ids ) ) {
  3753. $ids = $params->ids;
  3754. if ( !is_array( $ids ) )
  3755. $ids = explode( ',', $ids );
  3756. }
  3757. if ( empty( $ids ) )
  3758. $ids = false;
  3759. if ( empty( $cache_key ) )
  3760. $cache_key = 'pods_objects_' . $params->type;
  3761. else
  3762. $cache_key = 'pods_objects_' . $params->type . '_get' . $cache_key;
  3763. if ( ( 'pods_objects_' . $params->type != $cache_key || empty( $meta_query ) ) && empty( $limit ) && ( empty( $orderby ) || 'menu_order' == $orderby ) && empty( $ids ) ) {
  3764. $the_objects = pods_transient_get( $cache_key );
  3765. if ( false !== $the_objects )
  3766. return $the_objects;
  3767. }
  3768. $the_objects = array();
  3769. $objects = get_posts( array(
  3770. 'post_type' => '_pods_' . $params->type,
  3771. 'nopaging' => true,
  3772. 'posts_per_page' => $limit,
  3773. 'order' => $order,
  3774. 'orderby' => $orderby,
  3775. 'meta_query' => $meta_query,
  3776. 'post__in' => $ids
  3777. ) );
  3778. foreach ( $objects as $object ) {
  3779. $object = $this->load_object( $object );
  3780. $the_objects[ $object[ 'name' ] ] = $object;
  3781. }
  3782. if ( ( 'pods_objects_' . $params->type != $cache_key || empty( $meta_query ) ) && empty( $limit ) && ( empty( $orderby ) || 'menu_order' == $orderby ) && empty( $ids ) )
  3783. pods_transient_set( $cache_key, $the_objects );
  3784. return $the_objects;
  3785. }
  3786. /**
  3787. * @see PodsAPI::load_object
  3788. *
  3789. * Load a Pod Template
  3790. *
  3791. * $params['id'] int The template ID
  3792. * $params['name'] string The template name
  3793. *
  3794. * @param array $params An associative array of parameters
  3795. *
  3796. * @return array|bool
  3797. * @since 1.7.9
  3798. */
  3799. public function load_template ( $params ) {
  3800. if ( !class_exists( 'Pods_Templates' ) )
  3801. return false;
  3802. $params = (object) $params;
  3803. $params->type = 'template';
  3804. return $this->load_object( $params );
  3805. }
  3806. /**
  3807. * @see PodsAPI::load_objects
  3808. *
  3809. * Load Multiple Pod Templates
  3810. *
  3811. * $params['where'] string The WHERE clause of query
  3812. * $params['options'] array Pod Option(s) key=>value array to filter by
  3813. * $params['orderby'] string ORDER BY clause of query
  3814. * $params['limit'] string Number of templates to return
  3815. *
  3816. * @param array $params (optional) An associative array of parameters
  3817. * @return array
  3818. */
  3819. public function load_templates ( $params = null ) {
  3820. if ( !class_exists( 'Pods_Templates' ) )
  3821. return array();
  3822. $params = (object) $params;
  3823. $params->type = 'template';
  3824. return $this->load_objects( $params );
  3825. }
  3826. /**
  3827. * @see PodsAPI::load_object
  3828. *
  3829. * Load a Pod Page
  3830. *
  3831. * $params['id'] int The page ID
  3832. * $params['name'] string The page URI
  3833. *
  3834. * @param array $params An associative array of parameters
  3835. *
  3836. * @return array|bool
  3837. * @since 1.7.9
  3838. */
  3839. public function load_page ( $params ) {
  3840. if ( !class_exists( 'Pods_Pages' ) )
  3841. return false;
  3842. $params = (object) $params;
  3843. if ( !isset( $params->name ) && isset( $params->uri ) ) {
  3844. $params->name = $params->uri;
  3845. unset( $params->uri );
  3846. }
  3847. $params->type = 'page';
  3848. return $this->load_object( $params );
  3849. }
  3850. /**
  3851. * @see PodsAPI::load_objects
  3852. *
  3853. * Load Multiple Pod Pages
  3854. *
  3855. * $params['where'] string The WHERE clause of query
  3856. * $params['options'] array Pod Option(s) key=>value array to filter by
  3857. * $params['orderby'] string ORDER BY clause of query
  3858. * $params['limit'] string Number of pages to return
  3859. *
  3860. * @param array $params (optional) An associative array of parameters
  3861. * @return array
  3862. */
  3863. public function load_pages ( $params = null ) {
  3864. if ( !class_exists( 'Pods_Pages' ) )
  3865. return array();
  3866. $params = (object) $params;
  3867. $params->type = 'page';
  3868. return $this->load_objects( $params );
  3869. }
  3870. /**
  3871. * @see PodsAPI::load_object
  3872. *
  3873. * Load a Pod Helper
  3874. *
  3875. * $params['id'] int The helper ID
  3876. * $params['name'] string The helper name
  3877. *
  3878. * @param array $params An associative array of parameters
  3879. *
  3880. * @return array|bool
  3881. * @since 1.7.9
  3882. */
  3883. public function load_helper ( $params ) {
  3884. if ( !class_exists( 'Pods_Helpers' ) )
  3885. return false;
  3886. $params = (object) $params;
  3887. $params->type = 'helper';
  3888. return $this->load_object( $params );
  3889. }
  3890. /**
  3891. * @see PodsAPI::load_objects
  3892. *
  3893. * Load Multiple Pod Helpers
  3894. *
  3895. * $params['where'] string The WHERE clause of query
  3896. * $params['options'] array Pod Option(s) key=>value array to filter by
  3897. * $params['orderby'] string ORDER BY clause of query
  3898. * $params['limit'] string Number of pages to return
  3899. *
  3900. * @param array $params (optional) An associative array of parameters
  3901. * @return array
  3902. */
  3903. public function load_helpers ( $params = null ) {
  3904. if ( !class_exists( 'Pods_Helpers' ) )
  3905. return array();
  3906. $params = (object) $params;
  3907. $params->type = 'helper';
  3908. return $this->load_objects( $params );
  3909. }
  3910. /**
  3911. * Load the pod item object
  3912. *
  3913. * $params['pod'] string The datatype name
  3914. * $params['id'] int (optional) The item's ID
  3915. *
  3916. * @param array $params An associative array of parameters
  3917. *
  3918. * @return bool|\Pods
  3919. *
  3920. * @uses pods()
  3921. *
  3922. * @since 2.0.0
  3923. */
  3924. public function load_pod_item ( $params ) {
  3925. $params = (object) pods_sanitize( $params );
  3926. if ( !isset( $params->pod ) || empty( $params->pod ) )
  3927. return pods_error( __( 'Pod name required', 'pods' ), $this );
  3928. if ( !isset( $params->id ) || empty( $params->id ) )
  3929. return pods_error( __( 'Item ID required', 'pods' ), $this );
  3930. $pod = pods_cache_get( $params->id, 'pods_items_' . $params->pod );
  3931. if ( false !== $pod )
  3932. return $pod;
  3933. $pod = pods( $params->pod, $params->id );
  3934. pods_cache_set( $params->id, $pod, 'pods_items_' . $params->pod );
  3935. return $pod;
  3936. }
  3937. /**
  3938. * Load potential sister fields for a specific field
  3939. *
  3940. * $params['pod'] int The Pod name
  3941. * $params['related_pod'] string The related Pod name
  3942. *
  3943. * @param array $params An associative array of parameters
  3944. * @param array $pod (optional) Array of Pod data to use (to avoid lookup)
  3945. *
  3946. * @return array|bool
  3947. * @since 1.7.9
  3948. *
  3949. * @uses PodsAPI::load_pod
  3950. */
  3951. public function load_sister_fields ( $params, $pod = null ) {
  3952. $params = (object) pods_sanitize( $params );
  3953. if ( empty( $pod ) ) {
  3954. $pod = $this->load_pod( array( 'name' => $params->pod ), false );
  3955. if ( false === $pod )
  3956. return pods_error( __( 'Pod not found', 'pods' ), $this );
  3957. }
  3958. $params->pod_id = $pod[ 'id' ];
  3959. $params->pod = $pod[ 'name' ];
  3960. $type = false;
  3961. if ( 0 === strpos( $params->related_pod, 'pod-' ) ) {
  3962. $params->related_pod = pods_str_replace( 'pod-', '', $params->related_pod, 1 );
  3963. $type = 'pod';
  3964. }
  3965. elseif ( 0 === strpos( $params->related_pod, 'post_type-' ) ) {
  3966. $params->related_pod = pods_str_replace( 'post_type-', '', $params->related_pod, 1 );
  3967. $type = 'post_type';
  3968. }
  3969. elseif ( 0 === strpos( $params->related_pod, 'taxonomy-' ) ) {
  3970. $params->related_pod = pods_str_replace( 'taxonomy-', '', $params->related_pod, 1 );
  3971. $type = 'taxonomy';
  3972. }
  3973. $related_pod = $this->load_pod( array( 'name' => $params->related_pod ), false );
  3974. if ( false === $related_pod || ( false !== $type && 'pod' != $type && $type != $related_pod[ 'type' ] ) )
  3975. return pods_error( __( 'Related Pod not found', 'pods' ), $this );
  3976. $params->related_pod_id = $related_pod[ 'id' ];
  3977. $params->related_pod = $related_pod[ 'name' ];
  3978. $sister_fields = array();
  3979. foreach ( $related_pod[ 'fields' ] as $field ) {
  3980. if ( 'pick' == $field[ 'type' ] && in_array( $field[ 'pick_object' ], array( $pod[ 'type' ], 'pod' ) ) && $params->pod == $field[ 'pick_val' ] )
  3981. $sister_fields[ $field[ 'id' ] ] = esc_html( $field[ 'label' ] . ' (' . $field[ 'name' ] . ')' );
  3982. }
  3983. return $sister_fields;
  3984. }
  3985. /**
  3986. * Takes a sql field such as tinyint and returns the pods field type, such as num.
  3987. *
  3988. * @param string $sql_field The SQL field to look for
  3989. *
  3990. * @return string The field type
  3991. *
  3992. * @since 2.0.0
  3993. */
  3994. public static function detect_pod_field_from_sql_data_type ( $sql_field ) {
  3995. $sql_field = strtolower( $sql_field );
  3996. $field_to_field_map = array(
  3997. 'tinyint' => 'number',
  3998. 'smallint' => 'number',
  3999. 'mediumint' => 'number',
  4000. 'int' => 'number',
  4001. 'bigint' => 'number',
  4002. 'float' => 'number',
  4003. 'double' => 'number',
  4004. 'decimal' => 'number',
  4005. 'date' => 'date',
  4006. 'datetime' => 'datetime',
  4007. 'timestamp' => 'datetime',
  4008. 'time' => 'time',
  4009. 'year' => 'date',
  4010. 'varchar' => 'text',
  4011. 'text' => 'paragraph',
  4012. 'mediumtext' => 'paragraph',
  4013. 'longtext' => 'paragraph'
  4014. );
  4015. return ( array_key_exists( $sql_field, $field_to_field_map ) ) ? $field_to_field_map[ $sql_field ] : 'paragraph';
  4016. }
  4017. /**
  4018. * Gets all field types
  4019. *
  4020. * @return array Array of field types
  4021. *
  4022. * @uses PodsForm::field_loader
  4023. *
  4024. * @since 2.0.0
  4025. * @deprecated
  4026. */
  4027. public function get_field_types () {
  4028. return PodsForm::field_types();
  4029. }
  4030. /**
  4031. * Gets the schema definition of a field.
  4032. *
  4033. * @param string $type Field type to look for
  4034. * @param array $options (optional) Options of the field to pass to the schema function.
  4035. *
  4036. * @return array|bool|mixed|null
  4037. *
  4038. * @since 2.0.0
  4039. */
  4040. private function get_field_definition ( $type, $options = null ) {
  4041. $definition = PodsForm::field_method( $type, 'schema', $options );
  4042. return $this->do_hook( 'field_definition', $definition, $type, $options );
  4043. }
  4044. /**
  4045. * @see PodsForm:validate
  4046. *
  4047. * Validates the value of a field.
  4048. *
  4049. * @param mixed $value The value to validate
  4050. * @param string $field Field to use for validation
  4051. * @param array $object_fields Fields of the object we're validating
  4052. * @param array $fields Array of all fields data
  4053. * @param array $pod Array of pod data
  4054. * @param array|object $params Extra parameters to pass to the validation function of the field.
  4055. *
  4056. * @return array|bool
  4057. *
  4058. * @uses PodsForm::validate
  4059. *
  4060. * @since 2.0.0
  4061. */
  4062. public function handle_field_validation ( &$value, $field, $object_fields, $fields, $pod, $params ) {
  4063. $tableless_field_types = apply_filters( 'pods_tableless_field_types', array( 'pick', 'file', 'avatar', 'taxonomy' ) );
  4064. $fields = array_merge( $fields, $object_fields );
  4065. $options = $fields[ $field ];
  4066. $id = ( is_object( $params ) ? $params->id : ( is_object( $pod ) ? $pod->id() : 0 ) );
  4067. if ( is_object( $pod ) )
  4068. $pod = $pod->pod_data;
  4069. $type = $options[ 'type' ];
  4070. $label = $options[ 'label' ];
  4071. $label = empty( $label ) ? $field : $label;
  4072. // Verify required fields
  4073. if ( 1 == pods_var( 'required', $options[ 'options' ], 0 ) ) {
  4074. if ( '' == $value || null === $value )
  4075. return pods_error( sprintf( __( '%s is empty', 'pods' ), $label ), $this );
  4076. if ( 'multi' == pods_var( 'pick_format_type', $options[ 'options' ] ) && 'autocomplete' != pods_var( 'pick_format_multi', $options[ 'options' ] ) ) {
  4077. $has_value = false;
  4078. $check_value = (array) $value;
  4079. foreach ( $check_value as $val ) {
  4080. if ( '' != $val && null !== $val && 0 != $val )
  4081. $has_value = true;
  4082. }
  4083. if ( !$has_value )
  4084. return pods_error( sprintf( __( '%s is required', 'pods' ), $label ), $this );
  4085. }
  4086. }
  4087. // Verify unique fields
  4088. if ( 1 == pods_var( 'unique', $options[ 'options' ], 0 ) ) {
  4089. if ( empty( $pod ) )
  4090. return false;
  4091. if ( !in_array( $type, $tableless_field_types ) ) {
  4092. $exclude = '';
  4093. if ( !empty( $id ) )
  4094. $exclude = "AND `id` != {$id}";
  4095. $check = false;
  4096. $check_value = pods_sanitize( $value );
  4097. // Trigger an error if not unique
  4098. if ( 'table' == $pod[ 'storage' ] )
  4099. $check = pods_query( "SELECT `id` FROM `@wp_pods_" . $pod[ 'name' ] . "` WHERE `{$field}` = '{$check_value}' {$exclude} LIMIT 1", $this );
  4100. if ( !empty( $check ) )
  4101. return pods_error( sprintf( __( '%s needs to be unique', 'pods' ), $label ), $this );
  4102. }
  4103. else {
  4104. // @todo handle tableless check
  4105. }
  4106. }
  4107. $validate = PodsForm::validate( $options[ 'type' ], $value, $field, array_merge( pods_var( 'options', $options, array() ), $options ), $fields, $pod, $id, $params );
  4108. $validate = $this->do_hook( 'field_validation', $validate, $value, $field, $object_fields, $fields, $pod, $params );
  4109. return $validate;
  4110. }
  4111. /**
  4112. * Find items related to a parent field
  4113. *
  4114. * @param int $field_id The Field ID
  4115. * @param int $pod_id The Pod ID
  4116. * @param mixed $ids A comma-separated string (or array) of item IDs
  4117. * @param array $field Field data array
  4118. * @param array $pod Pod data array
  4119. *
  4120. * @return array|bool
  4121. *
  4122. * @since 2.0.0
  4123. *
  4124. * @uses pods_query()
  4125. */
  4126. public function lookup_related_items ( $field_id, $pod_id, $ids, $field = null, $pod = null ) {
  4127. if ( !is_array( $ids ) )
  4128. $ids = explode( ',', $ids );
  4129. $tableless_field_types = apply_filters( 'pods_tableless_field_types', array( 'pick', 'file', 'avatar', 'taxonomy' ) );
  4130. if ( empty( $ids ) || !in_array( pods_var( 'type', $field ), $tableless_field_types ) )
  4131. return false;
  4132. if ( !defined( 'PODS_TABLELESS' ) || !PODS_TABLELESS ) {
  4133. foreach ( $ids as &$id ) {
  4134. $id = (int) $id;
  4135. }
  4136. $ids = implode( ', ', $ids );
  4137. $field_id = (int) $field_id;
  4138. $sister_id = (int) pods_var_raw( 'sister_id', $field, 0 );
  4139. $related_where = "
  4140. `field_id` = {$field_id}
  4141. AND `item_id` IN ( {$ids} )
  4142. ";
  4143. $sql = "
  4144. SELECT *
  4145. FROM `@wp_podsrel`
  4146. WHERE
  4147. {$related_where}
  4148. ORDER BY `weight`
  4149. ";
  4150. $relationships = pods_query( $sql );
  4151. if ( !empty( $relationships ) ) {
  4152. $related_ids = array();
  4153. foreach ( $relationships as $relation ) {
  4154. if ( $field_id == $relation->field_id && !in_array( $relation->related_item_id, $related_ids ) )
  4155. $related_ids[] = (int) $relation->related_item_id;
  4156. elseif ( 0 < $sister_id && $field_id == $relation->related_field_id && !in_array( $relation->item_id, $related_ids ) )
  4157. $related_ids[] = (int) $relation->item_id;
  4158. }
  4159. $related_ids = array_unique( array_filter( $related_ids ) );
  4160. return $related_ids;
  4161. }
  4162. }
  4163. else {
  4164. if ( !is_array( $pod ) )
  4165. $pod = $this->load_pod( array( 'id' => $pod_id ), false );
  4166. if ( !empty( $pod ) && in_array( $pod[ 'type' ], array( 'post_type', 'media', 'user', 'comment' ) ) ) {
  4167. $related_ids = array();
  4168. $meta_type = $pod[ 'type' ];
  4169. if ( in_array( $pod[ 'type' ], array( 'post_type', 'media' ) ) )
  4170. $meta_type = 'post';
  4171. $no_conflict = pods_no_conflict_check( $meta_type );
  4172. if ( !$no_conflict )
  4173. pods_no_conflict_on( $meta_type );
  4174. foreach ( $ids as $id ) {
  4175. $related_id = get_metadata( $meta_type, $id, '_pods_' . $field[ 'name' ], true );
  4176. if ( empty( $related_id ) )
  4177. $related_id = get_metadata( $meta_type, $id, $field[ 'name' ], true );
  4178. if ( is_array( $related_id ) && !empty( $related_id ) ) {
  4179. foreach ( $related_id as $related ) {
  4180. if ( is_array( $related ) && !empty( $related ) ) {
  4181. foreach ( $related as $r ) {
  4182. $related_ids[] = (int) $r;
  4183. }
  4184. }
  4185. else
  4186. $related_ids[] = (int) $related;
  4187. }
  4188. }
  4189. }
  4190. if ( !$no_conflict )
  4191. pods_no_conflict_off( $meta_type );
  4192. $related_ids = array_unique( array_filter( $related_ids ) );
  4193. return $related_ids;
  4194. }
  4195. }
  4196. return false;
  4197. }
  4198. /**
  4199. * Get information about an objects MySQL table
  4200. *
  4201. * @param string $object_type
  4202. * @param string $object The object to look for
  4203. * @param null $name (optional) Name of the pod to load
  4204. * @param array $pod (optional) Array with pod information
  4205. * @param array $field (optional) Array with field information
  4206. *
  4207. * @return array|bool
  4208. *
  4209. * @since 2.0.0
  4210. */
  4211. public function get_table_info ( $object_type, $object, $name = null, $pod = null, $field = null ) {
  4212. /**
  4213. * @var $wpdb wpdb
  4214. * @var $sitepress SitePress
  4215. * @var $icl_adjust_id_url_filter_off boolean
  4216. */
  4217. global $wpdb, $sitepress, $icl_adjust_id_url_filter_off, $polylang;
  4218. $info = array(
  4219. //'select' => '`t`.*',
  4220. 'object_type' => null,
  4221. 'type' => null,
  4222. 'table' => $object,
  4223. 'meta_table' => $object,
  4224. 'pod_table' => $object,
  4225. 'field_id' => 'id',
  4226. 'field_index' => 'name',
  4227. 'field_slug' => null,
  4228. 'field_type' => null,
  4229. 'meta_field_id' => 'id',
  4230. 'meta_field_index' => 'name',
  4231. 'meta_field_value' => 'name',
  4232. 'pod_field_id' => 'id',
  4233. 'pod_field_index' => 'name',
  4234. 'join' => array(),
  4235. 'where' => null,
  4236. 'where_default' => null,
  4237. 'orderby' => null,
  4238. 'pod' => null,
  4239. 'recurse' => false
  4240. );
  4241. if ( empty( $object_type ) ) {
  4242. $object_type = 'post_type';
  4243. $object = 'post';
  4244. }
  4245. $pod_name = $pod;
  4246. if ( is_array( $pod_name ) )
  4247. $pod_name = pods_var_raw( 'name', $pod_name, ( version_compare( PHP_VERSION, '5.4.0', '>=' ) ? json_encode( $pod_name, JSON_UNESCAPED_UNICODE ) : json_encode( $pod_name ) ), null, true );
  4248. $field_name = $field;
  4249. if ( is_array( $field_name ) )
  4250. $field_name = pods_var_raw( 'name', $field_name, ( version_compare( PHP_VERSION, '5.4.0', '>=' ) ? json_encode( $pod_name, JSON_UNESCAPED_UNICODE ) : json_encode( $field_name ) ), null, true );
  4251. $transient = 'pods_get_table_info_' . md5( $object_type . '_object_' . $object . '_name_' . $name . '_pod_' . $pod_name . '_field_' . $field_name );
  4252. $current_language = false;
  4253. $current_language_t_id = $current_language_tt_id = 0;
  4254. // WPML support
  4255. if ( is_object( $sitepress ) && !$icl_adjust_id_url_filter_off )
  4256. $current_language = pods_sanitize( ICL_LANGUAGE_CODE );
  4257. // Polylang support
  4258. elseif ( is_object( $polylang ) && function_exists( 'pll_current_language' ) ) {
  4259. $current_language = pods_sanitize( pll_current_language( 'slug' ) );
  4260. if ( !empty( $current_language ) ) {
  4261. $current_language_t_id = (int) $polylang->get_language( $current_language )->term_id;
  4262. $current_language_tt_id = (int) $polylang->get_language( $current_language )->term_taxonomy_id;
  4263. }
  4264. }
  4265. if ( !empty( $current_language ) )
  4266. $transient = 'pods_get_table_info_' . $current_language . '_' . md5( $object_type . '_object_' . $object . '_name_' . $name . '_pod_' . $pod_name . '_field_' . $field_name );
  4267. $_info = pods_transient_get( $transient );
  4268. if ( false !== $_info )
  4269. $info = $_info;
  4270. else {
  4271. if ( 'pod' == $object_type && null === $pod ) {
  4272. if ( empty( $name ) ) {
  4273. $prefix = 'pod-';
  4274. // Make sure we actually have the prefix before trying anything with the name
  4275. if ( 0 === strpos( $object_type, $prefix ) )
  4276. $name = substr( $object_type, strlen( $prefix ), strlen( $object_type ) );
  4277. }
  4278. if ( empty( $name ) && !empty( $object ) )
  4279. $name = $object;
  4280. $pod = $this->load_pod( array( 'name' => $name ), false );
  4281. if ( !empty( $pod ) ) {
  4282. $object_type = $pod[ 'type' ];
  4283. $name = $pod[ 'name' ];
  4284. $object = $pod[ 'object' ];
  4285. $info[ 'pod' ] = $pod;
  4286. }
  4287. }
  4288. elseif ( null === $pod ) {
  4289. if ( empty( $name ) ) {
  4290. $prefix = $object_type . '-';
  4291. // Make sure we actually have the prefix before trying anything with the name
  4292. if ( 0 === strpos( $object_type, $prefix ) )
  4293. $name = substr( $object_type, strlen( $prefix ), strlen( $object_type ) );
  4294. }
  4295. if ( empty( $name ) && !empty( $object ) )
  4296. $name = $object;
  4297. if ( !empty( $name ) ) {
  4298. $pod = $this->load_pod( array( 'name' => $name ), false );
  4299. if ( !empty( $pod ) && $object_type == $pod[ 'type' ] ) {
  4300. $object_type = $pod[ 'type' ];
  4301. $name = $pod[ 'name' ];
  4302. $object = $pod[ 'object' ];
  4303. $info[ 'pod' ] = $pod;
  4304. }
  4305. }
  4306. }
  4307. if ( 0 === strpos( $object_type, 'pod' ) ) {
  4308. if ( empty( $name ) ) {
  4309. $prefix = 'pod-';
  4310. // Make sure we actually have the prefix before trying anything with the name
  4311. if ( 0 === strpos( $object_type, $prefix ) )
  4312. $name = substr( $object_type, strlen( $prefix ), strlen( $object_type ) );
  4313. }
  4314. $object_type = 'pod';
  4315. $info[ 'table' ] = $info[ 'meta_table' ] = $wpdb->prefix . 'pods_' . ( empty( $object ) ? $name : $object );
  4316. if ( is_array( $pod ) ) {
  4317. if ( isset( $pod[ 'options' ] ) && 'pod' == pods_var( 'type', $pod ) )
  4318. $info[ 'field_index' ] = $info[ 'meta_field_index' ] = $info[ 'meta_field_value' ] = pods_var( 'pod_index', $pod[ 'options' ], 'id', null, true );
  4319. $slug_field = get_posts( array(
  4320. 'post_type' => '_pods_field',
  4321. 'posts_per_page' => 1,
  4322. 'nopaging' => true,
  4323. 'post_parent' => $pod[ 'id' ],
  4324. 'orderby' => 'menu_order',
  4325. 'order' => 'ASC',
  4326. 'meta_query' => array(
  4327. array(
  4328. 'key' => 'type',
  4329. 'value' => 'slug',
  4330. )
  4331. )
  4332. ) );
  4333. if ( !empty( $slug_field ) ) {
  4334. $slug_field = $slug_field[ 0 ];
  4335. $info[ 'field_slug' ] = $slug_field->post_name;
  4336. }
  4337. }
  4338. }
  4339. elseif ( 0 === strpos( $object_type, 'post_type' ) || 'media' == $object_type ) {
  4340. $info[ 'table' ] = $wpdb->posts;
  4341. $info[ 'meta_table' ] = $wpdb->postmeta;
  4342. $info[ 'field_id' ] = 'ID';
  4343. $info[ 'field_index' ] = 'post_title';
  4344. $info[ 'field_slug' ] = 'post_name';
  4345. $info[ 'field_type' ] = 'post_type';
  4346. $info[ 'meta_field_id' ] = 'post_id';
  4347. $info[ 'meta_field_index' ] = 'meta_key';
  4348. $info[ 'meta_field_value' ] = 'meta_value';
  4349. if ( 'media' == $object_type )
  4350. $object = 'attachment';
  4351. if ( empty( $name ) ) {
  4352. $prefix = 'post_type-';
  4353. // Make sure we actually have the prefix before trying anything with the name
  4354. if ( 0 === strpos( $object_type, $prefix ) )
  4355. $name = substr( $object_type, strlen( $prefix ), strlen( $object_type ) );
  4356. }
  4357. if ( 'media' != $object_type )
  4358. $object_type = 'post_type';
  4359. $post_type = pods_sanitize( ( empty( $object ) ? $name : $object ) );
  4360. $info[ 'where' ] = array(
  4361. //'post_status' => '`t`.`post_status` IN ( "inherit", "publish" )', // @todo Figure out what statuses Attachments can be
  4362. 'post_type' => '`t`.`' . $info[ 'field_type' ] . '` = "' . $post_type . '"'
  4363. );
  4364. if ( 'post_type' == $object_type )
  4365. $info[ 'where_default' ] = '`t`.`post_status` = "publish"';
  4366. $info[ 'orderby' ] = '`t`.`menu_order`, `t`.`' . $info[ 'field_index' ] . '`, `t`.`post_date`';
  4367. // WPML support
  4368. if ( is_object( $sitepress ) && $sitepress->is_translated_post_type( $post_type ) && !$icl_adjust_id_url_filter_off ) {
  4369. $info[ 'join' ][ 'wpml_translations' ] = "
  4370. LEFT JOIN `{$wpdb->prefix}icl_translations` AS `wpml_translations`
  4371. ON `wpml_translations`.`element_id` = `t`.`ID`
  4372. AND `wpml_translations`.`element_type` = 'post_{$post_type}'
  4373. AND `wpml_translations`.`language_code` = '{$current_language}'
  4374. ";
  4375. $info[ 'join' ][ 'wpml_languages' ] = "
  4376. LEFT JOIN `{$wpdb->prefix}icl_languages` AS `wpml_languages`
  4377. ON `wpml_languages`.`code` = `wpml_translations`.`language_code` AND `wpml_languages`.`active` = 1
  4378. ";
  4379. $info[ 'where' ][ 'wpml_languages' ] = "`wpml_languages`.`code` IS NOT NULL";
  4380. }
  4381. // Polylang support
  4382. elseif( is_object( $polylang ) && !empty( $current_language ) && function_exists( 'pll_is_translated_post_type' ) && pll_is_translated_post_type( $post_type ) ) {
  4383. $info[ 'join' ][ 'polylang_languages' ] = "
  4384. LEFT JOIN `{$wpdb->term_relationships}` AS `polylang_languages`
  4385. ON `polylang_languages`.`object_id` = `t`.`ID`
  4386. AND `polylang_languages`.`term_taxonomy_id` = {$current_language_tt_id}
  4387. ";
  4388. $info[ 'where' ][ 'polylang_languages' ] = "`polylang_languages`.`object_id` IS NOT NULL";
  4389. }
  4390. $info[ 'object_fields' ] = $this->get_wp_object_fields( $object_type, $pod );
  4391. }
  4392. elseif ( 0 === strpos( $object_type, 'taxonomy' ) || in_array( $object_type, array( 'nav_menu', 'post_format' ) ) ) {
  4393. $info[ 'table' ] = $info[ 'meta_table' ] = $wpdb->terms;
  4394. $info[ 'join' ][ 'tt' ] = "LEFT JOIN `{$wpdb->term_taxonomy}` AS `tt` ON `tt`.`term_id` = `t`.`term_id`";
  4395. $info[ 'field_id' ] = $info[ 'meta_field_id' ] = 'term_id';
  4396. $info[ 'field_index' ] = $info[ 'meta_field_index' ] = $info[ 'meta_field_value' ] = 'name';
  4397. $info[ 'field_slug' ] = 'slug';
  4398. $info[ 'field_type' ] = 'taxonomy';
  4399. if ( 'nav_menu' == $object_type )
  4400. $object = 'nav_menu';
  4401. elseif ( 'post_format' == $object_type )
  4402. $object = 'post_format';
  4403. if ( empty( $name ) ) {
  4404. $prefix = 'taxonomy-';
  4405. // Make sure we actually have the prefix before trying anything with the name
  4406. if ( 0 === strpos( $object_type, $prefix ) )
  4407. $name = substr( $object_type, strlen( $prefix ), strlen( $object_type ) );
  4408. }
  4409. if ( !in_array( $object_type, array( 'nav_menu', 'post_format' ) ) )
  4410. $object_type = 'taxonomy';
  4411. $taxonomy = ( empty( $object ) ? $name : $object );
  4412. $info[ 'where' ] = array(
  4413. 'tt.taxonomy' => '`tt`.`' . $info[ 'field_type' ] . '` = "' . $taxonomy . '"'
  4414. );
  4415. // WPML Support
  4416. if ( is_object( $sitepress ) && $sitepress->is_translated_taxonomy( $taxonomy ) && !$icl_adjust_id_url_filter_off ) {
  4417. $info[ 'join' ][ 'wpml_translations' ] = "
  4418. LEFT JOIN `{$wpdb->prefix}icl_translations` AS `wpml_translations`
  4419. ON `wpml_translations`.`element_id` = `tt`.`term_taxonomy_id`
  4420. AND `wpml_translations`.`element_type` = 'tax_{$taxonomy}'
  4421. AND `wpml_translations`.`language_code` = '{$current_language}'
  4422. ";
  4423. $info[ 'join' ][ 'wpml_languages' ] = "
  4424. LEFT JOIN `{$wpdb->prefix}icl_languages` AS `wpml_languages`
  4425. ON `wpml_languages`.`code` = `wpml_translations`.`language_code` AND `wpml_languages`.`active` = 1
  4426. ";
  4427. $info[ 'where' ][ 'wpml_languages' ] = "`wpml_languages`.`code` IS NOT NULL";
  4428. }
  4429. // Polylang support
  4430. elseif ( is_object( $polylang ) && !empty( $current_language ) && function_exists( 'pll_is_translated_taxonomy' ) && pll_is_translated_taxonomy( $taxonomy ) ) {
  4431. $info[ 'join' ][ 'polylang_languages' ] = "
  4432. LEFT JOIN `{$wpdb->termmeta}` AS `polylang_languages`
  4433. ON `polylang_languages`.`term_id` = `t`.`term_id`
  4434. AND `polylang_languages`.`meta_value` = {$current_language_t_id}
  4435. ";
  4436. $info[ 'where' ][ 'polylang_languages' ] = "`polylang_languages`.`term_id` IS NOT NULL";
  4437. }
  4438. $info[ 'object_fields' ] = $this->get_wp_object_fields( $object_type, $pod );
  4439. }
  4440. elseif ( 'user' == $object_type ) {
  4441. $info[ 'table' ] = $wpdb->users;
  4442. $info[ 'meta_table' ] = $wpdb->usermeta;
  4443. $info[ 'field_id' ] = 'ID';
  4444. $info[ 'field_index' ] = 'display_name';
  4445. $info[ 'field_slug' ] = 'user_nicename';
  4446. $info[ 'meta_field_id' ] = 'user_id';
  4447. $info[ 'meta_field_index' ] = 'meta_key';
  4448. $info[ 'meta_field_value' ] = 'meta_value';
  4449. $info[ 'where' ] = array(
  4450. 'user_status' => '`t`.`user_status` = 0'
  4451. );
  4452. $info[ 'object_fields' ] = $this->get_wp_object_fields( $object_type, $pod );
  4453. }
  4454. elseif ( 'comment' == $object_type ) {
  4455. $info[ 'table' ] = $wpdb->comments;
  4456. $info[ 'meta_table' ] = $wpdb->commentmeta;
  4457. $info[ 'field_id' ] = 'comment_ID';
  4458. $info[ 'field_index' ] = 'comment_date';
  4459. $info[ 'field_type' ] = 'comment_type';
  4460. $info[ 'meta_field_id' ] = 'comment_id';
  4461. $info[ 'meta_field_index' ] = 'meta_key';
  4462. $info[ 'meta_field_value' ] = 'meta_value';
  4463. $object = 'comment';
  4464. $info[ 'where' ] = array(
  4465. 'comment_approved' => '`t`.`comment_approved` = 1',
  4466. 'comment_type' => '`t`.`' . $info[ 'field_type' ] . '` = "' . ( empty( $object ) ? $name : $object ) . '"'
  4467. );
  4468. $info[ 'orderby' ] = '`t`.`' . $info[ 'field_index' ] . '` DESC, `t`.`' . $info[ 'field_id' ] . '`';
  4469. }
  4470. elseif ( 'option' == $object_type ) {
  4471. $info[ 'table' ] = $wpdb->options;
  4472. $info[ 'meta_table' ] = $wpdb->options;
  4473. $info[ 'field_id' ] = 'option_id';
  4474. $info[ 'field_index' ] = 'option_name';
  4475. $info[ 'meta_field_id' ] = 'option_id';
  4476. $info[ 'meta_field_index' ] = 'option_name';
  4477. $info[ 'meta_field_value' ] = 'option_value';
  4478. $info[ 'orderby' ] = '`t`.`' . $info[ 'field_index' ] . '` ASC';
  4479. }
  4480. elseif ( is_multisite() && 'site_option' == $object_type ) {
  4481. $info[ 'table' ] = $wpdb->sitemeta;
  4482. $info[ 'meta_table' ] = $wpdb->sitemeta;
  4483. $info[ 'field_id' ] = 'site_id';
  4484. $info[ 'field_index' ] = 'meta_key';
  4485. $info[ 'meta_field_id' ] = 'site_id';
  4486. $info[ 'meta_field_index' ] = 'meta_key';
  4487. $info[ 'meta_field_value' ] = 'meta_value';
  4488. $info[ 'orderby' ] = '`t`.`' . $info[ 'field_index' ] . '` ASC';
  4489. }
  4490. elseif ( is_multisite() && 'network' == $object_type ) { // Network = Site
  4491. $info[ 'table' ] = $wpdb->site;
  4492. $info[ 'meta_table' ] = $wpdb->sitemeta;
  4493. $info[ 'field_id' ] = 'id';
  4494. $info[ 'field_index' ] = 'domain';
  4495. $info[ 'meta_field_id' ] = 'site_id';
  4496. $info[ 'meta_field_index' ] = 'meta_key';
  4497. $info[ 'meta_field_value' ] = 'meta_value';
  4498. $info[ 'orderby' ] = '`t`.`' . $info[ 'field_index' ] . '` ASC, `t`.`path` ASC, `t`.`' . $info[ 'field_id' ] . '`';
  4499. }
  4500. elseif ( is_multisite() && 'site' == $object_type ) { // Site = Blog
  4501. $info[ 'table' ] = $wpdb->blogs;
  4502. $info[ 'field_id' ] = 'blog_id';
  4503. $info[ 'field_index' ] = 'domain';
  4504. $info[ 'field_type' ] = 'site_id';
  4505. $info[ 'where' ] = array(
  4506. 'archived' => '`t`.`archived` = 0',
  4507. 'spam' => '`t`.`spam` = 0',
  4508. 'deleted' => '`t`.`deleted` = 0',
  4509. 'site_id' => '`t`.`' . $info[ 'field_type' ] . '` = ' . (int) get_current_site()->id
  4510. );
  4511. $info[ 'orderby' ] = '`t`.`' . $info[ 'field_index' ] . '` ASC, `t`.`path` ASC, `t`.`' . $info[ 'field_id' ] . '`';
  4512. }
  4513. elseif ( 'table' == $object_type ) {
  4514. $info[ 'table' ] = ( empty( $object ) ? $name : $object );
  4515. if ( !empty( $field ) && is_array( $field ) ) {
  4516. $info[ 'field_id' ] = pods_var_raw( 'pick_table_id', pods_var_raw( 'options', $field, $field ) );
  4517. $info[ 'field_index' ] = $info[ 'meta_field_index' ] = $info[ 'meta_field_value' ] = pods_var_raw( 'pick_table_index', pods_var_raw( 'options', $field, $field ) );
  4518. }
  4519. elseif ( !empty( $pod ) && is_array( $pod ) && 'table' == pods_var( 'type', $pod ) )
  4520. $info[ 'field_index' ] = $info[ 'meta_field_index' ] = $info[ 'meta_field_value' ] = pods_var( 'pod_index', $pod[ 'options' ], 'id', null, true );
  4521. }
  4522. $info[ 'table' ] = pods_clean_name( $info[ 'table' ], false, false );
  4523. $info[ 'meta_table' ] = pods_clean_name( $info[ 'meta_table' ], false, false );
  4524. $info[ 'field_id' ] = pods_clean_name( $info[ 'field_id' ], false, false );
  4525. $info[ 'field_index' ] = pods_clean_name( $info[ 'field_index' ], false, false );
  4526. $info[ 'field_slug' ] = pods_clean_name( $info[ 'field_slug' ], false, false );
  4527. $info[ 'meta_field_id' ] = pods_clean_name( $info[ 'meta_field_id' ], false, false );
  4528. $info[ 'meta_field_index' ] = pods_clean_name( $info[ 'meta_field_index' ], false, false );
  4529. $info[ 'meta_field_value' ] = pods_clean_name( $info[ 'meta_field_value' ], false, false );
  4530. if ( empty( $info[ 'orderby' ] ) )
  4531. $info[ 'orderby' ] = '`t`.`' . $info[ 'field_index' ] . '`, `t`.`' . $info[ 'field_id' ] . '`';
  4532. if ( !empty( $pod ) && 'table' == $pod[ 'storage' ] && !in_array( $object_type, array( 'pod', 'table' ) ) ) {
  4533. $info[ 'join' ][ 'd' ] = "LEFT JOIN `{$wpdb->prefix}pods_{$name}` AS `d` ON `d`.`id` = `t`.`" . $info[ 'field_id' ] . '`';
  4534. //$info[ 'select' ] .= ', `d`.*';
  4535. }
  4536. if ( !empty( $info[ 'pod' ] ) && is_array( $info[ 'pod' ] ) ) {
  4537. $info[ 'recurse' ] = true;
  4538. if ( !empty( $pod ) && 'table' == $pod[ 'storage' ] && !in_array( $object_type, array( 'pod', 'table' ) ) )
  4539. $info[ 'pod_table' ] = "{$wpdb->prefix}pods_{$name}";
  4540. }
  4541. $info[ 'type' ] = $object_type;
  4542. if ( did_action( 'init' ) )
  4543. pods_transient_set( $transient, $info );
  4544. }
  4545. $info = $this->do_hook( 'get_table_info', $info, $object_type, $object );
  4546. return $info;
  4547. }
  4548. /**
  4549. * Export a package
  4550. *
  4551. * $params['pod'] string Pod Type IDs to export
  4552. * $params['template'] string Template IDs to export
  4553. * $params['podpage'] string Pod Page IDs to export
  4554. * $params['helper'] string Helper IDs to export
  4555. *
  4556. * @param array $params An associative array of parameters
  4557. *
  4558. * @return array|bool
  4559. *
  4560. * @since 1.9.0
  4561. * @deprecated 2.0.0
  4562. */
  4563. public function export_package ( $params ) {
  4564. if ( class_exists( 'Pods_Migrate_Packages' ) )
  4565. return Pods_Migrate_Packages::export( $params );
  4566. return false;
  4567. }
  4568. /**
  4569. * Replace an existing package
  4570. *
  4571. * @param mixed $data (optional) An associative array containing a package, or the json encoded package
  4572. *
  4573. * @return bool
  4574. *
  4575. * @since 1.9.8
  4576. * @deprecated 2.0.0
  4577. */
  4578. public function replace_package ( $data = false ) {
  4579. return $this->import_package( $data, true );
  4580. }
  4581. /**
  4582. * Import a package
  4583. *
  4584. * @param mixed $data (optional) An associative array containing a package, or the json encoded package
  4585. * @param bool $replace (optional) Replace existing items when found
  4586. *
  4587. * @return bool
  4588. *
  4589. * @since 1.9.0
  4590. * @deprecated 2.0.0
  4591. */
  4592. public function import_package ( $data = false, $replace = false ) {
  4593. if ( class_exists( 'Pods_Migrate_Packages' ) )
  4594. return Pods_Migrate_Packages::import( $data, $replace );
  4595. return false;
  4596. }
  4597. /**
  4598. * Validate a package
  4599. *
  4600. * @param array|string $data (optional) An associative array containing a package, or the json encoded package
  4601. * @param bool $output (optional)
  4602. *
  4603. * @return array|bool
  4604. *
  4605. * @since 1.9.0
  4606. * @deprecated 2.0.0
  4607. */
  4608. public function validate_package ( $data = false, $output = false ) {
  4609. return true;
  4610. }
  4611. /**
  4612. * Import data from an array or a CSV file.
  4613. *
  4614. * @param mixed $import_data PHP associative array or CSV input
  4615. * @param bool $numeric_mode Use IDs instead of the name field when matching
  4616. * @param string $format Format of import data, options are php or csv
  4617. *
  4618. * @return array
  4619. * @since 1.7.1
  4620. * @todo This needs some love and use of table_info etc for relationships
  4621. */
  4622. public function import ( $import_data, $numeric_mode = false, $format = null ) {
  4623. /**
  4624. * @var $wpdb wpdb
  4625. */
  4626. global $wpdb;
  4627. if ( null === $format && null !== $this->format )
  4628. $format = $this->format;
  4629. if ( 'csv' == $format )
  4630. $import_data = $this->csv_to_php( $import_data );
  4631. pods_query( "SET NAMES utf8" );
  4632. pods_query( "SET CHARACTER SET utf8" );
  4633. // Loop through the array of items
  4634. $ids = array();
  4635. // Test to see if it's an array of arrays
  4636. if ( !is_array( @current( $import_data ) ) )
  4637. $import_data = array( $import_data );
  4638. $pod = $this->load_pod( array( 'name' => $this->pod ) );
  4639. if ( false === $pod )
  4640. return pods_error( __( 'Pod not found', 'pods' ), $this );
  4641. $fields = array_merge( $pod[ 'fields' ], $pod[ 'object_fields' ] );
  4642. $simple_tableless_objects = PodsForm::field_method( 'pick', 'simple_objects' );
  4643. foreach ( $import_data as $key => $data_row ) {
  4644. $data = array();
  4645. // Loop through each field (use $fields so only valid fields get parsed)
  4646. foreach ( $fields as $field_name => $field_data ) {
  4647. if ( !isset( $data_row[ $field_name ] ) )
  4648. continue;
  4649. $field_id = $field_data[ 'id' ];
  4650. $type = $field_data[ 'type' ];
  4651. $pick_object = isset( $field_data[ 'pick_object' ] ) ? $field_data[ 'pick_object' ] : '';
  4652. $pick_val = isset( $field_data[ 'pick_val' ] ) ? $field_data[ 'pick_val' ] : '';
  4653. $field_value = $data_row[ $field_name ];
  4654. if ( null != $field_value && false !== $field_value ) {
  4655. if ( 'pick' == $type || 'file' == $type ) {
  4656. $field_values = is_array( $field_value ) ? $field_value : array( $field_value );
  4657. $pick_values = array();
  4658. foreach ( $field_values as $pick_value ) {
  4659. if ( 'file' == $type || 'media' == $pick_object ) {
  4660. $where = "`guid` = '" . pods_sanitize( $pick_value ) . "'";
  4661. if ( 0 < pods_absint( $pick_value ) && false !== $numeric_mode )
  4662. $where = "`ID` = " . pods_absint( $pick_value );
  4663. $result = pods_query( "SELECT `ID` AS `id` FROM `{$wpdb->posts}` WHERE `post_type` = 'attachment' AND {$where} ORDER BY `ID`", $this );
  4664. if ( !empty( $result ) )
  4665. $pick_values[] = $result[ 0 ]->id;
  4666. }
  4667. // @todo This could and should be abstracted better and simplified
  4668. elseif ( 'pick' == $type ) {
  4669. $related_pod = false;
  4670. if ( 'pod' == $pick_object )
  4671. $related_pod = $this->load_pod( array( 'name' => $pick_val ), false );
  4672. if ( empty( $related_pod ) ) {
  4673. $related_pod = array(
  4674. 'id' => 0,
  4675. 'type' => $pick_object
  4676. );
  4677. }
  4678. if ( in_array( 'taxonomy', array( $pick_object, $related_pod[ 'type' ] ) ) ) {
  4679. $where = "`t`.`name` = '" . pods_sanitize( $pick_value ) . "'";
  4680. if ( 0 < pods_absint( $pick_value ) && false !== $numeric_mode )
  4681. $where = "`tt`.`term_id` = " . pods_absint( $pick_value );
  4682. $result = pods_query( "SELECT `t`.`term_id` AS `id` FROM `{$wpdb->term_taxonomy}` AS `tt` LEFT JOIN `{$wpdb->terms}` AS `t` ON `t`.`term_id` = `tt`.`term_id` WHERE `taxonomy` = '{$pick_val}' AND {$where} ORDER BY `t`.`term_id`", $this );
  4683. if ( !empty( $result ) )
  4684. $pick_values[] = $result[ 0 ]->id;
  4685. }
  4686. elseif ( in_array( 'post_type', array( $pick_object, $related_pod[ 'type' ] ) ) || in_array( 'media', array( $pick_object, $related_pod[ 'type' ] ) ) ) {
  4687. $where = "`post_title` = '" . pods_sanitize( $pick_value ) . "'";
  4688. if ( 0 < pods_absint( $pick_value ) && false !== $numeric_mode )
  4689. $where = "`ID` = " . pods_absint( $pick_value );
  4690. $result = pods_query( "SELECT `ID` AS `id` FROM `{$wpdb->posts}` WHERE `post_type` = '{$pick_val}' AND {$where} ORDER BY `ID`", $this );
  4691. if ( !empty( $result ) )
  4692. $pick_values[] = $result[ 0 ]->id;
  4693. }
  4694. elseif ( in_array( 'user', array( $pick_object, $related_pod[ 'type' ] ) ) ) {
  4695. $where = "`user_login` = '" . pods_sanitize( $pick_value ) . "'";
  4696. if ( 0 < pods_absint( $pick_value ) && false !== $numeric_mode )
  4697. $where = "`ID` = " . pods_absint( $pick_value );
  4698. $result = pods_query( "SELECT `ID` AS `id` FROM `{$wpdb->users}` WHERE {$where} ORDER BY `ID`", $this );
  4699. if ( !empty( $result ) )
  4700. $pick_values[] = $result[ 0 ]->id;
  4701. }
  4702. elseif ( in_array( 'comment', array( $pick_object, $related_pod[ 'type' ] ) ) ) {
  4703. $where = "`comment_ID` = " . pods_absint( $pick_value );
  4704. $result = pods_query( "SELECT `comment_ID` AS `id` FROM `{$wpdb->comments}` WHERE {$where} ORDER BY `ID`", $this );
  4705. if ( !empty( $result ) )
  4706. $pick_values[] = $result[ 0 ]->id;
  4707. }
  4708. elseif ( in_array( $pick_object, $simple_tableless_objects ) )
  4709. $pick_values[] = $pick_value;
  4710. elseif ( !empty( $related_pod[ 'id' ] ) ) {
  4711. $where = "`" . $related_pod[ 'field_index' ] . "` = '" . pods_sanitize( $pick_value ) . "'";
  4712. if ( 0 < pods_absint( $pick_value ) && false !== $numeric_mode )
  4713. $where = "`" . $related_pod[ 'field_id' ] . "` = " . pods_absint( $pick_value );
  4714. $result = pods_query( "SELECT `" . $related_pod[ 'field_id' ] . "` AS `id` FROM `" . $related_pod[ 'table' ] . "` WHERE {$where} ORDER BY `" . $related_pod[ 'field_id' ] . "`", $this );
  4715. if ( !empty( $result ) )
  4716. $pick_values[] = $result[ 0 ]->id;
  4717. }
  4718. }
  4719. }
  4720. $field_value = implode( ',', $pick_values );
  4721. }
  4722. $data[ $field_name ] = $field_value;
  4723. }
  4724. }
  4725. if ( !empty( $data ) ) {
  4726. $params = array(
  4727. 'pod' => $this->pod,
  4728. 'data' => $data
  4729. );
  4730. $ids[] = $this->save_pod_item( $params );
  4731. }
  4732. }
  4733. return $ids;
  4734. }
  4735. /**
  4736. * Export data from a Pod
  4737. *
  4738. * @param string|object $pod The pod name or Pods object
  4739. * @param array $params An associative array of parameters
  4740. *
  4741. * @return array Data arrays of all exported pod items
  4742. * @since 1.7.1
  4743. */
  4744. public function export ( $pod = null, $params = null ) {
  4745. if ( empty( $pod ) )
  4746. $pod = $this->pod;
  4747. $find = array(
  4748. 'limit' => -1,
  4749. 'search' => false,
  4750. 'pagination' => false
  4751. );
  4752. if ( !empty( $params ) && isset( $params[ 'params' ] ) ) {
  4753. $find = array_merge( $find, (array) $params[ 'params' ] );
  4754. unset( $params[ 'params' ] );
  4755. $pod = pods( $pod, $find );
  4756. }
  4757. elseif ( !is_object( $pod ) )
  4758. $pod = pods( $pod, $find );
  4759. $data = array();
  4760. while ( $pod->fetch() ) {
  4761. $data[ $pod->id() ] = $this->export_pod_item( $params, $pod );
  4762. }
  4763. $data = $this->do_hook( 'export', $data, $pod->pod, $pod );
  4764. return $data;
  4765. }
  4766. /**
  4767. * Convert CSV to a PHP array
  4768. *
  4769. * @param string $data The CSV input
  4770. *
  4771. * @return array
  4772. * @since 1.7.1
  4773. */
  4774. public function csv_to_php ( $data, $delimiter = ',' ) {
  4775. $expr = "/{$delimiter}(?=(?:[^\"]*\"[^\"]*\")*(?![^\"]*\"))/";
  4776. $data = str_replace( "\r\n", "\n", $data );
  4777. $data = str_replace( "\r", "\n", $data );
  4778. $lines = explode( "\n", $data );
  4779. $field_names = array_shift( $lines );
  4780. if ( function_exists( 'str_getcsv' ) )
  4781. $field_names = str_getcsv( $field_names, $delimiter );
  4782. else {
  4783. $field_names = explode( $delimiter, $field_names );
  4784. $field_names = preg_replace( "/^\"(.*)\"$/s", "$1", $field_names );
  4785. }
  4786. $out = array();
  4787. foreach ( $lines as $line ) {
  4788. // Skip the empty line
  4789. if ( strlen ( $line ) < 1 )
  4790. continue;
  4791. $row = array();
  4792. if ( function_exists( 'str_getcsv' ) )
  4793. $fields = str_getcsv( $line, $delimiter );
  4794. else {
  4795. $fields = preg_split( $expr, trim( $line ) );
  4796. $fields = preg_replace( "/^\"(.*)\"$/s", "$1", $fields );
  4797. }
  4798. foreach ( $field_names as $key => $field ) {
  4799. $row[ $field ] = $fields[ $key ];
  4800. }
  4801. $out[] = $row;
  4802. }
  4803. return $out;
  4804. }
  4805. /**
  4806. * Clear Pod-related cache
  4807. *
  4808. * @param array $pod
  4809. */
  4810. public function cache_flush_pods ( $pod = null ) {
  4811. /**
  4812. * @var $wpdb wpdb
  4813. */
  4814. global $wpdb;
  4815. pods_transient_clear( 'pods' );
  4816. pods_transient_clear( 'pods_components' );
  4817. if ( null !== $pod && is_array( $pod ) ) {
  4818. pods_transient_clear( 'pods_pod_' . $pod[ 'name' ] );
  4819. if ( in_array( $pod[ 'type' ], array( 'post_type', 'taxonomy' ) ) )
  4820. pods_transient_clear( 'pods_wp_cpt_ct' );
  4821. }
  4822. else
  4823. pods_transient_clear( 'pods_wp_cpt_ct' );
  4824. $wpdb->query( "DELETE FROM `{$wpdb->options}` WHERE `option_name` LIKE '_transient_pods%'" );
  4825. $wpdb->query( "DELETE FROM `{$wpdb->options}` WHERE `option_name` LIKE '_transient_timeout_pods%'" );
  4826. pods_cache_clear( true );
  4827. pods_transient_set( 'pods_flush_rewrites', 1 );
  4828. }
  4829. /**
  4830. * Process a Pod-based form
  4831. *
  4832. * @param mixed $params
  4833. * @param object $obj Pod object
  4834. * @param array $fields Fields being submitted in form ( key => settings )
  4835. * @param string $thank_you URL to send to upon success
  4836. *
  4837. * @return mixed
  4838. */
  4839. public function process_form ( $params, $obj = null, $fields = null, $thank_you = null ) {
  4840. $this->display_errors = false;
  4841. $form = null;
  4842. $nonce = pods_var( '_pods_nonce', $params );
  4843. $pod = pods_var( '_pods_pod', $params );
  4844. $id = pods_var( '_pods_id', $params );
  4845. $uri = pods_var( '_pods_uri', $params );
  4846. $form = pods_var( '_pods_form', $params );
  4847. if ( is_object( $obj ) ) {
  4848. $pod = $obj->pod;
  4849. $id = $obj->id();
  4850. }
  4851. if ( !empty( $fields ) ) {
  4852. $fields = array_keys( $fields );
  4853. $form = implode( ',', $fields );
  4854. }
  4855. else
  4856. $fields = explode( ',', $form );
  4857. if ( empty( $nonce ) || empty( $pod ) || empty( $uri ) || empty( $fields ) )
  4858. return pods_error( __( 'Invalid submission', 'pods' ), $this );
  4859. $uid = @session_id();
  4860. if ( is_user_logged_in() )
  4861. $uid = 'user_' . get_current_user_id();
  4862. $action = 'pods_form_' . $pod . '_' . $uid . '_' . $id . '_' . $uri . '_' . wp_hash( $form );
  4863. if ( empty( $uid ) )
  4864. return pods_error( __( 'Access denied for your session, please refresh and try again.', 'pods' ), $this );
  4865. if ( wp_verify_nonce( $nonce, $action ) )
  4866. return pods_error( __( 'Access denied, please refresh and try again.', 'pods' ), $this );
  4867. $data = array();
  4868. foreach ( $fields as $field ) {
  4869. $data[ $field ] = pods_var_raw( 'pods_field_' . $field, $params, '' );
  4870. }
  4871. $params = array(
  4872. 'pod' => $pod,
  4873. 'id' => $id,
  4874. 'data' => $data,
  4875. 'from' => 'process_form'
  4876. );
  4877. $id = $this->save_pod_item( $params );
  4878. if ( 0 < $id && !empty( $thank_you ) ) {
  4879. $thank_you = str_replace( 'X_ID_X', $id, $thank_you );
  4880. die( '<script type="text/javascript">document.location = \'' . addslashes( $thank_you ) . '\';</script>' );
  4881. }
  4882. return $id;
  4883. }
  4884. /**
  4885. * Handle filters / actions for the class
  4886. *
  4887. * @since 2.0.0
  4888. */
  4889. private function do_hook () {
  4890. $args = func_get_args();
  4891. if ( empty( $args ) )
  4892. return false;
  4893. $name = array_shift( $args );
  4894. return pods_do_hook( "api", $name, $args, $this );
  4895. }
  4896. /**
  4897. * Handle variables that have been deprecated
  4898. *
  4899. * @since 2.0.0
  4900. */
  4901. public function __get ( $name ) {
  4902. $name = (string) $name;
  4903. if ( !isset( $this->deprecated ) ) {
  4904. require_once( PODS_DIR . 'deprecated/classes/PodsAPI.php' );
  4905. $this->deprecated = new PodsAPI_Deprecated( $this );
  4906. }
  4907. $var = null;
  4908. if ( isset( $this->deprecated->{$name} ) ) {
  4909. pods_deprecated( "PodsAPI->{$name}", '2.0.0' );
  4910. $var = $this->deprecated->{$name};
  4911. }
  4912. else
  4913. pods_deprecated( "PodsAPI->{$name}", '2.0.0' );
  4914. return $var;
  4915. }
  4916. /**
  4917. * Handle methods that have been deprecated
  4918. *
  4919. * @since 2.0.0
  4920. */
  4921. public function __call ( $name, $args ) {
  4922. $name = (string) $name;
  4923. if ( !isset( $this->deprecated ) ) {
  4924. require_once( PODS_DIR . 'deprecated/classes/PodsAPI.php' );
  4925. $this->deprecated = new PodsAPI_Deprecated( $this );
  4926. }
  4927. if ( method_exists( $this->deprecated, $name ) )
  4928. return call_user_func_array( array( $this->deprecated, $name ), $args );
  4929. else
  4930. pods_deprecated( "PodsAPI::{$name}", '2.0.0' );
  4931. }
  4932. }